vcl: switch to closed state after app close
[vpp.git] / src / vcl / vppcom.c
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <vcl/vppcom.h>
19 #include <vcl/vcl_debug.h>
20 #include <vcl/vcl_private.h>
21 #include <svm/fifo_segment.h>
22
23 __thread uword __vcl_worker_index = ~0;
24
25 static int
26 vcl_segment_is_not_mounted (vcl_worker_t * wrk, u64 segment_handle)
27 {
28   u32 segment_index;
29
30   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
31     return 0;
32
33   segment_index = vcl_segment_table_lookup (segment_handle);
34   if (segment_index != VCL_INVALID_SEGMENT_INDEX)
35     return 0;
36
37   return 1;
38 }
39
40 static inline int
41 vcl_mq_dequeue_batch (vcl_worker_t * wrk, svm_msg_q_t * mq, u32 n_max_msg)
42 {
43   svm_msg_q_msg_t *msg;
44   u32 n_msgs;
45   int i;
46
47   n_msgs = clib_min (svm_msg_q_size (mq), n_max_msg);
48   for (i = 0; i < n_msgs; i++)
49     {
50       vec_add2 (wrk->mq_msg_vector, msg, 1);
51       svm_msg_q_sub_w_lock (mq, msg);
52     }
53   return n_msgs;
54 }
55
56 const char *
57 vppcom_session_state_str (vcl_session_state_t state)
58 {
59   char *st;
60
61   switch (state)
62     {
63     case STATE_CLOSED:
64       st = "STATE_CLOSED";
65       break;
66
67     case STATE_CONNECT:
68       st = "STATE_CONNECT";
69       break;
70
71     case STATE_LISTEN:
72       st = "STATE_LISTEN";
73       break;
74
75     case STATE_ACCEPT:
76       st = "STATE_ACCEPT";
77       break;
78
79     case STATE_VPP_CLOSING:
80       st = "STATE_VPP_CLOSING";
81       break;
82
83     case STATE_DISCONNECT:
84       st = "STATE_DISCONNECT";
85       break;
86
87     case STATE_FAILED:
88       st = "STATE_FAILED";
89       break;
90
91     case STATE_UPDATED:
92       st = "STATE_UPDATED";
93       break;
94
95     case STATE_LISTEN_NO_MQ:
96       st = "STATE_LISTEN_NO_MQ";
97       break;
98
99     default:
100       st = "UNKNOWN_STATE";
101       break;
102     }
103
104   return st;
105 }
106
107 u8 *
108 format_ip4_address (u8 * s, va_list * args)
109 {
110   u8 *a = va_arg (*args, u8 *);
111   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
112 }
113
114 u8 *
115 format_ip6_address (u8 * s, va_list * args)
116 {
117   ip6_address_t *a = va_arg (*args, ip6_address_t *);
118   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
119
120   i_max_n_zero = ARRAY_LEN (a->as_u16);
121   max_n_zeros = 0;
122   i_first_zero = i_max_n_zero;
123   n_zeros = 0;
124   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
125     {
126       u32 is_zero = a->as_u16[i] == 0;
127       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
128         {
129           i_first_zero = i;
130           n_zeros = 0;
131         }
132       n_zeros += is_zero;
133       if ((!is_zero && n_zeros > max_n_zeros)
134           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
135         {
136           i_max_n_zero = i_first_zero;
137           max_n_zeros = n_zeros;
138           i_first_zero = ARRAY_LEN (a->as_u16);
139           n_zeros = 0;
140         }
141     }
142
143   last_double_colon = 0;
144   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
145     {
146       if (i == i_max_n_zero && max_n_zeros > 1)
147         {
148           s = format (s, "::");
149           i += max_n_zeros - 1;
150           last_double_colon = 1;
151         }
152       else
153         {
154           s = format (s, "%s%x",
155                       (last_double_colon || i == 0) ? "" : ":",
156                       clib_net_to_host_u16 (a->as_u16[i]));
157           last_double_colon = 0;
158         }
159     }
160
161   return s;
162 }
163
164 /* Format an IP46 address. */
165 u8 *
166 format_ip46_address (u8 * s, va_list * args)
167 {
168   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
169   ip46_type_t type = va_arg (*args, ip46_type_t);
170   int is_ip4 = 1;
171
172   switch (type)
173     {
174     case IP46_TYPE_ANY:
175       is_ip4 = ip46_address_is_ip4 (ip46);
176       break;
177     case IP46_TYPE_IP4:
178       is_ip4 = 1;
179       break;
180     case IP46_TYPE_IP6:
181       is_ip4 = 0;
182       break;
183     }
184
185   return is_ip4 ?
186     format (s, "%U", format_ip4_address, &ip46->ip4) :
187     format (s, "%U", format_ip6_address, &ip46->ip6);
188 }
189
190 /*
191  * VPPCOM Utility Functions
192  */
193
194 static void
195 vcl_send_session_listen (vcl_worker_t * wrk, vcl_session_t * s)
196 {
197   app_session_evt_t _app_evt, *app_evt = &_app_evt;
198   session_listen_msg_t *mp;
199   svm_msg_q_t *mq;
200
201   mq = vcl_worker_ctrl_mq (wrk);
202   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_LISTEN);
203   mp = (session_listen_msg_t *) app_evt->evt->data;
204   memset (mp, 0, sizeof (*mp));
205   mp->client_index = wrk->my_client_index;
206   mp->context = s->session_index;
207   mp->wrk_index = wrk->vpp_wrk_index;
208   mp->is_ip4 = s->transport.is_ip4;
209   clib_memcpy_fast (&mp->ip, &s->transport.lcl_ip, sizeof (mp->ip));
210   mp->port = s->transport.lcl_port;
211   mp->proto = s->session_type;
212   app_send_ctrl_evt_to_vpp (mq, app_evt);
213 }
214
215 static void
216 vcl_send_session_connect (vcl_worker_t * wrk, vcl_session_t * s)
217 {
218   app_session_evt_t _app_evt, *app_evt = &_app_evt;
219   session_connect_msg_t *mp;
220   svm_msg_q_t *mq;
221
222   mq = vcl_worker_ctrl_mq (wrk);
223   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_CONNECT);
224   mp = (session_connect_msg_t *) app_evt->evt->data;
225   memset (mp, 0, sizeof (*mp));
226   mp->client_index = wrk->my_client_index;
227   mp->context = s->session_index;
228   mp->wrk_index = wrk->vpp_wrk_index;
229   mp->is_ip4 = s->transport.is_ip4;
230   mp->parent_handle = s->parent_handle;
231   clib_memcpy_fast (&mp->ip, &s->transport.rmt_ip, sizeof (mp->ip));
232   clib_memcpy_fast (&mp->lcl_ip, &s->transport.lcl_ip, sizeof (mp->lcl_ip));
233   mp->port = s->transport.rmt_port;
234   mp->proto = s->session_type;
235   app_send_ctrl_evt_to_vpp (mq, app_evt);
236 }
237
238 void
239 vcl_send_session_unlisten (vcl_worker_t * wrk, vcl_session_t * s)
240 {
241   app_session_evt_t _app_evt, *app_evt = &_app_evt;
242   session_unlisten_msg_t *mp;
243   svm_msg_q_t *mq;
244
245   mq = vcl_worker_ctrl_mq (wrk);
246   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_UNLISTEN);
247   mp = (session_unlisten_msg_t *) app_evt->evt->data;
248   memset (mp, 0, sizeof (*mp));
249   mp->client_index = wrk->my_client_index;
250   mp->wrk_index = wrk->vpp_wrk_index;
251   mp->handle = s->vpp_handle;
252   mp->context = wrk->wrk_index;
253   app_send_ctrl_evt_to_vpp (mq, app_evt);
254 }
255
256 static void
257 vcl_send_session_disconnect (vcl_worker_t * wrk, vcl_session_t * s)
258 {
259   app_session_evt_t _app_evt, *app_evt = &_app_evt;
260   session_disconnect_msg_t *mp;
261   svm_msg_q_t *mq;
262
263   /* Send to thread that owns the session */
264   mq = s->vpp_evt_q;
265   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_DISCONNECT);
266   mp = (session_disconnect_msg_t *) app_evt->evt->data;
267   memset (mp, 0, sizeof (*mp));
268   mp->client_index = wrk->my_client_index;
269   mp->handle = s->vpp_handle;
270   app_send_ctrl_evt_to_vpp (mq, app_evt);
271 }
272
273 static void
274 vcl_send_app_detach (vcl_worker_t * wrk)
275 {
276   app_session_evt_t _app_evt, *app_evt = &_app_evt;
277   session_app_detach_msg_t *mp;
278   svm_msg_q_t *mq;
279
280   mq = vcl_worker_ctrl_mq (wrk);
281   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_APP_DETACH);
282   mp = (session_app_detach_msg_t *) app_evt->evt->data;
283   memset (mp, 0, sizeof (*mp));
284   mp->client_index = wrk->my_client_index;
285   app_send_ctrl_evt_to_vpp (mq, app_evt);
286 }
287
288 static void
289 vcl_send_session_accepted_reply (svm_msg_q_t * mq, u32 context,
290                                  session_handle_t handle, int retval)
291 {
292   app_session_evt_t _app_evt, *app_evt = &_app_evt;
293   session_accepted_reply_msg_t *rmp;
294   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_ACCEPTED_REPLY);
295   rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
296   rmp->handle = handle;
297   rmp->context = context;
298   rmp->retval = retval;
299   app_send_ctrl_evt_to_vpp (mq, app_evt);
300 }
301
302 static void
303 vcl_send_session_disconnected_reply (svm_msg_q_t * mq, u32 context,
304                                      session_handle_t handle, int retval)
305 {
306   app_session_evt_t _app_evt, *app_evt = &_app_evt;
307   session_disconnected_reply_msg_t *rmp;
308   app_alloc_ctrl_evt_to_vpp (mq, app_evt,
309                              SESSION_CTRL_EVT_DISCONNECTED_REPLY);
310   rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
311   rmp->handle = handle;
312   rmp->context = context;
313   rmp->retval = retval;
314   app_send_ctrl_evt_to_vpp (mq, app_evt);
315 }
316
317 static void
318 vcl_send_session_reset_reply (svm_msg_q_t * mq, u32 context,
319                               session_handle_t handle, int retval)
320 {
321   app_session_evt_t _app_evt, *app_evt = &_app_evt;
322   session_reset_reply_msg_t *rmp;
323   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_RESET_REPLY);
324   rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
325   rmp->handle = handle;
326   rmp->context = context;
327   rmp->retval = retval;
328   app_send_ctrl_evt_to_vpp (mq, app_evt);
329 }
330
331 void
332 vcl_send_session_worker_update (vcl_worker_t * wrk, vcl_session_t * s,
333                                 u32 wrk_index)
334 {
335   app_session_evt_t _app_evt, *app_evt = &_app_evt;
336   session_worker_update_msg_t *mp;
337   svm_msg_q_t *mq;
338
339   mq = vcl_session_vpp_evt_q (wrk, s);
340   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_WORKER_UPDATE);
341   mp = (session_worker_update_msg_t *) app_evt->evt->data;
342   mp->client_index = wrk->my_client_index;
343   mp->handle = s->vpp_handle;
344   mp->req_wrk_index = wrk->vpp_wrk_index;
345   mp->wrk_index = wrk_index;
346   app_send_ctrl_evt_to_vpp (mq, app_evt);
347 }
348
349 static u32
350 vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp,
351                               u32 ls_index)
352 {
353   vcl_session_t *session, *listen_session;
354   svm_fifo_t *rx_fifo, *tx_fifo;
355   u32 vpp_wrk_index;
356   svm_msg_q_t *evt_q;
357
358   session = vcl_session_alloc (wrk);
359
360   listen_session = vcl_session_get (wrk, ls_index);
361   if (listen_session->vpp_handle != mp->listener_handle)
362     {
363       VDBG (0, "ERROR: listener handle %lu does not match session %u",
364             mp->listener_handle, ls_index);
365       goto error;
366     }
367
368   if (vcl_segment_is_not_mounted (wrk, mp->segment_handle))
369     {
370       VDBG (0, "ERROR: segment for session %u is not mounted!",
371             session->session_index);
372       goto error;
373     }
374
375   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
376   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
377   session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
378                                          svm_msg_q_t *);
379   rx_fifo->client_session_index = session->session_index;
380   tx_fifo->client_session_index = session->session_index;
381   rx_fifo->client_thread_index = vcl_get_worker_index ();
382   tx_fifo->client_thread_index = vcl_get_worker_index ();
383   vpp_wrk_index = tx_fifo->master_thread_index;
384   vec_validate (wrk->vpp_event_queues, vpp_wrk_index);
385   wrk->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
386
387   session->vpp_handle = mp->handle;
388   session->vpp_thread_index = rx_fifo->master_thread_index;
389   session->rx_fifo = rx_fifo;
390   session->tx_fifo = tx_fifo;
391
392   session->session_state = STATE_ACCEPT;
393   session->transport.rmt_port = mp->rmt.port;
394   session->transport.is_ip4 = mp->rmt.is_ip4;
395   clib_memcpy_fast (&session->transport.rmt_ip, &mp->rmt.ip,
396                     sizeof (ip46_address_t));
397
398   vcl_session_table_add_vpp_handle (wrk, mp->handle, session->session_index);
399   session->transport.lcl_port = listen_session->transport.lcl_port;
400   session->transport.lcl_ip = listen_session->transport.lcl_ip;
401   session->session_type = listen_session->session_type;
402   session->is_dgram = vcl_proto_is_dgram (session->session_type);
403   session->listener_index = listen_session->session_index;
404   listen_session->n_accepted_sessions++;
405
406   VDBG (1, "session %u [0x%llx]: client accept request from %s address %U"
407         " port %d queue %p!", session->session_index, mp->handle,
408         mp->rmt.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &mp->rmt.ip,
409         mp->rmt.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
410         clib_net_to_host_u16 (mp->rmt.port), session->vpp_evt_q);
411   vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index);
412
413   vcl_send_session_accepted_reply (session->vpp_evt_q, mp->context,
414                                    session->vpp_handle, 0);
415
416   return session->session_index;
417
418 error:
419   evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
420   vcl_send_session_accepted_reply (evt_q, mp->context, mp->handle,
421                                    VNET_API_ERROR_INVALID_ARGUMENT);
422   vcl_session_free (wrk, session);
423   return VCL_INVALID_SESSION_INDEX;
424 }
425
426 static u32
427 vcl_session_connected_handler (vcl_worker_t * wrk,
428                                session_connected_msg_t * mp)
429 {
430   u32 session_index, vpp_wrk_index;
431   svm_fifo_t *rx_fifo, *tx_fifo;
432   vcl_session_t *session = 0;
433
434   session_index = mp->context;
435   session = vcl_session_get (wrk, session_index);
436   if (!session)
437     {
438       VDBG (0, "ERROR: vpp handle 0x%llx has no session index (%u)!",
439             mp->handle, session_index);
440       return VCL_INVALID_SESSION_INDEX;
441     }
442   if (mp->retval)
443     {
444       VDBG (0, "ERROR: session index %u: connect failed! %U",
445             session_index, format_api_error, ntohl (mp->retval));
446       session->session_state = STATE_FAILED | STATE_DISCONNECT;
447       session->vpp_handle = mp->handle;
448       return session_index;
449     }
450
451   session->vpp_handle = mp->handle;
452   session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
453                                          svm_msg_q_t *);
454   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
455   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
456   if (vcl_segment_is_not_mounted (wrk, mp->segment_handle))
457     {
458       VDBG (0, "segment for session %u is not mounted!",
459             session->session_index);
460       session->session_state = STATE_FAILED | STATE_DISCONNECT;
461       vcl_send_session_disconnect (wrk, session);
462       return session_index;
463     }
464
465   rx_fifo->client_session_index = session_index;
466   tx_fifo->client_session_index = session_index;
467   rx_fifo->client_thread_index = vcl_get_worker_index ();
468   tx_fifo->client_thread_index = vcl_get_worker_index ();
469
470   vpp_wrk_index = tx_fifo->master_thread_index;
471   vec_validate (wrk->vpp_event_queues, vpp_wrk_index);
472   wrk->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
473
474   if (mp->ct_rx_fifo)
475     {
476       session->ct_rx_fifo = uword_to_pointer (mp->ct_rx_fifo, svm_fifo_t *);
477       session->ct_tx_fifo = uword_to_pointer (mp->ct_tx_fifo, svm_fifo_t *);
478       if (vcl_segment_is_not_mounted (wrk, mp->ct_segment_handle))
479         {
480           VDBG (0, "ct segment for session %u is not mounted!",
481                 session->session_index);
482           session->session_state = STATE_FAILED | STATE_DISCONNECT;
483           vcl_send_session_disconnect (wrk, session);
484           return session_index;
485         }
486     }
487
488   session->rx_fifo = rx_fifo;
489   session->tx_fifo = tx_fifo;
490   session->vpp_thread_index = rx_fifo->master_thread_index;
491   session->transport.is_ip4 = mp->lcl.is_ip4;
492   clib_memcpy_fast (&session->transport.lcl_ip, &mp->lcl.ip,
493                     sizeof (session->transport.lcl_ip));
494   session->transport.lcl_port = mp->lcl.port;
495   session->session_state = STATE_CONNECT;
496
497   /* Add it to lookup table */
498   vcl_session_table_add_vpp_handle (wrk, mp->handle, session_index);
499
500   VDBG (1, "session %u [0x%llx] connected! rx_fifo %p, refcnt %d, tx_fifo %p,"
501         " refcnt %d", session_index, mp->handle, session->rx_fifo,
502         session->rx_fifo->refcnt, session->tx_fifo, session->tx_fifo->refcnt);
503
504   return session_index;
505 }
506
507 static int
508 vcl_flag_accepted_session (vcl_session_t * session, u64 handle, u32 flags)
509 {
510   vcl_session_msg_t *accepted_msg;
511   int i;
512
513   for (i = 0; i < vec_len (session->accept_evts_fifo); i++)
514     {
515       accepted_msg = &session->accept_evts_fifo[i];
516       if (accepted_msg->accepted_msg.handle == handle)
517         {
518           accepted_msg->flags |= flags;
519           return 1;
520         }
521     }
522   return 0;
523 }
524
525 static u32
526 vcl_session_reset_handler (vcl_worker_t * wrk,
527                            session_reset_msg_t * reset_msg)
528 {
529   vcl_session_t *session;
530   u32 sid;
531
532   sid = vcl_session_index_from_vpp_handle (wrk, reset_msg->handle);
533   session = vcl_session_get (wrk, sid);
534   if (!session)
535     {
536       VDBG (0, "request to reset unknown handle 0x%llx", reset_msg->handle);
537       return VCL_INVALID_SESSION_INDEX;
538     }
539
540   /* Caught a reset before actually accepting the session */
541   if (session->session_state == STATE_LISTEN)
542     {
543
544       if (!vcl_flag_accepted_session (session, reset_msg->handle,
545                                       VCL_ACCEPTED_F_RESET))
546         VDBG (0, "session was not accepted!");
547       return VCL_INVALID_SESSION_INDEX;
548     }
549
550   session->session_state = STATE_DISCONNECT;
551   VDBG (0, "reset session %u [0x%llx]", sid, reset_msg->handle);
552   return sid;
553 }
554
555 static u32
556 vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
557 {
558   vcl_session_t *session;
559   u32 sid = mp->context;
560
561   session = vcl_session_get (wrk, sid);
562   if (mp->retval)
563     {
564       VERR ("session %u [0x%llx]: bind failed: %U", sid, mp->handle,
565             format_api_error, mp->retval);
566       if (session)
567         {
568           session->session_state = STATE_FAILED;
569           session->vpp_handle = mp->handle;
570           return sid;
571         }
572       else
573         {
574           VDBG (0, "ERROR: session %u [0x%llx]: Invalid session index!",
575                 sid, mp->handle);
576           return VCL_INVALID_SESSION_INDEX;
577         }
578     }
579
580   session->vpp_handle = mp->handle;
581   session->transport.is_ip4 = mp->lcl_is_ip4;
582   clib_memcpy_fast (&session->transport.lcl_ip, mp->lcl_ip,
583                     sizeof (ip46_address_t));
584   session->transport.lcl_port = mp->lcl_port;
585   vcl_session_table_add_listener (wrk, mp->handle, sid);
586   session->session_state = STATE_LISTEN;
587
588   session->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
589   vec_validate (wrk->vpp_event_queues, 0);
590   wrk->vpp_event_queues[0] = session->vpp_evt_q;
591
592   if (vcl_session_is_cl (session))
593     {
594       svm_fifo_t *rx_fifo, *tx_fifo;
595       session->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
596       rx_fifo = uword_to_pointer (mp->rx_fifo, svm_fifo_t *);
597       rx_fifo->client_session_index = sid;
598       tx_fifo = uword_to_pointer (mp->tx_fifo, svm_fifo_t *);
599       tx_fifo->client_session_index = sid;
600       session->rx_fifo = rx_fifo;
601       session->tx_fifo = tx_fifo;
602     }
603
604   VDBG (0, "session %u [0x%llx]: listen succeeded!", sid, mp->handle);
605   return sid;
606 }
607
608 static void
609 vcl_session_unlisten_reply_handler (vcl_worker_t * wrk, void *data)
610 {
611   session_unlisten_reply_msg_t *mp = (session_unlisten_reply_msg_t *) data;
612   vcl_session_t *s;
613
614   s = vcl_session_get_w_vpp_handle (wrk, mp->handle);
615   if (!s || s->session_state != STATE_DISCONNECT)
616     {
617       VDBG (0, "Unlisten reply with wrong handle %llx", mp->handle);
618       return;
619     }
620
621   if (mp->retval)
622     VDBG (0, "ERROR: session %u [0xllx]: unlisten failed: %U",
623           s->session_index, mp->handle, format_api_error, ntohl (mp->retval));
624
625   if (mp->context != wrk->wrk_index)
626     VDBG (0, "wrong context");
627
628   vcl_session_table_del_vpp_handle (wrk, mp->handle);
629   vcl_session_free (wrk, s);
630 }
631
632 static void
633 vcl_session_migrated_handler (vcl_worker_t * wrk, void *data)
634 {
635   session_migrated_msg_t *mp = (session_migrated_msg_t *) data;
636   vcl_session_t *s;
637
638   s = vcl_session_get_w_vpp_handle (wrk, mp->handle);
639   if (!s)
640     {
641       VDBG (0, "Migrated notification with wrong handle %llx", mp->handle);
642       return;
643     }
644
645   s->vpp_thread_index = mp->vpp_thread_index;
646   s->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
647
648   vec_validate (wrk->vpp_event_queues, s->vpp_thread_index);
649   wrk->vpp_event_queues[s->vpp_thread_index] = s->vpp_evt_q;
650
651   vcl_session_table_del_vpp_handle (wrk, mp->handle);
652   vcl_session_table_add_vpp_handle (wrk, mp->new_handle, s->session_index);
653
654   /* Generate new tx event if we have outstanding data */
655   if (svm_fifo_has_event (s->tx_fifo))
656     app_send_io_evt_to_vpp (s->vpp_evt_q, s->tx_fifo->master_session_index,
657                             SESSION_IO_EVT_TX, SVM_Q_WAIT);
658
659   VDBG (0, "Migrated 0x%x to thread %u", mp->handle, s->vpp_thread_index);
660 }
661
662 static vcl_session_t *
663 vcl_session_accepted (vcl_worker_t * wrk, session_accepted_msg_t * msg)
664 {
665   vcl_session_msg_t *vcl_msg;
666   vcl_session_t *session;
667
668   session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
669   if (PREDICT_FALSE (session != 0))
670     VWRN ("session overlap handle %lu state %u!", msg->handle,
671           session->session_state);
672
673   session = vcl_session_table_lookup_listener (wrk, msg->listener_handle);
674   if (!session)
675     {
676       VERR ("couldn't find listen session: listener handle %llx",
677             msg->listener_handle);
678       return 0;
679     }
680
681   clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
682   vcl_msg->accepted_msg = *msg;
683   /* Session handle points to listener until fully accepted by app */
684   vcl_session_table_add_vpp_handle (wrk, msg->handle, session->session_index);
685
686   return session;
687 }
688
689 static vcl_session_t *
690 vcl_session_disconnected_handler (vcl_worker_t * wrk,
691                                   session_disconnected_msg_t * msg)
692 {
693   vcl_session_t *session;
694
695   session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
696   if (!session)
697     {
698       VDBG (0, "request to disconnect unknown handle 0x%llx", msg->handle);
699       return 0;
700     }
701
702   /* Caught a disconnect before actually accepting the session */
703   if (session->session_state == STATE_LISTEN)
704     {
705       if (!vcl_flag_accepted_session (session, msg->handle,
706                                       VCL_ACCEPTED_F_CLOSED))
707         VDBG (0, "session was not accepted!");
708       return 0;
709     }
710
711   session->session_state = STATE_VPP_CLOSING;
712   return session;
713 }
714
715 static void
716 vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data)
717 {
718   session_cleanup_msg_t *msg;
719   vcl_session_t *session;
720
721   msg = (session_cleanup_msg_t *) data;
722   session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
723   if (!session)
724     {
725       VDBG (0, "disconnect confirmed for unknown handle 0x%llx", msg->handle);
726       return;
727     }
728
729   vcl_session_table_del_vpp_handle (wrk, msg->handle);
730   vcl_session_free (wrk, session);
731 }
732
733 static void
734 vcl_session_req_worker_update_handler (vcl_worker_t * wrk, void *data)
735 {
736   session_req_worker_update_msg_t *msg;
737   vcl_session_t *s;
738
739   msg = (session_req_worker_update_msg_t *) data;
740   s = vcl_session_get_w_vpp_handle (wrk, msg->session_handle);
741   if (!s)
742     return;
743
744   vec_add1 (wrk->pending_session_wrk_updates, s->session_index);
745 }
746
747 static void
748 vcl_session_worker_update_reply_handler (vcl_worker_t * wrk, void *data)
749 {
750   session_worker_update_reply_msg_t *msg;
751   vcl_session_t *s;
752
753   msg = (session_worker_update_reply_msg_t *) data;
754   s = vcl_session_get_w_vpp_handle (wrk, msg->handle);
755   if (!s)
756     {
757       VDBG (0, "unknown handle 0x%llx", msg->handle);
758       return;
759     }
760   if (vcl_segment_is_not_mounted (wrk, msg->segment_handle))
761     {
762       clib_warning ("segment for session %u is not mounted!",
763                     s->session_index);
764       return;
765     }
766
767   if (s->rx_fifo)
768     {
769       s->rx_fifo = uword_to_pointer (msg->rx_fifo, svm_fifo_t *);
770       s->tx_fifo = uword_to_pointer (msg->tx_fifo, svm_fifo_t *);
771       s->rx_fifo->client_session_index = s->session_index;
772       s->tx_fifo->client_session_index = s->session_index;
773       s->rx_fifo->client_thread_index = wrk->wrk_index;
774       s->tx_fifo->client_thread_index = wrk->wrk_index;
775     }
776   s->session_state = STATE_UPDATED;
777
778   VDBG (0, "session %u[0x%llx] moved to worker %u", s->session_index,
779         s->vpp_handle, wrk->wrk_index);
780 }
781
782 static void
783 vcl_session_app_add_segment_handler (vcl_worker_t * wrk, void *data)
784 {
785   ssvm_segment_type_t seg_type = SSVM_SEGMENT_SHM;
786   session_app_add_segment_msg_t *msg;
787   u64 segment_handle;
788   int fd = -1;
789
790   msg = (session_app_add_segment_msg_t *) data;
791
792   if (msg->fd_flags)
793     {
794       vl_socket_client_recv_fd_msg2 (&wrk->bapi_sock_ctx, &fd, 1, 5);
795       seg_type = SSVM_SEGMENT_MEMFD;
796     }
797
798   segment_handle = msg->segment_handle;
799   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
800     {
801       clib_warning ("invalid segment handle");
802       return;
803     }
804
805   if (vcl_segment_attach (segment_handle, (char *) msg->segment_name,
806                           seg_type, fd))
807     {
808       VDBG (0, "vcl_segment_attach ('%s') failed", msg->segment_name);
809       return;
810     }
811
812   VDBG (1, "mapped new segment '%s' size %d", msg->segment_name,
813         msg->segment_size);
814 }
815
816 static void
817 vcl_session_app_del_segment_handler (vcl_worker_t * wrk, void *data)
818 {
819   session_app_del_segment_msg_t *msg = (session_app_del_segment_msg_t *) data;
820   vcl_segment_detach (msg->segment_handle);
821   VDBG (1, "Unmapped segment: %d", msg->segment_handle);
822 }
823
824 static int
825 vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
826 {
827   session_disconnected_msg_t *disconnected_msg;
828   vcl_session_t *session;
829
830   switch (e->event_type)
831     {
832     case SESSION_IO_EVT_RX:
833     case SESSION_IO_EVT_TX:
834       session = vcl_session_get (wrk, e->session_index);
835       if (!session || !(session->session_state & STATE_OPEN))
836         break;
837       vec_add1 (wrk->unhandled_evts_vector, *e);
838       break;
839     case SESSION_CTRL_EVT_ACCEPTED:
840       vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
841       break;
842     case SESSION_CTRL_EVT_CONNECTED:
843       vcl_session_connected_handler (wrk,
844                                      (session_connected_msg_t *) e->data);
845       break;
846     case SESSION_CTRL_EVT_DISCONNECTED:
847       disconnected_msg = (session_disconnected_msg_t *) e->data;
848       session = vcl_session_disconnected_handler (wrk, disconnected_msg);
849       if (!session)
850         break;
851       VDBG (0, "disconnected session %u [0x%llx]", session->session_index,
852             session->vpp_handle);
853       break;
854     case SESSION_CTRL_EVT_RESET:
855       vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
856       break;
857     case SESSION_CTRL_EVT_BOUND:
858       vcl_session_bound_handler (wrk, (session_bound_msg_t *) e->data);
859       break;
860     case SESSION_CTRL_EVT_UNLISTEN_REPLY:
861       vcl_session_unlisten_reply_handler (wrk, e->data);
862       break;
863     case SESSION_CTRL_EVT_MIGRATED:
864       vcl_session_migrated_handler (wrk, e->data);
865       break;
866     case SESSION_CTRL_EVT_CLEANUP:
867       vcl_session_cleanup_handler (wrk, e->data);
868       break;
869     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
870       vcl_session_req_worker_update_handler (wrk, e->data);
871       break;
872     case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
873       vcl_session_worker_update_reply_handler (wrk, e->data);
874       break;
875     case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
876       vcl_session_app_add_segment_handler (wrk, e->data);
877       break;
878     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
879       vcl_session_app_del_segment_handler (wrk, e->data);
880       break;
881     default:
882       clib_warning ("unhandled %u", e->event_type);
883     }
884   return VPPCOM_OK;
885 }
886
887 static int
888 vppcom_wait_for_session_state_change (u32 session_index,
889                                       vcl_session_state_t state,
890                                       f64 wait_for_time)
891 {
892   vcl_worker_t *wrk = vcl_worker_get_current ();
893   f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
894   vcl_session_t *volatile session;
895   svm_msg_q_msg_t msg;
896   session_event_t *e;
897
898   do
899     {
900       session = vcl_session_get (wrk, session_index);
901       if (PREDICT_FALSE (!session))
902         {
903           return VPPCOM_EBADFD;
904         }
905       if (session->session_state & state)
906         {
907           return VPPCOM_OK;
908         }
909       if (session->session_state & STATE_FAILED)
910         {
911           return VPPCOM_ECONNREFUSED;
912         }
913
914       if (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0))
915         {
916           usleep (100);
917           continue;
918         }
919       e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
920       vcl_handle_mq_event (wrk, e);
921       svm_msg_q_free_msg (wrk->app_event_queue, &msg);
922     }
923   while (clib_time_now (&wrk->clib_time) < timeout);
924
925   VDBG (0, "timeout waiting for state 0x%x (%s)", state,
926         vppcom_session_state_str (state));
927   vcl_evt (VCL_EVT_SESSION_TIMEOUT, session, session_state);
928
929   return VPPCOM_ETIMEDOUT;
930 }
931
932 static void
933 vcl_handle_pending_wrk_updates (vcl_worker_t * wrk)
934 {
935   vcl_session_state_t state;
936   vcl_session_t *s;
937   u32 *sip;
938
939   if (PREDICT_TRUE (vec_len (wrk->pending_session_wrk_updates) == 0))
940     return;
941
942   vec_foreach (sip, wrk->pending_session_wrk_updates)
943   {
944     s = vcl_session_get (wrk, *sip);
945     vcl_send_session_worker_update (wrk, s, wrk->wrk_index);
946     state = s->session_state;
947     vppcom_wait_for_session_state_change (s->session_index, STATE_UPDATED, 5);
948     s->session_state = state;
949   }
950   vec_reset_length (wrk->pending_session_wrk_updates);
951 }
952
953 void
954 vcl_flush_mq_events (void)
955 {
956   vcl_worker_t *wrk = vcl_worker_get_current ();
957   svm_msg_q_msg_t *msg;
958   session_event_t *e;
959   svm_msg_q_t *mq;
960   int i;
961
962   mq = wrk->app_event_queue;
963   svm_msg_q_lock (mq);
964   vcl_mq_dequeue_batch (wrk, mq, ~0);
965   svm_msg_q_unlock (mq);
966
967   for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
968     {
969       msg = vec_elt_at_index (wrk->mq_msg_vector, i);
970       e = svm_msg_q_msg_data (mq, msg);
971       vcl_handle_mq_event (wrk, e);
972       svm_msg_q_free_msg (mq, msg);
973     }
974   vec_reset_length (wrk->mq_msg_vector);
975   vcl_handle_pending_wrk_updates (wrk);
976 }
977
978 static int
979 vppcom_app_session_enable (void)
980 {
981   int rv;
982
983   if (vcm->app_state != STATE_APP_ENABLED)
984     {
985       vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
986       rv = vcl_wait_for_app_state_change (STATE_APP_ENABLED);
987       if (PREDICT_FALSE (rv))
988         {
989           VDBG (0, "application session enable timed out! returning %d (%s)",
990                 rv, vppcom_retval_str (rv));
991           return rv;
992         }
993     }
994   return VPPCOM_OK;
995 }
996
997 static int
998 vppcom_app_attach (void)
999 {
1000   int rv;
1001
1002   vppcom_app_send_attach ();
1003   rv = vcl_wait_for_app_state_change (STATE_APP_ATTACHED);
1004   if (PREDICT_FALSE (rv))
1005     {
1006       VDBG (0, "application attach timed out! returning %d (%s)", rv,
1007             vppcom_retval_str (rv));
1008       return rv;
1009     }
1010
1011   return VPPCOM_OK;
1012 }
1013
1014 static int
1015 vppcom_session_unbind (u32 session_handle)
1016 {
1017   vcl_worker_t *wrk = vcl_worker_get_current ();
1018   session_accepted_msg_t *accepted_msg;
1019   vcl_session_t *session = 0;
1020   vcl_session_msg_t *evt;
1021
1022   session = vcl_session_get_w_handle (wrk, session_handle);
1023   if (!session)
1024     return VPPCOM_EBADFD;
1025
1026   /* Flush pending accept events, if any */
1027   while (clib_fifo_elts (session->accept_evts_fifo))
1028     {
1029       clib_fifo_sub2 (session->accept_evts_fifo, evt);
1030       accepted_msg = &evt->accepted_msg;
1031       vcl_session_table_del_vpp_handle (wrk, accepted_msg->handle);
1032       vcl_send_session_accepted_reply (session->vpp_evt_q,
1033                                        accepted_msg->context,
1034                                        session->vpp_handle, -1);
1035     }
1036   clib_fifo_free (session->accept_evts_fifo);
1037
1038   vcl_send_session_unlisten (wrk, session);
1039
1040   VDBG (1, "session %u [0x%llx]: sending unbind!", session->session_index,
1041         session->vpp_handle);
1042   vcl_evt (VCL_EVT_UNBIND, session);
1043
1044   session->vpp_handle = ~0;
1045   session->session_state = STATE_DISCONNECT;
1046
1047   return VPPCOM_OK;
1048 }
1049
1050 static int
1051 vppcom_session_disconnect (u32 session_handle)
1052 {
1053   vcl_worker_t *wrk = vcl_worker_get_current ();
1054   svm_msg_q_t *vpp_evt_q;
1055   vcl_session_t *session, *listen_session;
1056   vcl_session_state_t state;
1057   u64 vpp_handle;
1058
1059   session = vcl_session_get_w_handle (wrk, session_handle);
1060   if (!session)
1061     return VPPCOM_EBADFD;
1062
1063   vpp_handle = session->vpp_handle;
1064   state = session->session_state;
1065
1066   VDBG (1, "session %u [0x%llx] state 0x%x (%s)", session->session_index,
1067         vpp_handle, state, vppcom_session_state_str (state));
1068
1069   if (PREDICT_FALSE (state & STATE_LISTEN))
1070     {
1071       VDBG (0, "ERROR: Cannot disconnect a listen socket!");
1072       return VPPCOM_EBADFD;
1073     }
1074
1075   if (state & STATE_VPP_CLOSING)
1076     {
1077       vpp_evt_q = vcl_session_vpp_evt_q (wrk, session);
1078       vcl_send_session_disconnected_reply (vpp_evt_q, wrk->my_client_index,
1079                                            vpp_handle, 0);
1080       VDBG (1, "session %u [0x%llx]: sending disconnect REPLY...",
1081             session->session_index, vpp_handle);
1082     }
1083   else
1084     {
1085       VDBG (1, "session %u [0x%llx]: sending disconnect...",
1086             session->session_index, vpp_handle);
1087       vcl_send_session_disconnect (wrk, session);
1088     }
1089
1090   if (session->listener_index != VCL_INVALID_SESSION_INDEX)
1091     {
1092       listen_session = vcl_session_get (wrk, session->listener_index);
1093       listen_session->n_accepted_sessions--;
1094     }
1095
1096   return VPPCOM_OK;
1097 }
1098
1099 /**
1100  * Handle app exit
1101  *
1102  * Notify vpp of the disconnect and mark the worker as free. If we're the
1103  * last worker, do a full cleanup otherwise, since we're probably a forked
1104  * child, avoid syscalls as much as possible. We might've lost privileges.
1105  */
1106 void
1107 vppcom_app_exit (void)
1108 {
1109   if (!pool_elts (vcm->workers))
1110     return;
1111   vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
1112   vcl_set_worker_index (~0);
1113   vcl_elog_stop (vcm);
1114 }
1115
1116 /*
1117  * VPPCOM Public API functions
1118  */
1119 int
1120 vppcom_app_create (char *app_name)
1121 {
1122   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1123   int rv;
1124
1125   if (vcm->is_init)
1126     {
1127       VDBG (1, "already initialized");
1128       return VPPCOM_EEXIST;
1129     }
1130
1131   vcm->is_init = 1;
1132   vppcom_cfg (&vcm->cfg);
1133   vcl_cfg = &vcm->cfg;
1134
1135   vcm->main_cpu = pthread_self ();
1136   vcm->main_pid = getpid ();
1137   vcm->app_name = format (0, "%s", app_name);
1138   vppcom_init_error_string_table ();
1139   fifo_segment_main_init (&vcm->segment_main, vcl_cfg->segment_baseva,
1140                           20 /* timeout in secs */ );
1141   pool_alloc (vcm->workers, vcl_cfg->max_workers);
1142   clib_spinlock_init (&vcm->workers_lock);
1143   clib_rwlock_init (&vcm->segment_table_lock);
1144   atexit (vppcom_app_exit);
1145
1146   /* Allocate default worker */
1147   vcl_worker_alloc_and_init ();
1148
1149   /* API hookup and connect to VPP */
1150   vcl_elog_init (vcm);
1151   vcm->app_state = STATE_APP_START;
1152   rv = vppcom_connect_to_vpp (app_name);
1153   if (rv)
1154     {
1155       VERR ("couldn't connect to VPP!");
1156       return rv;
1157     }
1158   VDBG (0, "sending session enable");
1159   rv = vppcom_app_session_enable ();
1160   if (rv)
1161     {
1162       VERR ("vppcom_app_session_enable() failed!");
1163       return rv;
1164     }
1165
1166   VDBG (0, "sending app attach");
1167   rv = vppcom_app_attach ();
1168   if (rv)
1169     {
1170       VERR ("vppcom_app_attach() failed!");
1171       return rv;
1172     }
1173
1174   VDBG (0, "app_name '%s', my_client_index %d (0x%x)", app_name,
1175         vcm->workers[0].my_client_index, vcm->workers[0].my_client_index);
1176
1177   return VPPCOM_OK;
1178 }
1179
1180 void
1181 vppcom_app_destroy (void)
1182 {
1183   int rv;
1184   f64 orig_app_timeout;
1185
1186   if (!pool_elts (vcm->workers))
1187     return;
1188
1189   vcl_evt (VCL_EVT_DETACH, vcm);
1190
1191   if (pool_elts (vcm->workers) == 1)
1192     {
1193       vcl_send_app_detach (vcl_worker_get_current ());
1194       orig_app_timeout = vcm->cfg.app_timeout;
1195       vcm->cfg.app_timeout = 2.0;
1196       rv = vcl_wait_for_app_state_change (STATE_APP_ENABLED);
1197       vcm->cfg.app_timeout = orig_app_timeout;
1198       if (PREDICT_FALSE (rv))
1199         VDBG (0, "application detach timed out! returning %d (%s)", rv,
1200               vppcom_retval_str (rv));
1201       vec_free (vcm->app_name);
1202       vcl_worker_cleanup (vcl_worker_get_current (), 0 /* notify vpp */ );
1203     }
1204   else
1205     {
1206       vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
1207     }
1208
1209   vcl_set_worker_index (~0);
1210   vcl_elog_stop (vcm);
1211   vl_client_disconnect_from_vlib ();
1212 }
1213
1214 int
1215 vppcom_session_create (u8 proto, u8 is_nonblocking)
1216 {
1217   vcl_worker_t *wrk = vcl_worker_get_current ();
1218   vcl_session_t *session;
1219
1220   session = vcl_session_alloc (wrk);
1221
1222   session->session_type = proto;
1223   session->session_state = STATE_CLOSED;
1224   session->vpp_handle = ~0;
1225   session->is_dgram = vcl_proto_is_dgram (proto);
1226
1227   if (is_nonblocking)
1228     VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
1229
1230   vcl_evt (VCL_EVT_CREATE, session, session_type, session->session_state,
1231            is_nonblocking, session_index);
1232
1233   VDBG (0, "created session %u", session->session_index);
1234
1235   return vcl_session_handle (session);
1236 }
1237
1238 int
1239 vcl_session_cleanup (vcl_worker_t * wrk, vcl_session_t * session,
1240                      vcl_session_handle_t sh, u8 do_disconnect)
1241 {
1242   vcl_session_state_t state;
1243   u32 next_sh, vep_sh;
1244   int rv = VPPCOM_OK;
1245   u64 vpp_handle;
1246   u8 is_vep;
1247
1248   is_vep = session->is_vep;
1249   next_sh = session->vep.next_sh;
1250   vep_sh = session->vep.vep_sh;
1251   state = session->session_state;
1252   vpp_handle = session->vpp_handle;
1253
1254   VDBG (1, "session %u [0x%llx] closing", session->session_index, vpp_handle);
1255
1256   if (is_vep)
1257     {
1258       while (next_sh != ~0)
1259         {
1260           rv = vppcom_epoll_ctl (sh, EPOLL_CTL_DEL, next_sh, 0);
1261           if (PREDICT_FALSE (rv < 0))
1262             VDBG (0, "vpp handle 0x%llx, sh %u: EPOLL_CTL_DEL vep_idx %u"
1263                   " failed! rv %d (%s)", vpp_handle, next_sh, vep_sh, rv,
1264                   vppcom_retval_str (rv));
1265
1266           next_sh = session->vep.next_sh;
1267         }
1268       goto cleanup;
1269     }
1270
1271   if (session->is_vep_session)
1272     {
1273       rv = vppcom_epoll_ctl (vep_sh, EPOLL_CTL_DEL, sh, 0);
1274       if (rv < 0)
1275         VDBG (0, "session %u [0x%llx]: EPOLL_CTL_DEL vep_idx %u "
1276               "failed! rv %d (%s)", session->session_index, vpp_handle,
1277               vep_sh, rv, vppcom_retval_str (rv));
1278     }
1279
1280   if (!do_disconnect)
1281     {
1282       VDBG (1, "session %u [0x%llx] disconnect skipped",
1283             session->session_index, vpp_handle);
1284       goto cleanup;
1285     }
1286
1287   if (state & STATE_LISTEN)
1288     {
1289       rv = vppcom_session_unbind (sh);
1290       if (PREDICT_FALSE (rv < 0))
1291         VDBG (0, "session %u [0x%llx]: listener unbind failed! "
1292               "rv %d (%s)", session->session_index, vpp_handle, rv,
1293               vppcom_retval_str (rv));
1294       return rv;
1295     }
1296   else if ((state & STATE_OPEN)
1297            || (vcl_session_is_connectable_listener (wrk, session)))
1298     {
1299       rv = vppcom_session_disconnect (sh);
1300       if (PREDICT_FALSE (rv < 0))
1301         VDBG (0, "ERROR: session %u [0x%llx]: disconnect failed!"
1302               " rv %d (%s)", session->session_index, vpp_handle,
1303               rv, vppcom_retval_str (rv));
1304     }
1305   else if (state == STATE_DISCONNECT)
1306     {
1307       svm_msg_q_t *mq = vcl_session_vpp_evt_q (wrk, session);
1308       vcl_send_session_reset_reply (mq, wrk->my_client_index,
1309                                     session->vpp_handle, 0);
1310     }
1311
1312   session->session_state = STATE_CLOSED;
1313
1314   /* Session is removed only after vpp confirms the disconnect */
1315   return rv;
1316
1317 cleanup:
1318   vcl_session_table_del_vpp_handle (wrk, vpp_handle);
1319   vcl_session_free (wrk, session);
1320   vcl_evt (VCL_EVT_CLOSE, session, rv);
1321
1322   return rv;
1323 }
1324
1325 int
1326 vppcom_session_close (uint32_t session_handle)
1327 {
1328   vcl_worker_t *wrk = vcl_worker_get_current ();
1329   vcl_session_t *session;
1330
1331   session = vcl_session_get_w_handle (wrk, session_handle);
1332   if (!session)
1333     return VPPCOM_EBADFD;
1334   return vcl_session_cleanup (wrk, session, session_handle,
1335                               1 /* do_disconnect */ );
1336 }
1337
1338 int
1339 vppcom_session_bind (uint32_t session_handle, vppcom_endpt_t * ep)
1340 {
1341   vcl_worker_t *wrk = vcl_worker_get_current ();
1342   vcl_session_t *session = 0;
1343
1344   if (!ep || !ep->ip)
1345     return VPPCOM_EINVAL;
1346
1347   session = vcl_session_get_w_handle (wrk, session_handle);
1348   if (!session)
1349     return VPPCOM_EBADFD;
1350
1351   if (session->is_vep)
1352     {
1353       VDBG (0, "ERROR: cannot bind to epoll session %u!",
1354             session->session_index);
1355       return VPPCOM_EBADFD;
1356     }
1357
1358   session->transport.is_ip4 = ep->is_ip4;
1359   if (ep->is_ip4)
1360     clib_memcpy_fast (&session->transport.lcl_ip.ip4, ep->ip,
1361                       sizeof (ip4_address_t));
1362   else
1363     clib_memcpy_fast (&session->transport.lcl_ip.ip6, ep->ip,
1364                       sizeof (ip6_address_t));
1365   session->transport.lcl_port = ep->port;
1366
1367   VDBG (0, "session %u handle %u: binding to local %s address %U port %u, "
1368         "proto %s", session->session_index, session_handle,
1369         session->transport.is_ip4 ? "IPv4" : "IPv6",
1370         format_ip46_address, &session->transport.lcl_ip,
1371         session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1372         clib_net_to_host_u16 (session->transport.lcl_port),
1373         vppcom_proto_str (session->session_type));
1374   vcl_evt (VCL_EVT_BIND, session);
1375
1376   if (session->session_type == VPPCOM_PROTO_UDP)
1377     vppcom_session_listen (session_handle, 10);
1378
1379   return VPPCOM_OK;
1380 }
1381
1382 int
1383 vppcom_session_listen (uint32_t listen_sh, uint32_t q_len)
1384 {
1385   vcl_worker_t *wrk = vcl_worker_get_current ();
1386   vcl_session_t *listen_session = 0;
1387   u64 listen_vpp_handle;
1388   int rv;
1389
1390   listen_session = vcl_session_get_w_handle (wrk, listen_sh);
1391   if (!listen_session || listen_session->is_vep)
1392     return VPPCOM_EBADFD;
1393
1394   if (q_len == 0 || q_len == ~0)
1395     q_len = vcm->cfg.listen_queue_size;
1396
1397   listen_vpp_handle = listen_session->vpp_handle;
1398   if (listen_session->session_state & STATE_LISTEN)
1399     {
1400       VDBG (0, "session %u [0x%llx]: already in listen state!",
1401             listen_sh, listen_vpp_handle);
1402       return VPPCOM_OK;
1403     }
1404
1405   VDBG (0, "session %u: sending vpp listen request...", listen_sh);
1406
1407   /*
1408    * Send listen request to vpp and wait for reply
1409    */
1410   vcl_send_session_listen (wrk, listen_session);
1411   rv = vppcom_wait_for_session_state_change (listen_session->session_index,
1412                                              STATE_LISTEN,
1413                                              vcm->cfg.session_timeout);
1414
1415   if (PREDICT_FALSE (rv))
1416     {
1417       listen_session = vcl_session_get_w_handle (wrk, listen_sh);
1418       VDBG (0, "session %u [0x%llx]: listen failed! returning %d (%s)",
1419             listen_sh, listen_session->vpp_handle, rv,
1420             vppcom_retval_str (rv));
1421       return rv;
1422     }
1423
1424   return VPPCOM_OK;
1425 }
1426
1427 int
1428 vppcom_session_tls_add_cert (uint32_t session_handle, char *cert,
1429                              uint32_t cert_len)
1430 {
1431
1432   vcl_worker_t *wrk = vcl_worker_get_current ();
1433   vcl_session_t *session = 0;
1434
1435   session = vcl_session_get_w_handle (wrk, session_handle);
1436   if (!session)
1437     return VPPCOM_EBADFD;
1438
1439   if (cert_len == 0 || cert_len == ~0)
1440     return VPPCOM_EBADFD;
1441
1442   /*
1443    * Send listen request to vpp and wait for reply
1444    */
1445   vppcom_send_application_tls_cert_add (session, cert, cert_len);
1446   vcm->app_state = STATE_APP_ADDING_TLS_DATA;
1447   vcl_wait_for_app_state_change (STATE_APP_READY);
1448   return VPPCOM_OK;
1449
1450 }
1451
1452 int
1453 vppcom_session_tls_add_key (uint32_t session_handle, char *key,
1454                             uint32_t key_len)
1455 {
1456
1457   vcl_worker_t *wrk = vcl_worker_get_current ();
1458   vcl_session_t *session = 0;
1459
1460   session = vcl_session_get_w_handle (wrk, session_handle);
1461   if (!session)
1462     return VPPCOM_EBADFD;
1463
1464   if (key_len == 0 || key_len == ~0)
1465     return VPPCOM_EBADFD;
1466
1467   vppcom_send_application_tls_key_add (session, key, key_len);
1468   vcm->app_state = STATE_APP_ADDING_TLS_DATA;
1469   vcl_wait_for_app_state_change (STATE_APP_READY);
1470   return VPPCOM_OK;
1471 }
1472
1473 static int
1474 validate_args_session_accept_ (vcl_worker_t * wrk, vcl_session_t * ls)
1475 {
1476   if (ls->is_vep)
1477     {
1478       VDBG (0, "ERROR: cannot accept on epoll session %u!",
1479             ls->session_index);
1480       return VPPCOM_EBADFD;
1481     }
1482
1483   if ((ls->session_state != STATE_LISTEN)
1484       && (!vcl_session_is_connectable_listener (wrk, ls)))
1485     {
1486       VDBG (0,
1487             "ERROR: session [0x%llx]: not in listen state! state 0x%x"
1488             " (%s)", ls->vpp_handle, ls->session_state,
1489             vppcom_session_state_str (ls->session_state));
1490       return VPPCOM_EBADFD;
1491     }
1492   return VPPCOM_OK;
1493 }
1494
1495 int
1496 vppcom_unformat_proto (uint8_t * proto, char *proto_str)
1497 {
1498   if (!strcmp (proto_str, "TCP"))
1499     *proto = VPPCOM_PROTO_TCP;
1500   else if (!strcmp (proto_str, "tcp"))
1501     *proto = VPPCOM_PROTO_TCP;
1502   else if (!strcmp (proto_str, "UDP"))
1503     *proto = VPPCOM_PROTO_UDP;
1504   else if (!strcmp (proto_str, "udp"))
1505     *proto = VPPCOM_PROTO_UDP;
1506   else if (!strcmp (proto_str, "UDPC"))
1507     *proto = VPPCOM_PROTO_UDPC;
1508   else if (!strcmp (proto_str, "udpc"))
1509     *proto = VPPCOM_PROTO_UDPC;
1510   else if (!strcmp (proto_str, "SCTP"))
1511     *proto = VPPCOM_PROTO_SCTP;
1512   else if (!strcmp (proto_str, "sctp"))
1513     *proto = VPPCOM_PROTO_SCTP;
1514   else if (!strcmp (proto_str, "TLS"))
1515     *proto = VPPCOM_PROTO_TLS;
1516   else if (!strcmp (proto_str, "tls"))
1517     *proto = VPPCOM_PROTO_TLS;
1518   else if (!strcmp (proto_str, "QUIC"))
1519     *proto = VPPCOM_PROTO_QUIC;
1520   else if (!strcmp (proto_str, "quic"))
1521     *proto = VPPCOM_PROTO_QUIC;
1522   else
1523     return 1;
1524   return 0;
1525 }
1526
1527 int
1528 vppcom_session_accept (uint32_t listen_session_handle, vppcom_endpt_t * ep,
1529                        uint32_t flags)
1530 {
1531   u32 client_session_index = ~0, listen_session_index, accept_flags = 0;
1532   vcl_worker_t *wrk = vcl_worker_get_current ();
1533   session_accepted_msg_t accepted_msg;
1534   vcl_session_t *listen_session = 0;
1535   vcl_session_t *client_session = 0;
1536   vcl_session_msg_t *evt;
1537   svm_msg_q_msg_t msg;
1538   session_event_t *e;
1539   u8 is_nonblocking;
1540   int rv;
1541
1542   listen_session = vcl_session_get_w_handle (wrk, listen_session_handle);
1543   if (!listen_session)
1544     return VPPCOM_EBADFD;
1545
1546   listen_session_index = listen_session->session_index;
1547   if ((rv = validate_args_session_accept_ (wrk, listen_session)))
1548     return rv;
1549
1550   if (clib_fifo_elts (listen_session->accept_evts_fifo))
1551     {
1552       clib_fifo_sub2 (listen_session->accept_evts_fifo, evt);
1553       accept_flags = evt->flags;
1554       accepted_msg = evt->accepted_msg;
1555       goto handle;
1556     }
1557
1558   is_nonblocking = VCL_SESS_ATTR_TEST (listen_session->attr,
1559                                        VCL_SESS_ATTR_NONBLOCK);
1560   while (1)
1561     {
1562       if (svm_msg_q_is_empty (wrk->app_event_queue) && is_nonblocking)
1563         return VPPCOM_EAGAIN;
1564
1565       if (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_WAIT, 0))
1566         return VPPCOM_EAGAIN;
1567
1568       e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
1569       if (e->event_type != SESSION_CTRL_EVT_ACCEPTED)
1570         {
1571           vcl_handle_mq_event (wrk, e);
1572           svm_msg_q_free_msg (wrk->app_event_queue, &msg);
1573           continue;
1574         }
1575       clib_memcpy_fast (&accepted_msg, e->data, sizeof (accepted_msg));
1576       svm_msg_q_free_msg (wrk->app_event_queue, &msg);
1577       break;
1578     }
1579
1580 handle:
1581
1582   client_session_index = vcl_session_accepted_handler (wrk, &accepted_msg,
1583                                                        listen_session_index);
1584   if (client_session_index == VCL_INVALID_SESSION_INDEX)
1585     return VPPCOM_ECONNABORTED;
1586
1587   listen_session = vcl_session_get (wrk, listen_session_index);
1588   client_session = vcl_session_get (wrk, client_session_index);
1589
1590   if (flags & O_NONBLOCK)
1591     VCL_SESS_ATTR_SET (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
1592
1593   VDBG (1, "listener %u [0x%llx]: Got a connect request! session %u [0x%llx],"
1594         " flags %d, is_nonblocking %u", listen_session->session_index,
1595         listen_session->vpp_handle, client_session_index,
1596         client_session->vpp_handle, flags,
1597         VCL_SESS_ATTR_TEST (client_session->attr, VCL_SESS_ATTR_NONBLOCK));
1598
1599   if (ep)
1600     {
1601       ep->is_ip4 = client_session->transport.is_ip4;
1602       ep->port = client_session->transport.rmt_port;
1603       if (client_session->transport.is_ip4)
1604         clib_memcpy_fast (ep->ip, &client_session->transport.rmt_ip.ip4,
1605                           sizeof (ip4_address_t));
1606       else
1607         clib_memcpy_fast (ep->ip, &client_session->transport.rmt_ip.ip6,
1608                           sizeof (ip6_address_t));
1609     }
1610
1611   VDBG (0, "listener %u [0x%llx] accepted %u [0x%llx] peer: %U:%u "
1612         "local: %U:%u", listen_session_handle, listen_session->vpp_handle,
1613         client_session_index, client_session->vpp_handle,
1614         format_ip46_address, &client_session->transport.rmt_ip,
1615         client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1616         clib_net_to_host_u16 (client_session->transport.rmt_port),
1617         format_ip46_address, &client_session->transport.lcl_ip,
1618         client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1619         clib_net_to_host_u16 (client_session->transport.lcl_port));
1620   vcl_evt (VCL_EVT_ACCEPT, client_session, listen_session,
1621            client_session_index);
1622
1623   /*
1624    * Session might have been closed already
1625    */
1626   if (accept_flags)
1627     {
1628       if (accept_flags & VCL_ACCEPTED_F_CLOSED)
1629         client_session->session_state = STATE_VPP_CLOSING;
1630       else if (accept_flags & VCL_ACCEPTED_F_RESET)
1631         client_session->session_state = STATE_DISCONNECT;
1632     }
1633   return vcl_session_handle (client_session);
1634 }
1635
1636 static void
1637 vcl_ip_copy_from_ep (ip46_address_t * ip, vppcom_endpt_t * ep)
1638 {
1639   if (ep->is_ip4)
1640     clib_memcpy_fast (&ip->ip4, ep->ip, sizeof (ip4_address_t));
1641   else
1642     clib_memcpy_fast (&ip->ip6, ep->ip, sizeof (ip6_address_t));
1643 }
1644
1645 void
1646 vcl_ip_copy_to_ep (ip46_address_t * ip, vppcom_endpt_t * ep, u8 is_ip4)
1647 {
1648   ep->is_ip4 = is_ip4;
1649   if (is_ip4)
1650     clib_memcpy_fast (ep->ip, &ip->ip4, sizeof (ip4_address_t));
1651   else
1652     clib_memcpy_fast (ep->ip, &ip->ip6, sizeof (ip6_address_t));
1653 }
1654
1655 int
1656 vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep)
1657 {
1658   vcl_worker_t *wrk = vcl_worker_get_current ();
1659   vcl_session_t *session = 0;
1660   u32 session_index;
1661   int rv;
1662
1663   session = vcl_session_get_w_handle (wrk, session_handle);
1664   if (!session)
1665     return VPPCOM_EBADFD;
1666   session_index = session->session_index;
1667
1668   if (PREDICT_FALSE (session->is_vep))
1669     {
1670       VDBG (0, "ERROR: cannot connect epoll session %u!",
1671             session->session_index);
1672       return VPPCOM_EBADFD;
1673     }
1674
1675   if (PREDICT_FALSE (session->session_state & CLIENT_STATE_OPEN))
1676     {
1677       VDBG (0, "session handle %u [0x%llx]: session already "
1678             "connected to %s %U port %d proto %s, state 0x%x (%s)",
1679             session_handle, session->vpp_handle,
1680             session->transport.is_ip4 ? "IPv4" : "IPv6", format_ip46_address,
1681             &session->transport.rmt_ip, session->transport.is_ip4 ?
1682             IP46_TYPE_IP4 : IP46_TYPE_IP6,
1683             clib_net_to_host_u16 (session->transport.rmt_port),
1684             vppcom_proto_str (session->session_type), session->session_state,
1685             vppcom_session_state_str (session->session_state));
1686       return VPPCOM_OK;
1687     }
1688
1689   session->transport.is_ip4 = server_ep->is_ip4;
1690   vcl_ip_copy_from_ep (&session->transport.rmt_ip, server_ep);
1691   session->transport.rmt_port = server_ep->port;
1692   session->parent_handle = VCL_INVALID_SESSION_HANDLE;
1693
1694   VDBG (0, "session handle %u: connecting to server %s %U "
1695         "port %d proto %s", session_handle,
1696         session->transport.is_ip4 ? "IPv4" : "IPv6",
1697         format_ip46_address,
1698         &session->transport.rmt_ip, session->transport.is_ip4 ?
1699         IP46_TYPE_IP4 : IP46_TYPE_IP6,
1700         clib_net_to_host_u16 (session->transport.rmt_port),
1701         vppcom_proto_str (session->session_type));
1702
1703   vcl_send_session_connect (wrk, session);
1704
1705   if (VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK))
1706     return VPPCOM_EINPROGRESS;
1707
1708   /*
1709    * Wait for reply from vpp if blocking
1710    */
1711   rv = vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
1712                                              vcm->cfg.session_timeout);
1713
1714   session = vcl_session_get (wrk, session_index);
1715   VDBG (0, "session %u [0x%llx]: connect %s!", session->session_index,
1716         session->vpp_handle, rv ? "failed" : "succeeded");
1717
1718   return rv;
1719 }
1720
1721 int
1722 vppcom_session_stream_connect (uint32_t session_handle,
1723                                uint32_t parent_session_handle)
1724 {
1725   vcl_worker_t *wrk = vcl_worker_get_current ();
1726   vcl_session_t *session, *parent_session;
1727   u32 session_index, parent_session_index;
1728   int rv;
1729
1730   session = vcl_session_get_w_handle (wrk, session_handle);
1731   if (!session)
1732     return VPPCOM_EBADFD;
1733   parent_session = vcl_session_get_w_handle (wrk, parent_session_handle);
1734   if (!parent_session)
1735     return VPPCOM_EBADFD;
1736
1737   session_index = session->session_index;
1738   parent_session_index = parent_session->session_index;
1739   if (PREDICT_FALSE (session->is_vep))
1740     {
1741       VDBG (0, "ERROR: cannot connect epoll session %u!",
1742             session->session_index);
1743       return VPPCOM_EBADFD;
1744     }
1745
1746   if (PREDICT_FALSE (session->session_state & CLIENT_STATE_OPEN))
1747     {
1748       VDBG (0, "session handle %u [0x%llx]: session already "
1749             "connected to session %u [0x%llx] proto %s, state 0x%x (%s)",
1750             session_handle, session->vpp_handle,
1751             parent_session_handle, parent_session->vpp_handle,
1752             vppcom_proto_str (session->session_type), session->session_state,
1753             vppcom_session_state_str (session->session_state));
1754       return VPPCOM_OK;
1755     }
1756
1757   /* Connect to quic session specifics */
1758   session->transport.is_ip4 = parent_session->transport.is_ip4;
1759   session->transport.rmt_ip.ip4.as_u32 = (uint32_t) 1;
1760   session->transport.rmt_port = 0;
1761   session->parent_handle = parent_session->vpp_handle;
1762
1763   VDBG (0, "session handle %u: connecting to session %u [0x%llx]",
1764         session_handle, parent_session_handle, parent_session->vpp_handle);
1765
1766   /*
1767    * Send connect request and wait for reply from vpp
1768    */
1769   vcl_send_session_connect (wrk, session);
1770   rv = vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
1771                                              vcm->cfg.session_timeout);
1772
1773   session->listener_index = parent_session_index;
1774   parent_session = vcl_session_get_w_handle (wrk, parent_session_handle);
1775   if (parent_session)
1776     parent_session->n_accepted_sessions++;
1777
1778   session = vcl_session_get (wrk, session_index);
1779   VDBG (0, "session %u [0x%llx]: connect %s!", session->session_index,
1780         session->vpp_handle, rv ? "failed" : "succeeded");
1781
1782   return rv;
1783 }
1784
1785 static u8
1786 vcl_is_rx_evt_for_session (session_event_t * e, u32 sid, u8 is_ct)
1787 {
1788   return (e->event_type == SESSION_IO_EVT_RX && e->session_index == sid);
1789 }
1790
1791 static inline int
1792 vppcom_session_read_internal (uint32_t session_handle, void *buf, int n,
1793                               u8 peek)
1794 {
1795   vcl_worker_t *wrk = vcl_worker_get_current ();
1796   int n_read = 0, is_nonblocking;
1797   vcl_session_t *s = 0;
1798   svm_fifo_t *rx_fifo;
1799   svm_msg_q_msg_t msg;
1800   session_event_t *e;
1801   svm_msg_q_t *mq;
1802   u8 is_ct;
1803
1804   if (PREDICT_FALSE (!buf))
1805     return VPPCOM_EINVAL;
1806
1807   s = vcl_session_get_w_handle (wrk, session_handle);
1808   if (PREDICT_FALSE (!s || s->is_vep))
1809     return VPPCOM_EBADFD;
1810
1811   if (PREDICT_FALSE (!vcl_session_is_open (s)))
1812     {
1813       VDBG (0, "session %u[0x%llx] is not open! state 0x%x (%s)",
1814             s->session_index, s->vpp_handle, s->session_state,
1815             vppcom_session_state_str (s->session_state));
1816       return vcl_session_closed_error (s);
1817     }
1818
1819   is_nonblocking = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
1820   is_ct = vcl_session_is_ct (s);
1821   mq = wrk->app_event_queue;
1822   rx_fifo = is_ct ? s->ct_rx_fifo : s->rx_fifo;
1823   s->has_rx_evt = 0;
1824
1825   if (svm_fifo_is_empty_cons (rx_fifo))
1826     {
1827       if (is_nonblocking)
1828         {
1829           if (vcl_session_is_closing (s))
1830             return vcl_session_closing_error (s);
1831           svm_fifo_unset_event (s->rx_fifo);
1832           return VPPCOM_EWOULDBLOCK;
1833         }
1834       while (svm_fifo_is_empty_cons (rx_fifo))
1835         {
1836           if (vcl_session_is_closing (s))
1837             return vcl_session_closing_error (s);
1838
1839           svm_fifo_unset_event (s->rx_fifo);
1840           svm_msg_q_lock (mq);
1841           if (svm_msg_q_is_empty (mq))
1842             svm_msg_q_wait (mq);
1843
1844           svm_msg_q_sub_w_lock (mq, &msg);
1845           e = svm_msg_q_msg_data (mq, &msg);
1846           svm_msg_q_unlock (mq);
1847           if (!vcl_is_rx_evt_for_session (e, s->session_index, is_ct))
1848             vcl_handle_mq_event (wrk, e);
1849           svm_msg_q_free_msg (mq, &msg);
1850         }
1851     }
1852
1853   if (s->is_dgram)
1854     n_read = app_recv_dgram_raw (rx_fifo, buf, n, &s->transport, 0, peek);
1855   else
1856     n_read = app_recv_stream_raw (rx_fifo, buf, n, 0, peek);
1857
1858   if (svm_fifo_is_empty_cons (rx_fifo))
1859     svm_fifo_unset_event (s->rx_fifo);
1860
1861   /* Cut-through sessions might request tx notifications on rx fifos */
1862   if (PREDICT_FALSE (rx_fifo->want_deq_ntf))
1863     {
1864       app_send_io_evt_to_vpp (s->vpp_evt_q, s->rx_fifo->master_session_index,
1865                               SESSION_IO_EVT_RX, SVM_Q_WAIT);
1866       svm_fifo_reset_has_deq_ntf (s->rx_fifo);
1867     }
1868
1869   VDBG (2, "session %u[0x%llx]: read %d bytes from (%p)", s->session_index,
1870         s->vpp_handle, n_read, rx_fifo);
1871
1872   return n_read;
1873 }
1874
1875 int
1876 vppcom_session_read (uint32_t session_handle, void *buf, size_t n)
1877 {
1878   return (vppcom_session_read_internal (session_handle, buf, n, 0));
1879 }
1880
1881 static int
1882 vppcom_session_peek (uint32_t session_handle, void *buf, int n)
1883 {
1884   return (vppcom_session_read_internal (session_handle, buf, n, 1));
1885 }
1886
1887 int
1888 vppcom_session_read_segments (uint32_t session_handle,
1889                               vppcom_data_segments_t ds)
1890 {
1891   vcl_worker_t *wrk = vcl_worker_get_current ();
1892   int n_read = 0, is_nonblocking;
1893   vcl_session_t *s = 0;
1894   svm_fifo_t *rx_fifo;
1895   svm_msg_q_msg_t msg;
1896   session_event_t *e;
1897   svm_msg_q_t *mq;
1898   u8 is_ct;
1899
1900   s = vcl_session_get_w_handle (wrk, session_handle);
1901   if (PREDICT_FALSE (!s || s->is_vep))
1902     return VPPCOM_EBADFD;
1903
1904   if (PREDICT_FALSE (!vcl_session_is_open (s)))
1905     return vcl_session_closed_error (s);
1906
1907   is_nonblocking = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
1908   is_ct = vcl_session_is_ct (s);
1909   mq = is_ct ? s->our_evt_q : wrk->app_event_queue;
1910   rx_fifo = s->rx_fifo;
1911   s->has_rx_evt = 0;
1912
1913   if (is_ct)
1914     svm_fifo_unset_event (s->rx_fifo);
1915
1916   if (svm_fifo_is_empty_cons (rx_fifo))
1917     {
1918       if (is_nonblocking)
1919         {
1920           svm_fifo_unset_event (rx_fifo);
1921           return VPPCOM_EWOULDBLOCK;
1922         }
1923       while (svm_fifo_is_empty_cons (rx_fifo))
1924         {
1925           if (vcl_session_is_closing (s))
1926             return vcl_session_closing_error (s);
1927
1928           svm_fifo_unset_event (rx_fifo);
1929           svm_msg_q_lock (mq);
1930           if (svm_msg_q_is_empty (mq))
1931             svm_msg_q_wait (mq);
1932
1933           svm_msg_q_sub_w_lock (mq, &msg);
1934           e = svm_msg_q_msg_data (mq, &msg);
1935           svm_msg_q_unlock (mq);
1936           if (!vcl_is_rx_evt_for_session (e, s->session_index, is_ct))
1937             vcl_handle_mq_event (wrk, e);
1938           svm_msg_q_free_msg (mq, &msg);
1939         }
1940     }
1941
1942   n_read = svm_fifo_segments (rx_fifo, (svm_fifo_seg_t *) ds);
1943   svm_fifo_unset_event (rx_fifo);
1944
1945   return n_read;
1946 }
1947
1948 void
1949 vppcom_session_free_segments (uint32_t session_handle,
1950                               vppcom_data_segments_t ds)
1951 {
1952   vcl_worker_t *wrk = vcl_worker_get_current ();
1953   vcl_session_t *s;
1954
1955   s = vcl_session_get_w_handle (wrk, session_handle);
1956   if (PREDICT_FALSE (!s || s->is_vep))
1957     return;
1958
1959   svm_fifo_segments_free (s->rx_fifo, (svm_fifo_seg_t *) ds);
1960 }
1961
1962 int
1963 vppcom_data_segment_copy (void *buf, vppcom_data_segments_t ds, u32 max_bytes)
1964 {
1965   u32 first_copy = clib_min (ds[0].len, max_bytes);
1966   clib_memcpy_fast (buf, ds[0].data, first_copy);
1967   if (first_copy < max_bytes)
1968     {
1969       clib_memcpy_fast (buf + first_copy, ds[1].data,
1970                         clib_min (ds[1].len, max_bytes - first_copy));
1971     }
1972   return 0;
1973 }
1974
1975 static u8
1976 vcl_is_tx_evt_for_session (session_event_t * e, u32 sid, u8 is_ct)
1977 {
1978   return (e->event_type == SESSION_IO_EVT_TX && e->session_index == sid);
1979 }
1980
1981 static inline int
1982 vppcom_session_write_inline (uint32_t session_handle, void *buf, size_t n,
1983                              u8 is_flush)
1984 {
1985   vcl_worker_t *wrk = vcl_worker_get_current ();
1986   int n_write, is_nonblocking;
1987   vcl_session_t *s = 0;
1988   session_evt_type_t et;
1989   svm_msg_q_msg_t msg;
1990   svm_fifo_t *tx_fifo;
1991   session_event_t *e;
1992   svm_msg_q_t *mq;
1993   u8 is_ct;
1994
1995   if (PREDICT_FALSE (!buf || n == 0))
1996     return VPPCOM_EINVAL;
1997
1998   s = vcl_session_get_w_handle (wrk, session_handle);
1999   if (PREDICT_FALSE (!s))
2000     return VPPCOM_EBADFD;
2001
2002   if (PREDICT_FALSE (s->is_vep))
2003     {
2004       VDBG (0, "ERROR: session %u [0x%llx]: cannot write to an epoll"
2005             " session!", s->session_index, s->vpp_handle);
2006       return VPPCOM_EBADFD;
2007     }
2008
2009   if (PREDICT_FALSE (!vcl_session_is_open (s)))
2010     {
2011       VDBG (1, "session %u [0x%llx]: is not open! state 0x%x (%s)",
2012             s->session_index, s->vpp_handle, s->session_state,
2013             vppcom_session_state_str (s->session_state));
2014       return vcl_session_closed_error (s);;
2015     }
2016
2017   is_ct = vcl_session_is_ct (s);
2018   tx_fifo = is_ct ? s->ct_tx_fifo : s->tx_fifo;
2019   is_nonblocking = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
2020
2021   mq = wrk->app_event_queue;
2022   if (svm_fifo_is_full_prod (tx_fifo))
2023     {
2024       if (is_nonblocking)
2025         {
2026           return VPPCOM_EWOULDBLOCK;
2027         }
2028       while (svm_fifo_is_full_prod (tx_fifo))
2029         {
2030           svm_fifo_add_want_deq_ntf (tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
2031           if (vcl_session_is_closing (s))
2032             return vcl_session_closing_error (s);
2033           svm_msg_q_lock (mq);
2034           if (svm_msg_q_is_empty (mq))
2035             svm_msg_q_wait (mq);
2036
2037           svm_msg_q_sub_w_lock (mq, &msg);
2038           e = svm_msg_q_msg_data (mq, &msg);
2039           svm_msg_q_unlock (mq);
2040
2041           if (!vcl_is_tx_evt_for_session (e, s->session_index, is_ct))
2042             vcl_handle_mq_event (wrk, e);
2043           svm_msg_q_free_msg (mq, &msg);
2044         }
2045     }
2046
2047   et = SESSION_IO_EVT_TX;
2048   if (is_flush && !is_ct)
2049     et = SESSION_IO_EVT_TX_FLUSH;
2050
2051   if (s->is_dgram)
2052     n_write = app_send_dgram_raw (tx_fifo, &s->transport,
2053                                   s->vpp_evt_q, buf, n, et,
2054                                   0 /* do_evt */ , SVM_Q_WAIT);
2055   else
2056     n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et,
2057                                    0 /* do_evt */ , SVM_Q_WAIT);
2058
2059   if (svm_fifo_set_event (s->tx_fifo))
2060     app_send_io_evt_to_vpp (s->vpp_evt_q, s->tx_fifo->master_session_index,
2061                             et, SVM_Q_WAIT);
2062
2063   ASSERT (n_write > 0);
2064
2065   VDBG (2, "session %u [0x%llx]: wrote %d bytes", s->session_index,
2066         s->vpp_handle, n_write);
2067
2068   return n_write;
2069 }
2070
2071 int
2072 vppcom_session_write (uint32_t session_handle, void *buf, size_t n)
2073 {
2074   return vppcom_session_write_inline (session_handle, buf, n,
2075                                       0 /* is_flush */ );
2076 }
2077
2078 int
2079 vppcom_session_write_msg (uint32_t session_handle, void *buf, size_t n)
2080 {
2081   return vppcom_session_write_inline (session_handle, buf, n,
2082                                       1 /* is_flush */ );
2083 }
2084
2085 #define vcl_fifo_rx_evt_valid_or_break(_s)                              \
2086 if (PREDICT_FALSE (!_s->rx_fifo))                                       \
2087   break;                                                                \
2088 if (PREDICT_FALSE (svm_fifo_is_empty (_s->rx_fifo)))                    \
2089   {                                                                     \
2090     if (!vcl_session_is_ct (_s))                                        \
2091       {                                                                 \
2092         svm_fifo_unset_event (_s->rx_fifo);                             \
2093         if (svm_fifo_is_empty (_s->rx_fifo))                            \
2094           break;                                                        \
2095       }                                                                 \
2096     else if (svm_fifo_is_empty (_s->ct_rx_fifo))                        \
2097       {                                                                 \
2098         svm_fifo_unset_event (_s->ct_rx_fifo);                          \
2099         if (svm_fifo_is_empty (_s->ct_rx_fifo))                         \
2100           break;                                                        \
2101       }                                                                 \
2102   }                                                                     \
2103
2104 static void
2105 vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
2106                             unsigned long n_bits, unsigned long *read_map,
2107                             unsigned long *write_map,
2108                             unsigned long *except_map, u32 * bits_set)
2109 {
2110   session_disconnected_msg_t *disconnected_msg;
2111   session_connected_msg_t *connected_msg;
2112   vcl_session_t *session;
2113   u32 sid;
2114
2115   switch (e->event_type)
2116     {
2117     case SESSION_IO_EVT_RX:
2118       sid = e->session_index;
2119       session = vcl_session_get (wrk, sid);
2120       if (!session)
2121         break;
2122       vcl_fifo_rx_evt_valid_or_break (session);
2123       if (sid < n_bits && read_map)
2124         {
2125           clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2126           *bits_set += 1;
2127         }
2128       break;
2129     case SESSION_IO_EVT_TX:
2130       sid = e->session_index;
2131       session = vcl_session_get (wrk, sid);
2132       if (!session)
2133         break;
2134       if (sid < n_bits && write_map)
2135         {
2136           clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2137           *bits_set += 1;
2138         }
2139       break;
2140     case SESSION_CTRL_EVT_ACCEPTED:
2141       session = vcl_session_accepted (wrk,
2142                                       (session_accepted_msg_t *) e->data);
2143       if (!session)
2144         break;
2145       sid = session->session_index;
2146       if (sid < n_bits && read_map)
2147         {
2148           clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2149           *bits_set += 1;
2150         }
2151       break;
2152     case SESSION_CTRL_EVT_CONNECTED:
2153       connected_msg = (session_connected_msg_t *) e->data;
2154       sid = vcl_session_connected_handler (wrk, connected_msg);
2155       if (sid == VCL_INVALID_SESSION_INDEX)
2156         break;
2157       if (sid < n_bits && write_map)
2158         {
2159           clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2160           *bits_set += 1;
2161         }
2162       break;
2163     case SESSION_CTRL_EVT_DISCONNECTED:
2164       disconnected_msg = (session_disconnected_msg_t *) e->data;
2165       session = vcl_session_disconnected_handler (wrk, disconnected_msg);
2166       if (!session)
2167         break;
2168       sid = session->session_index;
2169       if (sid < n_bits && except_map)
2170         {
2171           clib_bitmap_set_no_check ((uword *) except_map, sid, 1);
2172           *bits_set += 1;
2173         }
2174       break;
2175     case SESSION_CTRL_EVT_RESET:
2176       sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
2177       if (sid < n_bits && except_map)
2178         {
2179           clib_bitmap_set_no_check ((uword *) except_map, sid, 1);
2180           *bits_set += 1;
2181         }
2182       break;
2183     case SESSION_CTRL_EVT_UNLISTEN_REPLY:
2184       vcl_session_unlisten_reply_handler (wrk, e->data);
2185       break;
2186     case SESSION_CTRL_EVT_MIGRATED:
2187       vcl_session_migrated_handler (wrk, e->data);
2188       break;
2189     case SESSION_CTRL_EVT_CLEANUP:
2190       vcl_session_cleanup_handler (wrk, e->data);
2191       break;
2192     case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
2193       vcl_session_worker_update_reply_handler (wrk, e->data);
2194       break;
2195     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
2196       vcl_session_req_worker_update_handler (wrk, e->data);
2197       break;
2198     case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
2199       vcl_session_app_add_segment_handler (wrk, e->data);
2200       break;
2201     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
2202       vcl_session_app_del_segment_handler (wrk, e->data);
2203       break;
2204     default:
2205       clib_warning ("unhandled: %u", e->event_type);
2206       break;
2207     }
2208 }
2209
2210 static int
2211 vcl_select_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
2212                       unsigned long n_bits, unsigned long *read_map,
2213                       unsigned long *write_map, unsigned long *except_map,
2214                       double time_to_wait, u32 * bits_set)
2215 {
2216   svm_msg_q_msg_t *msg;
2217   session_event_t *e;
2218   u32 i;
2219
2220   svm_msg_q_lock (mq);
2221   if (svm_msg_q_is_empty (mq))
2222     {
2223       if (*bits_set)
2224         {
2225           svm_msg_q_unlock (mq);
2226           return 0;
2227         }
2228
2229       if (!time_to_wait)
2230         {
2231           svm_msg_q_unlock (mq);
2232           return 0;
2233         }
2234       else if (time_to_wait < 0)
2235         {
2236           svm_msg_q_wait (mq);
2237         }
2238       else
2239         {
2240           if (svm_msg_q_timedwait (mq, time_to_wait))
2241             {
2242               svm_msg_q_unlock (mq);
2243               return 0;
2244             }
2245         }
2246     }
2247   vcl_mq_dequeue_batch (wrk, mq, ~0);
2248   svm_msg_q_unlock (mq);
2249
2250   for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
2251     {
2252       msg = vec_elt_at_index (wrk->mq_msg_vector, i);
2253       e = svm_msg_q_msg_data (mq, msg);
2254       vcl_select_handle_mq_event (wrk, e, n_bits, read_map, write_map,
2255                                   except_map, bits_set);
2256       svm_msg_q_free_msg (mq, msg);
2257     }
2258   vec_reset_length (wrk->mq_msg_vector);
2259   vcl_handle_pending_wrk_updates (wrk);
2260   return *bits_set;
2261 }
2262
2263 static int
2264 vppcom_select_condvar (vcl_worker_t * wrk, int n_bits,
2265                        vcl_si_set * read_map, vcl_si_set * write_map,
2266                        vcl_si_set * except_map, double time_to_wait,
2267                        u32 * bits_set)
2268 {
2269   double wait = 0, start = 0;
2270
2271   if (!*bits_set)
2272     {
2273       wait = time_to_wait;
2274       start = clib_time_now (&wrk->clib_time);
2275     }
2276
2277   do
2278     {
2279       vcl_select_handle_mq (wrk, wrk->app_event_queue, n_bits, read_map,
2280                             write_map, except_map, wait, bits_set);
2281       if (*bits_set)
2282         return *bits_set;
2283       if (wait == -1)
2284         continue;
2285
2286       wait = wait - (clib_time_now (&wrk->clib_time) - start);
2287     }
2288   while (wait > 0);
2289
2290   return 0;
2291 }
2292
2293 static int
2294 vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits,
2295                        vcl_si_set * read_map, vcl_si_set * write_map,
2296                        vcl_si_set * except_map, double time_to_wait,
2297                        u32 * bits_set)
2298 {
2299   vcl_mq_evt_conn_t *mqc;
2300   int __clib_unused n_read;
2301   int n_mq_evts, i;
2302   u64 buf;
2303
2304   vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
2305   n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
2306                           vec_len (wrk->mq_events), time_to_wait);
2307   for (i = 0; i < n_mq_evts; i++)
2308     {
2309       mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
2310       n_read = read (mqc->mq_fd, &buf, sizeof (buf));
2311       vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map,
2312                             except_map, 0, bits_set);
2313     }
2314
2315   return (n_mq_evts > 0 ? (int) *bits_set : 0);
2316 }
2317
2318 int
2319 vppcom_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map,
2320                vcl_si_set * except_map, double time_to_wait)
2321 {
2322   u32 sid, minbits = clib_max (n_bits, BITS (uword)), bits_set = 0;
2323   vcl_worker_t *wrk = vcl_worker_get_current ();
2324   vcl_session_t *session = 0;
2325   int rv, i;
2326
2327   if (n_bits && read_map)
2328     {
2329       clib_bitmap_validate (wrk->rd_bitmap, minbits);
2330       clib_memcpy_fast (wrk->rd_bitmap, read_map,
2331                         vec_len (wrk->rd_bitmap) * sizeof (vcl_si_set));
2332       memset (read_map, 0, vec_len (wrk->rd_bitmap) * sizeof (vcl_si_set));
2333     }
2334   if (n_bits && write_map)
2335     {
2336       clib_bitmap_validate (wrk->wr_bitmap, minbits);
2337       clib_memcpy_fast (wrk->wr_bitmap, write_map,
2338                         vec_len (wrk->wr_bitmap) * sizeof (vcl_si_set));
2339       memset (write_map, 0, vec_len (wrk->wr_bitmap) * sizeof (vcl_si_set));
2340     }
2341   if (n_bits && except_map)
2342     {
2343       clib_bitmap_validate (wrk->ex_bitmap, minbits);
2344       clib_memcpy_fast (wrk->ex_bitmap, except_map,
2345                         vec_len (wrk->ex_bitmap) * sizeof (vcl_si_set));
2346       memset (except_map, 0, vec_len (wrk->ex_bitmap) * sizeof (vcl_si_set));
2347     }
2348
2349   if (!n_bits)
2350     return 0;
2351
2352   if (!write_map)
2353     goto check_rd;
2354
2355   /* *INDENT-OFF* */
2356   clib_bitmap_foreach (sid, wrk->wr_bitmap, ({
2357     if (!(session = vcl_session_get (wrk, sid)))
2358       {
2359         if (except_map && sid < minbits)
2360           clib_bitmap_set_no_check (except_map, sid, 1);
2361         continue;
2362       }
2363
2364     rv = svm_fifo_is_full_prod (session->tx_fifo);
2365     if (!rv)
2366       {
2367         clib_bitmap_set_no_check ((uword*)write_map, sid, 1);
2368         bits_set++;
2369       }
2370     else
2371       svm_fifo_add_want_deq_ntf (session->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
2372   }));
2373
2374 check_rd:
2375   if (!read_map)
2376     goto check_mq;
2377
2378   clib_bitmap_foreach (sid, wrk->rd_bitmap, ({
2379     if (!(session = vcl_session_get (wrk, sid)))
2380       {
2381         if (except_map && sid < minbits)
2382           clib_bitmap_set_no_check (except_map, sid, 1);
2383         continue;
2384       }
2385
2386     rv = vcl_session_read_ready (session);
2387     if (rv)
2388       {
2389         clib_bitmap_set_no_check ((uword*)read_map, sid, 1);
2390         bits_set++;
2391       }
2392   }));
2393   /* *INDENT-ON* */
2394
2395 check_mq:
2396
2397   for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
2398     {
2399       vcl_select_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i], n_bits,
2400                                   read_map, write_map, except_map, &bits_set);
2401     }
2402   vec_reset_length (wrk->unhandled_evts_vector);
2403
2404   if (vcm->cfg.use_mq_eventfd)
2405     vppcom_select_eventfd (wrk, n_bits, read_map, write_map, except_map,
2406                            time_to_wait, &bits_set);
2407   else
2408     vppcom_select_condvar (wrk, n_bits, read_map, write_map, except_map,
2409                            time_to_wait, &bits_set);
2410
2411   return (bits_set);
2412 }
2413
2414 static inline void
2415 vep_verify_epoll_chain (vcl_worker_t * wrk, u32 vep_handle)
2416 {
2417   vcl_session_t *session;
2418   vppcom_epoll_t *vep;
2419   u32 sh = vep_handle;
2420
2421   if (VPPCOM_DEBUG <= 2)
2422     return;
2423
2424   session = vcl_session_get_w_handle (wrk, vep_handle);
2425   if (PREDICT_FALSE (!session))
2426     {
2427       VDBG (0, "ERROR: Invalid vep_sh (%u)!", vep_handle);
2428       goto done;
2429     }
2430   if (PREDICT_FALSE (!session->is_vep))
2431     {
2432       VDBG (0, "ERROR: vep_sh (%u) is not a vep!", vep_handle);
2433       goto done;
2434     }
2435   vep = &session->vep;
2436   VDBG (0, "vep_sh (%u): Dumping epoll chain\n"
2437         "{\n"
2438         "   is_vep         = %u\n"
2439         "   is_vep_session = %u\n"
2440         "   next_sh        = 0x%x (%u)\n"
2441         "}\n", vep_handle, session->is_vep, session->is_vep_session,
2442         vep->next_sh, vep->next_sh);
2443
2444   for (sh = vep->next_sh; sh != ~0; sh = vep->next_sh)
2445     {
2446       session = vcl_session_get_w_handle (wrk, sh);
2447       if (PREDICT_FALSE (!session))
2448         {
2449           VDBG (0, "ERROR: Invalid sh (%u)!", sh);
2450           goto done;
2451         }
2452       if (PREDICT_FALSE (session->is_vep))
2453         {
2454           VDBG (0, "ERROR: sh (%u) is a vep!", vep_handle);
2455         }
2456       else if (PREDICT_FALSE (!session->is_vep_session))
2457         {
2458           VDBG (0, "ERROR: sh (%u) is not a vep session handle!", sh);
2459           goto done;
2460         }
2461       vep = &session->vep;
2462       if (PREDICT_FALSE (vep->vep_sh != vep_handle))
2463         VDBG (0, "ERROR: session (%u) vep_sh (%u) != vep_sh (%u)!",
2464               sh, session->vep.vep_sh, vep_handle);
2465       if (session->is_vep_session)
2466         {
2467           VDBG (0, "vep_sh[%u]: sh 0x%x (%u)\n"
2468                 "{\n"
2469                 "   next_sh        = 0x%x (%u)\n"
2470                 "   prev_sh        = 0x%x (%u)\n"
2471                 "   vep_sh         = 0x%x (%u)\n"
2472                 "   ev.events      = 0x%x\n"
2473                 "   ev.data.u64    = 0x%llx\n"
2474                 "   et_mask        = 0x%x\n"
2475                 "}\n",
2476                 vep_handle, sh, sh, vep->next_sh, vep->next_sh, vep->prev_sh,
2477                 vep->prev_sh, vep->vep_sh, vep->vep_sh, vep->ev.events,
2478                 vep->ev.data.u64, vep->et_mask);
2479         }
2480     }
2481
2482 done:
2483   VDBG (0, "vep_sh (%u): Dump complete!\n", vep_handle);
2484 }
2485
2486 int
2487 vppcom_epoll_create (void)
2488 {
2489   vcl_worker_t *wrk = vcl_worker_get_current ();
2490   vcl_session_t *vep_session;
2491
2492   vep_session = vcl_session_alloc (wrk);
2493
2494   vep_session->is_vep = 1;
2495   vep_session->vep.vep_sh = ~0;
2496   vep_session->vep.next_sh = ~0;
2497   vep_session->vep.prev_sh = ~0;
2498   vep_session->vpp_handle = ~0;
2499
2500   vcl_evt (VCL_EVT_EPOLL_CREATE, vep_session, vep_session->session_index);
2501   VDBG (0, "Created vep_idx %u", vep_session->session_index);
2502
2503   return vcl_session_handle (vep_session);
2504 }
2505
2506 int
2507 vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
2508                   struct epoll_event *event)
2509 {
2510   vcl_worker_t *wrk = vcl_worker_get_current ();
2511   vcl_session_t *vep_session;
2512   vcl_session_t *session;
2513   int rv = VPPCOM_OK;
2514
2515   if (vep_handle == session_handle)
2516     {
2517       VDBG (0, "vep_sh == session handle (%u)!", vep_handle);
2518       return VPPCOM_EINVAL;
2519     }
2520
2521   vep_session = vcl_session_get_w_handle (wrk, vep_handle);
2522   if (PREDICT_FALSE (!vep_session))
2523     {
2524       VDBG (0, "Invalid vep_sh (%u)!", vep_handle);
2525       return VPPCOM_EBADFD;
2526     }
2527   if (PREDICT_FALSE (!vep_session->is_vep))
2528     {
2529       VDBG (0, "vep_sh (%u) is not a vep!", vep_handle);
2530       return VPPCOM_EINVAL;
2531     }
2532
2533   ASSERT (vep_session->vep.vep_sh == ~0);
2534   ASSERT (vep_session->vep.prev_sh == ~0);
2535
2536   session = vcl_session_get_w_handle (wrk, session_handle);
2537   if (PREDICT_FALSE (!session))
2538     {
2539       VDBG (0, "Invalid session_handle (%u)!", session_handle);
2540       return VPPCOM_EBADFD;
2541     }
2542   if (PREDICT_FALSE (session->is_vep))
2543     {
2544       VDBG (0, "session_handle (%u) is a vep!", vep_handle);
2545       return VPPCOM_EINVAL;
2546     }
2547
2548   switch (op)
2549     {
2550     case EPOLL_CTL_ADD:
2551       if (PREDICT_FALSE (!event))
2552         {
2553           VDBG (0, "EPOLL_CTL_ADD: NULL pointer to epoll_event structure!");
2554           return VPPCOM_EINVAL;
2555         }
2556       if (vep_session->vep.next_sh != ~0)
2557         {
2558           vcl_session_t *next_session;
2559           next_session = vcl_session_get_w_handle (wrk,
2560                                                    vep_session->vep.next_sh);
2561           if (PREDICT_FALSE (!next_session))
2562             {
2563               VDBG (0, "EPOLL_CTL_ADD: Invalid vep.next_sh (%u) on "
2564                     "vep_idx (%u)!", vep_session->vep.next_sh, vep_handle);
2565               return VPPCOM_EBADFD;
2566             }
2567           ASSERT (next_session->vep.prev_sh == vep_handle);
2568           next_session->vep.prev_sh = session_handle;
2569         }
2570       session->vep.next_sh = vep_session->vep.next_sh;
2571       session->vep.prev_sh = vep_handle;
2572       session->vep.vep_sh = vep_handle;
2573       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
2574       session->vep.ev = *event;
2575       session->is_vep = 0;
2576       session->is_vep_session = 1;
2577       vep_session->vep.next_sh = session_handle;
2578
2579       if (session->tx_fifo)
2580         svm_fifo_add_want_deq_ntf (session->tx_fifo,
2581                                    SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
2582
2583       /* Generate EPOLLOUT if tx fifo not full */
2584       if ((event->events & EPOLLOUT) &&
2585           (vcl_session_write_ready (session) > 0))
2586         {
2587           session_event_t e = { 0 };
2588           e.event_type = SESSION_IO_EVT_TX;
2589           e.session_index = session->session_index;
2590           vec_add1 (wrk->unhandled_evts_vector, e);
2591         }
2592       /* Generate EPOLLIN if rx fifo has data */
2593       if ((event->events & EPOLLIN) && (vcl_session_read_ready (session) > 0))
2594         {
2595           session_event_t e = { 0 };
2596           e.event_type = SESSION_IO_EVT_RX;
2597           e.session_index = session->session_index;
2598           vec_add1 (wrk->unhandled_evts_vector, e);
2599         }
2600       VDBG (1, "EPOLL_CTL_ADD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2601             vep_handle, session_handle, event->events, event->data.u64);
2602       vcl_evt (VCL_EVT_EPOLL_CTLADD, session, event->events, event->data.u64);
2603       break;
2604
2605     case EPOLL_CTL_MOD:
2606       if (PREDICT_FALSE (!event))
2607         {
2608           VDBG (0, "EPOLL_CTL_MOD: NULL pointer to epoll_event structure!");
2609           rv = VPPCOM_EINVAL;
2610           goto done;
2611         }
2612       else if (PREDICT_FALSE (!session->is_vep_session))
2613         {
2614           VDBG (0, "sh %u EPOLL_CTL_MOD: not a vep session!", session_handle);
2615           rv = VPPCOM_EINVAL;
2616           goto done;
2617         }
2618       else if (PREDICT_FALSE (session->vep.vep_sh != vep_handle))
2619         {
2620           VDBG (0, "EPOLL_CTL_MOD: sh %u vep_sh (%u) != vep_sh (%u)!",
2621                 session_handle, session->vep.vep_sh, vep_handle);
2622           rv = VPPCOM_EINVAL;
2623           goto done;
2624         }
2625
2626       /* Generate EPOLLOUT when tx_fifo/ct_tx_fifo not full */
2627       if ((event->events & EPOLLOUT) &&
2628           !(session->vep.ev.events & EPOLLOUT) &&
2629           (vcl_session_write_ready (session) > 0))
2630         {
2631           session_event_t e = { 0 };
2632           e.event_type = SESSION_IO_EVT_TX;
2633           e.session_index = session->session_index;
2634           vec_add1 (wrk->unhandled_evts_vector, e);
2635         }
2636       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
2637       session->vep.ev = *event;
2638       VDBG (1, "EPOLL_CTL_MOD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2639             vep_handle, session_handle, event->events, event->data.u64);
2640       break;
2641
2642     case EPOLL_CTL_DEL:
2643       if (PREDICT_FALSE (!session->is_vep_session))
2644         {
2645           VDBG (0, "EPOLL_CTL_DEL: %u not a vep session!", session_handle);
2646           rv = VPPCOM_EINVAL;
2647           goto done;
2648         }
2649       else if (PREDICT_FALSE (session->vep.vep_sh != vep_handle))
2650         {
2651           VDBG (0, "EPOLL_CTL_DEL: sh %u vep_sh (%u) != vep_sh (%u)!",
2652                 session_handle, session->vep.vep_sh, vep_handle);
2653           rv = VPPCOM_EINVAL;
2654           goto done;
2655         }
2656
2657       if (session->vep.prev_sh == vep_handle)
2658         vep_session->vep.next_sh = session->vep.next_sh;
2659       else
2660         {
2661           vcl_session_t *prev_session;
2662           prev_session = vcl_session_get_w_handle (wrk, session->vep.prev_sh);
2663           if (PREDICT_FALSE (!prev_session))
2664             {
2665               VDBG (0, "EPOLL_CTL_DEL: Invalid prev_sh (%u) on sh (%u)!",
2666                     session->vep.prev_sh, session_handle);
2667               return VPPCOM_EBADFD;
2668             }
2669           ASSERT (prev_session->vep.next_sh == session_handle);
2670           prev_session->vep.next_sh = session->vep.next_sh;
2671         }
2672       if (session->vep.next_sh != ~0)
2673         {
2674           vcl_session_t *next_session;
2675           next_session = vcl_session_get_w_handle (wrk, session->vep.next_sh);
2676           if (PREDICT_FALSE (!next_session))
2677             {
2678               VDBG (0, "EPOLL_CTL_DEL: Invalid next_sh (%u) on sh (%u)!",
2679                     session->vep.next_sh, session_handle);
2680               return VPPCOM_EBADFD;
2681             }
2682           ASSERT (next_session->vep.prev_sh == session_handle);
2683           next_session->vep.prev_sh = session->vep.prev_sh;
2684         }
2685
2686       memset (&session->vep, 0, sizeof (session->vep));
2687       session->vep.next_sh = ~0;
2688       session->vep.prev_sh = ~0;
2689       session->vep.vep_sh = ~0;
2690       session->is_vep_session = 0;
2691
2692       if (session->tx_fifo)
2693         svm_fifo_del_want_deq_ntf (session->tx_fifo, SVM_FIFO_NO_DEQ_NOTIF);
2694
2695       VDBG (1, "EPOLL_CTL_DEL: vep_idx %u, sh %u!", vep_handle,
2696             session_handle);
2697       vcl_evt (VCL_EVT_EPOLL_CTLDEL, session, vep_sh);
2698       break;
2699
2700     default:
2701       VDBG (0, "Invalid operation (%d)!", op);
2702       rv = VPPCOM_EINVAL;
2703     }
2704
2705   vep_verify_epoll_chain (wrk, vep_handle);
2706
2707 done:
2708   return rv;
2709 }
2710
2711 static inline void
2712 vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
2713                                 struct epoll_event *events, u32 * num_ev)
2714 {
2715   session_disconnected_msg_t *disconnected_msg;
2716   session_connected_msg_t *connected_msg;
2717   u32 sid = ~0, session_events;
2718   u64 session_evt_data = ~0;
2719   vcl_session_t *session;
2720   u8 add_event = 0;
2721
2722   switch (e->event_type)
2723     {
2724     case SESSION_IO_EVT_RX:
2725       sid = e->session_index;
2726       if (!(session = vcl_session_get (wrk, sid)))
2727         break;
2728       vcl_fifo_rx_evt_valid_or_break (session);
2729       session_events = session->vep.ev.events;
2730       if (!(EPOLLIN & session->vep.ev.events) || session->has_rx_evt)
2731         break;
2732       add_event = 1;
2733       events[*num_ev].events |= EPOLLIN;
2734       session_evt_data = session->vep.ev.data.u64;
2735       session->has_rx_evt = 1;
2736       break;
2737     case SESSION_IO_EVT_TX:
2738       sid = e->session_index;
2739       if (!(session = vcl_session_get (wrk, sid)))
2740         break;
2741       session_events = session->vep.ev.events;
2742       if (!(EPOLLOUT & session_events))
2743         break;
2744       add_event = 1;
2745       events[*num_ev].events |= EPOLLOUT;
2746       session_evt_data = session->vep.ev.data.u64;
2747       svm_fifo_reset_has_deq_ntf (session->tx_fifo);
2748       break;
2749     case SESSION_CTRL_EVT_ACCEPTED:
2750       session = vcl_session_accepted (wrk,
2751                                       (session_accepted_msg_t *) e->data);
2752       if (!session)
2753         break;
2754
2755       session_events = session->vep.ev.events;
2756       if (!(EPOLLIN & session_events))
2757         break;
2758
2759       add_event = 1;
2760       events[*num_ev].events |= EPOLLIN;
2761       session_evt_data = session->vep.ev.data.u64;
2762       break;
2763     case SESSION_CTRL_EVT_CONNECTED:
2764       connected_msg = (session_connected_msg_t *) e->data;
2765       sid = vcl_session_connected_handler (wrk, connected_msg);
2766       /* Generate EPOLLOUT because there's no connected event */
2767       if (!(session = vcl_session_get (wrk, sid)))
2768         break;
2769       session_events = session->vep.ev.events;
2770       if (!(EPOLLOUT & session_events))
2771         break;
2772       add_event = 1;
2773       events[*num_ev].events |= EPOLLOUT;
2774       session_evt_data = session->vep.ev.data.u64;
2775       if (session->session_state & STATE_FAILED)
2776         events[*num_ev].events |= EPOLLHUP;
2777       break;
2778     case SESSION_CTRL_EVT_DISCONNECTED:
2779       disconnected_msg = (session_disconnected_msg_t *) e->data;
2780       session = vcl_session_disconnected_handler (wrk, disconnected_msg);
2781       if (!session)
2782         break;
2783       session_events = session->vep.ev.events;
2784       add_event = 1;
2785       events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2786       session_evt_data = session->vep.ev.data.u64;
2787       break;
2788     case SESSION_CTRL_EVT_RESET:
2789       sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
2790       if (!(session = vcl_session_get (wrk, sid)))
2791         break;
2792       session_events = session->vep.ev.events;
2793       add_event = 1;
2794       events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2795       session_evt_data = session->vep.ev.data.u64;
2796       break;
2797     case SESSION_CTRL_EVT_UNLISTEN_REPLY:
2798       vcl_session_unlisten_reply_handler (wrk, e->data);
2799       break;
2800     case SESSION_CTRL_EVT_MIGRATED:
2801       vcl_session_migrated_handler (wrk, e->data);
2802       break;
2803     case SESSION_CTRL_EVT_CLEANUP:
2804       vcl_session_cleanup_handler (wrk, e->data);
2805       break;
2806     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
2807       vcl_session_req_worker_update_handler (wrk, e->data);
2808       break;
2809     case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
2810       vcl_session_worker_update_reply_handler (wrk, e->data);
2811       break;
2812     case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
2813       vcl_session_app_add_segment_handler (wrk, e->data);
2814       break;
2815     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
2816       vcl_session_app_del_segment_handler (wrk, e->data);
2817       break;
2818     default:
2819       VDBG (0, "unhandled: %u", e->event_type);
2820       break;
2821     }
2822
2823   if (add_event)
2824     {
2825       events[*num_ev].data.u64 = session_evt_data;
2826       if (EPOLLONESHOT & session_events)
2827         {
2828           session = vcl_session_get (wrk, sid);
2829           session->vep.ev.events = 0;
2830         }
2831       *num_ev += 1;
2832     }
2833 }
2834
2835 static int
2836 vcl_epoll_wait_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
2837                           struct epoll_event *events, u32 maxevents,
2838                           double wait_for_time, u32 * num_ev)
2839 {
2840   svm_msg_q_msg_t *msg;
2841   session_event_t *e;
2842   int i;
2843
2844   if (vec_len (wrk->mq_msg_vector) && svm_msg_q_is_empty (mq))
2845     goto handle_dequeued;
2846
2847   svm_msg_q_lock (mq);
2848   if (svm_msg_q_is_empty (mq))
2849     {
2850       if (!wait_for_time)
2851         {
2852           svm_msg_q_unlock (mq);
2853           return 0;
2854         }
2855       else if (wait_for_time < 0)
2856         {
2857           svm_msg_q_wait (mq);
2858         }
2859       else
2860         {
2861           if (svm_msg_q_timedwait (mq, wait_for_time / 1e3))
2862             {
2863               svm_msg_q_unlock (mq);
2864               return 0;
2865             }
2866         }
2867     }
2868   ASSERT (maxevents > *num_ev);
2869   vcl_mq_dequeue_batch (wrk, mq, maxevents - *num_ev);
2870   svm_msg_q_unlock (mq);
2871
2872 handle_dequeued:
2873   for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
2874     {
2875       msg = vec_elt_at_index (wrk->mq_msg_vector, i);
2876       e = svm_msg_q_msg_data (mq, msg);
2877       vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
2878       svm_msg_q_free_msg (mq, msg);
2879     }
2880   vec_reset_length (wrk->mq_msg_vector);
2881   vcl_handle_pending_wrk_updates (wrk);
2882   return *num_ev;
2883 }
2884
2885 static int
2886 vppcom_epoll_wait_condvar (vcl_worker_t * wrk, struct epoll_event *events,
2887                            int maxevents, u32 n_evts, double wait_for_time)
2888 {
2889   double wait = 0, start = 0, now;
2890
2891   if (!n_evts)
2892     {
2893       wait = wait_for_time;
2894       start = clib_time_now (&wrk->clib_time);
2895     }
2896
2897   do
2898     {
2899       vcl_epoll_wait_handle_mq (wrk, wrk->app_event_queue, events, maxevents,
2900                                 wait, &n_evts);
2901       if (n_evts)
2902         return n_evts;
2903       if (wait == -1)
2904         continue;
2905
2906       now = clib_time_now (&wrk->clib_time);
2907       wait -= now - start;
2908       start = now;
2909     }
2910   while (wait > 0);
2911
2912   return 0;
2913 }
2914
2915 static int
2916 vppcom_epoll_wait_eventfd (vcl_worker_t * wrk, struct epoll_event *events,
2917                            int maxevents, u32 n_evts, double wait_for_time)
2918 {
2919   vcl_mq_evt_conn_t *mqc;
2920   int __clib_unused n_read;
2921   int n_mq_evts, i;
2922   u64 buf;
2923
2924   vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
2925 again:
2926   n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
2927                           vec_len (wrk->mq_events), wait_for_time);
2928   for (i = 0; i < n_mq_evts; i++)
2929     {
2930       mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
2931       n_read = read (mqc->mq_fd, &buf, sizeof (buf));
2932       vcl_epoll_wait_handle_mq (wrk, mqc->mq, events, maxevents, 0, &n_evts);
2933     }
2934   if (!n_evts && n_mq_evts > 0)
2935     goto again;
2936
2937   return (int) n_evts;
2938 }
2939
2940 int
2941 vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events,
2942                    int maxevents, double wait_for_time)
2943 {
2944   vcl_worker_t *wrk = vcl_worker_get_current ();
2945   vcl_session_t *vep_session;
2946   u32 n_evts = 0;
2947   int i;
2948
2949   if (PREDICT_FALSE (maxevents <= 0))
2950     {
2951       VDBG (0, "ERROR: Invalid maxevents (%d)!", maxevents);
2952       return VPPCOM_EINVAL;
2953     }
2954
2955   vep_session = vcl_session_get_w_handle (wrk, vep_handle);
2956   if (!vep_session)
2957     return VPPCOM_EBADFD;
2958
2959   if (PREDICT_FALSE (!vep_session->is_vep))
2960     {
2961       VDBG (0, "ERROR: vep_idx (%u) is not a vep!", vep_handle);
2962       return VPPCOM_EINVAL;
2963     }
2964
2965   memset (events, 0, sizeof (*events) * maxevents);
2966
2967   if (vec_len (wrk->unhandled_evts_vector))
2968     {
2969       for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
2970         {
2971           vcl_epoll_wait_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i],
2972                                           events, &n_evts);
2973           if (n_evts == maxevents)
2974             {
2975               vec_delete (wrk->unhandled_evts_vector, i + 1, 0);
2976               return n_evts;
2977             }
2978         }
2979       vec_reset_length (wrk->unhandled_evts_vector);
2980     }
2981
2982   if (vcm->cfg.use_mq_eventfd)
2983     return vppcom_epoll_wait_eventfd (wrk, events, maxevents, n_evts,
2984                                       wait_for_time);
2985
2986   return vppcom_epoll_wait_condvar (wrk, events, maxevents, n_evts,
2987                                     wait_for_time);
2988 }
2989
2990 int
2991 vppcom_session_attr (uint32_t session_handle, uint32_t op,
2992                      void *buffer, uint32_t * buflen)
2993 {
2994   vcl_worker_t *wrk = vcl_worker_get_current ();
2995   vcl_session_t *session;
2996   int rv = VPPCOM_OK;
2997   u32 *flags = buffer, tmp_flags = 0;
2998   vppcom_endpt_t *ep = buffer;
2999
3000   session = vcl_session_get_w_handle (wrk, session_handle);
3001   if (!session)
3002     return VPPCOM_EBADFD;
3003
3004   switch (op)
3005     {
3006     case VPPCOM_ATTR_GET_NREAD:
3007       rv = vcl_session_read_ready (session);
3008       VDBG (2, "VPPCOM_ATTR_GET_NREAD: sh %u, nread = %d", session_handle,
3009             rv);
3010       break;
3011
3012     case VPPCOM_ATTR_GET_NWRITE:
3013       rv = vcl_session_write_ready (session);
3014       VDBG (2, "VPPCOM_ATTR_GET_NWRITE: sh %u, nwrite = %d", session_handle,
3015             rv);
3016       break;
3017
3018     case VPPCOM_ATTR_GET_FLAGS:
3019       if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
3020         {
3021           *flags = O_RDWR | (VCL_SESS_ATTR_TEST (session->attr,
3022                                                  VCL_SESS_ATTR_NONBLOCK));
3023           *buflen = sizeof (*flags);
3024           VDBG (2, "VPPCOM_ATTR_GET_FLAGS: sh %u, flags = 0x%08x, "
3025                 "is_nonblocking = %u", session_handle, *flags,
3026                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
3027         }
3028       else
3029         rv = VPPCOM_EINVAL;
3030       break;
3031
3032     case VPPCOM_ATTR_SET_FLAGS:
3033       if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
3034         {
3035           if (*flags & O_NONBLOCK)
3036             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
3037           else
3038             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
3039
3040           VDBG (2, "VPPCOM_ATTR_SET_FLAGS: sh %u, flags = 0x%08x,"
3041                 " is_nonblocking = %u", session_handle, *flags,
3042                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
3043         }
3044       else
3045         rv = VPPCOM_EINVAL;
3046       break;
3047
3048     case VPPCOM_ATTR_GET_PEER_ADDR:
3049       if (PREDICT_TRUE (buffer && buflen &&
3050                         (*buflen >= sizeof (*ep)) && ep->ip))
3051         {
3052           ep->is_ip4 = session->transport.is_ip4;
3053           ep->port = session->transport.rmt_port;
3054           if (session->transport.is_ip4)
3055             clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
3056                               sizeof (ip4_address_t));
3057           else
3058             clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
3059                               sizeof (ip6_address_t));
3060           *buflen = sizeof (*ep);
3061           VDBG (1, "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, "
3062                 "addr = %U, port %u", session_handle, ep->is_ip4,
3063                 format_ip46_address, &session->transport.rmt_ip,
3064                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3065                 clib_net_to_host_u16 (ep->port));
3066         }
3067       else
3068         rv = VPPCOM_EINVAL;
3069       break;
3070
3071     case VPPCOM_ATTR_GET_LCL_ADDR:
3072       if (PREDICT_TRUE (buffer && buflen &&
3073                         (*buflen >= sizeof (*ep)) && ep->ip))
3074         {
3075           ep->is_ip4 = session->transport.is_ip4;
3076           ep->port = session->transport.lcl_port;
3077           if (session->transport.is_ip4)
3078             clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip4,
3079                               sizeof (ip4_address_t));
3080           else
3081             clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip6,
3082                               sizeof (ip6_address_t));
3083           *buflen = sizeof (*ep);
3084           VDBG (1, "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
3085                 " port %d", session_handle, ep->is_ip4, format_ip46_address,
3086                 &session->transport.lcl_ip,
3087                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3088                 clib_net_to_host_u16 (ep->port));
3089         }
3090       else
3091         rv = VPPCOM_EINVAL;
3092       break;
3093
3094     case VPPCOM_ATTR_SET_LCL_ADDR:
3095       if (PREDICT_TRUE (buffer && buflen &&
3096                         (*buflen >= sizeof (*ep)) && ep->ip))
3097         {
3098           session->transport.is_ip4 = ep->is_ip4;
3099           session->transport.lcl_port = ep->port;
3100           vcl_ip_copy_from_ep (&session->transport.lcl_ip, ep);
3101           *buflen = sizeof (*ep);
3102           VDBG (1, "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
3103                 " port %d", session_handle, ep->is_ip4, format_ip46_address,
3104                 &session->transport.lcl_ip,
3105                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3106                 clib_net_to_host_u16 (ep->port));
3107         }
3108       else
3109         rv = VPPCOM_EINVAL;
3110       break;
3111
3112     case VPPCOM_ATTR_GET_LIBC_EPFD:
3113       rv = session->libc_epfd;
3114       VDBG (2, "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d", rv);
3115       break;
3116
3117     case VPPCOM_ATTR_SET_LIBC_EPFD:
3118       if (PREDICT_TRUE (buffer && buflen &&
3119                         (*buflen == sizeof (session->libc_epfd))))
3120         {
3121           session->libc_epfd = *(int *) buffer;
3122           *buflen = sizeof (session->libc_epfd);
3123
3124           VDBG (2, "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, buflen %d",
3125                 session->libc_epfd, *buflen);
3126         }
3127       else
3128         rv = VPPCOM_EINVAL;
3129       break;
3130
3131     case VPPCOM_ATTR_GET_PROTOCOL:
3132       if (buffer && buflen && (*buflen >= sizeof (int)))
3133         {
3134           *(int *) buffer = session->session_type;
3135           *buflen = sizeof (int);
3136
3137           VDBG (2, "VPPCOM_ATTR_GET_PROTOCOL: %d (%s), buflen %d",
3138                 *(int *) buffer, *(int *) buffer ? "UDP" : "TCP", *buflen);
3139         }
3140       else
3141         rv = VPPCOM_EINVAL;
3142       break;
3143
3144     case VPPCOM_ATTR_GET_LISTEN:
3145       if (buffer && buflen && (*buflen >= sizeof (int)))
3146         {
3147           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3148                                                 VCL_SESS_ATTR_LISTEN);
3149           *buflen = sizeof (int);
3150
3151           VDBG (2, "VPPCOM_ATTR_GET_LISTEN: %d, buflen %d", *(int *) buffer,
3152                 *buflen);
3153         }
3154       else
3155         rv = VPPCOM_EINVAL;
3156       break;
3157
3158     case VPPCOM_ATTR_GET_ERROR:
3159       if (buffer && buflen && (*buflen >= sizeof (int)))
3160         {
3161           *(int *) buffer = 0;
3162           *buflen = sizeof (int);
3163
3164           VDBG (2, "VPPCOM_ATTR_GET_ERROR: %d, buflen %d, #VPP-TBD#",
3165                 *(int *) buffer, *buflen);
3166         }
3167       else
3168         rv = VPPCOM_EINVAL;
3169       break;
3170
3171     case VPPCOM_ATTR_GET_TX_FIFO_LEN:
3172       if (buffer && buflen && (*buflen >= sizeof (u32)))
3173         {
3174
3175           /* VPP-TBD */
3176           *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
3177                                 session->tx_fifo ? session->tx_fifo->nitems :
3178                                 vcm->cfg.tx_fifo_size);
3179           *buflen = sizeof (u32);
3180
3181           VDBG (2, "VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3182                 " #VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer,
3183                 *buflen);
3184         }
3185       else
3186         rv = VPPCOM_EINVAL;
3187       break;
3188
3189     case VPPCOM_ATTR_SET_TX_FIFO_LEN:
3190       if (buffer && buflen && (*buflen == sizeof (u32)))
3191         {
3192           /* VPP-TBD */
3193           session->sndbuf_size = *(u32 *) buffer;
3194           VDBG (2, "VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3195                 " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3196                 *buflen);
3197         }
3198       else
3199         rv = VPPCOM_EINVAL;
3200       break;
3201
3202     case VPPCOM_ATTR_GET_RX_FIFO_LEN:
3203       if (buffer && buflen && (*buflen >= sizeof (u32)))
3204         {
3205
3206           /* VPP-TBD */
3207           *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
3208                                 session->rx_fifo ? session->rx_fifo->nitems :
3209                                 vcm->cfg.rx_fifo_size);
3210           *buflen = sizeof (u32);
3211
3212           VDBG (2, "VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), buflen %d, "
3213                 "#VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer, *buflen);
3214         }
3215       else
3216         rv = VPPCOM_EINVAL;
3217       break;
3218
3219     case VPPCOM_ATTR_SET_RX_FIFO_LEN:
3220       if (buffer && buflen && (*buflen == sizeof (u32)))
3221         {
3222           /* VPP-TBD */
3223           session->rcvbuf_size = *(u32 *) buffer;
3224           VDBG (2, "VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), buflen %d,"
3225                 " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3226                 *buflen);
3227         }
3228       else
3229         rv = VPPCOM_EINVAL;
3230       break;
3231
3232     case VPPCOM_ATTR_GET_REUSEADDR:
3233       if (buffer && buflen && (*buflen >= sizeof (int)))
3234         {
3235           /* VPP-TBD */
3236           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3237                                                 VCL_SESS_ATTR_REUSEADDR);
3238           *buflen = sizeof (int);
3239
3240           VDBG (2, "VPPCOM_ATTR_GET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3241                 *(int *) buffer, *buflen);
3242         }
3243       else
3244         rv = VPPCOM_EINVAL;
3245       break;
3246
3247     case VPPCOM_ATTR_SET_REUSEADDR:
3248       if (buffer && buflen && (*buflen == sizeof (int)) &&
3249           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
3250         {
3251           /* VPP-TBD */
3252           if (*(int *) buffer)
3253             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEADDR);
3254           else
3255             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEADDR);
3256
3257           VDBG (2, "VPPCOM_ATTR_SET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3258                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_REUSEADDR),
3259                 *buflen);
3260         }
3261       else
3262         rv = VPPCOM_EINVAL;
3263       break;
3264
3265     case VPPCOM_ATTR_GET_REUSEPORT:
3266       if (buffer && buflen && (*buflen >= sizeof (int)))
3267         {
3268           /* VPP-TBD */
3269           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3270                                                 VCL_SESS_ATTR_REUSEPORT);
3271           *buflen = sizeof (int);
3272
3273           VDBG (2, "VPPCOM_ATTR_GET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3274                 *(int *) buffer, *buflen);
3275         }
3276       else
3277         rv = VPPCOM_EINVAL;
3278       break;
3279
3280     case VPPCOM_ATTR_SET_REUSEPORT:
3281       if (buffer && buflen && (*buflen == sizeof (int)) &&
3282           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
3283         {
3284           /* VPP-TBD */
3285           if (*(int *) buffer)
3286             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEPORT);
3287           else
3288             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEPORT);
3289
3290           VDBG (2, "VPPCOM_ATTR_SET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3291                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_REUSEPORT),
3292                 *buflen);
3293         }
3294       else
3295         rv = VPPCOM_EINVAL;
3296       break;
3297
3298     case VPPCOM_ATTR_GET_BROADCAST:
3299       if (buffer && buflen && (*buflen >= sizeof (int)))
3300         {
3301           /* VPP-TBD */
3302           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3303                                                 VCL_SESS_ATTR_BROADCAST);
3304           *buflen = sizeof (int);
3305
3306           VDBG (2, "VPPCOM_ATTR_GET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3307                 *(int *) buffer, *buflen);
3308         }
3309       else
3310         rv = VPPCOM_EINVAL;
3311       break;
3312
3313     case VPPCOM_ATTR_SET_BROADCAST:
3314       if (buffer && buflen && (*buflen == sizeof (int)))
3315         {
3316           /* VPP-TBD */
3317           if (*(int *) buffer)
3318             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_BROADCAST);
3319           else
3320             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_BROADCAST);
3321
3322           VDBG (2, "VPPCOM_ATTR_SET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3323                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_BROADCAST),
3324                 *buflen);
3325         }
3326       else
3327         rv = VPPCOM_EINVAL;
3328       break;
3329
3330     case VPPCOM_ATTR_GET_V6ONLY:
3331       if (buffer && buflen && (*buflen >= sizeof (int)))
3332         {
3333           /* VPP-TBD */
3334           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3335                                                 VCL_SESS_ATTR_V6ONLY);
3336           *buflen = sizeof (int);
3337
3338           VDBG (2, "VPPCOM_ATTR_GET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3339                 *(int *) buffer, *buflen);
3340         }
3341       else
3342         rv = VPPCOM_EINVAL;
3343       break;
3344
3345     case VPPCOM_ATTR_SET_V6ONLY:
3346       if (buffer && buflen && (*buflen == sizeof (int)))
3347         {
3348           /* VPP-TBD */
3349           if (*(int *) buffer)
3350             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_V6ONLY);
3351           else
3352             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_V6ONLY);
3353
3354           VDBG (2, "VPPCOM_ATTR_SET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3355                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_V6ONLY),
3356                 *buflen);
3357         }
3358       else
3359         rv = VPPCOM_EINVAL;
3360       break;
3361
3362     case VPPCOM_ATTR_GET_KEEPALIVE:
3363       if (buffer && buflen && (*buflen >= sizeof (int)))
3364         {
3365           /* VPP-TBD */
3366           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3367                                                 VCL_SESS_ATTR_KEEPALIVE);
3368           *buflen = sizeof (int);
3369
3370           VDBG (2, "VPPCOM_ATTR_GET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3371                 *(int *) buffer, *buflen);
3372         }
3373       else
3374         rv = VPPCOM_EINVAL;
3375       break;
3376
3377     case VPPCOM_ATTR_SET_KEEPALIVE:
3378       if (buffer && buflen && (*buflen == sizeof (int)))
3379         {
3380           /* VPP-TBD */
3381           if (*(int *) buffer)
3382             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_KEEPALIVE);
3383           else
3384             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_KEEPALIVE);
3385
3386           VDBG (2, "VPPCOM_ATTR_SET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3387                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_KEEPALIVE),
3388                 *buflen);
3389         }
3390       else
3391         rv = VPPCOM_EINVAL;
3392       break;
3393
3394     case VPPCOM_ATTR_GET_TCP_NODELAY:
3395       if (buffer && buflen && (*buflen >= sizeof (int)))
3396         {
3397           /* VPP-TBD */
3398           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3399                                                 VCL_SESS_ATTR_TCP_NODELAY);
3400           *buflen = sizeof (int);
3401
3402           VDBG (2, "VPPCOM_ATTR_GET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3403                 *(int *) buffer, *buflen);
3404         }
3405       else
3406         rv = VPPCOM_EINVAL;
3407       break;
3408
3409     case VPPCOM_ATTR_SET_TCP_NODELAY:
3410       if (buffer && buflen && (*buflen == sizeof (int)))
3411         {
3412           /* VPP-TBD */
3413           if (*(int *) buffer)
3414             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3415           else
3416             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3417
3418           VDBG (2, "VPPCOM_ATTR_SET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3419                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_TCP_NODELAY),
3420                 *buflen);
3421         }
3422       else
3423         rv = VPPCOM_EINVAL;
3424       break;
3425
3426     case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
3427       if (buffer && buflen && (*buflen >= sizeof (int)))
3428         {
3429           /* VPP-TBD */
3430           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3431                                                 VCL_SESS_ATTR_TCP_KEEPIDLE);
3432           *buflen = sizeof (int);
3433
3434           VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3435                 *(int *) buffer, *buflen);
3436         }
3437       else
3438         rv = VPPCOM_EINVAL;
3439       break;
3440
3441     case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
3442       if (buffer && buflen && (*buflen == sizeof (int)))
3443         {
3444           /* VPP-TBD */
3445           if (*(int *) buffer)
3446             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3447           else
3448             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3449
3450           VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3451                 VCL_SESS_ATTR_TEST (session->attr,
3452                                     VCL_SESS_ATTR_TCP_KEEPIDLE), *buflen);
3453         }
3454       else
3455         rv = VPPCOM_EINVAL;
3456       break;
3457
3458     case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
3459       if (buffer && buflen && (*buflen >= sizeof (int)))
3460         {
3461           /* VPP-TBD */
3462           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3463                                                 VCL_SESS_ATTR_TCP_KEEPINTVL);
3464           *buflen = sizeof (int);
3465
3466           VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
3467                 *(int *) buffer, *buflen);
3468         }
3469       else
3470         rv = VPPCOM_EINVAL;
3471       break;
3472
3473     case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
3474       if (buffer && buflen && (*buflen == sizeof (int)))
3475         {
3476           /* VPP-TBD */
3477           if (*(int *) buffer)
3478             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3479           else
3480             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3481
3482           VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
3483                 VCL_SESS_ATTR_TEST (session->attr,
3484                                     VCL_SESS_ATTR_TCP_KEEPINTVL), *buflen);
3485         }
3486       else
3487         rv = VPPCOM_EINVAL;
3488       break;
3489
3490     case VPPCOM_ATTR_GET_TCP_USER_MSS:
3491       if (buffer && buflen && (*buflen >= sizeof (u32)))
3492         {
3493           /* VPP-TBD */
3494           *(u32 *) buffer = session->user_mss;
3495           *buflen = sizeof (int);
3496
3497           VDBG (2, "VPPCOM_ATTR_GET_TCP_USER_MSS: %d, buflen %d, #VPP-TBD#",
3498                 *(int *) buffer, *buflen);
3499         }
3500       else
3501         rv = VPPCOM_EINVAL;
3502       break;
3503
3504     case VPPCOM_ATTR_SET_TCP_USER_MSS:
3505       if (buffer && buflen && (*buflen == sizeof (u32)))
3506         {
3507           /* VPP-TBD */
3508           session->user_mss = *(u32 *) buffer;
3509
3510           VDBG (2, "VPPCOM_ATTR_SET_TCP_USER_MSS: %u, buflen %d, #VPP-TBD#",
3511                 session->user_mss, *buflen);
3512         }
3513       else
3514         rv = VPPCOM_EINVAL;
3515       break;
3516
3517     case VPPCOM_ATTR_SET_SHUT:
3518       if (*flags == SHUT_RD || *flags == SHUT_RDWR)
3519         VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_SHUT_RD);
3520       if (*flags == SHUT_WR || *flags == SHUT_RDWR)
3521         VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_SHUT_WR);
3522       break;
3523
3524     case VPPCOM_ATTR_GET_SHUT:
3525       if (VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_SHUT_RD))
3526         tmp_flags = 1;
3527       if (VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_SHUT_WR))
3528         tmp_flags |= 2;
3529       if (tmp_flags == 1)
3530         *(int *) buffer = SHUT_RD;
3531       else if (tmp_flags == 2)
3532         *(int *) buffer = SHUT_WR;
3533       else if (tmp_flags == 3)
3534         *(int *) buffer = SHUT_RDWR;
3535       *buflen = sizeof (int);
3536       break;
3537     default:
3538       rv = VPPCOM_EINVAL;
3539       break;
3540     }
3541
3542   return rv;
3543 }
3544
3545 int
3546 vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
3547                          uint32_t buflen, int flags, vppcom_endpt_t * ep)
3548 {
3549   vcl_worker_t *wrk = vcl_worker_get_current ();
3550   int rv = VPPCOM_OK;
3551   vcl_session_t *session = 0;
3552
3553   if (ep)
3554     {
3555       session = vcl_session_get_w_handle (wrk, session_handle);
3556       if (PREDICT_FALSE (!session))
3557         {
3558           VDBG (0, "sh 0x%llx is closed!", session_handle);
3559           return VPPCOM_EBADFD;
3560         }
3561       ep->is_ip4 = session->transport.is_ip4;
3562       ep->port = session->transport.rmt_port;
3563     }
3564
3565   if (flags == 0)
3566     rv = vppcom_session_read (session_handle, buffer, buflen);
3567   else if (flags & MSG_PEEK)
3568     rv = vppcom_session_peek (session_handle, buffer, buflen);
3569   else
3570     {
3571       VDBG (0, "Unsupport flags for recvfrom %d", flags);
3572       return VPPCOM_EAFNOSUPPORT;
3573     }
3574
3575   if (ep)
3576     {
3577       if (session->transport.is_ip4)
3578         clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
3579                           sizeof (ip4_address_t));
3580       else
3581         clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
3582                           sizeof (ip6_address_t));
3583     }
3584
3585   return rv;
3586 }
3587
3588 int
3589 vppcom_session_sendto (uint32_t session_handle, void *buffer,
3590                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
3591 {
3592   if (!buffer)
3593     return VPPCOM_EINVAL;
3594
3595   if (ep)
3596     {
3597       // TBD
3598       return VPPCOM_EINVAL;
3599     }
3600
3601   if (flags)
3602     {
3603       // TBD check the flags and do the right thing
3604       VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags);
3605     }
3606
3607   return (vppcom_session_write_inline (session_handle, buffer, buflen, 1));
3608 }
3609
3610 int
3611 vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
3612 {
3613   vcl_worker_t *wrk = vcl_worker_get_current ();
3614   f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
3615   u32 i, keep_trying = 1;
3616   svm_msg_q_msg_t msg;
3617   session_event_t *e;
3618   int rv, num_ev = 0;
3619
3620   VDBG (3, "vp %p, nsids %u, wait_for_time %f", vp, n_sids, wait_for_time);
3621
3622   if (!vp)
3623     return VPPCOM_EFAULT;
3624
3625   do
3626     {
3627       vcl_session_t *session;
3628
3629       /* Dequeue all events and drop all unhandled io events */
3630       while (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0) == 0)
3631         {
3632           e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
3633           vcl_handle_mq_event (wrk, e);
3634           svm_msg_q_free_msg (wrk->app_event_queue, &msg);
3635         }
3636       vec_reset_length (wrk->unhandled_evts_vector);
3637
3638       for (i = 0; i < n_sids; i++)
3639         {
3640           session = vcl_session_get (wrk, vp[i].sh);
3641           if (!session)
3642             {
3643               vp[i].revents = POLLHUP;
3644               num_ev++;
3645               continue;
3646             }
3647
3648           vp[i].revents = 0;
3649
3650           if (POLLIN & vp[i].events)
3651             {
3652               rv = vcl_session_read_ready (session);
3653               if (rv > 0)
3654                 {
3655                   vp[i].revents |= POLLIN;
3656                   num_ev++;
3657                 }
3658               else if (rv < 0)
3659                 {
3660                   switch (rv)
3661                     {
3662                     case VPPCOM_ECONNRESET:
3663                       vp[i].revents = POLLHUP;
3664                       break;
3665
3666                     default:
3667                       vp[i].revents = POLLERR;
3668                       break;
3669                     }
3670                   num_ev++;
3671                 }
3672             }
3673
3674           if (POLLOUT & vp[i].events)
3675             {
3676               rv = vcl_session_write_ready (session);
3677               if (rv > 0)
3678                 {
3679                   vp[i].revents |= POLLOUT;
3680                   num_ev++;
3681                 }
3682               else if (rv < 0)
3683                 {
3684                   switch (rv)
3685                     {
3686                     case VPPCOM_ECONNRESET:
3687                       vp[i].revents = POLLHUP;
3688                       break;
3689
3690                     default:
3691                       vp[i].revents = POLLERR;
3692                       break;
3693                     }
3694                   num_ev++;
3695                 }
3696             }
3697
3698           if (0)                // Note "done:" label used by VCL_SESSION_LOCK_AND_GET()
3699             {
3700               vp[i].revents = POLLNVAL;
3701               num_ev++;
3702             }
3703         }
3704       if (wait_for_time != -1)
3705         keep_trying = (clib_time_now (&wrk->clib_time) <= timeout) ? 1 : 0;
3706     }
3707   while ((num_ev == 0) && keep_trying);
3708
3709   return num_ev;
3710 }
3711
3712 int
3713 vppcom_mq_epoll_fd (void)
3714 {
3715   vcl_worker_t *wrk = vcl_worker_get_current ();
3716   return wrk->mqs_epfd;
3717 }
3718
3719 int
3720 vppcom_session_index (vcl_session_handle_t session_handle)
3721 {
3722   return session_handle & 0xFFFFFF;
3723 }
3724
3725 int
3726 vppcom_session_worker (vcl_session_handle_t session_handle)
3727 {
3728   return session_handle >> 24;
3729 }
3730
3731 int
3732 vppcom_worker_register (void)
3733 {
3734   vcl_worker_t *wrk;
3735   u8 *wrk_name = 0;
3736   int rv;
3737
3738   if (!vcl_worker_alloc_and_init ())
3739     return VPPCOM_EEXIST;
3740
3741   wrk = vcl_worker_get_current ();
3742   wrk_name = format (0, "%s-wrk-%u", vcm->app_name, wrk->wrk_index);
3743
3744   rv = vppcom_connect_to_vpp ((char *) wrk_name);
3745   vec_free (wrk_name);
3746
3747   if (rv)
3748     return VPPCOM_EFAULT;
3749
3750   if (vcl_worker_register_with_vpp ())
3751     return VPPCOM_EEXIST;
3752
3753   return VPPCOM_OK;
3754 }
3755
3756 void
3757 vppcom_worker_unregister (void)
3758 {
3759   vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
3760   vcl_set_worker_index (~0);
3761 }
3762
3763 int
3764 vppcom_worker_index (void)
3765 {
3766   return vcl_get_worker_index ();
3767 }
3768
3769 int
3770 vppcom_worker_mqs_epfd (void)
3771 {
3772   vcl_worker_t *wrk = vcl_worker_get_current ();
3773   if (!vcm->cfg.use_mq_eventfd)
3774     return -1;
3775   return wrk->mqs_epfd;
3776 }
3777
3778 int
3779 vppcom_session_is_connectable_listener (uint32_t session_handle)
3780 {
3781   vcl_session_t *session;
3782   vcl_worker_t *wrk = vcl_worker_get_current ();
3783   session = vcl_session_get_w_handle (wrk, session_handle);
3784   if (!session)
3785     return VPPCOM_EBADFD;
3786   return vcl_session_is_connectable_listener (wrk, session);
3787 }
3788
3789 int
3790 vppcom_session_listener (uint32_t session_handle)
3791 {
3792   vcl_worker_t *wrk = vcl_worker_get_current ();
3793   vcl_session_t *listen_session, *session;
3794   session = vcl_session_get_w_handle (wrk, session_handle);
3795   if (!session)
3796     return VPPCOM_EBADFD;
3797   if (session->listener_index == VCL_INVALID_SESSION_INDEX)
3798     return VPPCOM_EBADFD;
3799   listen_session = vcl_session_get_w_handle (wrk, session->listener_index);
3800   if (!listen_session)
3801     return VPPCOM_EBADFD;
3802   return vcl_session_handle (listen_session);
3803 }
3804
3805 int
3806 vppcom_session_n_accepted (uint32_t session_handle)
3807 {
3808   vcl_worker_t *wrk = vcl_worker_get_current ();
3809   vcl_session_t *session = vcl_session_get_w_handle (wrk, session_handle);
3810   if (!session)
3811     return VPPCOM_EBADFD;
3812   return session->n_accepted_sessions;
3813 }
3814
3815 /*
3816  * fd.io coding-style-patch-verification: ON
3817  *
3818  * Local Variables:
3819  * eval: (c-set-style "gnu")
3820  * End:
3821  */