+ VDBG (0, "disconnect confirmed for unknown handle 0x%llx", msg->handle);
+ return;
+ }
+
+ if (msg->type == SESSION_CLEANUP_TRANSPORT)
+ {
+ /* Transport was cleaned up before we confirmed close. Probably the
+ * app is still waiting for some data that cannot be delivered.
+ * Confirm close to make sure everything is cleaned up.
+ * Move to undetermined state to ensure that the session is not
+ * removed before both vpp and the app cleanup.
+ * - If the app closes first, the session is moved to CLOSED state
+ * and the session cleanup notification from vpp removes the
+ * session.
+ * - If vpp cleans up the session first, the session is moved to
+ * DETACHED state lower and subsequently the close from the app
+ * frees the session
+ */
+ if (session->session_state == VCL_STATE_VPP_CLOSING)
+ {
+ vppcom_session_disconnect (vcl_session_handle (session));
+ session->session_state = VCL_STATE_UPDATED;
+ }
+ else if (session->session_state == VCL_STATE_DISCONNECT)
+ {
+ vcl_send_session_reset_reply (wrk, session, 0);
+ session->session_state = VCL_STATE_UPDATED;
+ }
+ return;
+ }
+
+ vcl_session_table_del_vpp_handle (wrk, msg->handle);
+ /* Should not happen. App did not close the connection so don't free it. */
+ if (session->session_state != VCL_STATE_CLOSED)
+ {
+ VDBG (0, "app did not close session %d", session->session_index);
+ session->session_state = VCL_STATE_DETACHED;
+ session->vpp_handle = VCL_INVALID_SESSION_HANDLE;
+ return;
+ }
+ vcl_session_free (wrk, session);
+}
+
+static void
+vcl_session_req_worker_update_handler (vcl_worker_t * wrk, void *data)
+{
+ session_req_worker_update_msg_t *msg;
+ vcl_session_t *s;
+
+ msg = (session_req_worker_update_msg_t *) data;
+ s = vcl_session_get_w_vpp_handle (wrk, msg->session_handle);
+ if (!s)
+ return;
+
+ vec_add1 (wrk->pending_session_wrk_updates, s->session_index);
+}
+
+static void
+vcl_session_worker_update_reply_handler (vcl_worker_t * wrk, void *data)
+{
+ session_worker_update_reply_msg_t *msg;
+ vcl_session_t *s;
+
+ msg = (session_worker_update_reply_msg_t *) data;
+ s = vcl_session_get_w_vpp_handle (wrk, msg->handle);
+ if (!s)
+ {
+ VDBG (0, "unknown handle 0x%llx", msg->handle);
+ return;
+ }
+
+ if (s->rx_fifo)
+ {
+ if (vcl_segment_attach_session (msg->segment_handle, msg->rx_fifo,
+ msg->tx_fifo, (uword) ~0, 0, s))
+ {
+ VDBG (0, "failed to attach fifos for %u", s->session_index);
+ return;
+ }
+ }
+ s->session_state = VCL_STATE_UPDATED;
+
+ VDBG (0, "session %u[0x%llx] moved to worker %u", s->session_index,
+ s->vpp_handle, wrk->wrk_index);
+}
+
+static int
+vcl_api_recv_fd (vcl_worker_t * wrk, int *fds, int n_fds)
+{
+
+ if (vcm->cfg.vpp_app_socket_api)
+ return vcl_sapi_recv_fds (wrk, fds, n_fds);
+
+ return vcl_bapi_recv_fds (wrk, fds, n_fds);
+}
+
+static void
+vcl_session_app_add_segment_handler (vcl_worker_t * wrk, void *data)
+{
+ ssvm_segment_type_t seg_type = SSVM_SEGMENT_SHM;
+ session_app_add_segment_msg_t *msg;
+ u64 segment_handle;
+ int fd = -1;
+
+ msg = (session_app_add_segment_msg_t *) data;
+
+ if (msg->fd_flags)
+ {
+ vcl_api_recv_fd (wrk, &fd, 1);
+ seg_type = SSVM_SEGMENT_MEMFD;
+ }
+
+ segment_handle = msg->segment_handle;
+ if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
+ {
+ clib_warning ("invalid segment handle");
+ return;
+ }
+
+ if (vcl_segment_attach (segment_handle, (char *) msg->segment_name,
+ seg_type, fd))
+ {
+ VDBG (0, "vcl_segment_attach ('%s') failed", msg->segment_name);
+ return;
+ }
+
+ VDBG (1, "mapped new segment '%s' size %d", msg->segment_name,
+ msg->segment_size);
+}
+
+static void
+vcl_session_app_del_segment_handler (vcl_worker_t * wrk, void *data)
+{
+ session_app_del_segment_msg_t *msg = (session_app_del_segment_msg_t *) data;
+ vcl_segment_detach (msg->segment_handle);
+ VDBG (1, "Unmapped segment: %d", msg->segment_handle);
+}
+
+static void
+vcl_worker_rpc_handler (vcl_worker_t * wrk, void *data)
+{
+ if (!vcm->wrk_rpc_fn)
+ return;
+
+ (vcm->wrk_rpc_fn) (((session_app_wrk_rpc_msg_t *) data)->data);
+}
+
+static void
+vcl_session_transport_attr_reply_handler (vcl_worker_t *wrk, void *data)
+{
+ session_transport_attr_reply_msg_t *mp;
+
+ if (!wrk->session_attr_op)
+ return;
+
+ mp = (session_transport_attr_reply_msg_t *) data;
+
+ wrk->session_attr_op_rv = mp->retval;
+ wrk->session_attr_op = 0;
+ wrk->session_attr_rv = mp->attr;
+}
+
+static int
+vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
+{
+ session_disconnected_msg_t *disconnected_msg;
+ session_connected_msg_t *connected_msg;
+ session_reset_msg_t *reset_msg;
+ session_event_t *ecpy;
+ vcl_session_t *s;
+ u32 sid;
+
+ switch (e->event_type)
+ {
+ case SESSION_IO_EVT_RX:
+ case SESSION_IO_EVT_TX:
+ s = vcl_session_get (wrk, e->session_index);
+ if (!s || !vcl_session_is_open (s))
+ break;
+ vec_add1 (wrk->unhandled_evts_vector, *e);
+ break;
+ case SESSION_CTRL_EVT_BOUND:
+ /* We can only wait for only one listen so not postponed */
+ vcl_session_bound_handler (wrk, (session_bound_msg_t *) e->data);
+ break;
+ case SESSION_CTRL_EVT_ACCEPTED:
+ s = vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
+ if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
+ {
+ vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
+ *ecpy = *e;
+ ecpy->postponed = 1;
+ ecpy->session_index = s->session_index;
+ }
+ break;
+ case SESSION_CTRL_EVT_CONNECTED:
+ connected_msg = (session_connected_msg_t *) e->data;
+ sid = vcl_session_connected_handler (wrk, connected_msg);
+ if (!(s = vcl_session_get (wrk, sid)))
+ break;
+ if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
+ {
+ vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
+ *ecpy = *e;
+ ecpy->postponed = 1;
+ ecpy->session_index = s->session_index;
+ }
+ break;
+ case SESSION_CTRL_EVT_DISCONNECTED: