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