vcl/session: use mq for bind replies
[vpp.git] / src / vcl / vppcom.c
1 /*
2  * Copyright (c) 2017 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 <svm/svm_fifo_segment.h>
19 #include <vcl/vppcom.h>
20 #include <vcl/vcl_event.h>
21 #include <vcl/vcl_debug.h>
22 #include <vcl/vcl_private.h>
23
24 static u8 not_ready;
25
26 void
27 sigsegv_signal (int signum)
28 {
29   not_ready = 1;
30 }
31
32 static void
33 vcl_wait_for_memory (void *mem)
34 {
35   u8 __clib_unused test;
36   if (vcm->mounting_segment)
37     {
38       while (vcm->mounting_segment)
39         ;
40       return;
41     }
42   if (1 || vcm->debug)
43     {
44       usleep (1e5);
45       return;
46     }
47   if (signal (SIGSEGV, sigsegv_signal))
48     {
49       perror ("signal()");
50       return;
51     }
52   not_ready = 0;
53
54 again:
55   test = *(u8 *) mem;
56   if (not_ready)
57     {
58       not_ready = 0;
59       usleep (1);
60       goto again;
61     }
62
63   signal (SIGSEGV, SIG_DFL);
64 }
65
66 static const char *
67 vppcom_app_state_str (app_state_t state)
68 {
69   char *st;
70
71   switch (state)
72     {
73     case STATE_APP_START:
74       st = "STATE_APP_START";
75       break;
76
77     case STATE_APP_CONN_VPP:
78       st = "STATE_APP_CONN_VPP";
79       break;
80
81     case STATE_APP_ENABLED:
82       st = "STATE_APP_ENABLED";
83       break;
84
85     case STATE_APP_ATTACHED:
86       st = "STATE_APP_ATTACHED";
87       break;
88
89     default:
90       st = "UNKNOWN_APP_STATE";
91       break;
92     }
93
94   return st;
95 }
96
97 const char *
98 vppcom_session_state_str (session_state_t state)
99 {
100   char *st;
101
102   switch (state)
103     {
104     case STATE_START:
105       st = "STATE_START";
106       break;
107
108     case STATE_CONNECT:
109       st = "STATE_CONNECT";
110       break;
111
112     case STATE_LISTEN:
113       st = "STATE_LISTEN";
114       break;
115
116     case STATE_ACCEPT:
117       st = "STATE_ACCEPT";
118       break;
119
120     case STATE_CLOSE_ON_EMPTY:
121       st = "STATE_CLOSE_ON_EMPTY";
122       break;
123
124     case STATE_DISCONNECT:
125       st = "STATE_DISCONNECT";
126       break;
127
128     case STATE_FAILED:
129       st = "STATE_FAILED";
130       break;
131
132     default:
133       st = "UNKNOWN_STATE";
134       break;
135     }
136
137   return st;
138 }
139
140 u8 *
141 format_ip4_address (u8 * s, va_list * args)
142 {
143   u8 *a = va_arg (*args, u8 *);
144   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
145 }
146
147 u8 *
148 format_ip6_address (u8 * s, va_list * args)
149 {
150   ip6_address_t *a = va_arg (*args, ip6_address_t *);
151   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
152
153   i_max_n_zero = ARRAY_LEN (a->as_u16);
154   max_n_zeros = 0;
155   i_first_zero = i_max_n_zero;
156   n_zeros = 0;
157   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
158     {
159       u32 is_zero = a->as_u16[i] == 0;
160       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
161         {
162           i_first_zero = i;
163           n_zeros = 0;
164         }
165       n_zeros += is_zero;
166       if ((!is_zero && n_zeros > max_n_zeros)
167           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
168         {
169           i_max_n_zero = i_first_zero;
170           max_n_zeros = n_zeros;
171           i_first_zero = ARRAY_LEN (a->as_u16);
172           n_zeros = 0;
173         }
174     }
175
176   last_double_colon = 0;
177   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
178     {
179       if (i == i_max_n_zero && max_n_zeros > 1)
180         {
181           s = format (s, "::");
182           i += max_n_zeros - 1;
183           last_double_colon = 1;
184         }
185       else
186         {
187           s = format (s, "%s%x",
188                       (last_double_colon || i == 0) ? "" : ":",
189                       clib_net_to_host_u16 (a->as_u16[i]));
190           last_double_colon = 0;
191         }
192     }
193
194   return s;
195 }
196
197 /* Format an IP46 address. */
198 u8 *
199 format_ip46_address (u8 * s, va_list * args)
200 {
201   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
202   ip46_type_t type = va_arg (*args, ip46_type_t);
203   int is_ip4 = 1;
204
205   switch (type)
206     {
207     case IP46_TYPE_ANY:
208       is_ip4 = ip46_address_is_ip4 (ip46);
209       break;
210     case IP46_TYPE_IP4:
211       is_ip4 = 1;
212       break;
213     case IP46_TYPE_IP6:
214       is_ip4 = 0;
215       break;
216     }
217
218   return is_ip4 ?
219     format (s, "%U", format_ip4_address, &ip46->ip4) :
220     format (s, "%U", format_ip6_address, &ip46->ip6);
221 }
222
223 /*
224  * VPPCOM Utility Functions
225  */
226
227 static inline void
228 vppcom_session_table_del_listener (u64 listener_handle)
229 {
230   listener_handle |= 1ULL << 63;
231   hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
232 }
233
234 static inline int
235 vppcom_wait_for_app_state_change (app_state_t app_state)
236 {
237   f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout;
238
239   while (clib_time_now (&vcm->clib_time) < timeout)
240     {
241       if (vcm->app_state == app_state)
242         return VPPCOM_OK;
243     }
244   VDBG (0, "VCL<%d>: timeout waiting for state %s (%d)", getpid (),
245         vppcom_app_state_str (app_state), app_state);
246   vcl_evt (VCL_EVT_SESSION_TIMEOUT, vcm, app_state);
247
248   return VPPCOM_ETIMEDOUT;
249 }
250
251 static svm_msg_q_t *
252 vcl_session_vpp_evt_q (vcl_session_t * s)
253 {
254   if (vcl_session_is_ct (s))
255     return vcm->vpp_event_queues[0];
256   else
257     return vcm->vpp_event_queues[s->tx_fifo->master_thread_index];
258 }
259
260 static void
261 vcl_send_session_accepted_reply (svm_msg_q_t * mq, u32 context,
262                                  session_handle_t handle, int retval)
263 {
264   app_session_evt_t _app_evt, *app_evt = &_app_evt;
265   session_accepted_reply_msg_t *rmp;
266   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_ACCEPTED_REPLY);
267   rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
268   rmp->handle = handle;
269   rmp->context = context;
270   rmp->retval = retval;
271   app_send_ctrl_evt_to_vpp (mq, app_evt);
272 }
273
274 static void
275 vcl_send_session_disconnected_reply (svm_msg_q_t * mq, u32 context,
276                                      session_handle_t handle, int retval)
277 {
278   app_session_evt_t _app_evt, *app_evt = &_app_evt;
279   session_disconnected_reply_msg_t *rmp;
280   app_alloc_ctrl_evt_to_vpp (mq, app_evt,
281                              SESSION_CTRL_EVT_DISCONNECTED_REPLY);
282   rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
283   rmp->handle = handle;
284   rmp->context = context;
285   rmp->retval = retval;
286   app_send_ctrl_evt_to_vpp (mq, app_evt);
287 }
288
289 static void
290 vcl_send_session_reset_reply (svm_msg_q_t * mq, u32 context,
291                               session_handle_t handle, int retval)
292 {
293   app_session_evt_t _app_evt, *app_evt = &_app_evt;
294   session_reset_reply_msg_t *rmp;
295   app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_RESET_REPLY);
296   rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
297   rmp->handle = handle;
298   rmp->context = context;
299   rmp->retval = retval;
300   app_send_ctrl_evt_to_vpp (mq, app_evt);
301 }
302
303 static u32
304 vcl_session_accepted_handler (session_accepted_msg_t * mp)
305 {
306   vcl_session_t *session, *listen_session;
307   svm_fifo_t *rx_fifo, *tx_fifo;
308   u32 session_index, vpp_wrk_index;
309   svm_msg_q_t *evt_q;
310
311   VCL_SESSION_LOCK ();
312
313   session = vcl_session_alloc ();
314   session_index = vcl_session_index (session);
315
316   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
317   if (!listen_session)
318     {
319       svm_msg_q_t *evt_q;
320       evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
321       clib_warning ("VCL<%d>: ERROR: couldn't find listen session: "
322                     "unknown vpp listener handle %llx",
323                     getpid (), mp->listener_handle);
324       vcl_send_session_accepted_reply (evt_q, mp->context, mp->handle,
325                                        VNET_API_ERROR_INVALID_ARGUMENT);
326       vcl_session_free (session);
327       VCL_SESSION_UNLOCK ();
328       return VCL_INVALID_SESSION_INDEX;
329     }
330
331   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
332   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
333
334   if (mp->server_event_queue_address)
335     {
336       session->vpp_evt_q = uword_to_pointer (mp->client_event_queue_address,
337                                              svm_msg_q_t *);
338       session->our_evt_q = uword_to_pointer (mp->server_event_queue_address,
339                                              svm_msg_q_t *);
340       vcl_wait_for_memory (session->vpp_evt_q);
341       rx_fifo->master_session_index = session_index;
342       tx_fifo->master_session_index = session_index;
343       vec_validate (vcm->vpp_event_queues, 0);
344       evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
345       vcm->vpp_event_queues[0] = evt_q;
346     }
347   else
348     {
349       session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
350                                              svm_msg_q_t *);
351       rx_fifo->client_session_index = session_index;
352       tx_fifo->client_session_index = session_index;
353
354       vpp_wrk_index = tx_fifo->master_thread_index;
355       vec_validate (vcm->vpp_event_queues, vpp_wrk_index);
356       vcm->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
357     }
358
359   session->vpp_handle = mp->handle;
360   session->client_context = mp->context;
361   session->rx_fifo = rx_fifo;
362   session->tx_fifo = tx_fifo;
363
364   session->session_state = STATE_ACCEPT;
365   session->transport.rmt_port = mp->port;
366   session->transport.is_ip4 = mp->is_ip4;
367   clib_memcpy (&session->transport.rmt_ip, mp->ip, sizeof (ip46_address_t));
368
369   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
370   session->transport.lcl_port = listen_session->transport.lcl_port;
371   session->transport.lcl_ip = listen_session->transport.lcl_ip;
372   session->session_type = listen_session->session_type;
373   session->is_dgram = session->session_type == VPPCOM_PROTO_UDP;
374
375   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: client accept request from %s"
376         " address %U port %d queue %p!", getpid (), mp->handle, session_index,
377         mp->is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &mp->ip,
378         mp->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
379         clib_net_to_host_u16 (mp->port), session->vpp_evt_q);
380   vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index);
381
382   VCL_SESSION_UNLOCK ();
383   return session_index;
384 }
385
386 static u32
387 vcl_session_connected_handler (session_connected_msg_t * mp)
388 {
389   u32 session_index, vpp_wrk_index;
390   svm_fifo_t *rx_fifo, *tx_fifo;
391   vcl_session_t *session = 0;
392   svm_msg_q_t *evt_q;
393   int rv = VPPCOM_OK;
394
395   session_index = mp->context;
396   VCL_SESSION_LOCK_AND_GET (session_index, &session);
397 done:
398   if (mp->retval)
399     {
400       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
401                     "connect failed! %U",
402                     getpid (), mp->handle, session_index,
403                     format_api_error, ntohl (mp->retval));
404       if (session)
405         {
406           session->session_state = STATE_FAILED;
407           session->vpp_handle = mp->handle;
408         }
409       else
410         {
411           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
412                         "Invalid session index (%u)!",
413                         getpid (), mp->handle, session_index);
414         }
415       goto done_unlock;
416     }
417
418   if (rv)
419     goto done_unlock;
420
421   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
422   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
423   vcl_wait_for_memory (rx_fifo);
424   rx_fifo->client_session_index = session_index;
425   tx_fifo->client_session_index = session_index;
426
427   if (mp->client_event_queue_address)
428     {
429       session->vpp_evt_q = uword_to_pointer (mp->server_event_queue_address,
430                                              svm_msg_q_t *);
431       session->our_evt_q = uword_to_pointer (mp->client_event_queue_address,
432                                              svm_msg_q_t *);
433
434       vec_validate (vcm->vpp_event_queues, 0);
435       evt_q = uword_to_pointer (mp->vpp_event_queue_address, svm_msg_q_t *);
436       vcm->vpp_event_queues[0] = evt_q;
437     }
438   else
439     {
440       session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
441                                              svm_msg_q_t *);
442       vpp_wrk_index = tx_fifo->master_thread_index;
443       vec_validate (vcm->vpp_event_queues, vpp_wrk_index);
444       vcm->vpp_event_queues[vpp_wrk_index] = session->vpp_evt_q;
445     }
446
447   session->rx_fifo = rx_fifo;
448   session->tx_fifo = tx_fifo;
449   session->vpp_handle = mp->handle;
450   session->transport.is_ip4 = mp->is_ip4;
451   clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
452                sizeof (session->transport.lcl_ip));
453   session->transport.lcl_port = mp->lcl_port;
454   session->session_state = STATE_CONNECT;
455
456   /* Add it to lookup table */
457   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
458
459   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded! "
460         "session_rx_fifo %p, refcnt %d, session_tx_fifo %p, refcnt %d",
461         getpid (), mp->handle, session_index, session->rx_fifo,
462         session->rx_fifo->refcnt, session->tx_fifo, session->tx_fifo->refcnt);
463 done_unlock:
464   VCL_SESSION_UNLOCK ();
465   return session_index;
466 }
467
468 static u32
469 vcl_session_reset_handler (session_reset_msg_t * reset_msg)
470 {
471   vcl_session_t *session;
472   u32 sid;
473
474   sid = vcl_session_get_index_from_handle (reset_msg->handle);
475   session = vcl_session_get (sid);
476   if (!session)
477     {
478       VDBG (0, "request to reset unknown handle 0x%llx", reset_msg->handle);
479       return VCL_INVALID_SESSION_INDEX;
480     }
481   session->session_state = STATE_CLOSE_ON_EMPTY;
482   VDBG (0, "reset handle 0x%llx, sid %u ", reset_msg->handle, sid);
483   vcl_send_session_reset_reply (vcl_session_vpp_evt_q (session),
484                                 vcm->my_client_index, reset_msg->handle, 0);
485   return sid;
486 }
487
488 static u32
489 vcl_session_bound_handler (session_bound_msg_t * mp)
490 {
491   vcl_session_t *session;
492   u32 sid = mp->context;
493
494   session = vcl_session_get (sid);
495   if (mp->retval)
496     {
497       VDBG (0, "VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: bind failed: %U",
498             getpid (), mp->handle, sid, format_api_error, ntohl (mp->retval));
499       if (session)
500         {
501           session->session_state = STATE_FAILED;
502           session->vpp_handle = mp->handle;
503           return sid;
504         }
505       else
506         {
507           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
508                         "Invalid session index (%u)!",
509                         getpid (), mp->handle, sid);
510           return VCL_INVALID_SESSION_INDEX;
511         }
512     }
513
514   session->vpp_handle = mp->handle;
515   session->transport.is_ip4 = mp->lcl_is_ip4;
516   clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
517                sizeof (ip46_address_t));
518   session->transport.lcl_port = mp->lcl_port;
519   vppcom_session_table_add_listener (mp->handle, sid);
520   session->session_state = STATE_LISTEN;
521
522   if (session->is_dgram)
523     {
524       svm_fifo_t *rx_fifo, *tx_fifo;
525       session->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
526       rx_fifo = uword_to_pointer (mp->rx_fifo, svm_fifo_t *);
527       rx_fifo->client_session_index = sid;
528       tx_fifo = uword_to_pointer (mp->tx_fifo, svm_fifo_t *);
529       tx_fifo->client_session_index = sid;
530       session->rx_fifo = rx_fifo;
531       session->tx_fifo = tx_fifo;
532     }
533
534   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
535         getpid (), mp->handle, sid);
536   return sid;
537 }
538
539 int
540 vcl_handle_mq_ctrl_event (session_event_t * e)
541 {
542   session_accepted_msg_t *accepted_msg;
543   session_disconnected_msg_t *disconnected_msg;
544   vcl_session_msg_t *vcl_msg;
545   vcl_session_t *session;
546   u64 handle;
547   u32 sid;
548
549   switch (e->event_type)
550     {
551     case FIFO_EVENT_APP_RX:
552       clib_warning ("unhandled rx: sid %u (0x%x)",
553                     e->fifo->client_session_index,
554                     e->fifo->client_session_index);
555       break;
556     case SESSION_CTRL_EVT_ACCEPTED:
557       accepted_msg = (session_accepted_msg_t *) e->data;
558       handle = accepted_msg->listener_handle;
559       session = vppcom_session_table_lookup_listener (handle);
560       if (!session)
561         {
562           clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
563                         "listener handle %llx", getpid (), handle);
564           break;
565         }
566
567       clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
568       vcl_msg->accepted_msg = *accepted_msg;
569       break;
570     case SESSION_CTRL_EVT_CONNECTED:
571       vcl_session_connected_handler ((session_connected_msg_t *) e->data);
572       break;
573     case SESSION_CTRL_EVT_DISCONNECTED:
574       disconnected_msg = (session_disconnected_msg_t *) e->data;
575       sid = vcl_session_get_index_from_handle (disconnected_msg->handle);
576       session = vcl_session_get (sid);
577       if (!session)
578         {
579           VDBG (0, "request to disconnect unknown handle 0x%llx",
580                 disconnected_msg->handle);
581           break;
582         }
583       session->session_state = STATE_DISCONNECT;
584       VDBG (0, "disconnected handle 0xllx, sid %u", disconnected_msg->handle,
585             sid);
586       break;
587     case SESSION_CTRL_EVT_RESET:
588       vcl_session_reset_handler ((session_reset_msg_t *) e->data);
589       break;
590     case SESSION_CTRL_EVT_BOUND:
591       vcl_session_bound_handler ((session_bound_msg_t *) e->data);
592       break;
593     default:
594       clib_warning ("unhandled %u", e->event_type);
595     }
596   return VPPCOM_OK;
597 }
598
599 static inline int
600 vppcom_wait_for_session_state_change (u32 session_index,
601                                       session_state_t state,
602                                       f64 wait_for_time)
603 {
604   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
605   vcl_session_t *volatile session;
606   svm_msg_q_msg_t msg;
607   session_event_t *e;
608   int rv;
609
610   do
611     {
612       VCL_SESSION_LOCK ();
613       rv = vppcom_session_at_index (session_index, &session);
614       if (PREDICT_FALSE (rv))
615         {
616           VCL_SESSION_UNLOCK ();
617           return rv;
618         }
619       if (session->session_state & state)
620         {
621           VCL_SESSION_UNLOCK ();
622           return VPPCOM_OK;
623         }
624       if (session->session_state & STATE_FAILED)
625         {
626           VCL_SESSION_UNLOCK ();
627           return VPPCOM_ECONNREFUSED;
628         }
629       VCL_SESSION_UNLOCK ();
630
631       if (svm_msg_q_sub (vcm->app_event_queue, &msg, SVM_Q_NOWAIT, 0))
632         continue;
633       e = svm_msg_q_msg_data (vcm->app_event_queue, &msg);
634       vcl_handle_mq_ctrl_event (e);
635       svm_msg_q_free_msg (vcm->app_event_queue, &msg);
636     }
637   while (clib_time_now (&vcm->clib_time) < timeout);
638
639   VDBG (0, "VCL<%d>: timeout waiting for state 0x%x (%s)", getpid (), state,
640         vppcom_session_state_str (state));
641   vcl_evt (VCL_EVT_SESSION_TIMEOUT, session, session_state);
642
643   return VPPCOM_ETIMEDOUT;
644 }
645
646 static int
647 vppcom_app_session_enable (void)
648 {
649   int rv;
650
651   if (vcm->app_state != STATE_APP_ENABLED)
652     {
653       vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
654       rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
655       if (PREDICT_FALSE (rv))
656         {
657           VDBG (0, "VCL<%d>: application session enable timed out! "
658                 "returning %d (%s)", getpid (), rv, vppcom_retval_str (rv));
659           return rv;
660         }
661     }
662   return VPPCOM_OK;
663 }
664
665 static int
666 vppcom_app_attach (void)
667 {
668   int rv;
669
670   vppcom_app_send_attach ();
671   rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED);
672   if (PREDICT_FALSE (rv))
673     {
674       VDBG (0, "VCL<%d>: application attach timed out! returning %d (%s)",
675             getpid (), rv, vppcom_retval_str (rv));
676       return rv;
677     }
678
679   return VPPCOM_OK;
680 }
681
682 static int
683 vppcom_session_unbind (u32 session_index)
684 {
685   vcl_session_t *session = 0;
686   int rv;
687   u64 vpp_handle;
688
689   VCL_SESSION_LOCK_AND_GET (session_index, &session);
690
691   vpp_handle = session->vpp_handle;
692   vppcom_session_table_del_listener (vpp_handle);
693   session->vpp_handle = ~0;
694   session->session_state = STATE_DISCONNECT;
695
696   VCL_SESSION_UNLOCK ();
697
698   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending unbind msg! new state"
699         " 0x%x (%s)", getpid (), vpp_handle, session_index, STATE_DISCONNECT,
700         vppcom_session_state_str (STATE_DISCONNECT));
701   vcl_evt (VCL_EVT_UNBIND, session);
702   vppcom_send_unbind_sock (vpp_handle);
703
704 done:
705   return rv;
706 }
707
708 static int
709 vppcom_session_disconnect (u32 session_index)
710 {
711   svm_msg_q_t *vpp_evt_q;
712   vcl_session_t *session;
713   session_state_t state;
714   u64 vpp_handle;
715   int rv;
716
717   VCL_SESSION_LOCK_AND_GET (session_index, &session);
718
719   vpp_handle = session->vpp_handle;
720   state = session->session_state;
721   VCL_SESSION_UNLOCK ();
722
723   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u state 0x%x (%s)", getpid (),
724         vpp_handle, session_index, state, vppcom_session_state_str (state));
725
726   if (PREDICT_FALSE (state & STATE_LISTEN))
727     {
728       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
729                     "Cannot disconnect a listen socket!",
730                     getpid (), vpp_handle, session_index);
731       rv = VPPCOM_EBADFD;
732       goto done;
733     }
734
735   if (state & STATE_CLOSE_ON_EMPTY)
736     {
737       vpp_evt_q = vcl_session_vpp_evt_q (session);
738       vcl_send_session_disconnected_reply (vpp_evt_q, vcm->my_client_index,
739                                            vpp_handle, 0);
740       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending disconnect "
741             "REPLY...", getpid (), vpp_handle, session_index);
742     }
743   else
744     {
745       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending disconnect...",
746             getpid (), vpp_handle, session_index);
747       vppcom_send_disconnect_session (vpp_handle, session_index);
748     }
749
750 done:
751   return rv;
752 }
753
754 /*
755  * VPPCOM Public API functions
756  */
757 int
758 vppcom_app_create (char *app_name)
759 {
760   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
761   int rv;
762
763   if (!vcm->init)
764     {
765       vcm->init = 1;
766       vppcom_cfg (&vcm->cfg);
767       vcl_cfg = &vcm->cfg;
768
769       vcm->mqs_epfd = -1;
770       if (vcl_cfg->use_mq_eventfd)
771         vcm->mqs_epfd = epoll_create (1);
772
773       clib_spinlock_init (&vcm->session_fifo_lockp);
774       clib_fifo_validate (vcm->client_session_index_fifo,
775                           vcm->cfg.listen_queue_size);
776       clib_spinlock_init (&vcm->sessions_lockp);
777
778
779       vcm->main_cpu = os_get_thread_index ();
780
781       vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
782       vcm->ct_registration_by_mq = hash_create (0, sizeof (uword));
783       clib_spinlock_init (&vcm->ct_registration_lock);
784
785       clib_time_init (&vcm->clib_time);
786       vppcom_init_error_string_table ();
787       svm_fifo_segment_main_init (vcl_cfg->segment_baseva,
788                                   20 /* timeout in secs */ );
789       vec_validate (vcm->mq_events, 64);
790       vec_validate (vcm->mq_msg_vector, 128);
791       vec_reset_length (vcm->mq_msg_vector);
792     }
793
794   if (vcm->my_client_index == ~0)
795     {
796       /* API hookup and connect to VPP */
797       vppcom_api_hookup ();
798       vcl_elog_init (vcm);
799       vcm->app_state = STATE_APP_START;
800       rv = vppcom_connect_to_vpp (app_name);
801       if (rv)
802         {
803           clib_warning ("VCL<%d>: ERROR: couldn't connect to VPP!",
804                         getpid ());
805           return rv;
806         }
807
808       /* State event handling thread */
809
810       rv = vce_start_event_thread (&(vcm->event_thread), 20);
811
812       VDBG (0, "VCL<%d>: sending session enable", getpid ());
813
814       rv = vppcom_app_session_enable ();
815       if (rv)
816         {
817           clib_warning ("VCL<%d>: ERROR: vppcom_app_session_enable() "
818                         "failed!", getpid ());
819           return rv;
820         }
821
822       VDBG (0, "VCL<%d>: sending app attach", getpid ());
823
824       rv = vppcom_app_attach ();
825       if (rv)
826         {
827           clib_warning ("VCL<%d>: ERROR: vppcom_app_attach() failed!",
828                         getpid ());
829           return rv;
830         }
831
832       VDBG (0, "VCL<%d>: app_name '%s', my_client_index %d (0x%x)",
833             getpid (), app_name, vcm->my_client_index, vcm->my_client_index);
834     }
835
836   return VPPCOM_OK;
837 }
838
839 void
840 vppcom_app_destroy (void)
841 {
842   int rv;
843   f64 orig_app_timeout;
844
845   if (vcm->my_client_index == ~0)
846     return;
847
848   VDBG (0, "VCL<%d>: detaching from VPP, my_client_index %d (0x%x)",
849         getpid (), vcm->my_client_index, vcm->my_client_index);
850   vcl_evt (VCL_EVT_DETACH, vcm);
851
852   vppcom_app_send_detach ();
853   orig_app_timeout = vcm->cfg.app_timeout;
854   vcm->cfg.app_timeout = 2.0;
855   rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
856   vcm->cfg.app_timeout = orig_app_timeout;
857   if (PREDICT_FALSE (rv))
858     VDBG (0, "VCL<%d>: application detach timed out! returning %d (%s)",
859           getpid (), rv, vppcom_retval_str (rv));
860
861   vcl_elog_stop (vcm);
862   vl_client_disconnect_from_vlib ();
863   vcm->my_client_index = ~0;
864   vcm->app_state = STATE_APP_START;
865 }
866
867 int
868 vppcom_session_create (u8 proto, u8 is_nonblocking)
869 {
870   vcl_session_t *session;
871   u32 session_index;
872
873   VCL_SESSION_LOCK ();
874   pool_get (vcm->sessions, session);
875   memset (session, 0, sizeof (*session));
876   session_index = session - vcm->sessions;
877
878   session->session_type = proto;
879   session->session_state = STATE_START;
880   session->vpp_handle = ~0;
881   session->is_dgram = proto == VPPCOM_PROTO_UDP;
882
883   if (is_nonblocking)
884     VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
885
886   vcl_evt (VCL_EVT_CREATE, session, session_type, session->session_state,
887            is_nonblocking, session_index);
888
889   VCL_SESSION_UNLOCK ();
890
891   VDBG (0, "VCL<%d>: sid %u", getpid (), session_index);
892
893   return (int) session_index;
894 }
895
896 int
897 vppcom_session_close (uint32_t session_index)
898 {
899   vcl_session_t *session = 0;
900   int rv;
901   u8 is_vep;
902   u8 is_vep_session;
903   u32 next_sid;
904   u32 vep_idx;
905   u64 vpp_handle;
906   uword *p;
907   session_state_t state;
908
909   VCL_SESSION_LOCK_AND_GET (session_index, &session);
910   is_vep = session->is_vep;
911   is_vep_session = session->is_vep_session;
912   next_sid = session->vep.next_sid;
913   vep_idx = session->vep.vep_idx;
914   state = session->session_state;
915   vpp_handle = session->vpp_handle;
916   VCL_SESSION_UNLOCK ();
917
918   if (VPPCOM_DEBUG > 0)
919     {
920       if (is_vep)
921         clib_warning ("VCL<%d>: vep_idx %u / sid %u: "
922                       "closing epoll session...",
923                       getpid (), session_index, session_index);
924       else
925         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %d: "
926                       "closing session...",
927                       getpid (), vpp_handle, session_index);
928     }
929
930   if (is_vep)
931     {
932       while (next_sid != ~0)
933         {
934           rv = vppcom_epoll_ctl (session_index, EPOLL_CTL_DEL, next_sid, 0);
935           if (PREDICT_FALSE (rv < 0))
936             VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
937                   "vep_idx %u failed! rv %d (%s)",
938                   getpid (), vpp_handle, next_sid, vep_idx,
939                   rv, vppcom_retval_str (rv));
940
941           VCL_SESSION_LOCK_AND_GET (session_index, &session);
942           next_sid = session->vep.next_sid;
943           VCL_SESSION_UNLOCK ();
944         }
945     }
946   else
947     {
948       if (is_vep_session)
949         {
950           rv = vppcom_epoll_ctl (vep_idx, EPOLL_CTL_DEL, session_index, 0);
951           if (rv < 0)
952             VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
953                   "vep_idx %u failed! rv %d (%s)",
954                   getpid (), vpp_handle, session_index,
955                   vep_idx, rv, vppcom_retval_str (rv));
956         }
957
958       if (state & STATE_LISTEN)
959         {
960           rv = vppcom_session_unbind (session_index);
961           if (PREDICT_FALSE (rv < 0))
962             VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: listener unbind "
963                   "failed! rv %d (%s)",
964                   getpid (), vpp_handle, session_index,
965                   rv, vppcom_retval_str (rv));
966         }
967       else if (state & (CLIENT_STATE_OPEN | SERVER_STATE_OPEN))
968         {
969           rv = vppcom_session_disconnect (session_index);
970           if (PREDICT_FALSE (rv < 0))
971             clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
972                           "session disconnect failed! rv %d (%s)",
973                           getpid (), vpp_handle, session_index,
974                           rv, vppcom_retval_str (rv));
975         }
976     }
977
978   VCL_SESSION_LOCK_AND_GET (session_index, &session);
979   if (vcl_session_is_ct (session))
980     {
981       vcl_cut_through_registration_t *ctr;
982       uword mq_addr;
983
984       mq_addr = pointer_to_uword (session->our_evt_q);
985       ctr = vcl_ct_registration_lock_and_lookup (mq_addr);
986       ASSERT (ctr);
987       if (ctr->epoll_evt_conn_index != ~0)
988         vcl_mq_epoll_del_evfd (ctr->epoll_evt_conn_index);
989       VDBG (0, "Removing ct registration %u",
990             vcl_ct_registration_index (ctr));
991       vcl_ct_registration_del (ctr);
992       vcl_ct_registration_unlock ();
993     }
994
995   vpp_handle = session->vpp_handle;
996   if (vpp_handle != ~0)
997     {
998       p = hash_get (vcm->session_index_by_vpp_handles, vpp_handle);
999       if (p)
1000         hash_unset (vcm->session_index_by_vpp_handles, vpp_handle);
1001     }
1002   pool_put_index (vcm->sessions, session_index);
1003
1004   VCL_SESSION_UNLOCK ();
1005
1006   if (VPPCOM_DEBUG > 0)
1007     {
1008       if (is_vep)
1009         clib_warning ("VCL<%d>: vep_idx %u / sid %u: epoll session removed.",
1010                       getpid (), session_index, session_index);
1011       else
1012         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session removed.",
1013                       getpid (), vpp_handle, session_index);
1014     }
1015 done:
1016
1017   vcl_evt (VCL_EVT_CLOSE, session, rv);
1018
1019   return rv;
1020 }
1021
1022 int
1023 vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
1024 {
1025   vcl_session_t *session = 0;
1026   int rv;
1027
1028   if (!ep || !ep->ip)
1029     return VPPCOM_EINVAL;
1030
1031   VCL_SESSION_LOCK_AND_GET (session_index, &session);
1032
1033   if (session->is_vep)
1034     {
1035       VCL_SESSION_UNLOCK ();
1036       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
1037                     "bind to an epoll session!", getpid (), session_index);
1038       rv = VPPCOM_EBADFD;
1039       goto done;
1040     }
1041
1042   session->transport.is_ip4 = ep->is_ip4;
1043   if (ep->is_ip4)
1044     clib_memcpy (&session->transport.lcl_ip.ip4, ep->ip,
1045                  sizeof (ip4_address_t));
1046   else
1047     clib_memcpy (&session->transport.lcl_ip.ip6, ep->ip,
1048                  sizeof (ip6_address_t));
1049   session->transport.lcl_port = ep->port;
1050
1051   VDBG (0, "VCL<%d>: sid %u: binding to local %s address %U port %u, "
1052         "proto %s", getpid (), session_index,
1053         session->transport.is_ip4 ? "IPv4" : "IPv6",
1054         format_ip46_address, &session->transport.lcl_ip,
1055         session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1056         clib_net_to_host_u16 (session->transport.lcl_port),
1057         session->session_type ? "UDP" : "TCP");
1058   vcl_evt (VCL_EVT_BIND, session);
1059   VCL_SESSION_UNLOCK ();
1060
1061   if (session->session_type == VPPCOM_PROTO_UDP)
1062     vppcom_session_listen (session_index, 10);
1063
1064 done:
1065   return rv;
1066 }
1067
1068 int
1069 vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
1070 {
1071   vcl_session_t *listen_session = 0;
1072   u64 listen_vpp_handle;
1073   int rv, retval;
1074
1075   if (q_len == 0 || q_len == ~0)
1076     q_len = vcm->cfg.listen_queue_size;
1077
1078   VCL_SESSION_LOCK_AND_GET (listen_session_index, &listen_session);
1079
1080   if (listen_session->is_vep)
1081     {
1082       VCL_SESSION_UNLOCK ();
1083       clib_warning ("VCL<%d>: ERROR: sid %u: cannot listen on an "
1084                     "epoll session!", getpid (), listen_session_index);
1085       rv = VPPCOM_EBADFD;
1086       goto done;
1087     }
1088
1089   listen_vpp_handle = listen_session->vpp_handle;
1090   if (listen_session->session_state & STATE_LISTEN)
1091     {
1092       VCL_SESSION_UNLOCK ();
1093       VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: already in listen state!",
1094             getpid (), listen_vpp_handle, listen_session_index);
1095       rv = VPPCOM_OK;
1096       goto done;
1097     }
1098
1099   VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: sending VPP bind+listen "
1100         "request...", getpid (), listen_vpp_handle, listen_session_index);
1101
1102   vppcom_send_bind_sock (listen_session, listen_session_index);
1103   VCL_SESSION_UNLOCK ();
1104   retval = vppcom_wait_for_session_state_change (listen_session_index,
1105                                                  STATE_LISTEN,
1106                                                  vcm->cfg.session_timeout);
1107
1108   VCL_SESSION_LOCK_AND_GET (listen_session_index, &listen_session);
1109   if (PREDICT_FALSE (retval))
1110     {
1111       VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: bind+listen failed! "
1112             "returning %d (%s)", getpid (), listen_session->vpp_handle,
1113             listen_session_index, retval, vppcom_retval_str (retval));
1114       VCL_SESSION_UNLOCK ();
1115       rv = retval;
1116       goto done;
1117     }
1118
1119   VCL_SESSION_UNLOCK ();
1120
1121 done:
1122   return rv;
1123 }
1124
1125 int
1126 validate_args_session_accept_ (vcl_session_t * listen_session)
1127 {
1128   u32 listen_session_index = listen_session - vcm->sessions;
1129
1130   /* Input validation - expects spinlock on sessions_lockp */
1131   if (listen_session->is_vep)
1132     {
1133       clib_warning ("VCL<%d>: ERROR: sid %u: cannot accept on an "
1134                     "epoll session!", getpid (), listen_session_index);
1135       return VPPCOM_EBADFD;
1136     }
1137
1138   if (listen_session->session_state != STATE_LISTEN)
1139     {
1140       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1141                     "not in listen state! state 0x%x (%s)", getpid (),
1142                     listen_session->vpp_handle, listen_session_index,
1143                     listen_session->session_state,
1144                     vppcom_session_state_str (listen_session->session_state));
1145       return VPPCOM_EBADFD;
1146     }
1147   return VPPCOM_OK;
1148 }
1149
1150 int
1151 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
1152                        uint32_t flags)
1153 {
1154   session_accepted_msg_t accepted_msg;
1155   vcl_session_t *listen_session = 0;
1156   vcl_session_t *client_session = 0;
1157   u32 client_session_index = ~0;
1158   svm_msg_q_t *vpp_evt_q;
1159   vcl_session_msg_t *evt;
1160   u64 listen_vpp_handle;
1161   svm_msg_q_msg_t msg;
1162   session_event_t *e;
1163   u8 is_nonblocking;
1164   int rv;
1165
1166   VCL_SESSION_LOCK_AND_GET (listen_session_index, &listen_session);
1167
1168   if (validate_args_session_accept_ (listen_session))
1169     {
1170       VCL_SESSION_UNLOCK ();
1171       goto done;
1172     }
1173
1174   VCL_SESSION_UNLOCK ();
1175
1176   if (clib_fifo_elts (listen_session->accept_evts_fifo))
1177     {
1178       clib_fifo_sub2 (listen_session->accept_evts_fifo, evt);
1179       accepted_msg = evt->accepted_msg;
1180       goto handle;
1181     }
1182
1183   is_nonblocking = VCL_SESS_ATTR_TEST (listen_session->attr,
1184                                        VCL_SESS_ATTR_NONBLOCK);
1185   if (svm_msg_q_is_empty (vcm->app_event_queue) && is_nonblocking)
1186     return VPPCOM_EAGAIN;
1187
1188   while (1)
1189     {
1190       if (svm_msg_q_sub (vcm->app_event_queue, &msg, SVM_Q_WAIT, 0))
1191         return VPPCOM_EAGAIN;
1192
1193       e = svm_msg_q_msg_data (vcm->app_event_queue, &msg);
1194       if (e->event_type != SESSION_CTRL_EVT_ACCEPTED)
1195         {
1196           clib_warning ("discarded event: %u", e->event_type);
1197           svm_msg_q_free_msg (vcm->app_event_queue, &msg);
1198           continue;
1199         }
1200       clib_memcpy (&accepted_msg, e->data, sizeof (accepted_msg));
1201       svm_msg_q_free_msg (vcm->app_event_queue, &msg);
1202       break;
1203     }
1204
1205 handle:
1206
1207   client_session_index = vcl_session_accepted_handler (&accepted_msg);
1208   listen_session = vcl_session_get (listen_session_index);
1209   VCL_SESSION_LOCK_AND_GET (client_session_index, &client_session);
1210   rv = client_session_index;
1211
1212   if (flags & O_NONBLOCK)
1213     VCL_SESS_ATTR_SET (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
1214
1215   listen_vpp_handle = listen_session->vpp_handle;
1216   VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: Got a client request! "
1217         "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
1218         getpid (), listen_vpp_handle, listen_session_index,
1219         client_session->vpp_handle, client_session_index,
1220         flags, VCL_SESS_ATTR_TEST (client_session->attr,
1221                                    VCL_SESS_ATTR_NONBLOCK));
1222
1223   if (ep)
1224     {
1225       ep->is_ip4 = client_session->transport.is_ip4;
1226       ep->port = client_session->transport.rmt_port;
1227       if (client_session->transport.is_ip4)
1228         clib_memcpy (ep->ip, &client_session->transport.rmt_ip.ip4,
1229                      sizeof (ip4_address_t));
1230       else
1231         clib_memcpy (ep->ip, &client_session->transport.rmt_ip.ip6,
1232                      sizeof (ip6_address_t));
1233     }
1234
1235   if (accepted_msg.server_event_queue_address)
1236     vpp_evt_q = uword_to_pointer (accepted_msg.vpp_event_queue_address,
1237                                   svm_msg_q_t *);
1238   else
1239     vpp_evt_q = client_session->vpp_evt_q;
1240
1241   vcl_send_session_accepted_reply (vpp_evt_q, client_session->client_context,
1242                                    client_session->vpp_handle, 0);
1243
1244   VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: accepted vpp handle 0x%llx, "
1245         "sid %u connection from peer %s address %U port %u to local %s "
1246         "address %U port %u", getpid (), listen_vpp_handle,
1247         listen_session_index, client_session->vpp_handle,
1248         client_session_index,
1249         client_session->transport.is_ip4 ? "IPv4" : "IPv6",
1250         format_ip46_address, &client_session->transport.rmt_ip,
1251         client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1252         clib_net_to_host_u16 (client_session->transport.rmt_port),
1253         client_session->transport.is_ip4 ? "IPv4" : "IPv6",
1254         format_ip46_address, &client_session->transport.lcl_ip,
1255         client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1256         clib_net_to_host_u16 (client_session->transport.lcl_port));
1257   vcl_evt (VCL_EVT_ACCEPT, client_session, listen_session,
1258            client_session_index);
1259   VCL_SESSION_UNLOCK ();
1260
1261 done:
1262   return rv;
1263 }
1264
1265 int
1266 vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
1267 {
1268   vcl_session_t *session = 0;
1269   u64 vpp_handle = 0;
1270   int rv, retval = VPPCOM_OK;
1271
1272   VCL_SESSION_LOCK_AND_GET (session_index, &session);
1273
1274   if (PREDICT_FALSE (session->is_vep))
1275     {
1276       VCL_SESSION_UNLOCK ();
1277       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
1278                     "connect on an epoll session!", getpid (), session_index);
1279       rv = VPPCOM_EBADFD;
1280       goto done;
1281     }
1282
1283   if (PREDICT_FALSE (session->session_state & CLIENT_STATE_OPEN))
1284     {
1285       VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: session already "
1286             "connected to %s %U port %d proto %s, state 0x%x (%s)",
1287             getpid (), session->vpp_handle, session_index,
1288             session->transport.is_ip4 ? "IPv4" : "IPv6",
1289             format_ip46_address,
1290             &session->transport.rmt_ip, session->transport.is_ip4 ?
1291             IP46_TYPE_IP4 : IP46_TYPE_IP6,
1292             clib_net_to_host_u16 (session->transport.rmt_port),
1293             session->session_type ? "UDP" : "TCP", session->session_state,
1294             vppcom_session_state_str (session->session_state));
1295
1296       VCL_SESSION_UNLOCK ();
1297       goto done;
1298     }
1299
1300   session->transport.is_ip4 = server_ep->is_ip4;
1301   if (session->transport.is_ip4)
1302     clib_memcpy (&session->transport.rmt_ip.ip4, server_ep->ip,
1303                  sizeof (ip4_address_t));
1304   else
1305     clib_memcpy (&session->transport.rmt_ip.ip6, server_ep->ip,
1306                  sizeof (ip6_address_t));
1307   session->transport.rmt_port = server_ep->port;
1308
1309   VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: connecting to server %s %U "
1310         "port %d proto %s",
1311         getpid (), session->vpp_handle, session_index,
1312         session->transport.is_ip4 ? "IPv4" : "IPv6",
1313         format_ip46_address,
1314         &session->transport.rmt_ip, session->transport.is_ip4 ?
1315         IP46_TYPE_IP4 : IP46_TYPE_IP6,
1316         clib_net_to_host_u16 (session->transport.rmt_port),
1317         session->session_type ? "UDP" : "TCP");
1318
1319   vppcom_send_connect_sock (session, session_index);
1320   VCL_SESSION_UNLOCK ();
1321
1322   retval = vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
1323                                                  vcm->cfg.session_timeout);
1324
1325   VCL_SESSION_LOCK_AND_GET (session_index, &session);
1326   vpp_handle = session->vpp_handle;
1327   VCL_SESSION_UNLOCK ();
1328
1329 done:
1330   if (PREDICT_FALSE (retval))
1331     {
1332       rv = retval;
1333       if (VPPCOM_DEBUG > 0)
1334         {
1335           if (session)
1336             clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connect "
1337                           "failed! returning %d (%s)", getpid (), vpp_handle,
1338                           session_index, rv, vppcom_retval_str (rv));
1339           else
1340             clib_warning ("VCL<%d>: no session for sid %u: connect failed! "
1341                           "returning %d (%s)", getpid (),
1342                           session_index, rv, vppcom_retval_str (rv));
1343         }
1344     }
1345   else
1346     VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: connected!",
1347           getpid (), vpp_handle, session_index);
1348
1349   return rv;
1350 }
1351
1352 static u8
1353 vcl_is_rx_evt_for_session (session_event_t * e, u32 sid, u8 is_ct)
1354 {
1355   if (!is_ct)
1356     return (e->event_type == FIFO_EVENT_APP_RX
1357             && e->fifo->client_session_index == sid);
1358   else
1359     return (e->event_type == SESSION_IO_EVT_CT_TX);
1360 }
1361
1362 static inline u8
1363 vcl_session_is_readable (vcl_session_t * s)
1364 {
1365   return ((s->session_state & STATE_OPEN)
1366           || (s->session_state == STATE_LISTEN
1367               && s->session_type == VPPCOM_PROTO_UDP));
1368 }
1369
1370 static inline int
1371 vppcom_session_read_internal (uint32_t session_index, void *buf, int n,
1372                               u8 peek)
1373 {
1374   int n_read = 0, rv, is_nonblocking;
1375   vcl_session_t *s = 0;
1376   svm_fifo_t *rx_fifo;
1377   svm_msg_q_msg_t msg;
1378   session_event_t *e;
1379   svm_msg_q_t *mq;
1380   u8 is_full;
1381
1382   ASSERT (buf);
1383
1384   VCL_SESSION_LOCK_AND_GET (session_index, &s);
1385
1386   if (PREDICT_FALSE (s->is_vep))
1387     {
1388       VCL_SESSION_UNLOCK ();
1389       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
1390                     "read from an epoll session!", getpid (), session_index);
1391       rv = VPPCOM_EBADFD;
1392       goto done;
1393     }
1394
1395   is_nonblocking = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
1396   rx_fifo = s->rx_fifo;
1397
1398   if (PREDICT_FALSE (!vcl_session_is_readable (s)))
1399     {
1400       session_state_t state = s->session_state;
1401       VCL_SESSION_UNLOCK ();
1402       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
1403
1404       VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: %s session is not open! "
1405             "state 0x%x (%s), returning %d (%s)",
1406             getpid (), s->vpp_handle, session_index, state,
1407             vppcom_session_state_str (state), rv, vppcom_retval_str (rv));
1408       goto done;
1409     }
1410
1411   VCL_SESSION_UNLOCK ();
1412   mq = vcl_session_is_ct (s) ? s->our_evt_q : vcm->app_event_queue;
1413   svm_fifo_unset_event (rx_fifo);
1414   is_full = svm_fifo_is_full (rx_fifo);
1415
1416   if (svm_fifo_is_empty (rx_fifo))
1417     {
1418       if (is_nonblocking)
1419         {
1420           rv = VPPCOM_OK;
1421           goto done;
1422         }
1423       while (1)
1424         {
1425           svm_msg_q_lock (mq);
1426           if (svm_msg_q_is_empty (mq))
1427             svm_msg_q_wait (mq);
1428
1429           svm_msg_q_sub_w_lock (mq, &msg);
1430           e = svm_msg_q_msg_data (mq, &msg);
1431           svm_msg_q_unlock (mq);
1432           if (!vcl_is_rx_evt_for_session (e, session_index,
1433                                           s->our_evt_q != 0))
1434             {
1435               vcl_handle_mq_ctrl_event (e);
1436               svm_msg_q_free_msg (mq, &msg);
1437               continue;
1438             }
1439           svm_fifo_unset_event (rx_fifo);
1440           svm_msg_q_free_msg (mq, &msg);
1441           if (PREDICT_FALSE (s->session_state == STATE_CLOSE_ON_EMPTY))
1442             return 0;
1443           if (svm_fifo_is_empty (rx_fifo))
1444             continue;
1445           break;
1446         }
1447     }
1448
1449   if (s->is_dgram)
1450     n_read = app_recv_dgram_raw (rx_fifo, buf, n, &s->transport, 0, peek);
1451   else
1452     n_read = app_recv_stream_raw (rx_fifo, buf, n, 0, peek);
1453
1454   if (vcl_session_is_ct (s) && is_full)
1455     {
1456       /* If the peer is not polling send notification */
1457       if (!svm_fifo_has_event (s->rx_fifo))
1458         app_send_io_evt_to_vpp (s->vpp_evt_q, s->rx_fifo,
1459                                 SESSION_IO_EVT_CT_RX, SVM_Q_WAIT);
1460     }
1461
1462   if (VPPCOM_DEBUG > 2)
1463     {
1464       if (n_read > 0)
1465         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: read %d bytes "
1466                       "from (%p)", getpid (), s->vpp_handle,
1467                       session_index, n_read, rx_fifo);
1468       else
1469         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: nothing read! "
1470                       "returning %d (%s)", getpid (), s->vpp_handle,
1471                       session_index, rv, vppcom_retval_str (rv));
1472     }
1473   return n_read;
1474
1475 done:
1476   return rv;
1477 }
1478
1479 int
1480 vppcom_session_read (uint32_t session_index, void *buf, size_t n)
1481 {
1482   return (vppcom_session_read_internal (session_index, buf, n, 0));
1483 }
1484
1485 static int
1486 vppcom_session_peek (uint32_t session_index, void *buf, int n)
1487 {
1488   return (vppcom_session_read_internal (session_index, buf, n, 1));
1489 }
1490
1491 static inline int
1492 vppcom_session_read_ready (vcl_session_t * session)
1493 {
1494   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1495   if (PREDICT_FALSE (session->is_vep))
1496     {
1497       clib_warning ("VCL<%d>: ERROR: sid %u: cannot read from an "
1498                     "epoll session!", getpid (), vcl_session_index (session));
1499       return VPPCOM_EBADFD;
1500     }
1501
1502   if (PREDICT_FALSE (!(session->session_state & (STATE_OPEN | STATE_LISTEN))))
1503     {
1504       session_state_t state = session->session_state;
1505       int rv;
1506
1507       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
1508
1509       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: session is not open!"
1510             " state 0x%x (%s), returning %d (%s)", getpid (),
1511             session->vpp_handle, vcl_session_index (session), state,
1512             vppcom_session_state_str (state), rv, vppcom_retval_str (rv));
1513       return rv;
1514     }
1515
1516   if (session->session_state & STATE_LISTEN)
1517     return clib_fifo_elts (session->accept_evts_fifo);
1518
1519   return svm_fifo_max_dequeue (session->rx_fifo);
1520 }
1521
1522 static u8
1523 vcl_is_tx_evt_for_session (session_event_t * e, u32 sid, u8 is_ct)
1524 {
1525   if (!is_ct)
1526     return (e->event_type == FIFO_EVENT_APP_TX
1527             && e->fifo->client_session_index == sid);
1528   else
1529     return (e->event_type == SESSION_IO_EVT_CT_RX);
1530 }
1531
1532 int
1533 vppcom_session_write (uint32_t session_index, void *buf, size_t n)
1534 {
1535   int rv, n_write, is_nonblocking;
1536   vcl_session_t *s = 0;
1537   svm_fifo_t *tx_fifo = 0;
1538   session_evt_type_t et;
1539   svm_msg_q_msg_t msg;
1540   session_event_t *e;
1541   svm_msg_q_t *mq;
1542
1543   ASSERT (buf);
1544
1545   VCL_SESSION_LOCK_AND_GET (session_index, &s);
1546
1547   tx_fifo = s->tx_fifo;
1548   is_nonblocking = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
1549
1550   if (PREDICT_FALSE (s->is_vep))
1551     {
1552       VCL_SESSION_UNLOCK ();
1553       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1554                     "cannot write to an epoll session!",
1555                     getpid (), s->vpp_handle, session_index);
1556
1557       rv = VPPCOM_EBADFD;
1558       goto done;
1559     }
1560
1561   if (!(s->session_state & STATE_OPEN))
1562     {
1563       session_state_t state = s->session_state;
1564       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
1565       VCL_SESSION_UNLOCK ();
1566       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: session is not open! "
1567             "state 0x%x (%s)",
1568             getpid (), s->vpp_handle, session_index,
1569             state, vppcom_session_state_str (state));
1570       goto done;
1571     }
1572
1573   VCL_SESSION_UNLOCK ();
1574
1575   mq = vcl_session_is_ct (s) ? s->our_evt_q : vcm->app_event_queue;
1576   if (svm_fifo_is_full (tx_fifo))
1577     {
1578       if (is_nonblocking)
1579         {
1580           rv = VPPCOM_EWOULDBLOCK;
1581           goto done;
1582         }
1583       while (svm_fifo_is_full (tx_fifo))
1584         {
1585           svm_msg_q_lock (mq);
1586           while (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 10e-6))
1587             ;
1588           svm_msg_q_sub_w_lock (mq, &msg);
1589           e = svm_msg_q_msg_data (mq, &msg);
1590           svm_msg_q_unlock (mq);
1591
1592           if (!vcl_is_tx_evt_for_session (e, session_index,
1593                                           s->our_evt_q != 0))
1594             vcl_handle_mq_ctrl_event (e);
1595           svm_msg_q_free_msg (mq, &msg);
1596         }
1597     }
1598
1599   ASSERT (FIFO_EVENT_APP_TX + 1 == SESSION_IO_EVT_CT_TX);
1600   et = FIFO_EVENT_APP_TX + vcl_session_is_ct (s);
1601   if (s->is_dgram)
1602     n_write = app_send_dgram_raw (tx_fifo, &s->transport,
1603                                   s->vpp_evt_q, buf, n, et, SVM_Q_WAIT);
1604   else
1605     n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et,
1606                                    SVM_Q_WAIT);
1607
1608   ASSERT (n_write > 0);
1609
1610   if (VPPCOM_DEBUG > 2)
1611     {
1612       if (n_write <= 0)
1613         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1614                       "FIFO-FULL (%p)", getpid (), s->vpp_handle,
1615                       session_index, tx_fifo);
1616       else
1617         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1618                       "wrote %d bytes tx-fifo: (%p)", getpid (),
1619                       s->vpp_handle, session_index, n_write, tx_fifo);
1620     }
1621   return n_write;
1622
1623 done:
1624   return rv;
1625 }
1626
1627 static vcl_session_t *
1628 vcl_ct_session_get_from_fifo (svm_fifo_t * f, u8 type)
1629 {
1630   vcl_session_t *s;
1631   s = vcl_session_get (f->client_session_index);
1632   if (s)
1633     {
1634       /* rx fifo */
1635       if (type == 0 && s->rx_fifo == f)
1636         return s;
1637       /* tx fifo */
1638       if (type == 1 && s->tx_fifo == f)
1639         return s;
1640     }
1641   s = vcl_session_get (f->master_session_index);
1642   if (s)
1643     {
1644       if (type == 0 && s->rx_fifo == f)
1645         return s;
1646       if (type == 1 && s->tx_fifo == f)
1647         return s;
1648     }
1649   return 0;
1650 }
1651
1652 static inline int
1653 vppcom_session_write_ready (vcl_session_t * session, u32 session_index)
1654 {
1655   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1656   if (PREDICT_FALSE (session->is_vep))
1657     {
1658       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1659                     "cannot write to an epoll session!",
1660                     getpid (), session->vpp_handle, session_index);
1661       return VPPCOM_EBADFD;
1662     }
1663
1664   if (PREDICT_FALSE (session->session_state & STATE_LISTEN))
1665     {
1666       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1667                     "cannot write to a listen session!",
1668                     getpid (), session->vpp_handle, session_index);
1669       return VPPCOM_EBADFD;
1670     }
1671
1672   if (PREDICT_FALSE (!(session->session_state & STATE_OPEN)))
1673     {
1674       session_state_t state = session->session_state;
1675       int rv;
1676
1677       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
1678       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1679                     "session is not open! state 0x%x (%s), "
1680                     "returning %d (%s)", getpid (), session->vpp_handle,
1681                     session_index,
1682                     state, vppcom_session_state_str (state),
1683                     rv, vppcom_retval_str (rv));
1684       return rv;
1685     }
1686
1687   VDBG (3, "VCL<%d>: vpp handle 0x%llx, sid %u: peek %s (%p), ready = %d",
1688         getpid (), session->vpp_handle, session_index, session->tx_fifo,
1689         svm_fifo_max_enqueue (session->tx_fifo));
1690
1691   return svm_fifo_max_enqueue (session->tx_fifo);
1692 }
1693
1694 static inline int
1695 vcl_mq_dequeue_batch (svm_msg_q_t * mq)
1696 {
1697   svm_msg_q_msg_t *msg;
1698   u32 n_msgs;
1699   int i;
1700
1701   n_msgs = svm_msg_q_size (mq);
1702   for (i = 0; i < n_msgs; i++)
1703     {
1704       vec_add2 (vcm->mq_msg_vector, msg, 1);
1705       svm_msg_q_sub_w_lock (mq, msg);
1706     }
1707   return n_msgs;
1708 }
1709
1710 static int
1711 vcl_select_handle_mq (svm_msg_q_t * mq, unsigned long n_bits,
1712                       unsigned long *read_map, unsigned long *write_map,
1713                       unsigned long *except_map, double time_to_wait,
1714                       u32 * bits_set)
1715 {
1716   session_disconnected_msg_t *disconnected_msg;
1717   session_connected_msg_t *connected_msg;
1718   session_accepted_msg_t *accepted_msg;
1719   vcl_session_msg_t *vcl_msg;
1720   vcl_session_t *session;
1721   svm_msg_q_msg_t *msg;
1722   session_event_t *e;
1723   u32 i, sid;
1724   u64 handle;
1725
1726   svm_msg_q_lock (mq);
1727   if (svm_msg_q_is_empty (mq))
1728     {
1729       if (*bits_set)
1730         {
1731           svm_msg_q_unlock (mq);
1732           return 0;
1733         }
1734
1735       if (!time_to_wait)
1736         {
1737           svm_msg_q_unlock (mq);
1738           return 0;
1739         }
1740       else if (time_to_wait < 0)
1741         {
1742           svm_msg_q_wait (mq);
1743         }
1744       else
1745         {
1746           if (svm_msg_q_timedwait (mq, time_to_wait))
1747             {
1748               svm_msg_q_unlock (mq);
1749               return 0;
1750             }
1751         }
1752     }
1753   vcl_mq_dequeue_batch (mq);
1754   svm_msg_q_unlock (mq);
1755
1756   for (i = 0; i < vec_len (vcm->mq_msg_vector); i++)
1757     {
1758       msg = vec_elt_at_index (vcm->mq_msg_vector, i);
1759       e = svm_msg_q_msg_data (mq, msg);
1760       switch (e->event_type)
1761         {
1762         case FIFO_EVENT_APP_RX:
1763           sid = e->fifo->client_session_index;
1764           session = vcl_session_get (sid);
1765           if (sid < n_bits && read_map)
1766             {
1767               clib_bitmap_set_no_check (read_map, sid, 1);
1768               *bits_set += 1;
1769             }
1770           break;
1771         case FIFO_EVENT_APP_TX:
1772           sid = e->fifo->client_session_index;
1773           session = vcl_session_get (sid);
1774           if (!session)
1775             break;
1776           if (sid < n_bits && write_map)
1777             {
1778               clib_bitmap_set_no_check (write_map, sid, 1);
1779               *bits_set += 1;
1780             }
1781           break;
1782         case SESSION_IO_EVT_CT_TX:
1783           session = vcl_ct_session_get_from_fifo (e->fifo, 0);
1784           sid = vcl_session_index (session);
1785           if (sid < n_bits && read_map)
1786             {
1787               clib_bitmap_set_no_check (read_map, sid, 1);
1788               *bits_set += 1;
1789             }
1790           break;
1791           break;
1792         case SESSION_IO_EVT_CT_RX:
1793           session = vcl_ct_session_get_from_fifo (e->fifo, 1);
1794           sid = vcl_session_index (session);
1795           if (!session)
1796             break;
1797           if (sid < n_bits && write_map)
1798             {
1799               clib_bitmap_set_no_check (write_map, sid, 1);
1800               *bits_set += 1;
1801             }
1802           break;
1803         case SESSION_CTRL_EVT_ACCEPTED:
1804           accepted_msg = (session_accepted_msg_t *) e->data;
1805           handle = accepted_msg->listener_handle;
1806           session = vppcom_session_table_lookup_listener (handle);
1807           if (!session)
1808             {
1809               clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
1810                             "listener handle %llx", getpid (), handle);
1811               break;
1812             }
1813
1814           clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
1815           vcl_msg->accepted_msg = *accepted_msg;
1816           sid = session - vcm->sessions;
1817           if (sid < n_bits && read_map)
1818             {
1819               clib_bitmap_set_no_check (read_map, sid, 1);
1820               *bits_set += 1;
1821             }
1822           break;
1823         case SESSION_CTRL_EVT_CONNECTED:
1824           connected_msg = (session_connected_msg_t *) e->data;
1825           vcl_session_connected_handler (connected_msg);
1826           break;
1827         case SESSION_CTRL_EVT_DISCONNECTED:
1828           disconnected_msg = (session_disconnected_msg_t *) e->data;
1829           sid = vcl_session_get_index_from_handle (disconnected_msg->handle);
1830           if (sid < n_bits && except_map)
1831             {
1832               clib_bitmap_set_no_check (except_map, sid, 1);
1833               *bits_set += 1;
1834             }
1835           break;
1836         case SESSION_CTRL_EVT_RESET:
1837           sid = vcl_session_reset_handler ((session_reset_msg_t *) e->data);
1838           if (sid < n_bits && except_map)
1839             {
1840               clib_bitmap_set_no_check (except_map, sid, 1);
1841               *bits_set += 1;
1842             }
1843           break;
1844         default:
1845           clib_warning ("unhandled: %u", e->event_type);
1846           break;
1847         }
1848       svm_msg_q_free_msg (mq, msg);
1849     }
1850
1851   vec_reset_length (vcm->mq_msg_vector);
1852   return *bits_set;
1853 }
1854
1855 static int
1856 vppcom_select_condvar (unsigned long n_bits, unsigned long *read_map,
1857                        unsigned long *write_map, unsigned long *except_map,
1858                        double time_to_wait, u32 * bits_set)
1859 {
1860   double total_wait = 0, wait_slice;
1861   vcl_cut_through_registration_t *cr;
1862
1863   time_to_wait = (time_to_wait == -1) ? 10e9 : time_to_wait;
1864   wait_slice = vcm->cut_through_registrations ? 10e-6 : time_to_wait;
1865   do
1866     {
1867       /* *INDENT-OFF* */
1868       pool_foreach (cr, vcm->cut_through_registrations, ({
1869         vcl_select_handle_mq (cr->mq, n_bits, read_map, write_map, except_map,
1870                               0, bits_set);
1871       }));
1872       /* *INDENT-ON* */
1873
1874       vcl_select_handle_mq (vcm->app_event_queue, n_bits, read_map, write_map,
1875                             except_map, time_to_wait, bits_set);
1876       total_wait += wait_slice;
1877       if (*bits_set)
1878         return *bits_set;
1879     }
1880   while (total_wait < time_to_wait);
1881
1882   return 0;
1883 }
1884
1885 static int
1886 vppcom_select_eventfd (unsigned long n_bits, unsigned long *read_map,
1887                        unsigned long *write_map, unsigned long *except_map,
1888                        double time_to_wait, u32 * bits_set)
1889 {
1890   vcl_mq_evt_conn_t *mqc;
1891   int __clib_unused n_read;
1892   int n_mq_evts, i;
1893   u64 buf;
1894
1895   vec_validate (vcm->mq_events, pool_elts (vcm->mq_evt_conns));
1896   n_mq_evts = epoll_wait (vcm->mqs_epfd, vcm->mq_events,
1897                           vec_len (vcm->mq_events), time_to_wait);
1898   for (i = 0; i < n_mq_evts; i++)
1899     {
1900       mqc = vcl_mq_evt_conn_get (vcm->mq_events[i].data.u32);
1901       n_read = read (mqc->mq_fd, &buf, sizeof (buf));
1902       vcl_select_handle_mq (mqc->mq, n_bits, read_map, write_map,
1903                             except_map, 0, bits_set);
1904     }
1905
1906   return (n_mq_evts > 0 ? (int) *bits_set : 0);
1907 }
1908
1909 int
1910 vppcom_select (unsigned long n_bits, unsigned long *read_map,
1911                unsigned long *write_map, unsigned long *except_map,
1912                double time_to_wait)
1913 {
1914   u32 sid, minbits = clib_max (n_bits, BITS (uword)), bits_set = 0;
1915   vcl_session_t *session = 0;
1916   int rv;
1917
1918   ASSERT (sizeof (clib_bitmap_t) == sizeof (long int));
1919
1920   if (n_bits && read_map)
1921     {
1922       clib_bitmap_validate (vcm->rd_bitmap, minbits);
1923       clib_memcpy (vcm->rd_bitmap, read_map,
1924                    vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
1925       memset (read_map, 0, vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
1926     }
1927   if (n_bits && write_map)
1928     {
1929       clib_bitmap_validate (vcm->wr_bitmap, minbits);
1930       clib_memcpy (vcm->wr_bitmap, write_map,
1931                    vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
1932       memset (write_map, 0,
1933               vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
1934     }
1935   if (n_bits && except_map)
1936     {
1937       clib_bitmap_validate (vcm->ex_bitmap, minbits);
1938       clib_memcpy (vcm->ex_bitmap, except_map,
1939                    vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
1940       memset (except_map, 0,
1941               vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
1942     }
1943
1944   if (!n_bits)
1945     return 0;
1946
1947   if (!write_map)
1948     goto check_rd;
1949
1950   /* *INDENT-OFF* */
1951   clib_bitmap_foreach (sid, vcm->wr_bitmap, ({
1952     if (!(session = vcl_session_get (sid)))
1953       {
1954         VDBG (0, "VCL<%d>: session %d specified in write_map is closed.",
1955               getpid (), sid);
1956         return VPPCOM_EBADFD;
1957       }
1958
1959     rv = svm_fifo_is_full (session->tx_fifo);
1960     if (!rv)
1961       {
1962         clib_bitmap_set_no_check (write_map, sid, 1);
1963         bits_set++;
1964       }
1965   }));
1966
1967 check_rd:
1968   if (!read_map)
1969     goto check_mq;
1970
1971   clib_bitmap_foreach (sid, vcm->rd_bitmap, ({
1972     if (!(session = vcl_session_get (sid)))
1973       {
1974         VDBG (0, "VCL<%d>: session %d specified in write_map is closed.",
1975               getpid (), sid);
1976         return VPPCOM_EBADFD;
1977       }
1978
1979     rv = vppcom_session_read_ready (session);
1980     if (rv)
1981       {
1982         clib_bitmap_set_no_check (read_map, sid, 1);
1983         bits_set++;
1984       }
1985   }));
1986   /* *INDENT-ON* */
1987
1988 check_mq:
1989
1990   if (vcm->cfg.use_mq_eventfd)
1991     vppcom_select_eventfd (n_bits, read_map, write_map, except_map,
1992                            time_to_wait, &bits_set);
1993   else
1994     vppcom_select_condvar (n_bits, read_map, write_map, except_map,
1995                            time_to_wait, &bits_set);
1996
1997   return (bits_set);
1998 }
1999
2000 static inline void
2001 vep_verify_epoll_chain (u32 vep_idx)
2002 {
2003   vcl_session_t *session;
2004   vppcom_epoll_t *vep;
2005   int rv;
2006   u32 sid = vep_idx;
2007
2008   if (VPPCOM_DEBUG <= 1)
2009     return;
2010
2011   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
2012   rv = vppcom_session_at_index (vep_idx, &session);
2013   if (PREDICT_FALSE (rv))
2014     {
2015       clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!",
2016                     getpid (), vep_idx);
2017       goto done;
2018     }
2019   if (PREDICT_FALSE (!session->is_vep))
2020     {
2021       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
2022                     getpid (), vep_idx);
2023       goto done;
2024     }
2025   vep = &session->vep;
2026   clib_warning ("VCL<%d>: vep_idx (%u): Dumping epoll chain\n"
2027                 "{\n"
2028                 "   is_vep         = %u\n"
2029                 "   is_vep_session = %u\n"
2030                 "   next_sid       = 0x%x (%u)\n"
2031                 "   wait_cont_idx  = 0x%x (%u)\n"
2032                 "}\n", getpid (), vep_idx,
2033                 session->is_vep, session->is_vep_session,
2034                 vep->next_sid, vep->next_sid,
2035                 session->wait_cont_idx, session->wait_cont_idx);
2036
2037   for (sid = vep->next_sid; sid != ~0; sid = vep->next_sid)
2038     {
2039       rv = vppcom_session_at_index (sid, &session);
2040       if (PREDICT_FALSE (rv))
2041         {
2042           clib_warning ("VCL<%d>: ERROR: Invalid sid (%u)!", getpid (), sid);
2043           goto done;
2044         }
2045       if (PREDICT_FALSE (session->is_vep))
2046         clib_warning ("VCL<%d>: ERROR: sid (%u) is a vep!",
2047                       getpid (), vep_idx);
2048       else if (PREDICT_FALSE (!session->is_vep_session))
2049         {
2050           clib_warning ("VCL<%d>: ERROR: session (%u) "
2051                         "is not a vep session!", getpid (), sid);
2052           goto done;
2053         }
2054       vep = &session->vep;
2055       if (PREDICT_FALSE (vep->vep_idx != vep_idx))
2056         clib_warning ("VCL<%d>: ERROR: session (%u) vep_idx (%u) != "
2057                       "vep_idx (%u)!", getpid (),
2058                       sid, session->vep.vep_idx, vep_idx);
2059       if (session->is_vep_session)
2060         {
2061           clib_warning ("vep_idx[%u]: sid 0x%x (%u)\n"
2062                         "{\n"
2063                         "   next_sid       = 0x%x (%u)\n"
2064                         "   prev_sid       = 0x%x (%u)\n"
2065                         "   vep_idx        = 0x%x (%u)\n"
2066                         "   ev.events      = 0x%x\n"
2067                         "   ev.data.u64    = 0x%llx\n"
2068                         "   et_mask        = 0x%x\n"
2069                         "}\n",
2070                         vep_idx, sid, sid,
2071                         vep->next_sid, vep->next_sid,
2072                         vep->prev_sid, vep->prev_sid,
2073                         vep->vep_idx, vep->vep_idx,
2074                         vep->ev.events, vep->ev.data.u64, vep->et_mask);
2075         }
2076     }
2077
2078 done:
2079   clib_warning ("VCL<%d>: vep_idx (%u): Dump complete!\n",
2080                 getpid (), vep_idx);
2081 }
2082
2083 int
2084 vppcom_epoll_create (void)
2085 {
2086   vcl_session_t *vep_session;
2087   u32 vep_idx;
2088
2089   VCL_SESSION_LOCK ();
2090   pool_get (vcm->sessions, vep_session);
2091   memset (vep_session, 0, sizeof (*vep_session));
2092   vep_idx = vep_session - vcm->sessions;
2093
2094   vep_session->is_vep = 1;
2095   vep_session->vep.vep_idx = ~0;
2096   vep_session->vep.next_sid = ~0;
2097   vep_session->vep.prev_sid = ~0;
2098   vep_session->wait_cont_idx = ~0;
2099   vep_session->vpp_handle = ~0;
2100   vep_session->poll_reg = 0;
2101
2102   vcl_evt (VCL_EVT_EPOLL_CREATE, vep_session, vep_idx);
2103   VCL_SESSION_UNLOCK ();
2104
2105   VDBG (0, "VCL<%d>: Created vep_idx %u / sid %u!",
2106         getpid (), vep_idx, vep_idx);
2107
2108   return (vep_idx);
2109 }
2110
2111 int
2112 vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
2113                   struct epoll_event *event)
2114 {
2115   vcl_session_t *vep_session;
2116   vcl_session_t *session;
2117   int rv;
2118
2119   if (vep_idx == session_index)
2120     {
2121       clib_warning ("VCL<%d>: ERROR: vep_idx == session_index (%u)!",
2122                     getpid (), vep_idx);
2123       return VPPCOM_EINVAL;
2124     }
2125
2126   VCL_SESSION_LOCK ();
2127   rv = vppcom_session_at_index (vep_idx, &vep_session);
2128   if (PREDICT_FALSE (rv))
2129     {
2130       clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!", vep_idx);
2131       goto done;
2132     }
2133   if (PREDICT_FALSE (!vep_session->is_vep))
2134     {
2135       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
2136                     getpid (), vep_idx);
2137       rv = VPPCOM_EINVAL;
2138       goto done;
2139     }
2140
2141   ASSERT (vep_session->vep.vep_idx == ~0);
2142   ASSERT (vep_session->vep.prev_sid == ~0);
2143
2144   rv = vppcom_session_at_index (session_index, &session);
2145   if (PREDICT_FALSE (rv))
2146     {
2147       VDBG (0, "VCL<%d>: ERROR: Invalid session_index (%u)!",
2148             getpid (), session_index);
2149       goto done;
2150     }
2151   if (PREDICT_FALSE (session->is_vep))
2152     {
2153       clib_warning ("ERROR: session_index (%u) is a vep!", vep_idx);
2154       rv = VPPCOM_EINVAL;
2155       goto done;
2156     }
2157
2158   switch (op)
2159     {
2160     case EPOLL_CTL_ADD:
2161       if (PREDICT_FALSE (!event))
2162         {
2163           clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: NULL pointer to "
2164                         "epoll_event structure!", getpid ());
2165           rv = VPPCOM_EINVAL;
2166           goto done;
2167         }
2168       if (vep_session->vep.next_sid != ~0)
2169         {
2170           vcl_session_t *next_session;
2171           rv = vppcom_session_at_index (vep_session->vep.next_sid,
2172                                         &next_session);
2173           if (PREDICT_FALSE (rv))
2174             {
2175               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: Invalid "
2176                             "vep.next_sid (%u) on vep_idx (%u)!",
2177                             getpid (), vep_session->vep.next_sid, vep_idx);
2178               goto done;
2179             }
2180           ASSERT (next_session->vep.prev_sid == vep_idx);
2181           next_session->vep.prev_sid = session_index;
2182         }
2183       session->vep.next_sid = vep_session->vep.next_sid;
2184       session->vep.prev_sid = vep_idx;
2185       session->vep.vep_idx = vep_idx;
2186       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
2187       session->vep.ev = *event;
2188       session->is_vep = 0;
2189       session->is_vep_session = 1;
2190       vep_session->vep.next_sid = session_index;
2191
2192       /* VCL Event Register handler */
2193       if (session->session_state & STATE_LISTEN)
2194         {
2195           /* Register handler for connect_request event on listen_session_index */
2196           vce_event_key_t evk;
2197           evk.session_index = session_index;
2198           evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
2199           vep_session->poll_reg =
2200             vce_register_handler (&vcm->event_thread, &evk,
2201                                   vce_poll_wait_connect_request_handler_fn,
2202                                   0 /* No callback args */ );
2203         }
2204       VDBG (1, "VCL<%d>: EPOLL_CTL_ADD: vep_idx %u, "
2205             "sid %u, events 0x%x, data 0x%llx!",
2206             getpid (), vep_idx, session_index,
2207             event->events, event->data.u64);
2208       vcl_evt (VCL_EVT_EPOLL_CTLADD, session, event->events, event->data.u64);
2209       break;
2210
2211     case EPOLL_CTL_MOD:
2212       if (PREDICT_FALSE (!event))
2213         {
2214           clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_MOD: NULL pointer to "
2215                         "epoll_event structure!", getpid ());
2216           rv = VPPCOM_EINVAL;
2217           goto done;
2218         }
2219       else if (PREDICT_FALSE (!session->is_vep_session))
2220         {
2221           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
2222                         "not a vep session!", getpid (), session_index);
2223           rv = VPPCOM_EINVAL;
2224           goto done;
2225         }
2226       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
2227         {
2228           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
2229                         "vep_idx (%u) != vep_idx (%u)!",
2230                         getpid (), session_index,
2231                         session->vep.vep_idx, vep_idx);
2232           rv = VPPCOM_EINVAL;
2233           goto done;
2234         }
2235       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
2236       session->vep.ev = *event;
2237       VDBG (1, "VCL<%d>: EPOLL_CTL_MOD: vep_idx %u, sid %u, events 0x%x,"
2238             " data 0x%llx!", getpid (), vep_idx, session_index, event->events,
2239             event->data.u64);
2240       break;
2241
2242     case EPOLL_CTL_DEL:
2243       if (PREDICT_FALSE (!session->is_vep_session))
2244         {
2245           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
2246                         "not a vep session!", getpid (), session_index);
2247           rv = VPPCOM_EINVAL;
2248           goto done;
2249         }
2250       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
2251         {
2252           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
2253                         "vep_idx (%u) != vep_idx (%u)!",
2254                         getpid (), session_index,
2255                         session->vep.vep_idx, vep_idx);
2256           rv = VPPCOM_EINVAL;
2257           goto done;
2258         }
2259
2260       /* VCL Event Un-register handler */
2261       if ((session->session_state & STATE_LISTEN) && vep_session->poll_reg)
2262         {
2263           (void) vce_unregister_handler (&vcm->event_thread,
2264                                          vep_session->poll_reg);
2265         }
2266
2267       vep_session->wait_cont_idx =
2268         (vep_session->wait_cont_idx == session_index) ?
2269         session->vep.next_sid : vep_session->wait_cont_idx;
2270
2271       if (session->vep.prev_sid == vep_idx)
2272         vep_session->vep.next_sid = session->vep.next_sid;
2273       else
2274         {
2275           vcl_session_t *prev_session;
2276           rv = vppcom_session_at_index (session->vep.prev_sid, &prev_session);
2277           if (PREDICT_FALSE (rv))
2278             {
2279               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
2280                             "vep.prev_sid (%u) on sid (%u)!",
2281                             getpid (), session->vep.prev_sid, session_index);
2282               goto done;
2283             }
2284           ASSERT (prev_session->vep.next_sid == session_index);
2285           prev_session->vep.next_sid = session->vep.next_sid;
2286         }
2287       if (session->vep.next_sid != ~0)
2288         {
2289           vcl_session_t *next_session;
2290           rv = vppcom_session_at_index (session->vep.next_sid, &next_session);
2291           if (PREDICT_FALSE (rv))
2292             {
2293               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
2294                             "vep.next_sid (%u) on sid (%u)!",
2295                             getpid (), session->vep.next_sid, session_index);
2296               goto done;
2297             }
2298           ASSERT (next_session->vep.prev_sid == session_index);
2299           next_session->vep.prev_sid = session->vep.prev_sid;
2300         }
2301
2302       memset (&session->vep, 0, sizeof (session->vep));
2303       session->vep.next_sid = ~0;
2304       session->vep.prev_sid = ~0;
2305       session->vep.vep_idx = ~0;
2306       session->is_vep_session = 0;
2307       VDBG (1, "VCL<%d>: EPOLL_CTL_DEL: vep_idx %u, sid %u!",
2308             getpid (), vep_idx, session_index);
2309       vcl_evt (VCL_EVT_EPOLL_CTLDEL, session, vep_idx);
2310       break;
2311
2312     default:
2313       clib_warning ("VCL<%d>: ERROR: Invalid operation (%d)!", getpid (), op);
2314       rv = VPPCOM_EINVAL;
2315     }
2316
2317   vep_verify_epoll_chain (vep_idx);
2318
2319 done:
2320   VCL_SESSION_UNLOCK ();
2321   return rv;
2322 }
2323
2324 static int
2325 vcl_epoll_wait_handle_mq (svm_msg_q_t * mq, struct epoll_event *events,
2326                           u32 maxevents, double wait_for_time, u32 * num_ev)
2327 {
2328   session_disconnected_msg_t *disconnected_msg;
2329   session_connected_msg_t *connected_msg;
2330   session_accepted_msg_t *accepted_msg;
2331   u64 session_evt_data = ~0, handle;
2332   u32 sid = ~0, session_events;
2333   vcl_session_msg_t *vcl_msg;
2334   vcl_session_t *session;
2335   svm_msg_q_msg_t *msg;
2336   session_event_t *e;
2337   u8 add_event;
2338   int i;
2339
2340   svm_msg_q_lock (mq);
2341   if (svm_msg_q_is_empty (mq))
2342     {
2343       if (!wait_for_time)
2344         {
2345           svm_msg_q_unlock (mq);
2346           return 0;
2347         }
2348       else if (wait_for_time < 0)
2349         {
2350           svm_msg_q_wait (mq);
2351         }
2352       else
2353         {
2354           if (svm_msg_q_timedwait (mq, wait_for_time / 1e3))
2355             {
2356               svm_msg_q_unlock (mq);
2357               return 0;
2358             }
2359         }
2360     }
2361   vcl_mq_dequeue_batch (mq);
2362   svm_msg_q_unlock (mq);
2363
2364   for (i = 0; i < vec_len (vcm->mq_msg_vector); i++)
2365     {
2366       msg = vec_elt_at_index (vcm->mq_msg_vector, i);
2367       e = svm_msg_q_msg_data (mq, msg);
2368       add_event = 0;
2369       switch (e->event_type)
2370         {
2371         case FIFO_EVENT_APP_RX:
2372           sid = e->fifo->client_session_index;
2373           session = vcl_session_get (sid);
2374           session_events = session->vep.ev.events;
2375           if (!(EPOLLIN & session->vep.ev.events))
2376             break;
2377           add_event = 1;
2378           events[*num_ev].events |= EPOLLIN;
2379           session_evt_data = session->vep.ev.data.u64;
2380           break;
2381         case FIFO_EVENT_APP_TX:
2382           sid = e->fifo->client_session_index;
2383           session = vcl_session_get (sid);
2384           session_events = session->vep.ev.events;
2385           if (!(EPOLLOUT & session_events))
2386             break;
2387           add_event = 1;
2388           events[*num_ev].events |= EPOLLOUT;
2389           session_evt_data = session->vep.ev.data.u64;
2390           break;
2391         case SESSION_IO_EVT_CT_TX:
2392           session = vcl_ct_session_get_from_fifo (e->fifo, 0);
2393           sid = vcl_session_index (session);
2394           session_events = session->vep.ev.events;
2395           if (!(EPOLLIN & session->vep.ev.events))
2396             break;
2397           add_event = 1;
2398           events[*num_ev].events |= EPOLLIN;
2399           session_evt_data = session->vep.ev.data.u64;
2400           break;
2401         case SESSION_IO_EVT_CT_RX:
2402           session = vcl_ct_session_get_from_fifo (e->fifo, 1);
2403           sid = vcl_session_index (session);
2404           session_events = session->vep.ev.events;
2405           if (!(EPOLLOUT & session_events))
2406             break;
2407           add_event = 1;
2408           events[*num_ev].events |= EPOLLOUT;
2409           session_evt_data = session->vep.ev.data.u64;
2410           break;
2411         case SESSION_CTRL_EVT_ACCEPTED:
2412           accepted_msg = (session_accepted_msg_t *) e->data;
2413           handle = accepted_msg->listener_handle;
2414           session = vppcom_session_table_lookup_listener (handle);
2415           if (!session)
2416             {
2417               clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
2418                             "listener handle %llx", getpid (), handle);
2419               break;
2420             }
2421
2422           clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
2423           vcl_msg->accepted_msg = *accepted_msg;
2424           session_events = session->vep.ev.events;
2425           if (!(EPOLLIN & session_events))
2426             break;
2427
2428           add_event = 1;
2429           events[*num_ev].events |= EPOLLIN;
2430           session_evt_data = session->vep.ev.data.u64;
2431           break;
2432         case SESSION_CTRL_EVT_CONNECTED:
2433           connected_msg = (session_connected_msg_t *) e->data;
2434           vcl_session_connected_handler (connected_msg);
2435           /* Generate EPOLLOUT because there's no connected event */
2436           sid = vcl_session_get_index_from_handle (connected_msg->handle);
2437           clib_spinlock_lock (&vcm->sessions_lockp);
2438           session = vcl_session_get (sid);
2439           session_events = session->vep.ev.events;
2440           if (EPOLLOUT & session_events)
2441             {
2442               add_event = 1;
2443               events[*num_ev].events |= EPOLLOUT;
2444               session_evt_data = session->vep.ev.data.u64;
2445             }
2446           clib_spinlock_unlock (&vcm->sessions_lockp);
2447           break;
2448         case SESSION_CTRL_EVT_DISCONNECTED:
2449           disconnected_msg = (session_disconnected_msg_t *) e->data;
2450           sid = vcl_session_get_index_from_handle (disconnected_msg->handle);
2451           clib_spinlock_lock (&vcm->sessions_lockp);
2452           if (!(session = vcl_session_get (sid)))
2453             break;
2454           add_event = 1;
2455           events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2456           session_evt_data = session->vep.ev.data.u64;
2457           session_events = session->vep.ev.events;
2458           clib_spinlock_unlock (&vcm->sessions_lockp);
2459           break;
2460         case SESSION_CTRL_EVT_RESET:
2461           sid = vcl_session_reset_handler ((session_reset_msg_t *) e->data);
2462           if (!(session = vcl_session_get (sid)))
2463             break;
2464           add_event = 1;
2465           events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;
2466           session_evt_data = session->vep.ev.data.u64;
2467           session_events = session->vep.ev.events;
2468           break;
2469         default:
2470           clib_warning ("unhandled: %u", e->event_type);
2471           svm_msg_q_free_msg (mq, msg);
2472           continue;
2473         }
2474       svm_msg_q_free_msg (mq, msg);
2475
2476       if (add_event)
2477         {
2478           events[*num_ev].data.u64 = session_evt_data;
2479           if (EPOLLONESHOT & session_events)
2480             {
2481               clib_spinlock_lock (&vcm->sessions_lockp);
2482               session = vcl_session_get (sid);
2483               session->vep.ev.events = 0;
2484               clib_spinlock_unlock (&vcm->sessions_lockp);
2485             }
2486           *num_ev += 1;
2487           if (*num_ev == maxevents)
2488             break;
2489         }
2490     }
2491
2492   vec_reset_length (vcm->mq_msg_vector);
2493   return *num_ev;
2494 }
2495
2496 static int
2497 vppcom_epoll_wait_condvar (struct epoll_event *events, int maxevents,
2498                            double wait_for_time)
2499 {
2500   vcl_cut_through_registration_t *cr;
2501   double total_wait = 0, wait_slice;
2502   u32 num_ev = 0;
2503   int rv;
2504
2505   wait_for_time = (wait_for_time == -1) ? (double) 10e9 : wait_for_time;
2506   wait_slice = vcm->cut_through_registrations ? 10e-6 : wait_for_time;
2507
2508   do
2509     {
2510       /* *INDENT-OFF* */
2511       pool_foreach (cr, vcm->cut_through_registrations, ({
2512         vcl_epoll_wait_handle_mq (cr->mq, events, maxevents, 0, &num_ev);
2513       }));
2514       /* *INDENT-ON* */
2515
2516       rv = vcl_epoll_wait_handle_mq (vcm->app_event_queue, events, maxevents,
2517                                      num_ev ? 0 : wait_slice, &num_ev);
2518       if (rv)
2519         total_wait += wait_slice;
2520       if (num_ev)
2521         return num_ev;
2522     }
2523   while (total_wait < wait_for_time);
2524   return (int) num_ev;
2525 }
2526
2527 static int
2528 vppcom_epoll_wait_eventfd (struct epoll_event *events, int maxevents,
2529                            double wait_for_time)
2530 {
2531   vcl_mq_evt_conn_t *mqc;
2532   int __clib_unused n_read;
2533   int n_mq_evts, i;
2534   u32 n_evts = 0;
2535   u64 buf;
2536
2537   vec_validate (vcm->mq_events, pool_elts (vcm->mq_evt_conns));
2538   n_mq_evts = epoll_wait (vcm->mqs_epfd, vcm->mq_events,
2539                           vec_len (vcm->mq_events), wait_for_time);
2540   for (i = 0; i < n_mq_evts; i++)
2541     {
2542       mqc = vcl_mq_evt_conn_get (vcm->mq_events[i].data.u32);
2543       n_read = read (mqc->mq_fd, &buf, sizeof (buf));
2544       vcl_epoll_wait_handle_mq (mqc->mq, events, maxevents, 0, &n_evts);
2545     }
2546
2547   return (int) n_evts;
2548 }
2549
2550 int
2551 vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
2552                    int maxevents, double wait_for_time)
2553 {
2554   vcl_session_t *vep_session;
2555
2556   if (PREDICT_FALSE (maxevents <= 0))
2557     {
2558       clib_warning ("VCL<%d>: ERROR: Invalid maxevents (%d)!",
2559                     getpid (), maxevents);
2560       return VPPCOM_EINVAL;
2561     }
2562
2563   clib_spinlock_lock (&vcm->sessions_lockp);
2564   vep_session = vcl_session_get (vep_idx);
2565   if (PREDICT_FALSE (!vep_session->is_vep))
2566     {
2567       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
2568                     getpid (), vep_idx);
2569       clib_spinlock_unlock (&vcm->sessions_lockp);
2570       return VPPCOM_EINVAL;
2571     }
2572   clib_spinlock_unlock (&vcm->sessions_lockp);
2573
2574   memset (events, 0, sizeof (*events) * maxevents);
2575
2576   if (vcm->cfg.use_mq_eventfd)
2577     return vppcom_epoll_wait_eventfd (events, maxevents, wait_for_time);
2578
2579   return vppcom_epoll_wait_condvar (events, maxevents, wait_for_time);
2580 }
2581
2582 int
2583 vppcom_session_attr (uint32_t session_index, uint32_t op,
2584                      void *buffer, uint32_t * buflen)
2585 {
2586   vcl_session_t *session;
2587   int rv = VPPCOM_OK;
2588   u32 *flags = buffer;
2589   vppcom_endpt_t *ep = buffer;
2590
2591   VCL_SESSION_LOCK_AND_GET (session_index, &session);
2592
2593   ASSERT (session);
2594
2595   switch (op)
2596     {
2597     case VPPCOM_ATTR_GET_NREAD:
2598       rv = vppcom_session_read_ready (session);
2599       VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
2600             getpid (), rv);
2601       break;
2602
2603     case VPPCOM_ATTR_GET_NWRITE:
2604       rv = vppcom_session_write_ready (session, session_index);
2605       VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
2606             getpid (), session_index, rv);
2607       break;
2608
2609     case VPPCOM_ATTR_GET_FLAGS:
2610       if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
2611         {
2612           *flags = O_RDWR | (VCL_SESS_ATTR_TEST (session->attr,
2613                                                  VCL_SESS_ATTR_NONBLOCK));
2614           *buflen = sizeof (*flags);
2615           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_FLAGS: sid %u, flags = 0x%08x, "
2616                 "is_nonblocking = %u", getpid (),
2617                 session_index, *flags,
2618                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
2619         }
2620       else
2621         rv = VPPCOM_EINVAL;
2622       break;
2623
2624     case VPPCOM_ATTR_SET_FLAGS:
2625       if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
2626         {
2627           if (*flags & O_NONBLOCK)
2628             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
2629           else
2630             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
2631
2632           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_FLAGS: sid %u, flags = 0x%08x,"
2633                 " is_nonblocking = %u",
2634                 getpid (), session_index, *flags,
2635                 VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK));
2636         }
2637       else
2638         rv = VPPCOM_EINVAL;
2639       break;
2640
2641     case VPPCOM_ATTR_GET_PEER_ADDR:
2642       if (PREDICT_TRUE (buffer && buflen &&
2643                         (*buflen >= sizeof (*ep)) && ep->ip))
2644         {
2645           ep->is_ip4 = session->transport.is_ip4;
2646           ep->port = session->transport.rmt_port;
2647           if (session->transport.is_ip4)
2648             clib_memcpy (ep->ip, &session->transport.rmt_ip.ip4,
2649                          sizeof (ip4_address_t));
2650           else
2651             clib_memcpy (ep->ip, &session->transport.rmt_ip.ip6,
2652                          sizeof (ip6_address_t));
2653           *buflen = sizeof (*ep);
2654           VDBG (1, "VCL<%d>: VPPCOM_ATTR_GET_PEER_ADDR: sid %u, is_ip4 = %u, "
2655                 "addr = %U, port %u", getpid (),
2656                 session_index, ep->is_ip4, format_ip46_address,
2657                 &session->transport.rmt_ip,
2658                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
2659                 clib_net_to_host_u16 (ep->port));
2660         }
2661       else
2662         rv = VPPCOM_EINVAL;
2663       break;
2664
2665     case VPPCOM_ATTR_GET_LCL_ADDR:
2666       if (PREDICT_TRUE (buffer && buflen &&
2667                         (*buflen >= sizeof (*ep)) && ep->ip))
2668         {
2669           ep->is_ip4 = session->transport.is_ip4;
2670           ep->port = session->transport.lcl_port;
2671           if (session->transport.is_ip4)
2672             clib_memcpy (ep->ip, &session->transport.lcl_ip.ip4,
2673                          sizeof (ip4_address_t));
2674           else
2675             clib_memcpy (ep->ip, &session->transport.lcl_ip.ip6,
2676                          sizeof (ip6_address_t));
2677           *buflen = sizeof (*ep);
2678           VDBG (1, "VCL<%d>: VPPCOM_ATTR_GET_LCL_ADDR: sid %u, is_ip4 = %u,"
2679                 " addr = %U port %d", getpid (),
2680                 session_index, ep->is_ip4, format_ip46_address,
2681                 &session->transport.lcl_ip,
2682                 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
2683                 clib_net_to_host_u16 (ep->port));
2684         }
2685       else
2686         rv = VPPCOM_EINVAL;
2687       break;
2688
2689     case VPPCOM_ATTR_GET_LIBC_EPFD:
2690       rv = session->libc_epfd;
2691       VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d",
2692             getpid (), rv);
2693       break;
2694
2695     case VPPCOM_ATTR_SET_LIBC_EPFD:
2696       if (PREDICT_TRUE (buffer && buflen &&
2697                         (*buflen == sizeof (session->libc_epfd))))
2698         {
2699           session->libc_epfd = *(int *) buffer;
2700           *buflen = sizeof (session->libc_epfd);
2701
2702           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, "
2703                 "buflen %d", getpid (), session->libc_epfd, *buflen);
2704         }
2705       else
2706         rv = VPPCOM_EINVAL;
2707       break;
2708
2709     case VPPCOM_ATTR_GET_PROTOCOL:
2710       if (buffer && buflen && (*buflen >= sizeof (int)))
2711         {
2712           *(int *) buffer = session->session_type;
2713           *buflen = sizeof (int);
2714
2715           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_PROTOCOL: %d (%s), buflen %d",
2716                 getpid (), *(int *) buffer, *(int *) buffer ? "UDP" : "TCP",
2717                 *buflen);
2718         }
2719       else
2720         rv = VPPCOM_EINVAL;
2721       break;
2722
2723     case VPPCOM_ATTR_GET_LISTEN:
2724       if (buffer && buflen && (*buflen >= sizeof (int)))
2725         {
2726           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2727                                                 VCL_SESS_ATTR_LISTEN);
2728           *buflen = sizeof (int);
2729
2730           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_LISTEN: %d, buflen %d",
2731                 getpid (), *(int *) buffer, *buflen);
2732         }
2733       else
2734         rv = VPPCOM_EINVAL;
2735       break;
2736
2737     case VPPCOM_ATTR_GET_ERROR:
2738       if (buffer && buflen && (*buflen >= sizeof (int)))
2739         {
2740           *(int *) buffer = 0;
2741           *buflen = sizeof (int);
2742
2743           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_ERROR: %d, buflen %d, #VPP-TBD#",
2744                 getpid (), *(int *) buffer, *buflen);
2745         }
2746       else
2747         rv = VPPCOM_EINVAL;
2748       break;
2749
2750     case VPPCOM_ATTR_GET_TX_FIFO_LEN:
2751       if (buffer && buflen && (*buflen >= sizeof (u32)))
2752         {
2753
2754           /* VPP-TBD */
2755           *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
2756                                 session->tx_fifo ? session->tx_fifo->nitems :
2757                                 vcm->cfg.tx_fifo_size);
2758           *buflen = sizeof (u32);
2759
2760           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), "
2761                 "buflen %d, #VPP-TBD#", getpid (),
2762                 *(size_t *) buffer, *(size_t *) buffer, *buflen);
2763         }
2764       else
2765         rv = VPPCOM_EINVAL;
2766       break;
2767
2768     case VPPCOM_ATTR_SET_TX_FIFO_LEN:
2769       if (buffer && buflen && (*buflen == sizeof (u32)))
2770         {
2771           /* VPP-TBD */
2772           session->sndbuf_size = *(u32 *) buffer;
2773           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), "
2774                 "buflen %d, #VPP-TBD#", getpid (),
2775                 session->sndbuf_size, session->sndbuf_size, *buflen);
2776         }
2777       else
2778         rv = VPPCOM_EINVAL;
2779       break;
2780
2781     case VPPCOM_ATTR_GET_RX_FIFO_LEN:
2782       if (buffer && buflen && (*buflen >= sizeof (u32)))
2783         {
2784
2785           /* VPP-TBD */
2786           *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
2787                                 session->rx_fifo ? session->rx_fifo->nitems :
2788                                 vcm->cfg.rx_fifo_size);
2789           *buflen = sizeof (u32);
2790
2791           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), "
2792                 "buflen %d, #VPP-TBD#", getpid (),
2793                 *(size_t *) buffer, *(size_t *) buffer, *buflen);
2794         }
2795       else
2796         rv = VPPCOM_EINVAL;
2797       break;
2798
2799     case VPPCOM_ATTR_SET_RX_FIFO_LEN:
2800       if (buffer && buflen && (*buflen == sizeof (u32)))
2801         {
2802           /* VPP-TBD */
2803           session->rcvbuf_size = *(u32 *) buffer;
2804           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), "
2805                 "buflen %d, #VPP-TBD#", getpid (),
2806                 session->sndbuf_size, session->sndbuf_size, *buflen);
2807         }
2808       else
2809         rv = VPPCOM_EINVAL;
2810       break;
2811
2812     case VPPCOM_ATTR_GET_REUSEADDR:
2813       if (buffer && buflen && (*buflen >= sizeof (int)))
2814         {
2815           /* VPP-TBD */
2816           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2817                                                 VCL_SESS_ATTR_REUSEADDR);
2818           *buflen = sizeof (int);
2819
2820           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_REUSEADDR: %d, "
2821                 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2822         }
2823       else
2824         rv = VPPCOM_EINVAL;
2825       break;
2826
2827     case VPPCOM_ATTR_SET_REUSEADDR:
2828       if (buffer && buflen && (*buflen == sizeof (int)) &&
2829           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
2830         {
2831           /* VPP-TBD */
2832           if (*(int *) buffer)
2833             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEADDR);
2834           else
2835             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEADDR);
2836
2837           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_REUSEADDR: %d, buflen %d,"
2838                 " #VPP-TBD#", getpid (),
2839                 VCL_SESS_ATTR_TEST (session->attr,
2840                                     VCL_SESS_ATTR_REUSEADDR), *buflen);
2841         }
2842       else
2843         rv = VPPCOM_EINVAL;
2844       break;
2845
2846     case VPPCOM_ATTR_GET_REUSEPORT:
2847       if (buffer && buflen && (*buflen >= sizeof (int)))
2848         {
2849           /* VPP-TBD */
2850           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2851                                                 VCL_SESS_ATTR_REUSEPORT);
2852           *buflen = sizeof (int);
2853
2854           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_REUSEPORT: %d, buflen %d,"
2855                 " #VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2856         }
2857       else
2858         rv = VPPCOM_EINVAL;
2859       break;
2860
2861     case VPPCOM_ATTR_SET_REUSEPORT:
2862       if (buffer && buflen && (*buflen == sizeof (int)) &&
2863           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
2864         {
2865           /* VPP-TBD */
2866           if (*(int *) buffer)
2867             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEPORT);
2868           else
2869             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEPORT);
2870
2871           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_REUSEPORT: %d, buflen %d,"
2872                 " #VPP-TBD#", getpid (),
2873                 VCL_SESS_ATTR_TEST (session->attr,
2874                                     VCL_SESS_ATTR_REUSEPORT), *buflen);
2875         }
2876       else
2877         rv = VPPCOM_EINVAL;
2878       break;
2879
2880     case VPPCOM_ATTR_GET_BROADCAST:
2881       if (buffer && buflen && (*buflen >= sizeof (int)))
2882         {
2883           /* VPP-TBD */
2884           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2885                                                 VCL_SESS_ATTR_BROADCAST);
2886           *buflen = sizeof (int);
2887
2888           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_BROADCAST: %d, buflen %d,"
2889                 " #VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2890         }
2891       else
2892         rv = VPPCOM_EINVAL;
2893       break;
2894
2895     case VPPCOM_ATTR_SET_BROADCAST:
2896       if (buffer && buflen && (*buflen == sizeof (int)))
2897         {
2898           /* VPP-TBD */
2899           if (*(int *) buffer)
2900             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_BROADCAST);
2901           else
2902             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_BROADCAST);
2903
2904           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_BROADCAST: %d, buflen %d, "
2905                 "#VPP-TBD#", getpid (),
2906                 VCL_SESS_ATTR_TEST (session->attr,
2907                                     VCL_SESS_ATTR_BROADCAST), *buflen);
2908         }
2909       else
2910         rv = VPPCOM_EINVAL;
2911       break;
2912
2913     case VPPCOM_ATTR_GET_V6ONLY:
2914       if (buffer && buflen && (*buflen >= sizeof (int)))
2915         {
2916           /* VPP-TBD */
2917           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2918                                                 VCL_SESS_ATTR_V6ONLY);
2919           *buflen = sizeof (int);
2920
2921           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_V6ONLY: %d, buflen %d, "
2922                 "#VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2923         }
2924       else
2925         rv = VPPCOM_EINVAL;
2926       break;
2927
2928     case VPPCOM_ATTR_SET_V6ONLY:
2929       if (buffer && buflen && (*buflen == sizeof (int)))
2930         {
2931           /* VPP-TBD */
2932           if (*(int *) buffer)
2933             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_V6ONLY);
2934           else
2935             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_V6ONLY);
2936
2937           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_V6ONLY: %d, buflen %d, "
2938                 "#VPP-TBD#", getpid (),
2939                 VCL_SESS_ATTR_TEST (session->attr,
2940                                     VCL_SESS_ATTR_V6ONLY), *buflen);
2941         }
2942       else
2943         rv = VPPCOM_EINVAL;
2944       break;
2945
2946     case VPPCOM_ATTR_GET_KEEPALIVE:
2947       if (buffer && buflen && (*buflen >= sizeof (int)))
2948         {
2949           /* VPP-TBD */
2950           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2951                                                 VCL_SESS_ATTR_KEEPALIVE);
2952           *buflen = sizeof (int);
2953
2954           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_KEEPALIVE: %d, buflen %d, "
2955                 "#VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2956         }
2957       else
2958         rv = VPPCOM_EINVAL;
2959       break;
2960
2961     case VPPCOM_ATTR_SET_KEEPALIVE:
2962       if (buffer && buflen && (*buflen == sizeof (int)))
2963         {
2964           /* VPP-TBD */
2965           if (*(int *) buffer)
2966             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_KEEPALIVE);
2967           else
2968             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_KEEPALIVE);
2969
2970           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_KEEPALIVE: %d, buflen %d, "
2971                 "#VPP-TBD#", getpid (),
2972                 VCL_SESS_ATTR_TEST (session->attr,
2973                                     VCL_SESS_ATTR_KEEPALIVE), *buflen);
2974         }
2975       else
2976         rv = VPPCOM_EINVAL;
2977       break;
2978
2979     case VPPCOM_ATTR_GET_TCP_NODELAY:
2980       if (buffer && buflen && (*buflen >= sizeof (int)))
2981         {
2982           /* VPP-TBD */
2983           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
2984                                                 VCL_SESS_ATTR_TCP_NODELAY);
2985           *buflen = sizeof (int);
2986
2987           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_TCP_NODELAY: %d, buflen %d, "
2988                 "#VPP-TBD#", getpid (), *(int *) buffer, *buflen);
2989         }
2990       else
2991         rv = VPPCOM_EINVAL;
2992       break;
2993
2994     case VPPCOM_ATTR_SET_TCP_NODELAY:
2995       if (buffer && buflen && (*buflen == sizeof (int)))
2996         {
2997           /* VPP-TBD */
2998           if (*(int *) buffer)
2999             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3000           else
3001             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
3002
3003           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_TCP_NODELAY: %d, buflen %d, "
3004                 "#VPP-TBD#", getpid (),
3005                 VCL_SESS_ATTR_TEST (session->attr,
3006                                     VCL_SESS_ATTR_TCP_NODELAY), *buflen);
3007         }
3008       else
3009         rv = VPPCOM_EINVAL;
3010       break;
3011
3012     case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
3013       if (buffer && buflen && (*buflen >= sizeof (int)))
3014         {
3015           /* VPP-TBD */
3016           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3017                                                 VCL_SESS_ATTR_TCP_KEEPIDLE);
3018           *buflen = sizeof (int);
3019
3020           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, buflen %d, "
3021                 "#VPP-TBD#", getpid (), *(int *) buffer, *buflen);
3022         }
3023       else
3024         rv = VPPCOM_EINVAL;
3025       break;
3026
3027     case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
3028       if (buffer && buflen && (*buflen == sizeof (int)))
3029         {
3030           /* VPP-TBD */
3031           if (*(int *) buffer)
3032             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3033           else
3034             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
3035
3036           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, buflen %d, "
3037                 "#VPP-TBD#", getpid (),
3038                 VCL_SESS_ATTR_TEST (session->attr,
3039                                     VCL_SESS_ATTR_TCP_KEEPIDLE), *buflen);
3040         }
3041       else
3042         rv = VPPCOM_EINVAL;
3043       break;
3044
3045     case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
3046       if (buffer && buflen && (*buflen >= sizeof (int)))
3047         {
3048           /* VPP-TBD */
3049           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
3050                                                 VCL_SESS_ATTR_TCP_KEEPINTVL);
3051           *buflen = sizeof (int);
3052
3053           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, buflen %d, "
3054                 "#VPP-TBD#", getpid (), *(int *) buffer, *buflen);
3055         }
3056       else
3057         rv = VPPCOM_EINVAL;
3058       break;
3059
3060     case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
3061       if (buffer && buflen && (*buflen == sizeof (int)))
3062         {
3063           /* VPP-TBD */
3064           if (*(int *) buffer)
3065             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3066           else
3067             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
3068
3069           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, buflen %d, "
3070                 "#VPP-TBD#", getpid (),
3071                 VCL_SESS_ATTR_TEST (session->attr,
3072                                     VCL_SESS_ATTR_TCP_KEEPINTVL), *buflen);
3073         }
3074       else
3075         rv = VPPCOM_EINVAL;
3076       break;
3077
3078     case VPPCOM_ATTR_GET_TCP_USER_MSS:
3079       if (buffer && buflen && (*buflen >= sizeof (u32)))
3080         {
3081           /* VPP-TBD */
3082           *(u32 *) buffer = session->user_mss;
3083           *buflen = sizeof (int);
3084
3085           VDBG (2, "VCL<%d>: VPPCOM_ATTR_GET_TCP_USER_MSS: %d, buflen %d,"
3086                 " #VPP-TBD#", getpid (), *(int *) buffer, *buflen);
3087         }
3088       else
3089         rv = VPPCOM_EINVAL;
3090       break;
3091
3092     case VPPCOM_ATTR_SET_TCP_USER_MSS:
3093       if (buffer && buflen && (*buflen == sizeof (u32)))
3094         {
3095           /* VPP-TBD */
3096           session->user_mss = *(u32 *) buffer;
3097
3098           VDBG (2, "VCL<%d>: VPPCOM_ATTR_SET_TCP_USER_MSS: %u, buflen %d, "
3099                 "#VPP-TBD#", getpid (), session->user_mss, *buflen);
3100         }
3101       else
3102         rv = VPPCOM_EINVAL;
3103       break;
3104
3105     default:
3106       rv = VPPCOM_EINVAL;
3107       break;
3108     }
3109
3110 done:
3111   VCL_SESSION_UNLOCK ();
3112   return rv;
3113 }
3114
3115 int
3116 vppcom_session_recvfrom (uint32_t session_index, void *buffer,
3117                          uint32_t buflen, int flags, vppcom_endpt_t * ep)
3118 {
3119   int rv = VPPCOM_OK;
3120   vcl_session_t *session = 0;
3121
3122   if (ep)
3123     {
3124       VCL_SESSION_LOCK ();
3125       rv = vppcom_session_at_index (session_index, &session);
3126       if (PREDICT_FALSE (rv))
3127         {
3128           VCL_SESSION_UNLOCK ();
3129           VDBG (0, "VCL<%d>: invalid session, sid (%u) has been closed!",
3130                 getpid (), session_index);
3131           VCL_SESSION_UNLOCK ();
3132           return VPPCOM_EBADFD;
3133         }
3134       ep->is_ip4 = session->transport.is_ip4;
3135       ep->port = session->transport.rmt_port;
3136       VCL_SESSION_UNLOCK ();
3137     }
3138
3139   if (flags == 0)
3140     rv = vppcom_session_read (session_index, buffer, buflen);
3141   else if (flags & MSG_PEEK)
3142     rv = vppcom_session_peek (session_index, buffer, buflen);
3143   else
3144     {
3145       clib_warning ("VCL<%d>: Unsupport flags for recvfrom %d",
3146                     getpid (), flags);
3147       return VPPCOM_EAFNOSUPPORT;
3148     }
3149
3150   if (ep)
3151     {
3152       if (session->transport.is_ip4)
3153         clib_memcpy (ep->ip, &session->transport.rmt_ip.ip4,
3154                      sizeof (ip4_address_t));
3155       else
3156         clib_memcpy (ep->ip, &session->transport.rmt_ip.ip6,
3157                      sizeof (ip6_address_t));
3158     }
3159
3160   return rv;
3161 }
3162
3163 int
3164 vppcom_session_sendto (uint32_t session_index, void *buffer,
3165                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
3166 {
3167   if (!buffer)
3168     return VPPCOM_EINVAL;
3169
3170   if (ep)
3171     {
3172       // TBD
3173       return VPPCOM_EINVAL;
3174     }
3175
3176   if (flags)
3177     {
3178       // TBD check the flags and do the right thing
3179       VDBG (2, "VCL<%d>: handling flags 0x%u (%d) not implemented yet.",
3180             getpid (), flags, flags);
3181     }
3182
3183   return (vppcom_session_write (session_index, buffer, buflen));
3184 }
3185
3186 int
3187 vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
3188 {
3189   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
3190   u32 i, keep_trying = 1;
3191   int rv, num_ev = 0;
3192
3193   VDBG (3, "VCL<%d>: vp %p, nsids %u, wait_for_time %f",
3194         getpid (), vp, n_sids, wait_for_time);
3195
3196   if (!vp)
3197     return VPPCOM_EFAULT;
3198
3199   do
3200     {
3201       vcl_session_t *session;
3202
3203       for (i = 0; i < n_sids; i++)
3204         {
3205           ASSERT (vp[i].revents);
3206
3207           VCL_SESSION_LOCK_AND_GET (vp[i].sid, &session);
3208           VCL_SESSION_UNLOCK ();
3209
3210           if (*vp[i].revents)
3211             *vp[i].revents = 0;
3212
3213           if (POLLIN & vp[i].events)
3214             {
3215               VCL_SESSION_LOCK_AND_GET (vp[i].sid, &session);
3216               rv = vppcom_session_read_ready (session);
3217               VCL_SESSION_UNLOCK ();
3218               if (rv > 0)
3219                 {
3220                   *vp[i].revents |= POLLIN;
3221                   num_ev++;
3222                 }
3223               else if (rv < 0)
3224                 {
3225                   switch (rv)
3226                     {
3227                     case VPPCOM_ECONNRESET:
3228                       *vp[i].revents = POLLHUP;
3229                       break;
3230
3231                     default:
3232                       *vp[i].revents = POLLERR;
3233                       break;
3234                     }
3235                   num_ev++;
3236                 }
3237             }
3238
3239           if (POLLOUT & vp[i].events)
3240             {
3241               VCL_SESSION_LOCK_AND_GET (vp[i].sid, &session);
3242               rv = vppcom_session_write_ready (session, vp[i].sid);
3243               VCL_SESSION_UNLOCK ();
3244               if (rv > 0)
3245                 {
3246                   *vp[i].revents |= POLLOUT;
3247                   num_ev++;
3248                 }
3249               else if (rv < 0)
3250                 {
3251                   switch (rv)
3252                     {
3253                     case VPPCOM_ECONNRESET:
3254                       *vp[i].revents = POLLHUP;
3255                       break;
3256
3257                     default:
3258                       *vp[i].revents = POLLERR;
3259                       break;
3260                     }
3261                   num_ev++;
3262                 }
3263             }
3264
3265           if (0)                // Note "done:" label used by VCL_SESSION_LOCK_AND_GET()
3266             {
3267             done:
3268               *vp[i].revents = POLLNVAL;
3269               num_ev++;
3270             }
3271         }
3272       if (wait_for_time != -1)
3273         keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
3274     }
3275   while ((num_ev == 0) && keep_trying);
3276
3277   if (VPPCOM_DEBUG > 3)
3278     {
3279       clib_warning ("VCL<%d>: returning %d", getpid (), num_ev);
3280       for (i = 0; i < n_sids; i++)
3281         {
3282           clib_warning ("VCL<%d>: vp[%d].sid %d (0x%x), .events 0x%x, "
3283                         ".revents 0x%x", getpid (), i, vp[i].sid, vp[i].sid,
3284                         vp[i].events, *vp[i].revents);
3285         }
3286     }
3287   return num_ev;
3288 }
3289
3290 int
3291 vppcom_mq_epoll_fd (void)
3292 {
3293   return vcm->mqs_epfd;
3294 }
3295
3296 /*
3297  * fd.io coding-style-patch-verification: ON
3298  *
3299  * Local Variables:
3300  * eval: (c-set-style "gnu")
3301  * End:
3302  */