session: move add/del segment msg to mq
[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 (session->is_dgram)
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       VDBG (1, "EPOLL_CTL_ADD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2522             vep_handle, session_handle, event->events, event->data.u64);
2523       vcl_evt (VCL_EVT_EPOLL_CTLADD, session, event->events, event->data.u64);
2524       break;
2525
2526     case EPOLL_CTL_MOD:
2527       if (PREDICT_FALSE (!event))
2528         {
2529           VDBG (0, "EPOLL_CTL_MOD: NULL pointer to epoll_event structure!");
2530           rv = VPPCOM_EINVAL;
2531           goto done;
2532         }
2533       else if (PREDICT_FALSE (!session->is_vep_session))
2534         {
2535           VDBG (0, "sh %u EPOLL_CTL_MOD: not a vep session!", session_handle);
2536           rv = VPPCOM_EINVAL;
2537           goto done;
2538         }
2539       else if (PREDICT_FALSE (session->vep.vep_sh != vep_handle))
2540         {
2541           VDBG (0, "EPOLL_CTL_MOD: sh %u vep_sh (%u) != vep_sh (%u)!",
2542                 session_handle, session->vep.vep_sh, vep_handle);
2543           rv = VPPCOM_EINVAL;
2544           goto done;
2545         }
2546       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
2547       session->vep.ev = *event;
2548       VDBG (1, "EPOLL_CTL_MOD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2549             vep_handle, session_handle, event->events, event->data.u64);
2550       break;
2551
2552     case EPOLL_CTL_DEL:
2553       if (PREDICT_FALSE (!session->is_vep_session))
2554         {
2555           VDBG (0, "EPOLL_CTL_DEL: %u not a vep session!", session_handle);
2556           rv = VPPCOM_EINVAL;
2557           goto done;
2558         }
2559       else if (PREDICT_FALSE (session->vep.vep_sh != vep_handle))
2560         {
2561           VDBG (0, "EPOLL_CTL_DEL: sh %u vep_sh (%u) != vep_sh (%u)!",
2562                 session_handle, session->vep.vep_sh, vep_handle);
2563           rv = VPPCOM_EINVAL;
2564           goto done;
2565         }
2566
2567       if (session->vep.prev_sh == vep_handle)
2568         vep_session->vep.next_sh = session->vep.next_sh;
2569       else
2570         {
2571           vcl_session_t *prev_session;
2572           prev_session = vcl_session_get_w_handle (wrk, session->vep.prev_sh);
2573           if (PREDICT_FALSE (!prev_session))
2574             {
2575               VDBG (0, "EPOLL_CTL_DEL: Invalid prev_sh (%u) on sh (%u)!",
2576                     session->vep.prev_sh, session_handle);
2577               return VPPCOM_EBADFD;
2578             }
2579           ASSERT (prev_session->vep.next_sh == session_handle);
2580           prev_session->vep.next_sh = session->vep.next_sh;
2581         }
2582       if (session->vep.next_sh != ~0)
2583         {
2584           vcl_session_t *next_session;
2585           next_session = vcl_session_get_w_handle (wrk, session->vep.next_sh);
2586           if (PREDICT_FALSE (!next_session))
2587             {
2588               VDBG (0, "EPOLL_CTL_DEL: Invalid next_sh (%u) on sh (%u)!",
2589                     session->vep.next_sh, session_handle);
2590               return VPPCOM_EBADFD;
2591             }
2592           ASSERT (next_session->vep.prev_sh == session_handle);
2593           next_session->vep.prev_sh = session->vep.prev_sh;
2594         }
2595
2596       memset (&session->vep, 0, sizeof (session->vep));
2597       session->vep.next_sh = ~0;
2598       session->vep.prev_sh = ~0;
2599       session->vep.vep_sh = ~0;
2600       session->is_vep_session = 0;
2601
2602       if (session->tx_fifo)
2603         svm_fifo_del_want_deq_ntf (session->tx_fifo, SVM_FIFO_NO_DEQ_NOTIF);
2604
2605       VDBG (1, "EPOLL_CTL_DEL: vep_idx %u, sh %u!", vep_handle,
2606             session_handle);
2607       vcl_evt (VCL_EVT_EPOLL_CTLDEL, session, vep_sh);
2608       break;
2609
2610     default:
2611       VDBG (0, "Invalid operation (%d)!", op);
2612       rv = VPPCOM_EINVAL;
2613     }
2614
2615   vep_verify_epoll_chain (wrk, vep_handle);
2616
2617 done:
2618   return rv;
2619 }
2620
2621 static inline void
2622 vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
2623                                 struct epoll_event *events, u32 * num_ev)
2624 {
2625   session_disconnected_msg_t *disconnected_msg;
2626   session_connected_msg_t *connected_msg;
2627   u32 sid = ~0, session_events;
2628   u64 session_evt_data = ~0;
2629   vcl_session_t *session;
2630   u8 add_event = 0;
2631
2632   switch (e->event_type)
2633     {
2634     case SESSION_IO_EVT_RX:
2635       sid = e->session_index;
2636       if (!(session = vcl_session_get (wrk, sid)))
2637         break;
2638       vcl_fifo_rx_evt_valid_or_break (session);
2639       session_events = session->vep.ev.events;
2640       if (!(EPOLLIN & session->vep.ev.events) || session->has_rx_evt)
2641         break;
2642       add_event = 1;
2643       events[*num_ev].events |= EPOLLIN;
2644       session_evt_data = session->vep.ev.data.u64;
2645       session->has_rx_evt = 1;
2646       break;
2647     case SESSION_IO_EVT_TX:
2648       sid = e->session_index;
2649       if (!(session = vcl_session_get (wrk, sid)))
2650         break;
2651       session_events = session->vep.ev.events;
2652       if (!(EPOLLOUT & session_events))
2653         break;
2654       add_event = 1;
2655       events[*num_ev].events |= EPOLLOUT;
2656       session_evt_data = session->vep.ev.data.u64;
2657       svm_fifo_reset_has_deq_ntf (session->tx_fifo);
2658       break;
2659     case SESSION_CTRL_EVT_ACCEPTED:
2660       session = vcl_session_accepted (wrk,
2661                                       (session_accepted_msg_t *) e->data);
2662       if (!session)
2663         break;
2664
2665       session_events = session->vep.ev.events;
2666       if (!(EPOLLIN & session_events))
2667         break;
2668
2669       add_event = 1;
2670       events[*num_ev].events |= EPOLLIN;
2671       session_evt_data = session->vep.ev.data.u64;
2672       break;
2673     case SESSION_CTRL_EVT_CONNECTED:
2674       connected_msg = (session_connected_msg_t *) e->data;
2675       sid = vcl_session_connected_handler (wrk, connected_msg);
2676       /* Generate EPOLLOUT because there's no connected event */
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       if (session->session_state & STATE_FAILED)
2686         events[*num_ev].events |= EPOLLHUP;
2687       break;
2688     case SESSION_CTRL_EVT_DISCONNECTED:
2689       disconnected_msg = (session_disconnected_msg_t *) e->data;
2690       session = vcl_session_disconnected_handler (wrk, disconnected_msg);
2691       if (!session)
2692         break;
2693       session_events = session->vep.ev.events;
2694       if (!((EPOLLHUP | EPOLLRDHUP) & session_events))
2695         break;
2696       add_event = 1;
2697       events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2698       session_evt_data = session->vep.ev.data.u64;
2699       break;
2700     case SESSION_CTRL_EVT_RESET:
2701       sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
2702       if (!(session = vcl_session_get (wrk, sid)))
2703         break;
2704       session_events = session->vep.ev.events;
2705       if (!((EPOLLHUP | EPOLLRDHUP) & session_events))
2706         break;
2707       add_event = 1;
2708       events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2709       session_evt_data = session->vep.ev.data.u64;
2710       break;
2711     case SESSION_CTRL_EVT_UNLISTEN_REPLY:
2712       vcl_session_unlisten_reply_handler (wrk, e->data);
2713       break;
2714     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
2715       vcl_session_req_worker_update_handler (wrk, e->data);
2716       break;
2717     case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
2718       vcl_session_worker_update_reply_handler (wrk, e->data);
2719       break;
2720     case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
2721       vcl_session_app_add_segment_handler (wrk, e->data);
2722       break;
2723     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
2724       vcl_session_app_del_segment_handler (wrk, e->data);
2725       break;
2726     default:
2727       VDBG (0, "unhandled: %u", e->event_type);
2728       break;
2729     }
2730
2731   if (add_event)
2732     {
2733       events[*num_ev].data.u64 = session_evt_data;
2734       if (EPOLLONESHOT & session_events)
2735         {
2736           session = vcl_session_get (wrk, sid);
2737           session->vep.ev.events = 0;
2738         }
2739       *num_ev += 1;
2740     }
2741 }
2742
2743 static int
2744 vcl_epoll_wait_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
2745                           struct epoll_event *events, u32 maxevents,
2746                           double wait_for_time, u32 * num_ev)
2747 {
2748   svm_msg_q_msg_t *msg;
2749   session_event_t *e;
2750   int i;
2751
2752   if (vec_len (wrk->mq_msg_vector) && svm_msg_q_is_empty (mq))
2753     goto handle_dequeued;
2754
2755   svm_msg_q_lock (mq);
2756   if (svm_msg_q_is_empty (mq))
2757     {
2758       if (!wait_for_time)
2759         {
2760           svm_msg_q_unlock (mq);
2761           return 0;
2762         }
2763       else if (wait_for_time < 0)
2764         {
2765           svm_msg_q_wait (mq);
2766         }
2767       else
2768         {
2769           if (svm_msg_q_timedwait (mq, wait_for_time / 1e3))
2770             {
2771               svm_msg_q_unlock (mq);
2772               return 0;
2773             }
2774         }
2775     }
2776   ASSERT (maxevents > *num_ev);
2777   vcl_mq_dequeue_batch (wrk, mq, maxevents - *num_ev);
2778   svm_msg_q_unlock (mq);
2779
2780 handle_dequeued:
2781   for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
2782     {
2783       msg = vec_elt_at_index (wrk->mq_msg_vector, i);
2784       e = svm_msg_q_msg_data (mq, msg);
2785       vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
2786       svm_msg_q_free_msg (mq, msg);
2787     }
2788   vec_reset_length (wrk->mq_msg_vector);
2789   vcl_handle_pending_wrk_updates (wrk);
2790   return *num_ev;
2791 }
2792
2793 static int
2794 vppcom_epoll_wait_condvar (vcl_worker_t * wrk, struct epoll_event *events,
2795                            int maxevents, u32 n_evts, double wait_for_time)
2796 {
2797   double wait = 0, start = 0, now;
2798
2799   if (!n_evts)
2800     {
2801       wait = wait_for_time;
2802       start = clib_time_now (&wrk->clib_time);
2803     }
2804
2805   do
2806     {
2807       vcl_epoll_wait_handle_mq (wrk, wrk->app_event_queue, events, maxevents,
2808                                 wait, &n_evts);
2809       if (n_evts)
2810         return n_evts;
2811       if (wait == -1)
2812         continue;
2813
2814       now = clib_time_now (&wrk->clib_time);
2815       wait -= now - start;
2816       start = now;
2817     }
2818   while (wait > 0);
2819
2820   return 0;
2821 }
2822
2823 static int
2824 vppcom_epoll_wait_eventfd (vcl_worker_t * wrk, struct epoll_event *events,
2825                            int maxevents, u32 n_evts, double wait_for_time)
2826 {
2827   vcl_mq_evt_conn_t *mqc;
2828   int __clib_unused n_read;
2829   int n_mq_evts, i;
2830   u64 buf;
2831
2832   vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
2833 again:
2834   n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
2835                           vec_len (wrk->mq_events), wait_for_time);
2836   for (i = 0; i < n_mq_evts; i++)
2837     {
2838       mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
2839       n_read = read (mqc->mq_fd, &buf, sizeof (buf));
2840       vcl_epoll_wait_handle_mq (wrk, mqc->mq, events, maxevents, 0, &n_evts);
2841     }
2842   if (!n_evts && n_mq_evts > 0)
2843     goto again;
2844
2845   return (int) n_evts;
2846 }
2847
2848 int
2849 vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events,
2850                    int maxevents, double wait_for_time)
2851 {
2852   vcl_worker_t *wrk = vcl_worker_get_current ();
2853   vcl_session_t *vep_session;
2854   u32 n_evts = 0;
2855   int i;
2856
2857   if (PREDICT_FALSE (maxevents <= 0))
2858     {
2859       VDBG (0, "ERROR: Invalid maxevents (%d)!", maxevents);
2860       return VPPCOM_EINVAL;
2861     }
2862
2863   vep_session = vcl_session_get_w_handle (wrk, vep_handle);
2864   if (!vep_session)
2865     return VPPCOM_EBADFD;
2866
2867   if (PREDICT_FALSE (!vep_session->is_vep))
2868     {
2869       VDBG (0, "ERROR: vep_idx (%u) is not a vep!", vep_handle);
2870       return VPPCOM_EINVAL;
2871     }
2872
2873   memset (events, 0, sizeof (*events) * maxevents);
2874
2875   if (vec_len (wrk->unhandled_evts_vector))
2876     {
2877       for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
2878         {
2879           vcl_epoll_wait_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i],
2880                                           events, &n_evts);
2881           if (n_evts == maxevents)
2882             {
2883               vec_delete (wrk->unhandled_evts_vector, i + 1, 0);
2884               return n_evts;
2885             }
2886         }
2887       vec_reset_length (wrk->unhandled_evts_vector);
2888     }
2889
2890   if (vcm->cfg.use_mq_eventfd)
2891     return vppcom_epoll_wait_eventfd (wrk, events, maxevents, n_evts,
2892                                       wait_for_time);
2893
2894   return vppcom_epoll_wait_condvar (wrk, events, maxevents, n_evts,
2895                                     wait_for_time);
2896 }
2897
2898 int
2899 vppcom_session_attr (uint32_t session_handle, uint32_t op,
2900                      void *buffer, uint32_t * buflen)
2901 {
2902   vcl_worker_t *wrk = vcl_worker_get_current ();
2903   vcl_session_t *session;
2904   int rv = VPPCOM_OK;
2905   u32 *flags = buffer, tmp_flags = 0;
2906   vppcom_endpt_t *ep = buffer;
2907
2908   session = vcl_session_get_w_handle (wrk, session_handle);
2909   if (!session)
2910     return VPPCOM_EBADFD;
2911
2912   switch (op)
2913     {
2914     case VPPCOM_ATTR_GET_NREAD:
2915       rv = vcl_session_read_ready (session);
2916       VDBG (2, "VPPCOM_ATTR_GET_NREAD: sh %u, nread = %d", session_handle,
2917             rv);
2918       break;
2919
2920     case VPPCOM_ATTR_GET_NWRITE:
2921       rv = vcl_session_write_ready (session);
2922       VDBG (2, "VPPCOM_ATTR_GET_NWRITE: sh %u, nwrite = %d", session_handle,
2923             rv);
2924       break;
2925
2926     case VPPCOM_ATTR_GET_FLAGS:
2927       if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
2928         {
2929           *flags = O_RDWR | (VCL_SESS_ATTR_TEST (session->attr,
2930                                                  VCL_SESS_ATTR_NONBLOCK));
2931           *buflen = sizeof (*flags);
2932           VDBG (2, "VPPCOM_ATTR_GET_FLAGS: sh %u, flags = 0x%08x, "
2933                 "is_nonblocking = %u", session_handle, *flags,
2934                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
2935         }
2936       else
2937         rv = VPPCOM_EINVAL;
2938       break;
2939
2940     case VPPCOM_ATTR_SET_FLAGS:
2941       if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
2942         {
2943           if (*flags & O_NONBLOCK)
2944             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
2945           else
2946             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
2947
2948           VDBG (2, "VPPCOM_ATTR_SET_FLAGS: sh %u, flags = 0x%08x,"
2949                 " is_nonblocking = %u", session_handle, *flags,
2950                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
2951         }
2952       else
2953         rv = VPPCOM_EINVAL;
2954       break;
2955
2956     case VPPCOM_ATTR_GET_PEER_ADDR:
2957       if (PREDICT_TRUE (buffer && buflen &&
2958                         (*buflen >= sizeof (*ep)) && ep->ip))
2959         {
2960           ep->is_ip4 = session->transport.is_ip4;
2961           ep->port = session->transport.rmt_port;
2962           if (session->transport.is_ip4)
2963             clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
2964                               sizeof (ip4_address_t));
2965           else
2966             clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
2967                               sizeof (ip6_address_t));
2968           *buflen = sizeof (*ep);
2969           VDBG (1, "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, "
2970                 "addr = %U, port %u", session_handle, ep->is_ip4,
2971                 format_ip46_address, &session->transport.rmt_ip,
2972                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
2973                 clib_net_to_host_u16 (ep->port));
2974         }
2975       else
2976         rv = VPPCOM_EINVAL;
2977       break;
2978
2979     case VPPCOM_ATTR_GET_LCL_ADDR:
2980       if (PREDICT_TRUE (buffer && buflen &&
2981                         (*buflen >= sizeof (*ep)) && ep->ip))
2982         {
2983           ep->is_ip4 = session->transport.is_ip4;
2984           ep->port = session->transport.lcl_port;
2985           if (session->transport.is_ip4)
2986             clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip4,
2987                               sizeof (ip4_address_t));
2988           else
2989             clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip6,
2990                               sizeof (ip6_address_t));
2991           *buflen = sizeof (*ep);
2992           VDBG (1, "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
2993                 " port %d", session_handle, ep->is_ip4, format_ip46_address,
2994                 &session->transport.lcl_ip,
2995                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
2996                 clib_net_to_host_u16 (ep->port));
2997         }
2998       else
2999         rv = VPPCOM_EINVAL;
3000       break;
3001
3002     case VPPCOM_ATTR_SET_LCL_ADDR:
3003       if (PREDICT_TRUE (buffer && buflen &&
3004                         (*buflen >= sizeof (*ep)) && ep->ip))
3005         {
3006           session->transport.is_ip4 = ep->is_ip4;
3007           session->transport.lcl_port = ep->port;
3008           vcl_ip_copy_from_ep (&session->transport.lcl_ip, ep);
3009           *buflen = sizeof (*ep);
3010           VDBG (1, "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
3011                 " port %d", session_handle, ep->is_ip4, format_ip46_address,
3012                 &session->transport.lcl_ip,
3013                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3014                 clib_net_to_host_u16 (ep->port));
3015         }
3016       else
3017         rv = VPPCOM_EINVAL;
3018       break;
3019
3020     case VPPCOM_ATTR_GET_LIBC_EPFD:
3021       rv = session->libc_epfd;
3022       VDBG (2, "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d", rv);
3023       break;
3024
3025     case VPPCOM_ATTR_SET_LIBC_EPFD:
3026       if (PREDICT_TRUE (buffer && buflen &&
3027                         (*buflen == sizeof (session->libc_epfd))))
3028         {
3029           session->libc_epfd = *(int *) buffer;
3030           *buflen = sizeof (session->libc_epfd);
3031
3032           VDBG (2, "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, buflen %d",
3033                 session->libc_epfd, *buflen);
3034         }
3035       else
3036         rv = VPPCOM_EINVAL;
3037       break;
3038
3039     case VPPCOM_ATTR_GET_PROTOCOL:
3040       if (buffer && buflen && (*buflen >= sizeof (int)))
3041         {
3042           *(int *) buffer = session->session_type;
3043           *buflen = sizeof (int);
3044
3045           VDBG (2, "VPPCOM_ATTR_GET_PROTOCOL: %d (%s), buflen %d",
3046                 *(int *) buffer, *(int *) buffer ? "UDP" : "TCP", *buflen);
3047         }
3048       else
3049         rv = VPPCOM_EINVAL;
3050       break;
3051
3052     case VPPCOM_ATTR_GET_LISTEN:
3053       if (buffer && buflen && (*buflen >= sizeof (int)))
3054         {
3055           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3056                                                 VCL_SESS_ATTR_LISTEN);
3057           *buflen = sizeof (int);
3058
3059           VDBG (2, "VPPCOM_ATTR_GET_LISTEN: %d, buflen %d", *(int *) buffer,
3060                 *buflen);
3061         }
3062       else
3063         rv = VPPCOM_EINVAL;
3064       break;
3065
3066     case VPPCOM_ATTR_GET_ERROR:
3067       if (buffer && buflen && (*buflen >= sizeof (int)))
3068         {
3069           *(int *) buffer = 0;
3070           *buflen = sizeof (int);
3071
3072           VDBG (2, "VPPCOM_ATTR_GET_ERROR: %d, buflen %d, #VPP-TBD#",
3073                 *(int *) buffer, *buflen);
3074         }
3075       else
3076         rv = VPPCOM_EINVAL;
3077       break;
3078
3079     case VPPCOM_ATTR_GET_TX_FIFO_LEN:
3080       if (buffer && buflen && (*buflen >= sizeof (u32)))
3081         {
3082
3083           /* VPP-TBD */
3084           *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
3085                                 session->tx_fifo ? session->tx_fifo->nitems :
3086                                 vcm->cfg.tx_fifo_size);
3087           *buflen = sizeof (u32);
3088
3089           VDBG (2, "VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3090                 " #VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer,
3091                 *buflen);
3092         }
3093       else
3094         rv = VPPCOM_EINVAL;
3095       break;
3096
3097     case VPPCOM_ATTR_SET_TX_FIFO_LEN:
3098       if (buffer && buflen && (*buflen == sizeof (u32)))
3099         {
3100           /* VPP-TBD */
3101           session->sndbuf_size = *(u32 *) buffer;
3102           VDBG (2, "VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3103                 " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3104                 *buflen);
3105         }
3106       else
3107         rv = VPPCOM_EINVAL;
3108       break;
3109
3110     case VPPCOM_ATTR_GET_RX_FIFO_LEN:
3111       if (buffer && buflen && (*buflen >= sizeof (u32)))
3112         {
3113
3114           /* VPP-TBD */
3115           *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
3116                                 session->rx_fifo ? session->rx_fifo->nitems :
3117                                 vcm->cfg.rx_fifo_size);
3118           *buflen = sizeof (u32);
3119
3120           VDBG (2, "VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), buflen %d, "
3121                 "#VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer, *buflen);
3122         }
3123       else
3124         rv = VPPCOM_EINVAL;
3125       break;
3126
3127     case VPPCOM_ATTR_SET_RX_FIFO_LEN:
3128       if (buffer && buflen && (*buflen == sizeof (u32)))
3129         {
3130           /* VPP-TBD */
3131           session->rcvbuf_size = *(u32 *) buffer;
3132           VDBG (2, "VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), buflen %d,"
3133                 " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3134                 *buflen);
3135         }
3136       else
3137         rv = VPPCOM_EINVAL;
3138       break;
3139
3140     case VPPCOM_ATTR_GET_REUSEADDR:
3141       if (buffer && buflen && (*buflen >= sizeof (int)))
3142         {
3143           /* VPP-TBD */
3144           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3145                                                 VCL_SESS_ATTR_REUSEADDR);
3146           *buflen = sizeof (int);
3147
3148           VDBG (2, "VPPCOM_ATTR_GET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3149                 *(int *) buffer, *buflen);
3150         }
3151       else
3152         rv = VPPCOM_EINVAL;
3153       break;
3154
3155     case VPPCOM_ATTR_SET_REUSEADDR:
3156       if (buffer && buflen && (*buflen == sizeof (int)) &&
3157           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
3158         {
3159           /* VPP-TBD */
3160           if (*(int *) buffer)
3161             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEADDR);
3162           else
3163             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEADDR);
3164
3165           VDBG (2, "VPPCOM_ATTR_SET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3166                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_REUSEADDR),
3167                 *buflen);
3168         }
3169       else
3170         rv = VPPCOM_EINVAL;
3171       break;
3172
3173     case VPPCOM_ATTR_GET_REUSEPORT:
3174       if (buffer && buflen && (*buflen >= sizeof (int)))
3175         {
3176           /* VPP-TBD */
3177           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3178                                                 VCL_SESS_ATTR_REUSEPORT);
3179           *buflen = sizeof (int);
3180
3181           VDBG (2, "VPPCOM_ATTR_GET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3182                 *(int *) buffer, *buflen);
3183         }
3184       else
3185         rv = VPPCOM_EINVAL;
3186       break;
3187
3188     case VPPCOM_ATTR_SET_REUSEPORT:
3189       if (buffer && buflen && (*buflen == sizeof (int)) &&
3190           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
3191         {
3192           /* VPP-TBD */
3193           if (*(int *) buffer)
3194             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEPORT);
3195           else
3196             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEPORT);
3197
3198           VDBG (2, "VPPCOM_ATTR_SET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3199                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_REUSEPORT),
3200                 *buflen);
3201         }
3202       else
3203         rv = VPPCOM_EINVAL;
3204       break;
3205
3206     case VPPCOM_ATTR_GET_BROADCAST:
3207       if (buffer && buflen && (*buflen >= sizeof (int)))
3208         {
3209           /* VPP-TBD */
3210           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3211                                                 VCL_SESS_ATTR_BROADCAST);
3212           *buflen = sizeof (int);
3213
3214           VDBG (2, "VPPCOM_ATTR_GET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3215                 *(int *) buffer, *buflen);
3216         }
3217       else
3218         rv = VPPCOM_EINVAL;
3219       break;
3220
3221     case VPPCOM_ATTR_SET_BROADCAST:
3222       if (buffer && buflen && (*buflen == sizeof (int)))
3223         {
3224           /* VPP-TBD */
3225           if (*(int *) buffer)
3226             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_BROADCAST);
3227           else
3228             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_BROADCAST);
3229
3230           VDBG (2, "VPPCOM_ATTR_SET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3231                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_BROADCAST),
3232                 *buflen);
3233         }
3234       else
3235         rv = VPPCOM_EINVAL;
3236       break;
3237
3238     case VPPCOM_ATTR_GET_V6ONLY:
3239       if (buffer && buflen && (*buflen >= sizeof (int)))
3240         {
3241           /* VPP-TBD */
3242           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3243                                                 VCL_SESS_ATTR_V6ONLY);
3244           *buflen = sizeof (int);
3245
3246           VDBG (2, "VPPCOM_ATTR_GET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3247                 *(int *) buffer, *buflen);
3248         }
3249       else
3250         rv = VPPCOM_EINVAL;
3251       break;
3252
3253     case VPPCOM_ATTR_SET_V6ONLY:
3254       if (buffer && buflen && (*buflen == sizeof (int)))
3255         {
3256           /* VPP-TBD */
3257           if (*(int *) buffer)
3258             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_V6ONLY);
3259           else
3260             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_V6ONLY);
3261
3262           VDBG (2, "VPPCOM_ATTR_SET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3263                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_V6ONLY),
3264                 *buflen);
3265         }
3266       else
3267         rv = VPPCOM_EINVAL;
3268       break;
3269
3270     case VPPCOM_ATTR_GET_KEEPALIVE:
3271       if (buffer && buflen && (*buflen >= sizeof (int)))
3272         {
3273           /* VPP-TBD */
3274           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3275                                                 VCL_SESS_ATTR_KEEPALIVE);
3276           *buflen = sizeof (int);
3277
3278           VDBG (2, "VPPCOM_ATTR_GET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3279                 *(int *) buffer, *buflen);
3280         }
3281       else
3282         rv = VPPCOM_EINVAL;
3283       break;
3284
3285     case VPPCOM_ATTR_SET_KEEPALIVE:
3286       if (buffer && buflen && (*buflen == sizeof (int)))
3287         {
3288           /* VPP-TBD */
3289           if (*(int *) buffer)
3290             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_KEEPALIVE);
3291           else
3292             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_KEEPALIVE);
3293
3294           VDBG (2, "VPPCOM_ATTR_SET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3295                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_KEEPALIVE),
3296                 *buflen);
3297         }
3298       else
3299         rv = VPPCOM_EINVAL;
3300       break;
3301
3302     case VPPCOM_ATTR_GET_TCP_NODELAY:
3303       if (buffer && buflen && (*buflen >= sizeof (int)))
3304         {
3305           /* VPP-TBD */
3306           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3307                                                 VCL_SESS_ATTR_TCP_NODELAY);
3308           *buflen = sizeof (int);
3309
3310           VDBG (2, "VPPCOM_ATTR_GET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3311                 *(int *) buffer, *buflen);
3312         }
3313       else
3314         rv = VPPCOM_EINVAL;
3315       break;
3316
3317     case VPPCOM_ATTR_SET_TCP_NODELAY:
3318       if (buffer && buflen && (*buflen == sizeof (int)))
3319         {
3320           /* VPP-TBD */
3321           if (*(int *) buffer)
3322             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3323           else
3324             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3325
3326           VDBG (2, "VPPCOM_ATTR_SET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3327                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_TCP_NODELAY),
3328                 *buflen);
3329         }
3330       else
3331         rv = VPPCOM_EINVAL;
3332       break;
3333
3334     case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
3335       if (buffer && buflen && (*buflen >= sizeof (int)))
3336         {
3337           /* VPP-TBD */
3338           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3339                                                 VCL_SESS_ATTR_TCP_KEEPIDLE);
3340           *buflen = sizeof (int);
3341
3342           VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3343                 *(int *) buffer, *buflen);
3344         }
3345       else
3346         rv = VPPCOM_EINVAL;
3347       break;
3348
3349     case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
3350       if (buffer && buflen && (*buflen == sizeof (int)))
3351         {
3352           /* VPP-TBD */
3353           if (*(int *) buffer)
3354             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3355           else
3356             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3357
3358           VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3359                 VCL_SESS_ATTR_TEST (session->attr,
3360                                     VCL_SESS_ATTR_TCP_KEEPIDLE), *buflen);
3361         }
3362       else
3363         rv = VPPCOM_EINVAL;
3364       break;
3365
3366     case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
3367       if (buffer && buflen && (*buflen >= sizeof (int)))
3368         {
3369           /* VPP-TBD */
3370           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3371                                                 VCL_SESS_ATTR_TCP_KEEPINTVL);
3372           *buflen = sizeof (int);
3373
3374           VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
3375                 *(int *) buffer, *buflen);
3376         }
3377       else
3378         rv = VPPCOM_EINVAL;
3379       break;
3380
3381     case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
3382       if (buffer && buflen && (*buflen == sizeof (int)))
3383         {
3384           /* VPP-TBD */
3385           if (*(int *) buffer)
3386             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3387           else
3388             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3389
3390           VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
3391                 VCL_SESS_ATTR_TEST (session->attr,
3392                                     VCL_SESS_ATTR_TCP_KEEPINTVL), *buflen);
3393         }
3394       else
3395         rv = VPPCOM_EINVAL;
3396       break;
3397
3398     case VPPCOM_ATTR_GET_TCP_USER_MSS:
3399       if (buffer && buflen && (*buflen >= sizeof (u32)))
3400         {
3401           /* VPP-TBD */
3402           *(u32 *) buffer = session->user_mss;
3403           *buflen = sizeof (int);
3404
3405           VDBG (2, "VPPCOM_ATTR_GET_TCP_USER_MSS: %d, buflen %d, #VPP-TBD#",
3406                 *(int *) buffer, *buflen);
3407         }
3408       else
3409         rv = VPPCOM_EINVAL;
3410       break;
3411
3412     case VPPCOM_ATTR_SET_TCP_USER_MSS:
3413       if (buffer && buflen && (*buflen == sizeof (u32)))
3414         {
3415           /* VPP-TBD */
3416           session->user_mss = *(u32 *) buffer;
3417
3418           VDBG (2, "VPPCOM_ATTR_SET_TCP_USER_MSS: %u, buflen %d, #VPP-TBD#",
3419                 session->user_mss, *buflen);
3420         }
3421       else
3422         rv = VPPCOM_EINVAL;
3423       break;
3424
3425     case VPPCOM_ATTR_SET_SHUT:
3426       if (*flags == SHUT_RD || *flags == SHUT_RDWR)
3427         VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_SHUT_RD);
3428       if (*flags == SHUT_WR || *flags == SHUT_RDWR)
3429         VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_SHUT_WR);
3430       break;
3431
3432     case VPPCOM_ATTR_GET_SHUT:
3433       if (VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_SHUT_RD))
3434         tmp_flags = 1;
3435       if (VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_SHUT_WR))
3436         tmp_flags |= 2;
3437       if (tmp_flags == 1)
3438         *(int *) buffer = SHUT_RD;
3439       else if (tmp_flags == 2)
3440         *(int *) buffer = SHUT_WR;
3441       else if (tmp_flags == 3)
3442         *(int *) buffer = SHUT_RDWR;
3443       *buflen = sizeof (int);
3444       break;
3445     default:
3446       rv = VPPCOM_EINVAL;
3447       break;
3448     }
3449
3450   return rv;
3451 }
3452
3453 int
3454 vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
3455                          uint32_t buflen, int flags, vppcom_endpt_t * ep)
3456 {
3457   vcl_worker_t *wrk = vcl_worker_get_current ();
3458   int rv = VPPCOM_OK;
3459   vcl_session_t *session = 0;
3460
3461   if (ep)
3462     {
3463       session = vcl_session_get_w_handle (wrk, session_handle);
3464       if (PREDICT_FALSE (!session))
3465         {
3466           VDBG (0, "sh 0x%llx is closed!", session_handle);
3467           return VPPCOM_EBADFD;
3468         }
3469       ep->is_ip4 = session->transport.is_ip4;
3470       ep->port = session->transport.rmt_port;
3471     }
3472
3473   if (flags == 0)
3474     rv = vppcom_session_read (session_handle, buffer, buflen);
3475   else if (flags & MSG_PEEK)
3476     rv = vppcom_session_peek (session_handle, buffer, buflen);
3477   else
3478     {
3479       VDBG (0, "Unsupport flags for recvfrom %d", flags);
3480       return VPPCOM_EAFNOSUPPORT;
3481     }
3482
3483   if (ep)
3484     {
3485       if (session->transport.is_ip4)
3486         clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
3487                           sizeof (ip4_address_t));
3488       else
3489         clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
3490                           sizeof (ip6_address_t));
3491     }
3492
3493   return rv;
3494 }
3495
3496 int
3497 vppcom_session_sendto (uint32_t session_handle, void *buffer,
3498                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
3499 {
3500   if (!buffer)
3501     return VPPCOM_EINVAL;
3502
3503   if (ep)
3504     {
3505       // TBD
3506       return VPPCOM_EINVAL;
3507     }
3508
3509   if (flags)
3510     {
3511       // TBD check the flags and do the right thing
3512       VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags);
3513     }
3514
3515   return (vppcom_session_write_inline (session_handle, buffer, buflen, 1));
3516 }
3517
3518 int
3519 vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
3520 {
3521   vcl_worker_t *wrk = vcl_worker_get_current ();
3522   f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
3523   u32 i, keep_trying = 1;
3524   svm_msg_q_msg_t msg;
3525   session_event_t *e;
3526   int rv, num_ev = 0;
3527
3528   VDBG (3, "vp %p, nsids %u, wait_for_time %f", vp, n_sids, wait_for_time);
3529
3530   if (!vp)
3531     return VPPCOM_EFAULT;
3532
3533   do
3534     {
3535       vcl_session_t *session;
3536
3537       /* Dequeue all events and drop all unhandled io events */
3538       while (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0) == 0)
3539         {
3540           e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
3541           vcl_handle_mq_event (wrk, e);
3542           svm_msg_q_free_msg (wrk->app_event_queue, &msg);
3543         }
3544       vec_reset_length (wrk->unhandled_evts_vector);
3545
3546       for (i = 0; i < n_sids; i++)
3547         {
3548           session = vcl_session_get (wrk, vp[i].sh);
3549           if (!session)
3550             {
3551               vp[i].revents = POLLHUP;
3552               num_ev++;
3553               continue;
3554             }
3555
3556           vp[i].revents = 0;
3557
3558           if (POLLIN & vp[i].events)
3559             {
3560               rv = vcl_session_read_ready (session);
3561               if (rv > 0)
3562                 {
3563                   vp[i].revents |= POLLIN;
3564                   num_ev++;
3565                 }
3566               else if (rv < 0)
3567                 {
3568                   switch (rv)
3569                     {
3570                     case VPPCOM_ECONNRESET:
3571                       vp[i].revents = POLLHUP;
3572                       break;
3573
3574                     default:
3575                       vp[i].revents = POLLERR;
3576                       break;
3577                     }
3578                   num_ev++;
3579                 }
3580             }
3581
3582           if (POLLOUT & vp[i].events)
3583             {
3584               rv = vcl_session_write_ready (session);
3585               if (rv > 0)
3586                 {
3587                   vp[i].revents |= POLLOUT;
3588                   num_ev++;
3589                 }
3590               else if (rv < 0)
3591                 {
3592                   switch (rv)
3593                     {
3594                     case VPPCOM_ECONNRESET:
3595                       vp[i].revents = POLLHUP;
3596                       break;
3597
3598                     default:
3599                       vp[i].revents = POLLERR;
3600                       break;
3601                     }
3602                   num_ev++;
3603                 }
3604             }
3605
3606           if (0)                // Note "done:" label used by VCL_SESSION_LOCK_AND_GET()
3607             {
3608               vp[i].revents = POLLNVAL;
3609               num_ev++;
3610             }
3611         }
3612       if (wait_for_time != -1)
3613         keep_trying = (clib_time_now (&wrk->clib_time) <= timeout) ? 1 : 0;
3614     }
3615   while ((num_ev == 0) && keep_trying);
3616
3617   return num_ev;
3618 }
3619
3620 int
3621 vppcom_mq_epoll_fd (void)
3622 {
3623   vcl_worker_t *wrk = vcl_worker_get_current ();
3624   return wrk->mqs_epfd;
3625 }
3626
3627 int
3628 vppcom_session_index (vcl_session_handle_t session_handle)
3629 {
3630   return session_handle & 0xFFFFFF;
3631 }
3632
3633 int
3634 vppcom_session_worker (vcl_session_handle_t session_handle)
3635 {
3636   return session_handle >> 24;
3637 }
3638
3639 int
3640 vppcom_worker_register (void)
3641 {
3642   vcl_worker_t *wrk;
3643   u8 *wrk_name = 0;
3644   int rv;
3645
3646   if (!vcl_worker_alloc_and_init ())
3647     return VPPCOM_EEXIST;
3648
3649   wrk = vcl_worker_get_current ();
3650   wrk_name = format (0, "%s-wrk-%u", vcm->app_name, wrk->wrk_index);
3651
3652   rv = vppcom_connect_to_vpp ((char *) wrk_name);
3653   vec_free (wrk_name);
3654
3655   if (rv)
3656     return VPPCOM_EFAULT;
3657
3658   if (vcl_worker_register_with_vpp ())
3659     return VPPCOM_EEXIST;
3660
3661   return VPPCOM_OK;
3662 }
3663
3664 void
3665 vppcom_worker_unregister (void)
3666 {
3667   vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
3668   vcl_set_worker_index (~0);
3669 }
3670
3671 int
3672 vppcom_worker_index (void)
3673 {
3674   return vcl_get_worker_index ();
3675 }
3676
3677 int
3678 vppcom_worker_mqs_epfd (void)
3679 {
3680   vcl_worker_t *wrk = vcl_worker_get_current ();
3681   if (!vcm->cfg.use_mq_eventfd)
3682     return -1;
3683   return wrk->mqs_epfd;
3684 }
3685
3686 int
3687 vppcom_session_is_connectable_listener (uint32_t session_handle)
3688 {
3689   vcl_session_t *session;
3690   vcl_worker_t *wrk = vcl_worker_get_current ();
3691   session = vcl_session_get_w_handle (wrk, session_handle);
3692   if (!session)
3693     return VPPCOM_EBADFD;
3694   return vcl_session_is_connectable_listener (wrk, session);
3695 }
3696
3697 int
3698 vppcom_session_listener (uint32_t session_handle)
3699 {
3700   vcl_worker_t *wrk = vcl_worker_get_current ();
3701   vcl_session_t *listen_session, *session;
3702   session = vcl_session_get_w_handle (wrk, session_handle);
3703   if (!session)
3704     return VPPCOM_EBADFD;
3705   if (session->listener_index == VCL_INVALID_SESSION_INDEX)
3706     return VPPCOM_EBADFD;
3707   listen_session = vcl_session_get_w_handle (wrk, session->listener_index);
3708   if (!listen_session)
3709     return VPPCOM_EBADFD;
3710   return vcl_session_handle (listen_session);
3711 }
3712
3713 int
3714 vppcom_session_n_accepted (uint32_t session_handle)
3715 {
3716   vcl_worker_t *wrk = vcl_worker_get_current ();
3717   vcl_session_t *session = vcl_session_get_w_handle (wrk, session_handle);
3718   if (!session)
3719     return VPPCOM_EBADFD;
3720   return session->n_accepted_sessions;
3721 }
3722
3723 /*
3724  * fd.io coding-style-patch-verification: ON
3725  *
3726  * Local Variables:
3727  * eval: (c-set-style "gnu")
3728  * End:
3729  */