+int vnet_application_detach (vnet_app_detach_args_t * a);
+int vnet_disconnect_session (vnet_disconnect_args_t * a);
+
+clib_error_t *vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a);
+clib_error_t *vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a);
+
+extern const char test_srv_crt_rsa[];
+extern const u32 test_srv_crt_rsa_len;
+extern const char test_srv_key_rsa[];
+extern const u32 test_srv_key_rsa_len;
+
+typedef struct app_session_transport_
+{
+ ip46_address_t rmt_ip; /**< remote ip */
+ ip46_address_t lcl_ip; /**< local ip */
+ u16 rmt_port; /**< remote port (network order) */
+ u16 lcl_port; /**< local port (network order) */
+ u8 is_ip4; /**< set if uses ip4 networking */
+} app_session_transport_t;
+
+#define foreach_app_session_field \
+ _(svm_fifo_t, *rx_fifo) /**< rx fifo */ \
+ _(svm_fifo_t, *tx_fifo) /**< tx fifo */ \
+ _(session_type_t, session_type) /**< session type */ \
+ _(volatile u8, session_state) /**< session state */ \
+ _(u32, session_index) /**< index in owning pool */ \
+ _(app_session_transport_t, transport) /**< transport info */ \
+ _(svm_msg_q_t, *vpp_evt_q) /**< vpp event queue */ \
+ _(u8, is_dgram) /**< flag for dgram mode */ \
+
+typedef struct
+{
+#define _(type, name) type name;
+ foreach_app_session_field
+#undef _
+} app_session_t;
+
+typedef struct session_bound_msg_
+{
+ u32 context;
+ u64 handle;
+ i32 retval;
+ u8 lcl_is_ip4;
+ u8 lcl_ip[16];
+ u16 lcl_port;
+ u64 rx_fifo;
+ u64 tx_fifo;
+ u64 vpp_evt_q;
+ u32 segment_size;
+ u8 segment_name_length;
+ u8 segment_name[128];
+} __clib_packed session_bound_msg_t;
+
+typedef struct session_accepted_msg_
+{
+ u32 context;
+ u64 listener_handle;
+ u64 handle;
+ u64 server_rx_fifo;
+ u64 server_tx_fifo;
+ u64 segment_handle;
+ u64 vpp_event_queue_address;
+ u64 server_event_queue_address;
+ u64 client_event_queue_address;
+ u16 port;
+ u8 is_ip4;
+ u8 ip[16];
+} __clib_packed session_accepted_msg_t;
+
+typedef struct session_accepted_reply_msg_
+{
+ u32 context;
+ i32 retval;
+ u64 handle;
+} __clib_packed session_accepted_reply_msg_t;
+
+/* Make sure this is not too large, otherwise it won't fit when dequeued in
+ * the session queue node */
+STATIC_ASSERT (sizeof (session_accepted_reply_msg_t) <= 16, "accept reply");
+
+typedef struct session_connected_msg_
+{
+ u32 context;
+ i32 retval;
+ u64 handle;
+ u64 server_rx_fifo;
+ u64 server_tx_fifo;
+ u64 segment_handle;
+ u64 vpp_event_queue_address;
+ u64 client_event_queue_address;
+ u64 server_event_queue_address;
+ u32 segment_size;
+ u8 segment_name_length;
+ u8 segment_name[64];
+ u8 lcl_ip[16];
+ u8 is_ip4;
+ u16 lcl_port;
+} __clib_packed session_connected_msg_t;
+
+typedef struct session_disconnected_msg_
+{
+ u32 client_index;
+ u32 context;
+ u64 handle;
+} __clib_packed session_disconnected_msg_t;
+
+typedef struct session_disconnected_reply_msg_
+{
+ u32 context;
+ i32 retval;
+ u64 handle;
+} __clib_packed session_disconnected_reply_msg_t;
+
+typedef struct session_reset_msg_
+{
+ u32 client_index;
+ u32 context;
+ u64 handle;
+} __clib_packed session_reset_msg_t;
+
+typedef struct session_reset_reply_msg_
+{
+ u32 client_index;
+ u32 context;
+ i32 retval;
+ u64 handle;
+} __clib_packed session_reset_reply_msg_t;
+
+typedef struct app_session_event_
+{
+ svm_msg_q_msg_t msg;
+ session_event_t *evt;
+} __clib_packed app_session_evt_t;
+
+static inline void
+app_alloc_ctrl_evt_to_vpp (svm_msg_q_t * mq, app_session_evt_t * app_evt,
+ u8 evt_type)
+{
+ svm_msg_q_lock_and_alloc_msg_w_ring (mq,
+ SESSION_MQ_CTRL_EVT_RING,
+ SVM_Q_WAIT, &app_evt->msg);
+ svm_msg_q_unlock (mq);
+ app_evt->evt = svm_msg_q_msg_data (mq, &app_evt->msg);
+ clib_memset (app_evt->evt, 0, sizeof (*app_evt->evt));
+ app_evt->evt->event_type = evt_type;
+}
+
+static inline void
+app_send_ctrl_evt_to_vpp (svm_msg_q_t * mq, app_session_evt_t * app_evt)
+{
+ svm_msg_q_add (mq, &app_evt->msg, SVM_Q_WAIT);
+}
+
+/**
+ * Send fifo io event to vpp worker thread
+ *
+ * Because there may be multiple writers to one of vpp's queues, this
+ * protects message allocation and enqueueing.
+ *
+ * @param mq vpp message queue
+ * @param f fifo for which the event is sent
+ * @param evt_type type of event
+ * @param noblock flag to indicate is request is blocking or not
+ * @return 0 if success, negative integer otherwise
+ */
+static inline int
+app_send_io_evt_to_vpp (svm_msg_q_t * mq, svm_fifo_t * f, u8 evt_type,
+ u8 noblock)
+{
+ session_event_t *evt;
+ svm_msg_q_msg_t msg;
+
+ if (noblock)
+ {
+ if (svm_msg_q_try_lock (mq))
+ return -1;
+ if (PREDICT_FALSE (svm_msg_q_ring_is_full (mq, SESSION_MQ_IO_EVT_RING)))
+ {
+ svm_msg_q_unlock (mq);
+ return -2;
+ }
+ msg = svm_msg_q_alloc_msg_w_ring (mq, SESSION_MQ_IO_EVT_RING);
+ if (PREDICT_FALSE (svm_msg_q_msg_is_invalid (&msg)))
+ {
+ svm_msg_q_unlock (mq);
+ return -2;
+ }
+ evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg);
+ evt->fifo = f;
+ evt->event_type = evt_type;
+ svm_msg_q_add_and_unlock (mq, &msg);
+ return 0;
+ }
+ else
+ {
+ svm_msg_q_lock (mq);
+ while (svm_msg_q_ring_is_full (mq, SESSION_MQ_IO_EVT_RING))
+ svm_msg_q_wait (mq);
+ msg = svm_msg_q_alloc_msg_w_ring (mq, SESSION_MQ_IO_EVT_RING);
+ evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg);
+ evt->fifo = f;
+ evt->event_type = evt_type;
+ if (svm_msg_q_is_full (mq))
+ svm_msg_q_wait (mq);
+ svm_msg_q_add_and_unlock (mq, &msg);
+ return 0;
+ }
+}
+
+always_inline int
+app_send_dgram_raw (svm_fifo_t * f, app_session_transport_t * at,
+ svm_msg_q_t * vpp_evt_q, u8 * data, u32 len, u8 evt_type,
+ u8 noblock)
+{
+ u32 max_enqueue, actual_write;
+ session_dgram_hdr_t hdr;
+ int rv;
+
+ max_enqueue = svm_fifo_max_enqueue (f);
+ if (max_enqueue <= sizeof (session_dgram_hdr_t))
+ return 0;
+
+ max_enqueue -= sizeof (session_dgram_hdr_t);
+ actual_write = clib_min (len, max_enqueue);
+ hdr.data_length = actual_write;
+ hdr.data_offset = 0;
+ clib_memcpy_fast (&hdr.rmt_ip, &at->rmt_ip, sizeof (ip46_address_t));
+ hdr.is_ip4 = at->is_ip4;
+ hdr.rmt_port = at->rmt_port;
+ clib_memcpy_fast (&hdr.lcl_ip, &at->lcl_ip, sizeof (ip46_address_t));
+ hdr.lcl_port = at->lcl_port;
+ rv = svm_fifo_enqueue_nowait (f, sizeof (hdr), (u8 *) & hdr);
+ ASSERT (rv == sizeof (hdr));
+
+ if ((rv = svm_fifo_enqueue_nowait (f, actual_write, data)) > 0)
+ {
+ if (svm_fifo_set_event (f))
+ app_send_io_evt_to_vpp (vpp_evt_q, f, evt_type, noblock);
+ }
+ ASSERT (rv);
+ return rv;
+}
+
+always_inline int
+app_send_dgram (app_session_t * s, u8 * data, u32 len, u8 noblock)
+{
+ return app_send_dgram_raw (s->tx_fifo, &s->transport, s->vpp_evt_q, data,
+ len, FIFO_EVENT_APP_TX, noblock);
+}
+
+always_inline int
+app_send_stream_raw (svm_fifo_t * f, svm_msg_q_t * vpp_evt_q, u8 * data,
+ u32 len, u8 evt_type, u8 noblock)
+{
+ int rv;
+
+ if ((rv = svm_fifo_enqueue_nowait (f, len, data)) > 0)
+ {
+ if (svm_fifo_set_event (f))
+ app_send_io_evt_to_vpp (vpp_evt_q, f, evt_type, noblock);
+ }
+ return rv;
+}
+
+always_inline int
+app_send_stream (app_session_t * s, u8 * data, u32 len, u8 noblock)
+{
+ return app_send_stream_raw (s->tx_fifo, s->vpp_evt_q, data, len,
+ FIFO_EVENT_APP_TX, noblock);
+}
+
+always_inline int
+app_send (app_session_t * s, u8 * data, u32 len, u8 noblock)
+{
+ if (s->is_dgram)
+ return app_send_dgram (s, data, len, noblock);
+ return app_send_stream (s, data, len, noblock);
+}