+static void
+vcl_send_session_accepted_reply (svm_msg_q_t * mq, u32 context,
+ session_handle_t handle, int retval)
+{
+ app_session_evt_t _app_evt, *app_evt = &_app_evt;
+ session_accepted_reply_msg_t *rmp;
+ app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_ACCEPTED_REPLY);
+ rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
+ rmp->handle = handle;
+ rmp->context = context;
+ rmp->retval = retval;
+ app_send_ctrl_evt_to_vpp (mq, app_evt);
+}
+
+static void
+vcl_send_session_disconnected_reply (svm_msg_q_t * mq, u32 context,
+ session_handle_t handle, int retval)
+{
+ app_session_evt_t _app_evt, *app_evt = &_app_evt;
+ session_disconnected_reply_msg_t *rmp;
+ app_alloc_ctrl_evt_to_vpp (mq, app_evt,
+ SESSION_CTRL_EVT_DISCONNECTED_REPLY);
+ rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
+ rmp->handle = handle;
+ rmp->context = context;
+ rmp->retval = retval;
+ app_send_ctrl_evt_to_vpp (mq, app_evt);
+}
+
+static u32
+vcl_session_accepted_handler (session_accepted_msg_t * mp)
+{
+ vcl_session_t *session, *listen_session;
+ svm_fifo_t *rx_fifo, *tx_fifo;
+ u32 session_index, vpp_wrk_index;
+ svm_msg_q_t *evt_q;
+
+ VCL_SESSION_LOCK ();
+
+ session = vcl_session_alloc ();
+ session_index = vcl_session_index (session);
+
+ listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
+ if (!listen_session)
+ {
+ svm_msg_q_t *evt_q;
+ evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
+ clib_warning ("VCL<%d>: ERROR: couldn't find listen session: "
+ "unknown vpp listener handle %llx",
+ getpid (), mp->listener_handle);
+ vcl_send_session_accepted_reply (evt_q, mp->context, mp->handle,
+ VNET_API_ERROR_INVALID_ARGUMENT);
+ vcl_session_free (session);
+ VCL_SESSION_UNLOCK ();
+ return VCL_INVALID_SESSION_INDEX;
+ }
+
+ rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
+ tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
+
+ if (mp->server_event_queue_address)
+ {
+ session->vpp_evt_q = uword_to_pointer (mp->client_event_queue_address,
+ svm_msg_q_t *);
+ session->our_evt_q = uword_to_pointer (mp->server_event_queue_address,
+ svm_msg_q_t *);
+ vcl_wait_for_memory (session->vpp_evt_q);
+ rx_fifo->master_session_index = session_index;
+ tx_fifo->master_session_index = session_index;
+ vec_validate (vcm->vpp_event_queues, 0);
+ evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
+ vcm->vpp_event_queues[0] = evt_q;
+ }
+ else
+ {
+ session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
+ svm_msg_q_t *);
+ rx_fifo->client_session_index = session_index;
+ tx_fifo->client_session_index = session_index;
+
+ vpp_wrk_index = tx_fifo->master_thread_index;
+ vec_validate (vcm->vpp_event_queues, vpp_wrk_index);
+ vcm->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
+ }
+
+ session->vpp_handle = mp->handle;
+ session->client_context = mp->context;
+ session->rx_fifo = rx_fifo;
+ session->tx_fifo = tx_fifo;
+
+ session->session_state = STATE_ACCEPT;
+ session->transport.rmt_port = mp->port;
+ session->transport.is_ip4 = mp->is_ip4;
+ clib_memcpy (&session->transport.rmt_ip, mp->ip, sizeof (ip46_address_t));
+
+ hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
+ session->transport.lcl_port = listen_session->transport.lcl_port;
+ session->transport.lcl_ip = listen_session->transport.lcl_ip;
+ session->session_type = listen_session->session_type;
+ session->is_dgram = session->session_type == VPPCOM_PROTO_UDP;
+
+ VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: client accept request from %s"
+ " address %U port %d queue %p!", getpid (), mp->handle, session_index,
+ mp->is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &mp->ip,
+ mp->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
+ clib_net_to_host_u16 (mp->port), session->vpp_evt_q);
+ vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index);
+
+ VCL_SESSION_UNLOCK ();
+ return session_index;
+}
+
+static u32
+vcl_session_connected_handler (session_connected_msg_t * mp)
+{
+ u32 session_index, vpp_wrk_index;
+ svm_fifo_t *rx_fifo, *tx_fifo;
+ vcl_session_t *session = 0;
+ svm_msg_q_t *evt_q;
+ int rv = VPPCOM_OK;
+
+ session_index = mp->context;
+ VCL_SESSION_LOCK_AND_GET (session_index, &session);
+done:
+ if (mp->retval)
+ {
+ clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
+ "connect failed! %U",
+ getpid (), mp->handle, session_index,
+ format_api_error, ntohl (mp->retval));
+ if (session)
+ {
+ session->session_state = STATE_FAILED;
+ session->vpp_handle = mp->handle;
+ }
+ else
+ {
+ clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
+ "Invalid session index (%u)!",
+ getpid (), mp->handle, session_index);
+ }
+ goto done_unlock;
+ }
+
+ if (rv)
+ goto done_unlock;
+
+ rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
+ tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
+ vcl_wait_for_memory (rx_fifo);
+ rx_fifo->client_session_index = session_index;
+ tx_fifo->client_session_index = session_index;
+
+ if (mp->client_event_queue_address)
+ {
+ session->vpp_evt_q = uword_to_pointer (mp->server_event_queue_address,
+ svm_msg_q_t *);
+ session->our_evt_q = uword_to_pointer (mp->client_event_queue_address,
+ svm_msg_q_t *);
+
+ vec_validate (vcm->vpp_event_queues, 0);
+ evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
+ vcm->vpp_event_queues[0] = evt_q;
+ }
+ else
+ {
+ session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
+ svm_msg_q_t *);
+ vpp_wrk_index = tx_fifo->master_thread_index;
+ vec_validate (vcm->vpp_event_queues, vpp_wrk_index);
+ vcm->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
+ }
+
+ session->rx_fifo = rx_fifo;
+ session->tx_fifo = tx_fifo;
+ session->vpp_handle = mp->handle;
+ session->transport.is_ip4 = mp->is_ip4;
+ clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
+ sizeof (session->transport.lcl_ip));
+ session->transport.lcl_port = mp->lcl_port;
+ session->session_state = STATE_CONNECT;
+
+ /* Add it to lookup table */
+ hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
+
+ VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded! "
+ "session_rx_fifo %p, refcnt %d, session_tx_fifo %p, refcnt %d",
+ getpid (), mp->handle, session_index, session->rx_fifo,
+ session->rx_fifo->refcnt, session->tx_fifo, session->tx_fifo->refcnt);
+done_unlock:
+ VCL_SESSION_UNLOCK ();
+ return session_index;
+}
+
+int
+vcl_handle_mq_ctrl_event (session_event_t * e)
+{
+ session_accepted_msg_t *accepted_msg;
+ session_disconnected_msg_t *disconnected_msg;
+ vcl_session_msg_t *vcl_msg;
+ vcl_session_t *session;
+ u64 handle;
+ u32 sid;
+
+ switch (e->event_type)
+ {
+ case FIFO_EVENT_APP_RX:
+ clib_warning ("unhandled rx: sid %u (0x%x)",
+ e->fifo->client_session_index,
+ e->fifo->client_session_index);
+ break;
+ case SESSION_CTRL_EVT_ACCEPTED:
+ accepted_msg = (session_accepted_msg_t *) e->data;
+ handle = accepted_msg->listener_handle;
+ session = vppcom_session_table_lookup_listener (handle);
+ if (!session)
+ {
+ clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
+ "listener handle %llx", getpid (), handle);
+ break;
+ }
+
+ clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
+ vcl_msg->accepted_msg = *accepted_msg;
+ break;
+ case SESSION_CTRL_EVT_CONNECTED:
+ vcl_session_connected_handler ((session_connected_msg_t *) e->data);
+ break;
+ case SESSION_CTRL_EVT_DISCONNECTED:
+ disconnected_msg = (session_disconnected_msg_t *) e->data;
+ sid = vcl_session_get_index_from_handle (disconnected_msg->handle);
+ session = vcl_session_get (sid);
+ session->session_state = STATE_DISCONNECT;
+ VDBG (0, "disconnected %u", sid);
+ break;
+ default:
+ clib_warning ("unhandled %u", e->event_type);
+ }
+ return VPPCOM_OK;
+}
+