VCL registration handler added to session for polling sessions
[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 <signal.h>
19 #include <svm/svm_fifo_segment.h>
20 #include <vlibmemory/api.h>
21 #include <vpp/api/vpe_msg_enum.h>
22 #include <vnet/session/application_interface.h>
23 #include <vcl/vppcom.h>
24 #include <vcl/vcl_event.h>
25 #include <vlib/unix/unix.h>
26 #include <vppinfra/vec_bootstrap.h>
27 #include <vppinfra/elog.h>
28
29 #define vl_typedefs             /* define message structures */
30 #include <vpp/api/vpe_all_api_h.h>
31 #undef vl_typedefs
32
33 /* declare message handlers for each api */
34
35 #define vl_endianfun            /* define message structures */
36 #include <vpp/api/vpe_all_api_h.h>
37 #undef vl_endianfun
38
39 /* instantiate all the print functions we know about */
40 #define vl_print(handle, ...)
41 #define vl_printfun
42 #include <vpp/api/vpe_all_api_h.h>
43 #undef vl_printfun
44
45 #if (CLIB_DEBUG > 0)
46 /* Set VPPCOM_DEBUG_INIT 2 for connection debug,
47  *                       3 for read/write debug output
48  * or
49  *    export VCL_DEBUG=<#> to set dynamically.
50  */
51 #define VPPCOM_DEBUG_INIT 1
52 #else
53 #define VPPCOM_DEBUG_INIT 0
54 #endif
55
56 #define VPPCOM_DEBUG vcm->debug
57
58 /*
59  * VPPCOM Private definitions and functions.
60  */
61 typedef enum
62 {
63   STATE_APP_START,
64   STATE_APP_CONN_VPP,
65   STATE_APP_ENABLED,
66   STATE_APP_ATTACHED,
67 } app_state_t;
68
69 typedef enum
70 {
71   STATE_START = 0x01,
72   STATE_CONNECT = 0x02,
73   STATE_LISTEN = 0x04,
74   STATE_ACCEPT = 0x08,
75   STATE_CLOSE_ON_EMPTY = 0x10,
76   STATE_DISCONNECT = 0x20,
77   STATE_FAILED = 0x40
78 } session_state_t;
79
80 #define SERVER_STATE_OPEN  (STATE_ACCEPT|STATE_CLOSE_ON_EMPTY)
81 #define CLIENT_STATE_OPEN  (STATE_CONNECT|STATE_CLOSE_ON_EMPTY)
82
83 typedef struct epoll_event vppcom_epoll_event_t;
84
85 typedef struct
86 {
87   u32 next_sid;
88   u32 prev_sid;
89   u32 vep_idx;
90   vppcom_epoll_event_t ev;
91 #define VEP_DEFAULT_ET_MASK  (EPOLLIN|EPOLLOUT)
92 #define VEP_UNSUPPORTED_EVENTS (EPOLLONESHOT|EPOLLEXCLUSIVE)
93   u32 et_mask;
94 } vppcom_epoll_t;
95
96 typedef struct
97 {
98   u8 is_ip4;
99   ip46_address_t ip46;
100 } vppcom_ip46_t;
101
102 enum
103 {
104   VCL_SESS_ATTR_SERVER,
105   VCL_SESS_ATTR_CUT_THRU,
106   VCL_SESS_ATTR_VEP,
107   VCL_SESS_ATTR_VEP_SESSION,
108   VCL_SESS_ATTR_LISTEN,         // SOL_SOCKET,SO_ACCEPTCONN
109   VCL_SESS_ATTR_NONBLOCK,       // fcntl,O_NONBLOCK
110   VCL_SESS_ATTR_REUSEADDR,      // SOL_SOCKET,SO_REUSEADDR
111   VCL_SESS_ATTR_REUSEPORT,      // SOL_SOCKET,SO_REUSEPORT
112   VCL_SESS_ATTR_BROADCAST,      // SOL_SOCKET,SO_BROADCAST
113   VCL_SESS_ATTR_V6ONLY,         // SOL_TCP,IPV6_V6ONLY
114   VCL_SESS_ATTR_KEEPALIVE,      // SOL_SOCKET,SO_KEEPALIVE
115   VCL_SESS_ATTR_TCP_NODELAY,    // SOL_TCP,TCP_NODELAY
116   VCL_SESS_ATTR_TCP_KEEPIDLE,   // SOL_TCP,TCP_KEEPIDLE
117   VCL_SESS_ATTR_TCP_KEEPINTVL,  // SOL_TCP,TCP_KEEPINTVL
118   VCL_SESS_ATTR_MAX
119 } vppcom_session_attr_t;
120
121 #define VCL_SESS_ATTR_SET(ATTR, VAL)            \
122 do {                                            \
123   (ATTR) |= 1 << (VAL);                         \
124  } while (0)
125
126 #define VCL_SESS_ATTR_CLR(ATTR, VAL)            \
127 do {                                            \
128   (ATTR) &= ~(1 << (VAL));                      \
129  } while (0)
130
131 #define VCL_SESS_ATTR_TEST(ATTR, VAL)           \
132   ((ATTR) & (1 << (VAL)) ? 1 : 0)
133
134 typedef struct
135 {
136   volatile session_state_t state;
137
138   svm_fifo_t *rx_fifo;
139   svm_fifo_t *tx_fifo;
140   u32 sndbuf_size;              // VPP-TBD: Hack until support setsockopt(SO_SNDBUF)
141   u32 rcvbuf_size;              // VPP-TBD: Hack until support setsockopt(SO_RCVBUF)
142   u32 user_mss;                 // VPP-TBD: Hack until support setsockopt(TCP_MAXSEG)
143   u8 *segment_name;
144   u32 sm_seg_index;
145   u32 client_context;
146   u64 vpp_handle;
147   svm_queue_t *vpp_event_queue;
148
149   /* Socket configuration state */
150   u8 is_vep;
151   u8 is_vep_session;
152   u32 attr;
153   u32 wait_cont_idx;
154   vppcom_epoll_t vep;
155   int libc_epfd;
156   vppcom_ip46_t lcl_addr;
157   vppcom_ip46_t peer_addr;
158   u16 lcl_port;                 // network order
159   u16 peer_port;                // network order
160   u8 proto;
161   u64 client_queue_address;
162   u64 options[16];
163   elog_track_t elog_track;
164   vce_event_handler_reg_t *poll_reg;
165 } session_t;
166
167 typedef struct vppcom_cfg_t_
168 {
169   u64 heapsize;
170   u32 vpp_api_q_length;
171   u64 segment_baseva;
172   u32 segment_size;
173   u32 add_segment_size;
174   u32 preallocated_fifo_pairs;
175   u32 rx_fifo_size;
176   u32 tx_fifo_size;
177   u32 event_queue_size;
178   u32 listen_queue_size;
179   u8 app_proxy_transport_tcp;
180   u8 app_proxy_transport_udp;
181   u8 app_scope_local;
182   u8 app_scope_global;
183   u8 *namespace_id;
184   u64 namespace_secret;
185   f64 app_timeout;
186   f64 session_timeout;
187   f64 accept_timeout;
188   u32 event_ring_size;
189   char *event_log_path;
190   u8 *vpp_api_filename;
191 } vppcom_cfg_t;
192
193 /* VPPCOM Event typedefs */
194 typedef enum vcl_event_id_
195 {
196   VCL_EVENT_CONNECT_REQ_ACCEPTED,
197   VCL_EVENT_N_EVENTS
198 } vcl_event_id_t;
199
200 typedef struct vce_event_connect_request_
201 {
202   u8 size;
203   u8 handled;
204   u32 accepted_session_index;
205 } vce_event_connect_request_t;
206
207 typedef struct vppcom_main_t_
208 {
209   u8 init;
210   u32 debug;
211   u32 *client_session_index_fifo;
212   int main_cpu;
213
214   /* vpp input queue */
215   svm_queue_t *vl_input_queue;
216
217   /* API client handle */
218   u32 my_client_index;
219
220   /* Session pool */
221   clib_spinlock_t sessions_lockp;
222   session_t *sessions;
223
224   /* Hash table for disconnect processing */
225   uword *session_index_by_vpp_handles;
226
227   /* Select bitmaps */
228   clib_bitmap_t *rd_bitmap;
229   clib_bitmap_t *wr_bitmap;
230   clib_bitmap_t *ex_bitmap;
231
232   /* Our event queue */
233   svm_queue_t *app_event_queue;
234
235   /* unique segment name counter */
236   u32 unique_segment_index;
237
238   /* For deadman timers */
239   clib_time_t clib_time;
240
241   /* State of the connection, shared between msg RX thread and main thread */
242   volatile app_state_t app_state;
243
244   vppcom_cfg_t cfg;
245
246   /* Event thread */
247   vce_event_thread_t event_thread;
248
249   /* VPP Event-logger */
250   elog_main_t elog_main;
251   elog_track_t elog_track;
252
253   /* VNET_API_ERROR_FOO -> "Foo" hash table */
254   uword *error_string_by_error_number;
255 } vppcom_main_t;
256
257 /* NOTE: _vppcom_main is only used until the heap is allocated.
258  *       Do not access it directly -- use vcm which will point to
259  *       the heap allocated copy after init.
260  */
261 static vppcom_main_t _vppcom_main = {
262   .debug = VPPCOM_DEBUG_INIT,
263   .my_client_index = ~0
264 };
265
266 static vppcom_main_t *vcm = &_vppcom_main;
267
268 #define VCL_LOCK_AND_GET_SESSION(I, S)                          \
269 do {                                                            \
270   clib_spinlock_lock (&vcm->sessions_lockp);                    \
271   rv = vppcom_session_at_index (I, S);                          \
272   if (PREDICT_FALSE (rv))                                       \
273     {                                                           \
274       clib_spinlock_unlock (&vcm->sessions_lockp);              \
275       clib_warning ("VCL<%d>: ERROR: Invalid ##I (%u)!",        \
276                     getpid (), I);                              \
277       goto done;                                                \
278     }                                                           \
279 } while (0)
280
281 static const char *
282 vppcom_app_state_str (app_state_t state)
283 {
284   char *st;
285
286   switch (state)
287     {
288     case STATE_APP_START:
289       st = "STATE_APP_START";
290       break;
291
292     case STATE_APP_CONN_VPP:
293       st = "STATE_APP_CONN_VPP";
294       break;
295
296     case STATE_APP_ENABLED:
297       st = "STATE_APP_ENABLED";
298       break;
299
300     case STATE_APP_ATTACHED:
301       st = "STATE_APP_ATTACHED";
302       break;
303
304     default:
305       st = "UNKNOWN_APP_STATE";
306       break;
307     }
308
309   return st;
310 }
311
312 static const char *
313 vppcom_session_state_str (session_state_t state)
314 {
315   char *st;
316
317   switch (state)
318     {
319     case STATE_START:
320       st = "STATE_START";
321       break;
322
323     case STATE_CONNECT:
324       st = "STATE_CONNECT";
325       break;
326
327     case STATE_LISTEN:
328       st = "STATE_LISTEN";
329       break;
330
331     case STATE_ACCEPT:
332       st = "STATE_ACCEPT";
333       break;
334
335     case STATE_CLOSE_ON_EMPTY:
336       st = "STATE_CLOSE_ON_EMPTY";
337       break;
338
339     case STATE_DISCONNECT:
340       st = "STATE_DISCONNECT";
341       break;
342
343     case STATE_FAILED:
344       st = "STATE_FAILED";
345       break;
346
347     default:
348       st = "UNKNOWN_STATE";
349       break;
350     }
351
352   return st;
353 }
354
355
356 /*
357  * VPPCOM Utility Functions
358  */
359 static inline int
360 vppcom_session_at_index (u32 session_index, session_t * volatile *sess)
361 {
362   /* Assumes that caller has acquired spinlock: vcm->sessions_lockp */
363   if (PREDICT_FALSE ((session_index == ~0) ||
364                      pool_is_free_index (vcm->sessions, session_index)))
365     {
366       clib_warning ("VCL<%d>: invalid session, sid (%u) has been closed!",
367                     getpid (), session_index);
368       return VPPCOM_EBADFD;
369     }
370   *sess = pool_elt_at_index (vcm->sessions, session_index);
371   return VPPCOM_OK;
372 }
373
374 static inline void
375 vppcom_session_table_add_listener (u64 listener_handle, u32 value)
376 {
377   /* Session and listener handles have different formats. The latter has
378    * the thread index in the upper 32 bits while the former has the session
379    * type. Knowing that, for listeners we just flip the MSB to 1 */
380   listener_handle |= 1ULL << 63;
381   hash_set (vcm->session_index_by_vpp_handles, listener_handle, value);
382 }
383
384 static inline session_t *
385 vppcom_session_table_lookup_listener (u64 listener_handle)
386 {
387   uword *p;
388   u64 handle = listener_handle | (1ULL << 63);
389   session_t *session;
390
391   p = hash_get (vcm->session_index_by_vpp_handles, handle);
392   if (!p)
393     {
394       clib_warning ("VCL<%d>: couldn't find listen session: unknown vpp "
395                     "listener handle %llx", getpid (), listener_handle);
396       return 0;
397     }
398   if (pool_is_free_index (vcm->sessions, p[0]))
399     {
400       if (VPPCOM_DEBUG > 1)
401         clib_warning ("VCL<%d>: invalid listen session, sid (%u)",
402                       getpid (), p[0]);
403       return 0;
404     }
405
406   session = pool_elt_at_index (vcm->sessions, p[0]);
407   ASSERT (session->state & STATE_LISTEN);
408   return session;
409 }
410
411 static inline void
412 vppcom_session_table_del_listener (u64 listener_handle)
413 {
414   listener_handle |= 1ULL << 63;
415   hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
416 }
417
418 static void
419 write_elog (void)
420 {
421   elog_main_t *em = &vcm->elog_main;
422   char *chroot_file;
423   clib_error_t *error = 0;
424
425   chroot_file =
426     (char *) format (0, "%s/%d-%d-vcl-elog%c", vcm->cfg.event_log_path,
427                      vcm->my_client_index, getpid (), 0);
428   error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
429   if (error)
430     {
431       clib_error_report (error);
432     }
433   if (VPPCOM_DEBUG > 0)
434     clib_warning ("[%d] Event Log:'%s' ", getpid (), chroot_file);
435
436 }
437
438 /*
439  * VPPCOM Event Functions
440  */
441
442 /**
443  *  * @brief vce_connect_request_handler_fn
444  * - used for listener sessions
445  * - when a vl_api_accept_session_t_handler() generates an event
446  *   this callback is alerted and sets fields that consumers such as
447  *   vppcom_session_accept() expect to see, ie. accepted_client_index
448  *
449  * @param arg - void* to be cast to vce_event_handler_reg_t*
450  */
451 void
452 vce_connect_request_handler_fn (void *arg)
453 {
454   vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
455
456   vce_event_connect_request_t *ecr;
457   vce_event_t *ev;
458
459   ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
460
461   ecr = (vce_event_connect_request_t *) ev->data;
462
463   pthread_mutex_lock (&reg->handler_lock);
464   ecr->handled = 1;
465   pthread_cond_signal (&reg->handler_cond);
466   pthread_mutex_unlock (&reg->handler_lock);
467 }
468
469 /**
470  * @brief vce_epoll_wait_connect_request_handler_fn
471  * - used by vppcom_epoll_xxxx() for listener sessions
472  * - when a vl_api_accept_session_t_handler() generates an event
473  *   this callback is alerted and sets the fields that vppcom_epoll_wait()
474  *   expects to see.
475  *
476  * @param arg - void* to be cast to vce_event_handler_reg_t*
477  */
478 void
479 vce_epoll_wait_connect_request_handler_fn (void *arg)
480 {
481   vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
482   vce_event_t *ev;
483   /* Retrieve the VCL_EVENT_CONNECT_REQ_ACCEPTED event */
484   ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
485   vce_event_connect_request_t *ecr = (vce_event_connect_request_t *) ev->data;
486
487   /* Add the accepted_session_index to the FIFO */
488   clib_spinlock_lock (&vcm->sessions_lockp);
489   clib_fifo_add1 (vcm->client_session_index_fifo,
490                   ecr->accepted_session_index);
491   clib_spinlock_unlock (&vcm->sessions_lockp);
492
493   /* Recycling the event. */
494   clib_spinlock_lock (&(vcm->event_thread.events_lockp));
495   vcm->event_thread.recycle_event = 1;
496   clib_fifo_add1 (vcm->event_thread.event_index_fifo, reg->ev_idx);
497   clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
498 }
499
500 static int
501 vppcom_connect_to_vpp (char *app_name)
502 {
503   api_main_t *am = &api_main;
504   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
505   int rv = VPPCOM_OK;
506
507   if (!vcl_cfg->vpp_api_filename)
508     vcl_cfg->vpp_api_filename = format (0, "/vpe-api%c", 0);
509
510   if (VPPCOM_DEBUG > 0)
511     clib_warning ("VCL<%d>: app (%s) connecting to VPP api (%s)...",
512                   getpid (), app_name, vcl_cfg->vpp_api_filename);
513
514   if (vl_client_connect_to_vlib ((char *) vcl_cfg->vpp_api_filename, app_name,
515                                  vcm->cfg.vpp_api_q_length) < 0)
516     {
517       clib_warning ("VCL<%d>: app (%s) connect failed!", getpid (), app_name);
518       rv = VPPCOM_ECONNREFUSED;
519     }
520   else
521     {
522       vcm->vl_input_queue = am->shmem_hdr->vl_input_queue;
523       vcm->my_client_index = (u32) am->my_client_index;
524       vcm->app_state = STATE_APP_CONN_VPP;
525
526       if (VPPCOM_DEBUG > 0)
527         clib_warning ("VCL<%d>: app (%s) is connected to VPP!",
528                       getpid (), app_name);
529     }
530
531   if (VPPCOM_DEBUG > 0)
532     {
533       vcm->elog_main.lock =
534         clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
535       vcm->elog_main.lock[0] = 0;
536       vcm->elog_main.event_ring_size = vcm->cfg.event_ring_size;
537       elog_init (&vcm->elog_main, vcm->elog_main.event_ring_size);
538       elog_enable_disable (&vcm->elog_main, 1);
539
540       vcm->elog_track.name =
541         (char *) format (0, "P:%d:C:%d%c", getpid (),
542                          vcm->my_client_index, 0);
543       elog_track_register (&vcm->elog_main, &vcm->elog_track);
544
545       /* *INDENT-OFF* */
546       ELOG_TYPE_DECLARE (e) =
547       {
548         .format = "connect_vpp:rv:%d",
549         .format_args = "i4",
550       };
551       struct
552       {
553         u32 data;
554       } *ed;
555       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
556       ed->data = (u32) rv;
557       /* *INDENT-ON* */
558     }
559   return rv;
560 }
561
562 static u8 *
563 format_api_error (u8 * s, va_list * args)
564 {
565   i32 error = va_arg (*args, u32);
566   uword *p;
567
568   p = hash_get (vcm->error_string_by_error_number, -error);
569
570   if (p)
571     s = format (s, "%s (%d)", p[0], error);
572   else
573     s = format (s, "%d", error);
574   return s;
575 }
576
577 static void
578 vppcom_init_error_string_table (void)
579 {
580   vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
581
582 #define _(n, v, s) hash_set (vcm->error_string_by_error_number, -v, s);
583   foreach_vnet_api_error;
584 #undef _
585
586   hash_set (vcm->error_string_by_error_number, 99, "Misc");
587 }
588
589 static inline int
590 vppcom_wait_for_app_state_change (app_state_t app_state)
591 {
592   f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout;
593
594   while (clib_time_now (&vcm->clib_time) < timeout)
595     {
596       if (vcm->app_state == app_state)
597         return VPPCOM_OK;
598     }
599   if (VPPCOM_DEBUG > 0)
600     clib_warning ("VCL<%d>: timeout waiting for state %s (%d)", getpid (),
601                   vppcom_app_state_str (app_state), app_state);
602
603   if (VPPCOM_DEBUG > 0)
604     {
605       /* *INDENT-OFF* */
606       ELOG_TYPE_DECLARE (e) =
607         {
608           .format = "ERR: timeout state:%d",
609           .format_args = "i4",
610         };
611       struct
612       {
613         u32 data;
614       } *ed;
615
616       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
617
618       ed->data = app_state;
619       /* *INDENT-ON* */
620     }
621
622   return VPPCOM_ETIMEDOUT;
623 }
624
625 static inline int
626 vppcom_wait_for_session_state_change (u32 session_index,
627                                       session_state_t state,
628                                       f64 wait_for_time)
629 {
630   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
631   session_t *volatile session;
632   int rv;
633
634   do
635     {
636       clib_spinlock_lock (&vcm->sessions_lockp);
637       rv = vppcom_session_at_index (session_index, &session);
638       if (PREDICT_FALSE (rv))
639         {
640           clib_spinlock_unlock (&vcm->sessions_lockp);
641           return rv;
642         }
643       if (session->state & state)
644         {
645           clib_spinlock_unlock (&vcm->sessions_lockp);
646           return VPPCOM_OK;
647         }
648       if (session->state & STATE_FAILED)
649         {
650           clib_spinlock_unlock (&vcm->sessions_lockp);
651           return VPPCOM_ECONNREFUSED;
652         }
653
654       clib_spinlock_unlock (&vcm->sessions_lockp);
655     }
656   while (clib_time_now (&vcm->clib_time) < timeout);
657
658   if (VPPCOM_DEBUG > 0)
659     clib_warning ("VCL<%d>: timeout waiting for state 0x%x (%s)", getpid (),
660                   state, vppcom_session_state_str (state));
661
662   if (VPPCOM_DEBUG > 0)
663     {
664       /* *INDENT-OFF* */
665       ELOG_TYPE_DECLARE (e) =
666         {
667           .format = "ERR: timeout state:%d",
668           .format_args = "i4",
669         };
670       struct
671       {
672         u32 data;
673       } *ed;
674
675       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
676
677       ed->data = state;
678       /* *INDENT-ON* */
679     }
680
681   return VPPCOM_ETIMEDOUT;
682 }
683
684 /*
685  * VPP-API message functions
686  */
687 static void
688 vppcom_send_session_enable_disable (u8 is_enable)
689 {
690   vl_api_session_enable_disable_t *bmp;
691   bmp = vl_msg_api_alloc (sizeof (*bmp));
692   memset (bmp, 0, sizeof (*bmp));
693
694   bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
695   bmp->client_index = vcm->my_client_index;
696   bmp->context = htonl (0xfeedface);
697   bmp->is_enable = is_enable;
698   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
699 }
700
701 static int
702 vppcom_app_session_enable (void)
703 {
704   int rv;
705
706   if (vcm->app_state != STATE_APP_ENABLED)
707     {
708       vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
709       rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
710       if (PREDICT_FALSE (rv))
711         {
712           if (VPPCOM_DEBUG > 0)
713             clib_warning ("VCL<%d>: application session enable timed out! "
714                           "returning %d (%s)",
715                           getpid (), rv, vppcom_retval_str (rv));
716           return rv;
717         }
718     }
719   return VPPCOM_OK;
720 }
721
722 static void
723   vl_api_session_enable_disable_reply_t_handler
724   (vl_api_session_enable_disable_reply_t * mp)
725 {
726   if (mp->retval)
727     {
728       clib_warning ("VCL<%d>: session_enable_disable failed: %U", getpid (),
729                     format_api_error, ntohl (mp->retval));
730     }
731   else
732     vcm->app_state = STATE_APP_ENABLED;
733 }
734
735 static void
736 vppcom_app_send_attach (void)
737 {
738   vl_api_application_attach_t *bmp;
739   u8 nsid_len = vec_len (vcm->cfg.namespace_id);
740   u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
741                      vcm->cfg.app_proxy_transport_udp);
742
743   bmp = vl_msg_api_alloc (sizeof (*bmp));
744   memset (bmp, 0, sizeof (*bmp));
745
746   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
747   bmp->client_index = vcm->my_client_index;
748   bmp->context = htonl (0xfeedface);
749   bmp->options[APP_OPTIONS_FLAGS] =
750     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
751     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
752     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
753     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0);
754   bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
755     (vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
756     (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0);
757   bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
758   bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
759   bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
760   bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
761   bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
762     vcm->cfg.preallocated_fifo_pairs;
763   bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
764   if (nsid_len)
765     {
766       bmp->namespace_id_len = nsid_len;
767       clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
768       bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
769     }
770   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
771 }
772
773 static int
774 vppcom_app_attach (void)
775 {
776   int rv;
777
778   vppcom_app_send_attach ();
779   rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED);
780   if (PREDICT_FALSE (rv))
781     {
782       if (VPPCOM_DEBUG > 0)
783         clib_warning ("VCL<%d>: application attach timed out! "
784                       "returning %d (%s)",
785                       getpid (), rv, vppcom_retval_str (rv));
786       return rv;
787     }
788
789   return VPPCOM_OK;
790 }
791
792 static void
793 vppcom_app_detach (void)
794 {
795   vl_api_application_detach_t *bmp;
796   bmp = vl_msg_api_alloc (sizeof (*bmp));
797   memset (bmp, 0, sizeof (*bmp));
798
799   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
800   bmp->client_index = vcm->my_client_index;
801   bmp->context = htonl (0xfeedface);
802   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
803 }
804
805 static void
806 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
807                                            mp)
808 {
809   static svm_fifo_segment_create_args_t _a;
810   svm_fifo_segment_create_args_t *a = &_a;
811   int rv;
812
813   memset (a, 0, sizeof (*a));
814   if (mp->retval)
815     {
816       clib_warning ("VCL<%d>: attach failed: %U", getpid (),
817                     format_api_error, ntohl (mp->retval));
818       return;
819     }
820
821   if (mp->segment_name_length == 0)
822     {
823       clib_warning ("VCL<%d>: segment_name_length zero", getpid ());
824       return;
825     }
826
827   a->segment_name = (char *) mp->segment_name;
828   a->segment_size = mp->segment_size;
829
830   ASSERT (mp->app_event_queue_address);
831
832   /* Attach to the segment vpp created */
833   rv = svm_fifo_segment_attach (a);
834   vec_reset_length (a->new_segment_indices);
835   if (PREDICT_FALSE (rv))
836     {
837       clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
838                     getpid (), mp->segment_name);
839       return;
840     }
841
842   vcm->app_event_queue =
843     uword_to_pointer (mp->app_event_queue_address, svm_queue_t *);
844
845   vcm->app_state = STATE_APP_ATTACHED;
846 }
847
848 static void
849 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
850                                            mp)
851 {
852   if (mp->retval)
853     clib_warning ("VCL<%d>: detach failed: %U", getpid (), format_api_error,
854                   ntohl (mp->retval));
855
856   vcm->app_state = STATE_APP_ENABLED;
857 }
858
859 static void
860 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
861                                            mp)
862 {
863   if (mp->retval)
864     clib_warning ("VCL<%d>: vpp handle 0x%llx: disconnect session failed: %U",
865                   getpid (), mp->handle, format_api_error,
866                   ntohl (mp->retval));
867 }
868
869 static void
870 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
871 {
872   static svm_fifo_segment_create_args_t _a;
873   svm_fifo_segment_create_args_t *a = &_a;
874   int rv;
875
876   memset (a, 0, sizeof (*a));
877   a->segment_name = (char *) mp->segment_name;
878   a->segment_size = mp->segment_size;
879   /* Attach to the segment vpp created */
880   rv = svm_fifo_segment_attach (a);
881   vec_reset_length (a->new_segment_indices);
882   if (PREDICT_FALSE (rv))
883     {
884       clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
885                     getpid (), mp->segment_name);
886       return;
887     }
888   if (VPPCOM_DEBUG > 1)
889     clib_warning ("VCL<%d>: mapped new segment '%s' size %d", getpid (),
890                   mp->segment_name, mp->segment_size);
891 }
892
893 static void
894 vl_api_unmap_segment_t_handler (vl_api_unmap_segment_t * mp)
895 {
896
897 /*
898  * XXX Need segment_name to session_id hash,
899  * XXX - have sessionID by handle hash currently
900  */
901   if (VPPCOM_DEBUG > 1)
902     clib_warning ("Unmapped segment '%s'", mp->segment_name);
903 }
904
905 static void
906 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
907 {
908   uword *p;
909
910   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
911   if (p)
912     {
913       int rv;
914       session_t *session = 0;
915       u32 session_index = p[0];
916
917       VCL_LOCK_AND_GET_SESSION (session_index, &session);
918       session->state = STATE_CLOSE_ON_EMPTY;
919
920       if (VPPCOM_DEBUG > 1)
921         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
922                       "setting state to 0x%x (%s)",
923                       getpid (), mp->handle, session_index, session->state,
924                       vppcom_session_state_str (session->state));
925       clib_spinlock_unlock (&vcm->sessions_lockp);
926       return;
927
928     done:
929       if (VPPCOM_DEBUG > 1)
930         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
931                       "session lookup failed!",
932                       getpid (), mp->handle, session_index);
933     }
934   else
935     clib_warning ("VCL<%d>: vpp handle 0x%llx: session lookup by "
936                   "handle failed!", getpid (), mp->handle);
937 }
938
939 static void
940 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
941 {
942   session_t *session = 0;
943   vl_api_reset_session_reply_t *rmp;
944   uword *p;
945   int rv = 0;
946
947   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
948   if (p)
949     {
950       int rval;
951       clib_spinlock_lock (&vcm->sessions_lockp);
952       rval = vppcom_session_at_index (p[0], &session);
953       if (PREDICT_FALSE (rval))
954         {
955           rv = VNET_API_ERROR_INVALID_VALUE_2;
956           clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
957                         "session lookup failed! returning %d %U",
958                         getpid (), mp->handle, p[0],
959                         rv, format_api_error, rv);
960         }
961       else
962         {
963           /* TBD: should this disconnect immediately and
964            * flush the fifos?
965            */
966           session->state = STATE_CLOSE_ON_EMPTY;
967
968           if (VPPCOM_DEBUG > 1)
969             clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
970                           "state set to %d (%s)!", getpid (),
971                           mp->handle, p[0], session->state,
972                           vppcom_session_state_str (session->state));
973         }
974       clib_spinlock_unlock (&vcm->sessions_lockp);
975     }
976   else
977     {
978       rv = VNET_API_ERROR_INVALID_VALUE;
979       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx: session lookup "
980                     "failed! returning %d %U",
981                     getpid (), mp->handle, rv, format_api_error, rv);
982     }
983
984   rmp = vl_msg_api_alloc (sizeof (*rmp));
985   memset (rmp, 0, sizeof (*rmp));
986   rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
987   rmp->retval = htonl (rv);
988   rmp->handle = mp->handle;
989   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
990 }
991
992 static void
993 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
994 {
995   session_t *session = 0;
996   u32 session_index;
997   svm_fifo_t *rx_fifo, *tx_fifo;
998   int rv = VPPCOM_OK;
999
1000   session_index = mp->context;
1001   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1002 done:
1003   if (mp->retval)
1004     {
1005       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1006                     "connect failed! %U",
1007                     getpid (), mp->handle, session_index,
1008                     format_api_error, ntohl (mp->retval));
1009       if (session)
1010         {
1011           session->state = STATE_FAILED;
1012           session->vpp_handle = mp->handle;
1013         }
1014       else
1015         {
1016           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
1017                         "Invalid session index (%u)!",
1018                         getpid (), mp->handle, session_index);
1019         }
1020       goto done_unlock;
1021     }
1022
1023   if (rv)
1024     goto done_unlock;
1025
1026   /*
1027    * Setup session
1028    */
1029   session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1030                                                svm_queue_t *);
1031
1032   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1033   rx_fifo->client_session_index = session_index;
1034   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1035   tx_fifo->client_session_index = session_index;
1036
1037   session->rx_fifo = rx_fifo;
1038   session->tx_fifo = tx_fifo;
1039   session->vpp_handle = mp->handle;
1040   session->lcl_addr.is_ip4 = mp->is_ip4;
1041   clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
1042                sizeof (session->peer_addr.ip46));
1043   session->lcl_port = mp->lcl_port;
1044   session->state = STATE_CONNECT;
1045
1046   /* Add it to lookup table */
1047   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1048
1049   if (VPPCOM_DEBUG > 1)
1050     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded!"
1051                   " session_rx_fifo %p, refcnt %d,"
1052                   " session_tx_fifo %p, refcnt %d",
1053                   getpid (), mp->handle, session_index,
1054                   session->rx_fifo,
1055                   session->rx_fifo->refcnt,
1056                   session->tx_fifo, session->tx_fifo->refcnt);
1057 done_unlock:
1058   clib_spinlock_unlock (&vcm->sessions_lockp);
1059 }
1060
1061 static void
1062 vppcom_send_connect_sock (session_t * session, u32 session_index)
1063 {
1064   vl_api_connect_sock_t *cmp;
1065
1066   /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */
1067   cmp = vl_msg_api_alloc (sizeof (*cmp));
1068   memset (cmp, 0, sizeof (*cmp));
1069   cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK);
1070   cmp->client_index = vcm->my_client_index;
1071   cmp->context = session_index;
1072
1073   cmp->is_ip4 = session->peer_addr.is_ip4;
1074   clib_memcpy (cmp->ip, &session->peer_addr.ip46, sizeof (cmp->ip));
1075   cmp->port = session->peer_port;
1076   cmp->proto = session->proto;
1077   clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
1078   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
1079 }
1080
1081 static inline void
1082 vppcom_send_disconnect_session_reply (u64 vpp_handle, u32 session_index,
1083                                       int rv)
1084 {
1085   vl_api_disconnect_session_reply_t *rmp;
1086
1087   if (VPPCOM_DEBUG > 1)
1088     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1089                   "sending disconnect msg",
1090                   getpid (), vpp_handle, session_index);
1091
1092   rmp = vl_msg_api_alloc (sizeof (*rmp));
1093   memset (rmp, 0, sizeof (*rmp));
1094
1095   rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
1096   rmp->retval = htonl (rv);
1097   rmp->handle = vpp_handle;
1098   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1099 }
1100
1101 static inline void
1102 vppcom_send_disconnect_session (u64 vpp_handle, u32 session_index)
1103 {
1104   vl_api_disconnect_session_t *dmp;
1105
1106   if (VPPCOM_DEBUG > 1)
1107     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1108                   "sending disconnect msg",
1109                   getpid (), vpp_handle, session_index);
1110
1111   dmp = vl_msg_api_alloc (sizeof (*dmp));
1112   memset (dmp, 0, sizeof (*dmp));
1113   dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
1114   dmp->client_index = vcm->my_client_index;
1115   dmp->handle = vpp_handle;
1116   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp);
1117 }
1118
1119 static void
1120 vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
1121 {
1122   session_t *session = 0;
1123   u32 session_index = mp->context;
1124   int rv;
1125
1126   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1127 done:
1128   if (mp->retval)
1129     {
1130       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, "
1131                     "sid %u: bind failed: %U",
1132                     getpid (), mp->handle, session_index,
1133                     format_api_error, ntohl (mp->retval));
1134       rv = vppcom_session_at_index (session_index, &session);
1135       if (rv == VPPCOM_OK)
1136         {
1137           session->state = STATE_FAILED;
1138           session->vpp_handle = mp->handle;
1139         }
1140       else
1141         {
1142           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
1143                         "Invalid session index (%u)!",
1144                         getpid (), mp->handle, session_index);
1145         }
1146       goto done_unlock;
1147     }
1148
1149   session->vpp_handle = mp->handle;
1150   session->lcl_addr.is_ip4 = mp->lcl_is_ip4;
1151   clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
1152                sizeof (session->peer_addr.ip46));
1153   session->lcl_port = mp->lcl_port;
1154   vppcom_session_table_add_listener (mp->handle, session_index);
1155   session->state = STATE_LISTEN;
1156
1157   if (VPPCOM_DEBUG > 1)
1158     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
1159                   getpid (), mp->handle, mp->context);
1160 done_unlock:
1161   clib_spinlock_unlock (&vcm->sessions_lockp);
1162 }
1163
1164 static void
1165 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
1166 {
1167   if (mp->retval)
1168     clib_warning ("VCL<%d>: ERROR: sid %u: unbind failed: %U",
1169                   getpid (), mp->context, format_api_error,
1170                   ntohl (mp->retval));
1171
1172   else if (VPPCOM_DEBUG > 1)
1173     clib_warning ("VCL<%d>: sid %u: unbind succeeded!",
1174                   getpid (), mp->context);
1175 }
1176
1177 u8 *
1178 format_ip4_address (u8 * s, va_list * args)
1179 {
1180   u8 *a = va_arg (*args, u8 *);
1181   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
1182 }
1183
1184 u8 *
1185 format_ip6_address (u8 * s, va_list * args)
1186 {
1187   ip6_address_t *a = va_arg (*args, ip6_address_t *);
1188   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
1189
1190   i_max_n_zero = ARRAY_LEN (a->as_u16);
1191   max_n_zeros = 0;
1192   i_first_zero = i_max_n_zero;
1193   n_zeros = 0;
1194   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1195     {
1196       u32 is_zero = a->as_u16[i] == 0;
1197       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
1198         {
1199           i_first_zero = i;
1200           n_zeros = 0;
1201         }
1202       n_zeros += is_zero;
1203       if ((!is_zero && n_zeros > max_n_zeros)
1204           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
1205         {
1206           i_max_n_zero = i_first_zero;
1207           max_n_zeros = n_zeros;
1208           i_first_zero = ARRAY_LEN (a->as_u16);
1209           n_zeros = 0;
1210         }
1211     }
1212
1213   last_double_colon = 0;
1214   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1215     {
1216       if (i == i_max_n_zero && max_n_zeros > 1)
1217         {
1218           s = format (s, "::");
1219           i += max_n_zeros - 1;
1220           last_double_colon = 1;
1221         }
1222       else
1223         {
1224           s = format (s, "%s%x",
1225                       (last_double_colon || i == 0) ? "" : ":",
1226                       clib_net_to_host_u16 (a->as_u16[i]));
1227           last_double_colon = 0;
1228         }
1229     }
1230
1231   return s;
1232 }
1233
1234 /* Format an IP46 address. */
1235 u8 *
1236 format_ip46_address (u8 * s, va_list * args)
1237 {
1238   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1239   ip46_type_t type = va_arg (*args, ip46_type_t);
1240   int is_ip4 = 1;
1241
1242   switch (type)
1243     {
1244     case IP46_TYPE_ANY:
1245       is_ip4 = ip46_address_is_ip4 (ip46);
1246       break;
1247     case IP46_TYPE_IP4:
1248       is_ip4 = 1;
1249       break;
1250     case IP46_TYPE_IP6:
1251       is_ip4 = 0;
1252       break;
1253     }
1254
1255   return is_ip4 ?
1256     format (s, "%U", format_ip4_address, &ip46->ip4) :
1257     format (s, "%U", format_ip6_address, &ip46->ip6);
1258 }
1259
1260 static inline void
1261 vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
1262 {
1263   vl_api_accept_session_reply_t *rmp;
1264
1265   rmp = vl_msg_api_alloc (sizeof (*rmp));
1266   memset (rmp, 0, sizeof (*rmp));
1267   rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
1268   rmp->retval = htonl (retval);
1269   rmp->context = context;
1270   rmp->handle = handle;
1271   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1272 }
1273
1274 static void
1275 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
1276 {
1277   svm_fifo_t *rx_fifo, *tx_fifo;
1278   session_t *session, *listen_session;
1279   u32 session_index;
1280   vce_event_connect_request_t *ecr;
1281   vce_event_t *ev;
1282   int rv;
1283   u32 ev_idx;
1284
1285
1286   clib_spinlock_lock (&vcm->sessions_lockp);
1287   if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
1288     {
1289       clib_warning ("VCL<%d>: client session queue is full!", getpid ());
1290       vppcom_send_accept_session_reply (mp->handle, mp->context,
1291                                         VNET_API_ERROR_QUEUE_FULL);
1292       clib_spinlock_unlock (&vcm->sessions_lockp);
1293       return;
1294     }
1295
1296   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1297   if (!listen_session)
1298     {
1299       clib_warning ("VCL<%d>: ERROR: couldn't find listen session: "
1300                     "unknown vpp listener handle %llx",
1301                     getpid (), mp->listener_handle);
1302       vppcom_send_accept_session_reply (mp->handle, mp->context,
1303                                         VNET_API_ERROR_INVALID_ARGUMENT);
1304       clib_spinlock_unlock (&vcm->sessions_lockp);
1305       return;
1306     }
1307
1308   /* TODO check listener depth and update */
1309   /* TODO on "child" fd close, update listener depth */
1310
1311   /* Allocate local session and set it up */
1312   pool_get (vcm->sessions, session);
1313   memset (session, 0, sizeof (*session));
1314   session_index = session - vcm->sessions;
1315
1316   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1317   rx_fifo->client_session_index = session_index;
1318   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1319   tx_fifo->client_session_index = session_index;
1320
1321   session->vpp_handle = mp->handle;
1322   session->client_context = mp->context;
1323   session->rx_fifo = rx_fifo;
1324   session->tx_fifo = tx_fifo;
1325   session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1326                                                svm_queue_t *);
1327   session->state = STATE_ACCEPT;
1328   session->peer_port = mp->port;
1329   session->peer_addr.is_ip4 = mp->is_ip4;
1330   clib_memcpy (&session->peer_addr.ip46, mp->ip,
1331                sizeof (session->peer_addr.ip46));
1332
1333   /* Add it to lookup table */
1334   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1335   session->lcl_port = listen_session->lcl_port;
1336   session->lcl_addr = listen_session->lcl_addr;
1337
1338   /* Create an event for handlers */
1339
1340   clib_spinlock_lock (&vcm->event_thread.events_lockp);
1341
1342   pool_get (vcm->event_thread.vce_events, ev);
1343   ev->data = clib_mem_alloc (sizeof (vce_event_connect_request_t));
1344   ev->refcnt = 0;
1345   ev_idx = (u32) (ev - vcm->event_thread.vce_events);
1346   ecr = ev->data;
1347   ev->evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
1348   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1349   ev->evk.session_index = (u32) (listen_session - vcm->sessions);
1350   ecr->handled = 0;
1351   ecr->accepted_session_index = session_index;
1352
1353   clib_spinlock_unlock (&vcm->event_thread.events_lockp);
1354
1355   rv = vce_generate_event (&vcm->event_thread, ev_idx);
1356
1357   ASSERT (rv == 0);
1358
1359   if (VPPCOM_DEBUG > 1)
1360     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: client accept "
1361                   "request from %s address %U port %d queue %p!", getpid (),
1362                   mp->handle, session_index, mp->is_ip4 ? "IPv4" : "IPv6",
1363                   format_ip46_address, &mp->ip, mp->is_ip4,
1364                   clib_net_to_host_u16 (mp->port), session->vpp_event_queue);
1365
1366   if (VPPCOM_DEBUG > 0)
1367     {
1368       session->elog_track.name =
1369         (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
1370                          session_index, 0);
1371       elog_track_register (&vcm->elog_main, &session->elog_track);
1372
1373       if (session->peer_addr.is_ip4)
1374         {
1375           /* *INDENT-OFF* */
1376           ELOG_TYPE_DECLARE (e) =
1377           {
1378             .format =
1379             "client_accept:handle:%x addr:%d.%d.%d.%d:%d",
1380             .format_args = "i8i1i1i1i1i2",
1381           };
1382
1383           CLIB_PACKED (struct {
1384             u64 handle; //8
1385             u8 addr[4]; //4
1386             u16 port;   //2
1387           }) * ed;
1388
1389           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
1390
1391           ed->handle = mp->handle;
1392           ed->addr[0] = session->peer_addr.ip46.ip4.as_u8[0];
1393           ed->addr[1] = session->peer_addr.ip46.ip4.as_u8[1];
1394           ed->addr[2] = session->peer_addr.ip46.ip4.as_u8[2];
1395           ed->addr[3] = session->peer_addr.ip46.ip4.as_u8[3];
1396           ed->port = clib_net_to_host_u16 (session->peer_port);
1397           /* *INDENT-ON* */
1398         }
1399       else
1400         {
1401           clib_warning ("ip6");
1402         }
1403     }
1404   clib_spinlock_unlock (&vcm->sessions_lockp);
1405
1406 }
1407
1408 static void
1409 vppcom_send_bind_sock (session_t * session, u32 session_index)
1410 {
1411   vl_api_bind_sock_t *bmp;
1412
1413   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1414   bmp = vl_msg_api_alloc (sizeof (*bmp));
1415   memset (bmp, 0, sizeof (*bmp));
1416
1417   bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK);
1418   bmp->client_index = vcm->my_client_index;
1419   bmp->context = session_index;
1420   bmp->is_ip4 = session->lcl_addr.is_ip4;
1421   clib_memcpy (bmp->ip, &session->lcl_addr.ip46, sizeof (bmp->ip));
1422   bmp->port = session->lcl_port;
1423   bmp->proto = session->proto;
1424   clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
1425   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
1426 }
1427
1428 static void
1429 vppcom_send_unbind_sock (u64 vpp_handle)
1430 {
1431   vl_api_unbind_sock_t *ump;
1432
1433   ump = vl_msg_api_alloc (sizeof (*ump));
1434   memset (ump, 0, sizeof (*ump));
1435
1436   ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK);
1437   ump->client_index = vcm->my_client_index;
1438   ump->handle = vpp_handle;
1439   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump);
1440 }
1441
1442 static int
1443 vppcom_session_unbind (u32 session_index)
1444 {
1445   session_t *session = 0;
1446   int rv;
1447   u64 vpp_handle;
1448   elog_track_t session_elog_track;
1449
1450   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1451
1452   vpp_handle = session->vpp_handle;
1453   vppcom_session_table_del_listener (vpp_handle);
1454   session->vpp_handle = ~0;
1455   session->state = STATE_DISCONNECT;
1456   session_elog_track = session->elog_track;
1457
1458   clib_spinlock_unlock (&vcm->sessions_lockp);
1459
1460   if (VPPCOM_DEBUG > 1)
1461     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1462                   "sending unbind msg! new state 0x%x (%s)",
1463                   getpid (), vpp_handle, session_index,
1464                   STATE_DISCONNECT,
1465                   vppcom_session_state_str (STATE_DISCONNECT));
1466
1467   if (VPPCOM_DEBUG > 0)
1468     {
1469       /* *INDENT-OFF* */
1470       ELOG_TYPE_DECLARE (e) =
1471       {
1472         .format = "unbind: handle:%x",
1473         .format_args = "i8",
1474       };
1475
1476       struct
1477       {
1478         u64 handle;
1479       } *ed;
1480
1481       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
1482       ed->handle = vpp_handle;
1483       /* *INDENT-ON* */
1484     }
1485
1486   vppcom_send_unbind_sock (vpp_handle);
1487
1488 done:
1489   return rv;
1490 }
1491
1492 static inline int
1493 vppcom_session_disconnect (u32 session_index)
1494 {
1495   int rv;
1496   session_t *session;
1497   u64 vpp_handle;
1498   session_state_t state;
1499
1500   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1501
1502   vpp_handle = session->vpp_handle;
1503   state = session->state;
1504   clib_spinlock_unlock (&vcm->sessions_lockp);
1505
1506   if (VPPCOM_DEBUG > 1)
1507     {
1508       clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u "
1509                     "state 0x%x (%s)",
1510                     getpid (), vpp_handle, session_index,
1511                     state, vppcom_session_state_str (state));
1512     }
1513
1514   if (PREDICT_FALSE (state & STATE_LISTEN))
1515     {
1516       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1517                     "Cannot disconnect a listen socket!",
1518                     getpid (), vpp_handle, session_index);
1519       rv = VPPCOM_EBADFD;
1520       goto done;
1521     }
1522
1523   /* The peer has already initiated the close,
1524    * so send the disconnect session reply.
1525    */
1526   if (state & STATE_CLOSE_ON_EMPTY)
1527     {
1528       //XXX alagalah - Check and drain here?
1529       vppcom_send_disconnect_session_reply (vpp_handle,
1530                                             session_index, 0 /* rv */ );
1531       if (VPPCOM_DEBUG > 1)
1532         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1533                       "sending disconnect REPLY...",
1534                       getpid (), vpp_handle, session_index);
1535     }
1536
1537   /* Otherwise, send a disconnect session msg...
1538    */
1539   else
1540     {
1541       if (VPPCOM_DEBUG > 1)
1542         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1543                       "sending disconnect...",
1544                       getpid (), vpp_handle, session_index);
1545
1546       vppcom_send_disconnect_session (vpp_handle, session_index);
1547     }
1548
1549 done:
1550   return rv;
1551 }
1552
1553 #define foreach_sock_msg                                        \
1554 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply)   \
1555 _(BIND_SOCK_REPLY, bind_sock_reply)                             \
1556 _(UNBIND_SOCK_REPLY, unbind_sock_reply)                         \
1557 _(ACCEPT_SESSION, accept_session)                               \
1558 _(CONNECT_SESSION_REPLY, connect_session_reply)                 \
1559 _(DISCONNECT_SESSION, disconnect_session)                       \
1560 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)           \
1561 _(RESET_SESSION, reset_session)                                 \
1562 _(APPLICATION_ATTACH_REPLY, application_attach_reply)           \
1563 _(APPLICATION_DETACH_REPLY, application_detach_reply)           \
1564 _(MAP_ANOTHER_SEGMENT, map_another_segment)                     \
1565 _(UNMAP_SEGMENT, unmap_segment)
1566
1567 static void
1568 vppcom_api_hookup (void)
1569 {
1570 #define _(N, n)                                                  \
1571     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1572                            vl_api_##n##_t_handler,              \
1573                            vl_noop_handler,                     \
1574                            vl_api_##n##_t_endian,               \
1575                            vl_api_##n##_t_print,                \
1576                            sizeof(vl_api_##n##_t), 1);
1577   foreach_sock_msg;
1578 #undef _
1579 }
1580
1581 static void
1582 vppcom_cfg_init (vppcom_cfg_t * vcl_cfg)
1583 {
1584   ASSERT (vcl_cfg);
1585
1586   vcl_cfg->heapsize = (256ULL << 20);
1587   vcl_cfg->vpp_api_q_length = 1024;
1588   vcl_cfg->segment_baseva = 0x200000000ULL;
1589   vcl_cfg->segment_size = (256 << 20);
1590   vcl_cfg->add_segment_size = (128 << 20);
1591   vcl_cfg->preallocated_fifo_pairs = 8;
1592   vcl_cfg->rx_fifo_size = (1 << 20);
1593   vcl_cfg->tx_fifo_size = (1 << 20);
1594   vcl_cfg->event_queue_size = 2048;
1595   vcl_cfg->listen_queue_size = CLIB_CACHE_LINE_BYTES / sizeof (u32);
1596   vcl_cfg->app_timeout = 10 * 60.0;
1597   vcl_cfg->session_timeout = 10 * 60.0;
1598   vcl_cfg->accept_timeout = 60.0;
1599   vcl_cfg->event_ring_size = (128 << 10);
1600   vcl_cfg->event_log_path = "/dev/shm";
1601 }
1602
1603 static void
1604 vppcom_cfg_heapsize (char *conf_fname)
1605 {
1606   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1607   FILE *fp;
1608   char inbuf[4096];
1609   int argc = 1;
1610   char **argv = NULL;
1611   char *arg = NULL;
1612   char *p;
1613   int i;
1614   u8 *sizep;
1615   u32 size;
1616   void *vcl_mem;
1617   void *heap;
1618
1619   fp = fopen (conf_fname, "r");
1620   if (fp == NULL)
1621     {
1622       if (VPPCOM_DEBUG > 0)
1623         clib_warning ("VCL<%d>: using default heapsize %lld (0x%llx)",
1624                       getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1625       goto defaulted;
1626     }
1627
1628   argv = calloc (1, sizeof (char *));
1629   if (argv == NULL)
1630     {
1631       if (VPPCOM_DEBUG > 0)
1632         clib_warning ("VCL<%d>: calloc failed, using default "
1633                       "heapsize %lld (0x%llx)",
1634                       getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1635       goto defaulted;
1636     }
1637
1638   while (1)
1639     {
1640       if (fgets (inbuf, 4096, fp) == 0)
1641         break;
1642       p = strtok (inbuf, " \t\n");
1643       while (p != NULL)
1644         {
1645           if (*p == '#')
1646             break;
1647           argc++;
1648           char **tmp = realloc (argv, argc * sizeof (char *));
1649           if (tmp == NULL)
1650             {
1651               if (VPPCOM_DEBUG > 0)
1652                 clib_warning ("VCL<%d>: realloc failed, "
1653                               "using default heapsize %lld (0x%llx)",
1654                               getpid (), vcl_cfg->heapsize,
1655                               vcl_cfg->heapsize);
1656               goto defaulted;
1657             }
1658           argv = tmp;
1659           arg = strndup (p, 1024);
1660           if (arg == NULL)
1661             {
1662               if (VPPCOM_DEBUG > 0)
1663                 clib_warning ("VCL<%d>: strndup failed, "
1664                               "using default heapsize %lld (0x%llx)",
1665                               getpid (), vcl_cfg->heapsize,
1666                               vcl_cfg->heapsize);
1667               goto defaulted;
1668             }
1669           argv[argc - 1] = arg;
1670           p = strtok (NULL, " \t\n");
1671         }
1672     }
1673
1674   fclose (fp);
1675   fp = NULL;
1676
1677   char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
1678   if (tmp == NULL)
1679     {
1680       if (VPPCOM_DEBUG > 0)
1681         clib_warning ("VCL<%d>: realloc failed, "
1682                       "using default heapsize %lld (0x%llx)",
1683                       getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1684       goto defaulted;
1685     }
1686   argv = tmp;
1687   argv[argc] = NULL;
1688
1689   /*
1690    * Look for and parse the "heapsize" config parameter.
1691    * Manual since none of the clib infra has been bootstrapped yet.
1692    *
1693    * Format: heapsize <nn>[mM][gG]
1694    */
1695
1696   for (i = 1; i < (argc - 1); i++)
1697     {
1698       if (!strncmp (argv[i], "heapsize", 8))
1699         {
1700           sizep = (u8 *) argv[i + 1];
1701           size = 0;
1702           while (*sizep >= '0' && *sizep <= '9')
1703             {
1704               size *= 10;
1705               size += *sizep++ - '0';
1706             }
1707           if (size == 0)
1708             {
1709               if (VPPCOM_DEBUG > 0)
1710                 clib_warning ("VCL<%d>: parse error '%s %s', "
1711                               "using default heapsize %lld (0x%llx)",
1712                               getpid (), argv[i], argv[i + 1],
1713                               vcl_cfg->heapsize, vcl_cfg->heapsize);
1714               goto defaulted;
1715             }
1716
1717           if (*sizep == 'g' || *sizep == 'G')
1718             vcl_cfg->heapsize = size << 30;
1719           else if (*sizep == 'm' || *sizep == 'M')
1720             vcl_cfg->heapsize = size << 20;
1721           else
1722             {
1723               if (VPPCOM_DEBUG > 0)
1724                 clib_warning ("VCL<%d>: parse error '%s %s', "
1725                               "using default heapsize %lld (0x%llx)",
1726                               getpid (), argv[i], argv[i + 1],
1727                               vcl_cfg->heapsize, vcl_cfg->heapsize);
1728               goto defaulted;
1729             }
1730         }
1731     }
1732
1733 defaulted:
1734   if (fp != NULL)
1735     fclose (fp);
1736   if (argv != NULL)
1737     free (argv);
1738
1739   vcl_mem = mmap (0, vcl_cfg->heapsize, PROT_READ | PROT_WRITE,
1740                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1741   if (vcl_mem == MAP_FAILED)
1742     {
1743       clib_unix_error ("VCL<%d>: ERROR: mmap(0, %lld == 0x%llx, "
1744                        "PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, "
1745                        "-1, 0) failed!",
1746                        getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1747       ASSERT (vcl_mem != MAP_FAILED);
1748       return;
1749     }
1750   heap = clib_mem_init (vcl_mem, vcl_cfg->heapsize);
1751   if (!heap)
1752     {
1753       clib_warning ("VCL<%d>: ERROR: clib_mem_init() failed!", getpid ());
1754       ASSERT (heap);
1755       return;
1756     }
1757   vcl_mem = clib_mem_alloc (sizeof (_vppcom_main));
1758   if (!vcl_mem)
1759     {
1760       clib_warning ("VCL<%d>: ERROR: clib_mem_alloc() failed!", getpid ());
1761       ASSERT (vcl_mem);
1762       return;
1763     }
1764
1765   clib_memcpy (vcl_mem, &_vppcom_main, sizeof (_vppcom_main));
1766   vcm = vcl_mem;
1767
1768   if (VPPCOM_DEBUG > 0)
1769     clib_warning ("VCL<%d>: allocated VCL heap = %p, size %lld (0x%llx)",
1770                   getpid (), heap, vcl_cfg->heapsize, vcl_cfg->heapsize);
1771 }
1772
1773 static void
1774 vppcom_cfg_read (char *conf_fname)
1775 {
1776   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1777   int fd;
1778   unformat_input_t _input, *input = &_input;
1779   unformat_input_t _line_input, *line_input = &_line_input;
1780   u8 vc_cfg_input = 0;
1781   u8 *chroot_path;
1782   struct stat s;
1783   u32 uid, gid, q_len;
1784
1785   fd = open (conf_fname, O_RDONLY);
1786   if (fd < 0)
1787     {
1788       if (VPPCOM_DEBUG > 0)
1789         clib_warning ("VCL<%d>: using default configuration.",
1790                       getpid (), conf_fname);
1791       goto file_done;
1792     }
1793
1794   if (fstat (fd, &s) < 0)
1795     {
1796       if (VPPCOM_DEBUG > 0)
1797         clib_warning ("VCL<%d>: failed to stat `%s', "
1798                       "using default configuration", getpid (), conf_fname);
1799       goto file_done;
1800     }
1801
1802   if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
1803     {
1804       if (VPPCOM_DEBUG > 0)
1805         clib_warning ("VCL<%d>: not a regular file `%s', "
1806                       "using default configuration", getpid (), conf_fname);
1807       goto file_done;
1808     }
1809
1810   unformat_init_clib_file (input, fd);
1811
1812   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1813     {
1814       (void) unformat_user (input, unformat_line_input, line_input);
1815       unformat_skip_white_space (line_input);
1816
1817       if (unformat (line_input, "vcl {"))
1818         {
1819           vc_cfg_input = 1;
1820           continue;
1821         }
1822
1823       if (vc_cfg_input)
1824         {
1825           if (unformat (line_input, "heapsize %s", &chroot_path))
1826             {
1827               vec_terminate_c_string (chroot_path);
1828               if (VPPCOM_DEBUG > 0)
1829                 clib_warning ("VCL<%d>: configured heapsize %s, "
1830                               "actual heapsize %lld (0x%llx)",
1831                               getpid (), chroot_path, vcl_cfg->heapsize,
1832                               vcl_cfg->heapsize);
1833               vec_free (chroot_path);
1834             }
1835           else if (unformat (line_input, "api-prefix %s", &chroot_path))
1836             {
1837               vec_terminate_c_string (chroot_path);
1838               if (vcl_cfg->vpp_api_filename)
1839                 vec_free (vcl_cfg->vpp_api_filename);
1840               vcl_cfg->vpp_api_filename = format (0, "/%s-vpe-api%c",
1841                                                   chroot_path, 0);
1842               vl_set_memory_root_path ((char *) chroot_path);
1843
1844               if (VPPCOM_DEBUG > 0)
1845                 clib_warning ("VCL<%d>: configured api-prefix (%s) and "
1846                               "api filename (%s)", getpid (), chroot_path,
1847                               vcl_cfg->vpp_api_filename);
1848               chroot_path = 0;  /* Don't vec_free() it! */
1849             }
1850           else if (unformat (line_input, "vpp-api-q-length %d", &q_len))
1851             {
1852               if (q_len < vcl_cfg->vpp_api_q_length)
1853                 {
1854                   clib_warning ("VCL<%d>: ERROR: configured vpp-api-q-length "
1855                                 "(%u) is too small! Using default: %u ",
1856                                 getpid (), q_len, vcl_cfg->vpp_api_q_length);
1857                 }
1858               else
1859                 {
1860                   vcl_cfg->vpp_api_q_length = q_len;
1861
1862                   if (VPPCOM_DEBUG > 0)
1863                     clib_warning ("VCL<%d>: configured vpp-api-q-length %u",
1864                                   getpid (), vcl_cfg->vpp_api_q_length);
1865                 }
1866             }
1867           else if (unformat (line_input, "uid %d", &uid))
1868             {
1869               vl_set_memory_uid (uid);
1870               if (VPPCOM_DEBUG > 0)
1871                 clib_warning ("VCL<%d>: configured uid %d", getpid (), uid);
1872             }
1873           else if (unformat (line_input, "gid %d", &gid))
1874             {
1875               vl_set_memory_gid (gid);
1876               if (VPPCOM_DEBUG > 0)
1877                 clib_warning ("VCL<%d>: configured gid %d", getpid (), gid);
1878             }
1879           else if (unformat (line_input, "segment-baseva 0x%lx",
1880                              &vcl_cfg->segment_baseva))
1881             {
1882               if (VPPCOM_DEBUG > 0)
1883                 clib_warning ("VCL<%d>: configured segment_baseva 0x%lx",
1884                               getpid (), vcl_cfg->segment_baseva);
1885             }
1886           else if (unformat (line_input, "segment-size 0x%lx",
1887                              &vcl_cfg->segment_size))
1888             {
1889               if (VPPCOM_DEBUG > 0)
1890                 clib_warning ("VCL<%d>: configured segment_size 0x%lx (%ld)",
1891                               getpid (), vcl_cfg->segment_size,
1892                               vcl_cfg->segment_size);
1893             }
1894           else if (unformat (line_input, "segment-size %ld",
1895                              &vcl_cfg->segment_size))
1896             {
1897               if (VPPCOM_DEBUG > 0)
1898                 clib_warning ("VCL<%d>: configured segment_size %ld (0x%lx)",
1899                               getpid (), vcl_cfg->segment_size,
1900                               vcl_cfg->segment_size);
1901             }
1902           else if (unformat (line_input, "add-segment-size 0x%lx",
1903                              &vcl_cfg->add_segment_size))
1904             {
1905               if (VPPCOM_DEBUG > 0)
1906                 clib_warning
1907                   ("VCL<%d>: configured add_segment_size 0x%lx (%ld)",
1908                    getpid (), vcl_cfg->add_segment_size,
1909                    vcl_cfg->add_segment_size);
1910             }
1911           else if (unformat (line_input, "add-segment-size %ld",
1912                              &vcl_cfg->add_segment_size))
1913             {
1914               if (VPPCOM_DEBUG > 0)
1915                 clib_warning
1916                   ("VCL<%d>: configured add_segment_size %ld (0x%lx)",
1917                    getpid (), vcl_cfg->add_segment_size,
1918                    vcl_cfg->add_segment_size);
1919             }
1920           else if (unformat (line_input, "preallocated-fifo-pairs %d",
1921                              &vcl_cfg->preallocated_fifo_pairs))
1922             {
1923               if (VPPCOM_DEBUG > 0)
1924                 clib_warning ("VCL<%d>: configured preallocated_fifo_pairs "
1925                               "%d (0x%x)", getpid (),
1926                               vcl_cfg->preallocated_fifo_pairs,
1927                               vcl_cfg->preallocated_fifo_pairs);
1928             }
1929           else if (unformat (line_input, "rx-fifo-size 0x%lx",
1930                              &vcl_cfg->rx_fifo_size))
1931             {
1932               if (VPPCOM_DEBUG > 0)
1933                 clib_warning ("VCL<%d>: configured rx_fifo_size 0x%lx (%ld)",
1934                               getpid (), vcl_cfg->rx_fifo_size,
1935                               vcl_cfg->rx_fifo_size);
1936             }
1937           else if (unformat (line_input, "rx-fifo-size %ld",
1938                              &vcl_cfg->rx_fifo_size))
1939             {
1940               if (VPPCOM_DEBUG > 0)
1941                 clib_warning ("VCL<%d>: configured rx_fifo_size %ld (0x%lx)",
1942                               getpid (), vcl_cfg->rx_fifo_size,
1943                               vcl_cfg->rx_fifo_size);
1944             }
1945           else if (unformat (line_input, "tx-fifo-size 0x%lx",
1946                              &vcl_cfg->tx_fifo_size))
1947             {
1948               if (VPPCOM_DEBUG > 0)
1949                 clib_warning ("VCL<%d>: configured tx_fifo_size 0x%lx (%ld)",
1950                               getpid (), vcl_cfg->tx_fifo_size,
1951                               vcl_cfg->tx_fifo_size);
1952             }
1953           else if (unformat (line_input, "tx-fifo-size %ld",
1954                              &vcl_cfg->tx_fifo_size))
1955             {
1956               if (VPPCOM_DEBUG > 0)
1957                 clib_warning ("VCL<%d>: configured tx_fifo_size %ld (0x%lx)",
1958                               getpid (), vcl_cfg->tx_fifo_size,
1959                               vcl_cfg->tx_fifo_size);
1960             }
1961           else if (unformat (line_input, "event-queue-size 0x%lx",
1962                              &vcl_cfg->event_queue_size))
1963             {
1964               if (VPPCOM_DEBUG > 0)
1965                 clib_warning ("VCL<%d>: configured event_queue_size "
1966                               "0x%lx (%ld)",
1967                               getpid (), vcl_cfg->event_queue_size,
1968                               vcl_cfg->event_queue_size);
1969             }
1970           else if (unformat (line_input, "event-queue-size %ld",
1971                              &vcl_cfg->event_queue_size))
1972             {
1973               if (VPPCOM_DEBUG > 0)
1974                 clib_warning ("VCL<%d>: configured event_queue_size "
1975                               "%ld (0x%lx)",
1976                               getpid (), vcl_cfg->event_queue_size,
1977                               vcl_cfg->event_queue_size);
1978             }
1979           else if (unformat (line_input, "listen-queue-size 0x%lx",
1980                              &vcl_cfg->listen_queue_size))
1981             {
1982               if (VPPCOM_DEBUG > 0)
1983                 clib_warning ("VCL<%d>: configured listen_queue_size "
1984                               "0x%lx (%ld)",
1985                               getpid (), vcl_cfg->listen_queue_size,
1986                               vcl_cfg->listen_queue_size);
1987             }
1988           else if (unformat (line_input, "listen-queue-size %ld",
1989                              &vcl_cfg->listen_queue_size))
1990             {
1991               if (VPPCOM_DEBUG > 0)
1992                 clib_warning ("VCL<%d>: configured listen_queue_size "
1993                               "%ld (0x%lx)",
1994                               getpid (), vcl_cfg->listen_queue_size,
1995                               vcl_cfg->listen_queue_size);
1996             }
1997           else if (unformat (line_input, "app-timeout %f",
1998                              &vcl_cfg->app_timeout))
1999             {
2000               if (VPPCOM_DEBUG > 0)
2001                 clib_warning ("VCL<%d>: configured app_timeout %f",
2002                               getpid (), vcl_cfg->app_timeout);
2003             }
2004           else if (unformat (line_input, "session-timeout %f",
2005                              &vcl_cfg->session_timeout))
2006             {
2007               if (VPPCOM_DEBUG > 0)
2008                 clib_warning ("VCL<%d>: configured session_timeout %f",
2009                               getpid (), vcl_cfg->session_timeout);
2010             }
2011           else if (unformat (line_input, "accept-timeout %f",
2012                              &vcl_cfg->accept_timeout))
2013             {
2014               if (VPPCOM_DEBUG > 0)
2015                 clib_warning ("VCL<%d>: configured accept_timeout %f",
2016                               getpid (), vcl_cfg->accept_timeout);
2017             }
2018           else if (unformat (line_input, "app-proxy-transport-tcp"))
2019             {
2020               vcl_cfg->app_proxy_transport_tcp = 1;
2021               if (VPPCOM_DEBUG > 0)
2022                 clib_warning ("VCL<%d>: configured "
2023                               "app_proxy_transport_tcp (%d)",
2024                               getpid (), vcl_cfg->app_proxy_transport_tcp);
2025             }
2026           else if (unformat (line_input, "app-proxy-transport-udp"))
2027             {
2028               vcl_cfg->app_proxy_transport_udp = 1;
2029               if (VPPCOM_DEBUG > 0)
2030                 clib_warning ("VCL<%d>: configured "
2031                               "app_proxy_transport_udp (%d)",
2032                               getpid (), vcl_cfg->app_proxy_transport_udp);
2033             }
2034           else if (unformat (line_input, "app-scope-local"))
2035             {
2036               vcl_cfg->app_scope_local = 1;
2037               if (VPPCOM_DEBUG > 0)
2038                 clib_warning ("VCL<%d>: configured app_scope_local (%d)",
2039                               getpid (), vcl_cfg->app_scope_local);
2040             }
2041           else if (unformat (line_input, "app-scope-global"))
2042             {
2043               vcl_cfg->app_scope_global = 1;
2044               if (VPPCOM_DEBUG > 0)
2045                 clib_warning ("VCL<%d>: configured app_scope_global (%d)",
2046                               getpid (), vcl_cfg->app_scope_global);
2047             }
2048           else if (unformat (line_input, "namespace-secret %lu",
2049                              &vcl_cfg->namespace_secret))
2050             {
2051               if (VPPCOM_DEBUG > 0)
2052                 clib_warning
2053                   ("VCL<%d>: configured namespace_secret %lu (0x%lx)",
2054                    getpid (), vcl_cfg->namespace_secret,
2055                    vcl_cfg->namespace_secret);
2056             }
2057           else if (unformat (line_input, "namespace-id %v",
2058                              &vcl_cfg->namespace_id))
2059             {
2060               vl_api_application_attach_t *mp;
2061               u32 max_nsid_vec_len = sizeof (mp->namespace_id) - 1;
2062               u32 nsid_vec_len = vec_len (vcl_cfg->namespace_id);
2063               if (nsid_vec_len > max_nsid_vec_len)
2064                 {
2065                   _vec_len (vcl_cfg->namespace_id) = max_nsid_vec_len;
2066                   if (VPPCOM_DEBUG > 0)
2067                     clib_warning ("VCL<%d>: configured namespace_id is "
2068                                   "too long, truncated to %d characters!",
2069                                   getpid (), max_nsid_vec_len);
2070                 }
2071
2072               if (VPPCOM_DEBUG > 0)
2073                 clib_warning ("VCL<%d>: configured namespace_id %v",
2074                               getpid (), vcl_cfg->namespace_id);
2075             }
2076           else if (unformat (line_input, "}"))
2077             {
2078               vc_cfg_input = 0;
2079               if (VPPCOM_DEBUG > 0)
2080                 clib_warning ("VCL<%d>: completed parsing vppcom config!",
2081                               getpid ());
2082               goto input_done;
2083             }
2084           else
2085             {
2086               if (line_input->buffer[line_input->index] != '#')
2087                 {
2088                   clib_warning ("VCL<%d>: Unknown vppcom config option: '%s'",
2089                                 getpid (), (char *)
2090                                 &line_input->buffer[line_input->index]);
2091                 }
2092             }
2093         }
2094     }
2095
2096 input_done:
2097   unformat_free (input);
2098
2099 file_done:
2100   if (fd >= 0)
2101     close (fd);
2102 }
2103
2104 /*
2105  * VPPCOM Public API functions
2106  */
2107 int
2108 vppcom_app_create (char *app_name)
2109 {
2110   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
2111   u8 *heap;
2112   mheap_t *h;
2113   int rv;
2114
2115   if (!vcm->init)
2116     {
2117       char *conf_fname;
2118       char *env_var_str;
2119
2120       vcm->init = 1;
2121       vppcom_cfg_init (vcl_cfg);
2122       env_var_str = getenv (VPPCOM_ENV_DEBUG);
2123       if (env_var_str)
2124         {
2125           u32 tmp;
2126           if (sscanf (env_var_str, "%u", &tmp) != 1)
2127             clib_warning ("VCL<%d>: WARNING: Invalid debug level specified "
2128                           "in the environment variable " VPPCOM_ENV_DEBUG
2129                           " (%s)!\n", getpid (), env_var_str);
2130           else
2131             {
2132               vcm->debug = tmp;
2133               if (VPPCOM_DEBUG > 0)
2134                 clib_warning ("VCL<%d>: configured VCL debug level (%u) from "
2135                               VPPCOM_ENV_DEBUG "!", getpid (), vcm->debug);
2136             }
2137         }
2138       conf_fname = getenv (VPPCOM_ENV_CONF);
2139       if (!conf_fname)
2140         conf_fname = VPPCOM_CONF_DEFAULT;
2141       vppcom_cfg_heapsize (conf_fname);
2142       vcl_cfg = &vcm->cfg;
2143       clib_fifo_validate (vcm->client_session_index_fifo,
2144                           vcm->cfg.listen_queue_size);
2145       vppcom_cfg_read (conf_fname);
2146
2147       env_var_str = getenv (VPPCOM_ENV_API_PREFIX);
2148       if (env_var_str)
2149         {
2150           if (vcl_cfg->vpp_api_filename)
2151             vec_free (vcl_cfg->vpp_api_filename);
2152           vcl_cfg->vpp_api_filename = format (0, "/%s-vpe-api%c",
2153                                               env_var_str, 0);
2154           vl_set_memory_root_path ((char *) env_var_str);
2155
2156           if (VPPCOM_DEBUG > 0)
2157             clib_warning ("VCL<%d>: configured api prefix (%s) and "
2158                           "filename (%s) from " VPPCOM_ENV_API_PREFIX "!",
2159                           getpid (), env_var_str, vcl_cfg->vpp_api_filename);
2160         }
2161
2162       env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
2163       if (env_var_str)
2164         {
2165           u64 tmp;
2166           if (sscanf (env_var_str, "%lu", &tmp) != 1)
2167             clib_warning ("VCL<%d>: WARNING: Invalid namespace secret "
2168                           "specified in the environment variable "
2169                           VPPCOM_ENV_APP_NAMESPACE_SECRET
2170                           " (%s)!\n", getpid (), env_var_str);
2171           else
2172             {
2173               vcm->cfg.namespace_secret = tmp;
2174               if (VPPCOM_DEBUG > 0)
2175                 clib_warning ("VCL<%d>: configured namespace secret "
2176                               "(%lu) from " VPPCOM_ENV_APP_NAMESPACE_ID "!",
2177                               getpid (), vcm->cfg.namespace_secret);
2178             }
2179         }
2180       env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_ID);
2181       if (env_var_str)
2182         {
2183           u32 ns_id_vec_len = strlen (env_var_str);
2184
2185           vec_reset_length (vcm->cfg.namespace_id);
2186           vec_validate (vcm->cfg.namespace_id, ns_id_vec_len - 1);
2187           clib_memcpy (vcm->cfg.namespace_id, env_var_str, ns_id_vec_len);
2188
2189           if (VPPCOM_DEBUG > 0)
2190             clib_warning ("VCL<%d>: configured namespace_id (%v) from "
2191                           VPPCOM_ENV_APP_NAMESPACE_ID
2192                           "!", getpid (), vcm->cfg.namespace_id);
2193         }
2194       env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
2195       if (env_var_str)
2196         {
2197           u64 tmp;
2198           if (sscanf (env_var_str, "%lu", &tmp) != 1)
2199             clib_warning ("VCL<%d>: WARNING: Invalid namespace secret "
2200                           "specified in the environment variable "
2201                           VPPCOM_ENV_APP_NAMESPACE_SECRET
2202                           " (%s)!\n", getpid (), env_var_str);
2203           else
2204             {
2205               vcm->cfg.namespace_secret = tmp;
2206               if (VPPCOM_DEBUG > 0)
2207                 clib_warning ("VCL<%d>: configured namespace secret "
2208                               "(%lu) from "
2209                               VPPCOM_ENV_APP_NAMESPACE_ID
2210                               "!", getpid (), vcm->cfg.namespace_secret);
2211             }
2212         }
2213       if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP))
2214         {
2215           vcm->cfg.app_proxy_transport_tcp = 1;
2216           if (VPPCOM_DEBUG > 0)
2217             clib_warning ("VCL<%d>: configured app_proxy_transport_tcp "
2218                           "(%u) from "
2219                           VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP
2220                           "!", getpid (), vcm->cfg.app_proxy_transport_tcp);
2221         }
2222       if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP))
2223         {
2224           vcm->cfg.app_proxy_transport_udp = 1;
2225           if (VPPCOM_DEBUG > 0)
2226             clib_warning ("VCL<%d>: configured app_proxy_transport_udp "
2227                           "(%u) from "
2228                           VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP
2229                           "!", getpid (), vcm->cfg.app_proxy_transport_udp);
2230         }
2231       if (getenv (VPPCOM_ENV_APP_SCOPE_LOCAL))
2232         {
2233           vcm->cfg.app_scope_local = 1;
2234           if (VPPCOM_DEBUG > 0)
2235             clib_warning ("VCL<%d>: configured app_scope_local (%u) from "
2236                           VPPCOM_ENV_APP_SCOPE_LOCAL
2237                           "!", getpid (), vcm->cfg.app_scope_local);
2238         }
2239       if (getenv (VPPCOM_ENV_APP_SCOPE_GLOBAL))
2240         {
2241           vcm->cfg.app_scope_global = 1;
2242           if (VPPCOM_DEBUG > 0)
2243             clib_warning ("VCL<%d>: configured app_scope_global (%u) from "
2244                           VPPCOM_ENV_APP_SCOPE_GLOBAL
2245                           "!", getpid (), vcm->cfg.app_scope_global);
2246         }
2247
2248       vcm->main_cpu = os_get_thread_index ();
2249       heap = clib_mem_get_per_cpu_heap ();
2250       h = mheap_header (heap);
2251
2252       /* make the main heap thread-safe */
2253       h->flags |= MHEAP_FLAG_THREAD_SAFE;
2254
2255       vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
2256
2257       clib_time_init (&vcm->clib_time);
2258       vppcom_init_error_string_table ();
2259       svm_fifo_segment_main_init (vcl_cfg->segment_baseva,
2260                                   20 /* timeout in secs */ );
2261       clib_spinlock_init (&vcm->sessions_lockp);
2262     }
2263
2264   if (vcm->my_client_index == ~0)
2265     {
2266
2267       /* API hookup and connect to VPP */
2268       vppcom_api_hookup ();
2269       vcm->app_state = STATE_APP_START;
2270       rv = vppcom_connect_to_vpp (app_name);
2271       if (rv)
2272         {
2273           clib_warning ("VCL<%d>: ERROR: couldn't connect to VPP!",
2274                         getpid ());
2275           return rv;
2276         }
2277
2278       /* State event handling thread */
2279
2280       rv = vce_start_event_thread (&(vcm->event_thread), 20);
2281
2282
2283       if (VPPCOM_DEBUG > 0)
2284         clib_warning ("VCL<%d>: sending session enable", getpid ());
2285
2286       rv = vppcom_app_session_enable ();
2287       if (rv)
2288         {
2289           clib_warning ("VCL<%d>: ERROR: vppcom_app_session_enable() "
2290                         "failed!", getpid ());
2291           return rv;
2292         }
2293
2294       if (VPPCOM_DEBUG > 0)
2295         clib_warning ("VCL<%d>: sending app attach", getpid ());
2296
2297       rv = vppcom_app_attach ();
2298       if (rv)
2299         {
2300           clib_warning ("VCL<%d>: ERROR: vppcom_app_attach() failed!",
2301                         getpid ());
2302           return rv;
2303         }
2304
2305       if (VPPCOM_DEBUG > 0)
2306         clib_warning ("VCL<%d>: app_name '%s', my_client_index %d (0x%x)",
2307                       getpid (), app_name, vcm->my_client_index,
2308                       vcm->my_client_index);
2309     }
2310
2311   return VPPCOM_OK;
2312 }
2313
2314 void
2315 vppcom_app_destroy (void)
2316 {
2317   int rv;
2318
2319   if (vcm->my_client_index == ~0)
2320     return;
2321
2322   if (VPPCOM_DEBUG > 0)
2323     clib_warning ("VCL<%d>: detaching from VPP, my_client_index %d (0x%x)",
2324                   getpid (), vcm->my_client_index, vcm->my_client_index);
2325
2326   if (VPPCOM_DEBUG > 0)
2327     {
2328       /* *INDENT-OFF* */
2329       ELOG_TYPE_DECLARE (e) =
2330       {
2331         .format = "app_detach:C:%d",
2332         .format_args = "i4",
2333       };
2334
2335       struct
2336       {
2337         u32 data;
2338       } *ed;
2339       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
2340       ed->data = vcm->my_client_index;
2341       /* *INDENT-ON* */
2342     }
2343
2344   vppcom_app_detach ();
2345   rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
2346   if (PREDICT_FALSE (rv))
2347     {
2348       if (VPPCOM_DEBUG > 0)
2349         clib_warning ("VCL<%d>: application detach timed out! "
2350                       "returning %d (%s)",
2351                       getpid (), rv, vppcom_retval_str (rv));
2352     }
2353
2354   /* Finished with logging before client gets reset to ~0 */
2355   if (VPPCOM_DEBUG > 0)
2356     write_elog ();
2357
2358   vl_client_disconnect_from_vlib ();
2359   vcm->my_client_index = ~0;
2360   vcm->app_state = STATE_APP_START;
2361 }
2362
2363 int
2364 vppcom_session_create (u8 proto, u8 is_nonblocking)
2365 {
2366   session_t *session;
2367   u32 session_index;
2368   session_state_t state;
2369   elog_track_t session_elog_track;
2370
2371   clib_spinlock_lock (&vcm->sessions_lockp);
2372   pool_get (vcm->sessions, session);
2373   memset (session, 0, sizeof (*session));
2374   session_index = session - vcm->sessions;
2375
2376   session->proto = proto;
2377   session->state = STATE_START;
2378   state = session->state;
2379   session->vpp_handle = ~0;
2380
2381   if (is_nonblocking)
2382     VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
2383   else
2384     VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
2385
2386   if (VPPCOM_DEBUG > 0)
2387     {
2388       session->elog_track.name =
2389         (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
2390                          session_index, 0);
2391       elog_track_register (&vcm->elog_main, &session->elog_track);
2392       session_elog_track = session->elog_track;
2393     }
2394
2395   clib_spinlock_unlock (&vcm->sessions_lockp);
2396
2397   if (VPPCOM_DEBUG > 0)
2398     clib_warning ("VCL<%d>: sid %u", getpid (), session_index);
2399
2400   if (VPPCOM_DEBUG > 0)
2401     {
2402       /* *INDENT-OFF* */
2403       ELOG_TYPE_DECLARE (e) =
2404       {
2405         .format = "session_create:proto:%d state:%d is_nonblocking:%d",
2406         .format_args = "i4i4i4",
2407       };
2408
2409       struct
2410       {
2411         u32 data[3];
2412       } *ed;
2413
2414       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
2415       ed->data[0] = proto;
2416       ed->data[1] = state;
2417       ed->data[2] = is_nonblocking;
2418       /* *INDENT-ON* */
2419     }
2420
2421   return (int) session_index;
2422 }
2423
2424 int
2425 vppcom_session_close (uint32_t session_index)
2426 {
2427   session_t *session = 0;
2428   int rv;
2429   u8 is_vep;
2430   u8 is_vep_session;
2431   u32 next_sid;
2432   u32 vep_idx;
2433   u64 vpp_handle;
2434   uword *p;
2435   session_state_t state;
2436   elog_track_t session_elog_track;
2437
2438   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2439   is_vep = session->is_vep;
2440   is_vep_session = session->is_vep_session;
2441   next_sid = session->vep.next_sid;
2442   vep_idx = session->vep.vep_idx;
2443   state = session->state;
2444   vpp_handle = session->vpp_handle;
2445   clib_spinlock_unlock (&vcm->sessions_lockp);
2446
2447   /*
2448    * Why two if(VPPCOM_DEBUG) checks?
2449    *
2450    * Eventually all clib_warnings need their own way of being
2451    * logged and signalled (like severity) where event logging
2452    * is a separate debugging tool. It will make the separation
2453    * easier. ... parting is such sweet sorrow ...
2454    */
2455   if (VPPCOM_DEBUG > 0)
2456     {
2457       session_elog_track = session->elog_track;
2458     }
2459
2460   if (VPPCOM_DEBUG > 0)
2461     {
2462       if (is_vep)
2463         clib_warning ("VCL<%d>: vep_idx %u / sid %u: "
2464                       "closing epoll session...",
2465                       getpid (), session_index, session_index);
2466       else
2467         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %d: "
2468                       "closing session...",
2469                       getpid (), vpp_handle, session_index);
2470     }
2471
2472   if (is_vep)
2473     {
2474       while (next_sid != ~0)
2475         {
2476           rv = vppcom_epoll_ctl (session_index, EPOLL_CTL_DEL, next_sid, 0);
2477           if ((VPPCOM_DEBUG > 0) && PREDICT_FALSE (rv < 0))
2478             clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2479                           "EPOLL_CTL_DEL vep_idx %u failed! rv %d (%s)",
2480                           getpid (), vpp_handle, next_sid, vep_idx,
2481                           rv, vppcom_retval_str (rv));
2482
2483           VCL_LOCK_AND_GET_SESSION (session_index, &session);
2484           next_sid = session->vep.next_sid;
2485           clib_spinlock_unlock (&vcm->sessions_lockp);
2486         }
2487     }
2488   else
2489     {
2490       if (is_vep_session)
2491         {
2492           rv = vppcom_epoll_ctl (vep_idx, EPOLL_CTL_DEL, session_index, 0);
2493           if ((VPPCOM_DEBUG > 0) && (rv < 0))
2494             clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2495                           "EPOLL_CTL_DEL vep_idx %u failed! rv %d (%s)",
2496                           getpid (), vpp_handle, session_index,
2497                           vep_idx, rv, vppcom_retval_str (rv));
2498         }
2499
2500       if (state & STATE_LISTEN)
2501         {
2502           rv = vppcom_session_unbind (session_index);
2503           if (PREDICT_FALSE (rv < 0))
2504             {
2505               if (VPPCOM_DEBUG > 0)
2506                 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2507                               "listener unbind failed! rv %d (%s)",
2508                               getpid (), vpp_handle, session_index,
2509                               rv, vppcom_retval_str (rv));
2510             }
2511         }
2512
2513       else if (state & (CLIENT_STATE_OPEN | SERVER_STATE_OPEN))
2514         {
2515           rv = vppcom_session_disconnect (session_index);
2516           if (PREDICT_FALSE (rv < 0))
2517             clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
2518                           "session disconnect failed! rv %d (%s)",
2519                           getpid (), vpp_handle, session_index,
2520                           rv, vppcom_retval_str (rv));
2521         }
2522     }
2523
2524   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2525   vpp_handle = session->vpp_handle;
2526   if (vpp_handle != ~0)
2527     {
2528       p = hash_get (vcm->session_index_by_vpp_handles, vpp_handle);
2529       if (p)
2530         hash_unset (vcm->session_index_by_vpp_handles, vpp_handle);
2531     }
2532   pool_put_index (vcm->sessions, session_index);
2533
2534   clib_spinlock_unlock (&vcm->sessions_lockp);
2535
2536   if (VPPCOM_DEBUG > 0)
2537     {
2538       if (is_vep)
2539         clib_warning ("VCL<%d>: vep_idx %u / sid %u: epoll session removed.",
2540                       getpid (), session_index, session_index);
2541       else
2542         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session removed.",
2543                       getpid (), vpp_handle, session_index);
2544     }
2545 done:
2546
2547   if (VPPCOM_DEBUG > 0)
2548     {
2549       /* *INDENT-OFF* */
2550       ELOG_TYPE_DECLARE (e) =
2551       {
2552         .format = "session_close:rv:%d",
2553         .format_args = "i4",
2554       };
2555
2556       struct
2557       {
2558         u32 data;
2559       } *ed;
2560
2561       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
2562       ed->data = rv;
2563       /* *INDENT-ON* */
2564     }
2565
2566   return rv;
2567 }
2568
2569 int
2570 vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
2571 {
2572   session_t *session = 0;
2573   int rv;
2574
2575   if (!ep || !ep->ip)
2576     return VPPCOM_EINVAL;
2577
2578   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2579
2580   if (session->is_vep)
2581     {
2582       clib_spinlock_unlock (&vcm->sessions_lockp);
2583       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
2584                     "bind to an epoll session!", getpid (), session_index);
2585       rv = VPPCOM_EBADFD;
2586       goto done;
2587     }
2588
2589   session->lcl_addr.is_ip4 = ep->is_ip4;
2590   session->lcl_addr.ip46 = to_ip46 (!ep->is_ip4, ep->ip);
2591   session->lcl_port = ep->port;
2592
2593   if (VPPCOM_DEBUG > 0)
2594     clib_warning ("VCL<%d>: sid %u: binding to local %s address %U "
2595                   "port %u, proto %s", getpid (), session_index,
2596                   session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2597                   format_ip46_address, &session->lcl_addr.ip46,
2598                   session->lcl_addr.is_ip4,
2599                   clib_net_to_host_u16 (session->lcl_port),
2600                   session->proto ? "UDP" : "TCP");
2601
2602   if (VPPCOM_DEBUG > 0)
2603     {
2604       if (session->lcl_addr.is_ip4)
2605         {
2606           /* *INDENT-OFF* */
2607           ELOG_TYPE_DECLARE (e) =
2608           {
2609             .format = "bind local:%s:%d.%d.%d.%d:%d ",
2610             .format_args = "t1i1i1i1i1i2",
2611             .n_enum_strings = 2,
2612             .enum_strings = {"TCP", "UDP",},
2613           };
2614
2615           CLIB_PACKED (struct {
2616             u8 proto;
2617             u8 addr[4];
2618             u16 port;
2619           }) *ed;
2620
2621           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
2622           ed->proto = session->proto;
2623           ed->addr[0] = session->lcl_addr.ip46.ip4.as_u8[0];
2624           ed->addr[1] = session->lcl_addr.ip46.ip4.as_u8[1];
2625           ed->addr[2] = session->lcl_addr.ip46.ip4.as_u8[2];
2626           ed->addr[3] = session->lcl_addr.ip46.ip4.as_u8[3];
2627           ed->port = clib_net_to_host_u16 (session->lcl_port);
2628           /* *INDENT-ON* */
2629         }
2630     }
2631
2632   clib_spinlock_unlock (&vcm->sessions_lockp);
2633 done:
2634   return rv;
2635 }
2636
2637 int
2638 vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
2639 {
2640   session_t *listen_session = 0;
2641   u64 listen_vpp_handle;
2642   int rv, retval;
2643
2644   if (q_len == 0 || q_len == ~0)
2645     q_len = vcm->cfg.listen_queue_size;
2646
2647   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2648
2649   if (listen_session->is_vep)
2650     {
2651       clib_spinlock_unlock (&vcm->sessions_lockp);
2652       clib_warning ("VCL<%d>: ERROR: sid %u: cannot listen on an "
2653                     "epoll session!", getpid (), listen_session_index);
2654       rv = VPPCOM_EBADFD;
2655       goto done;
2656     }
2657
2658   listen_vpp_handle = listen_session->vpp_handle;
2659   if (listen_session->state & STATE_LISTEN)
2660     {
2661       clib_spinlock_unlock (&vcm->sessions_lockp);
2662       if (VPPCOM_DEBUG > 0)
2663         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2664                       "already in listen state!",
2665                       getpid (), listen_vpp_handle, listen_session_index);
2666       rv = VPPCOM_OK;
2667       goto done;
2668     }
2669
2670   if (VPPCOM_DEBUG > 0)
2671     clib_warning ("VCL<%d>: vpp handle 0x%llx, "
2672                   "sid %u: sending bind request...",
2673                   getpid (), listen_vpp_handle, listen_session_index);
2674
2675   vppcom_send_bind_sock (listen_session, listen_session_index);
2676   clib_spinlock_unlock (&vcm->sessions_lockp);
2677   retval =
2678     vppcom_wait_for_session_state_change (listen_session_index, STATE_LISTEN,
2679                                           vcm->cfg.session_timeout);
2680
2681   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2682   if (PREDICT_FALSE (retval))
2683     {
2684       if (VPPCOM_DEBUG > 0)
2685         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: bind failed! "
2686                       "returning %d (%s)", getpid (),
2687                       listen_session->vpp_handle, listen_session_index,
2688                       retval, vppcom_retval_str (retval));
2689       clib_spinlock_unlock (&vcm->sessions_lockp);
2690       rv = retval;
2691       goto done;
2692     }
2693
2694   clib_fifo_validate (vcm->client_session_index_fifo, q_len);
2695   clib_spinlock_unlock (&vcm->sessions_lockp);
2696 done:
2697   return rv;
2698 }
2699
2700 int
2701 validate_args_session_accept_ (session_t * listen_session)
2702 {
2703   u32 listen_session_index = listen_session - vcm->sessions;
2704
2705   /* Input validation - expects spinlock on sessions_lockp */
2706   if (listen_session->is_vep)
2707     {
2708       clib_warning ("VCL<%d>: ERROR: sid %u: cannot accept on an "
2709                     "epoll session!", getpid (), listen_session_index);
2710       return VPPCOM_EBADFD;
2711     }
2712
2713   if (listen_session->state != STATE_LISTEN)
2714     {
2715       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
2716                     "not in listen state! state 0x%x (%s)", getpid (),
2717                     listen_session->vpp_handle, listen_session_index,
2718                     listen_session->state,
2719                     vppcom_session_state_str (listen_session->state));
2720       return VPPCOM_EBADFD;
2721     }
2722   return VPPCOM_OK;
2723 }
2724
2725 int
2726 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
2727                        uint32_t flags)
2728 {
2729   session_t *listen_session = 0;
2730   session_t *client_session = 0;
2731   u32 client_session_index = ~0;
2732   int rv;
2733   u64 listen_vpp_handle;
2734   vce_event_handler_reg_t *reg;
2735   vce_event_t *ev;
2736   vce_event_connect_request_t *result;
2737   struct timespec ts;
2738   struct timeval tv;
2739   int millisecond_timeout = 1;
2740   int hours_timeout = 20 * 60 * 60;
2741
2742   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2743   listen_vpp_handle = listen_session->vpp_handle;       // For debugging
2744
2745   rv = validate_args_session_accept_ (listen_session);
2746   if (rv)
2747     {
2748       clib_spinlock_unlock (&vcm->sessions_lockp);
2749       goto done;
2750     }
2751
2752   /* Using an aggressive timer of 1ms and a generous timer of
2753    * 20 hours, we can implement a blocking and non-blocking listener
2754    * as both event and time driven */
2755   gettimeofday (&tv, NULL);
2756   ts.tv_nsec = (tv.tv_usec * 1000) + (1000 * millisecond_timeout);
2757   ts.tv_sec = tv.tv_sec;
2758
2759   /* Predict that the Listener is blocking more often than not */
2760   if (PREDICT_TRUE (!VCL_SESS_ATTR_TEST (listen_session->attr,
2761                                          VCL_SESS_ATTR_NONBLOCK)))
2762     ts.tv_sec += hours_timeout;
2763
2764   clib_spinlock_unlock (&vcm->sessions_lockp);
2765
2766   /* Register handler for connect_request event on listen_session_index */
2767   vce_event_key_t evk;
2768   evk.session_index = listen_session_index;
2769   evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
2770   reg = vce_register_handler (&vcm->event_thread, &evk,
2771                               vce_connect_request_handler_fn);
2772   ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
2773
2774   result = (vce_event_connect_request_t *) ev->data;
2775   pthread_mutex_lock (&reg->handler_lock);
2776   while (!result->handled)
2777     {
2778       rv =
2779         pthread_cond_timedwait (&reg->handler_cond, &reg->handler_lock, &ts);
2780       if (rv == ETIMEDOUT)
2781         {
2782           rv = VPPCOM_EAGAIN;
2783           goto cleanup;
2784         }
2785     }
2786   client_session_index = result->accepted_session_index;
2787
2788
2789
2790   /* Remove from the FIFO used to service epoll */
2791   clib_spinlock_lock (&vcm->sessions_lockp);
2792   if (clib_fifo_elts (vcm->client_session_index_fifo))
2793     {
2794       u32 tmp_client_session_index;
2795       clib_fifo_sub1 (vcm->client_session_index_fifo,
2796                       tmp_client_session_index);
2797       if (tmp_client_session_index != client_session_index)
2798         clib_fifo_add1 (vcm->client_session_index_fifo,
2799                         tmp_client_session_index);
2800     }
2801   clib_spinlock_unlock (&vcm->sessions_lockp);
2802
2803   rv = vppcom_session_at_index (client_session_index, &client_session);
2804   if (PREDICT_FALSE (rv))
2805     {
2806       rv = VPPCOM_ECONNABORTED;
2807       clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: client sid %u "
2808                     "lookup failed! returning %d (%s)", getpid (),
2809                     listen_vpp_handle, listen_session_index,
2810                     client_session_index, rv, vppcom_retval_str (rv));
2811       goto done;
2812     }
2813
2814   if (flags & O_NONBLOCK)
2815     VCL_SESS_ATTR_SET (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
2816   else
2817     VCL_SESS_ATTR_CLR (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
2818
2819   if (VPPCOM_DEBUG > 0)
2820     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: Got a client request! "
2821                   "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
2822                   getpid (), listen_vpp_handle, listen_session_index,
2823                   client_session->vpp_handle, client_session_index,
2824                   flags, VCL_SESS_ATTR_TEST (client_session->attr,
2825                                              VCL_SESS_ATTR_NONBLOCK));
2826
2827   if (ep)
2828     {
2829       ep->is_ip4 = client_session->peer_addr.is_ip4;
2830       ep->port = client_session->peer_port;
2831       if (client_session->peer_addr.is_ip4)
2832         clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip4,
2833                      sizeof (ip4_address_t));
2834       else
2835         clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip6,
2836                      sizeof (ip6_address_t));
2837     }
2838
2839   vppcom_send_accept_session_reply (client_session->vpp_handle,
2840                                     client_session->client_context,
2841                                     0 /* retval OK */ );
2842
2843   if (VPPCOM_DEBUG > 0)
2844     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: accepted vpp handle "
2845                   "0x%llx, sid %u connection to local %s address "
2846                   "%U port %u", getpid (), listen_vpp_handle,
2847                   listen_session_index, client_session->vpp_handle,
2848                   client_session_index,
2849                   client_session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2850                   format_ip46_address, &client_session->lcl_addr.ip46,
2851                   client_session->lcl_addr.is_ip4,
2852                   clib_net_to_host_u16 (client_session->lcl_port));
2853
2854   if (VPPCOM_DEBUG > 0)
2855     {
2856       client_session->elog_track.name =
2857         (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
2858                          client_session_index, 0);
2859       elog_track_register (&vcm->elog_main, &client_session->elog_track);
2860
2861       // Two elog entries due to 20-byte per entry constraint.
2862       /* *INDENT-OFF* */
2863       ELOG_TYPE_DECLARE (e) =
2864       {
2865         .format = "accept: listen_handle:%x from_handle:%x",
2866         .format_args = "i8i8",
2867       };
2868
2869       struct
2870       {
2871         u64 handle[2];
2872       } *ed;
2873
2874       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, client_session->elog_track);
2875       ed->handle[0] = listen_vpp_handle;
2876       ed->handle[1] = client_session->vpp_handle;
2877       /* *INDENT-ON* */
2878
2879       if (client_session->lcl_addr.is_ip4)
2880         {
2881           /* *INDENT-OFF* */
2882           ELOG_TYPE_DECLARE (e2) =
2883           {
2884             .format = "accept: S:%d %d.%d.%d.%d:%d ",
2885             .format_args = "i4i1i1i1i1i2",
2886           };
2887
2888           CLIB_PACKED (struct {
2889             u32 session;
2890             u8 addr[4];
2891             u16 port;
2892           }) *ed2;
2893
2894           ed2 =
2895             ELOG_TRACK_DATA (&vcm->elog_main, e2, client_session->elog_track);
2896           ed2->session = client_session_index;
2897           ed2->addr[0] = client_session->lcl_addr.ip46.ip4.as_u8[0];
2898           ed2->addr[1] = client_session->lcl_addr.ip46.ip4.as_u8[1];
2899           ed2->addr[2] = client_session->lcl_addr.ip46.ip4.as_u8[2];
2900           ed2->addr[3] = client_session->lcl_addr.ip46.ip4.as_u8[3];
2901           ed2->port = clib_net_to_host_u16 (client_session->lcl_port);
2902           /* *INDENT-ON* */
2903         }
2904     }
2905
2906   clib_spinlock_unlock (&vcm->sessions_lockp);
2907   rv = (int) client_session_index;
2908
2909   vce_clear_event (&vcm->event_thread, ev);
2910 cleanup:
2911   vce_unregister_handler (&vcm->event_thread, ev);
2912   pthread_mutex_unlock (&reg->handler_lock);
2913 done:
2914   return rv;
2915 }
2916
2917 int
2918 vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
2919 {
2920   session_t *session = 0;
2921   u64 vpp_handle = 0;
2922   int rv, retval = VPPCOM_OK;
2923
2924   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2925
2926   if (PREDICT_FALSE (session->is_vep))
2927     {
2928       clib_spinlock_unlock (&vcm->sessions_lockp);
2929       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
2930                     "connect on an epoll session!", getpid (), session_index);
2931       rv = VPPCOM_EBADFD;
2932       goto done;
2933     }
2934
2935   if (PREDICT_FALSE (session->state & CLIENT_STATE_OPEN))
2936     {
2937       if (VPPCOM_DEBUG > 0)
2938         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session already "
2939                       "connected to %s %U port %d proto %s, state 0x%x (%s)",
2940                       getpid (), session->vpp_handle, session_index,
2941                       session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
2942                       format_ip46_address,
2943                       &session->peer_addr.ip46, session->peer_addr.is_ip4,
2944                       clib_net_to_host_u16 (session->peer_port),
2945                       session->proto ? "UDP" : "TCP", session->state,
2946                       vppcom_session_state_str (session->state));
2947
2948       clib_spinlock_unlock (&vcm->sessions_lockp);
2949       goto done;
2950     }
2951
2952   session->peer_addr.is_ip4 = server_ep->is_ip4;
2953   session->peer_addr.ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip);
2954   session->peer_port = server_ep->port;
2955
2956   if (VPPCOM_DEBUG > 0)
2957     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connecting to server "
2958                   "%s %U port %d proto %s",
2959                   getpid (), session->vpp_handle, session_index,
2960                   session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
2961                   format_ip46_address,
2962                   &session->peer_addr.ip46, session->peer_addr.is_ip4,
2963                   clib_net_to_host_u16 (session->peer_port),
2964                   session->proto ? "UDP" : "TCP");
2965
2966   vppcom_send_connect_sock (session, session_index);
2967   clib_spinlock_unlock (&vcm->sessions_lockp);
2968
2969   retval =
2970     vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
2971                                           vcm->cfg.session_timeout);
2972
2973   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2974   vpp_handle = session->vpp_handle;
2975   clib_spinlock_unlock (&vcm->sessions_lockp);
2976
2977 done:
2978   if (PREDICT_FALSE (retval))
2979     {
2980       rv = retval;
2981       if (VPPCOM_DEBUG > 0)
2982         {
2983           if (session)
2984             clib_warning
2985               ("VCL<%d>: vpp handle 0x%llx, sid %u: connect failed! "
2986                "returning %d (%s)", getpid (), vpp_handle,
2987                session_index, rv, vppcom_retval_str (rv));
2988           else
2989             clib_warning ("VCL<%d>: no session for sid %u: connect failed! "
2990                           "returning %d (%s)", getpid (),
2991                           session_index, rv, vppcom_retval_str (rv));
2992         }
2993     }
2994   else if (VPPCOM_DEBUG > 0)
2995     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connected!",
2996                   getpid (), vpp_handle, session_index);
2997
2998   return rv;
2999 }
3000
3001 static inline int
3002 vppcom_session_read_internal (uint32_t session_index, void *buf, int n,
3003                               u8 peek)
3004 {
3005   session_t *session = 0;
3006   svm_fifo_t *rx_fifo;
3007   int n_read = 0;
3008   int rv;
3009   int is_nonblocking;
3010
3011   u64 vpp_handle;
3012   u32 poll_et;
3013   session_state_t state;
3014
3015   ASSERT (buf);
3016
3017   VCL_LOCK_AND_GET_SESSION (session_index, &session);
3018
3019   is_nonblocking = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
3020   rx_fifo = session->rx_fifo;
3021   state = session->state;
3022   vpp_handle = session->vpp_handle;
3023
3024   if (PREDICT_FALSE (session->is_vep))
3025     {
3026       clib_spinlock_unlock (&vcm->sessions_lockp);
3027       clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
3028                     "read from an epoll session!", getpid (), session_index);
3029       rv = VPPCOM_EBADFD;
3030       goto done;
3031     }
3032
3033   if (PREDICT_FALSE (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN))))
3034     {
3035       clib_spinlock_unlock (&vcm->sessions_lockp);
3036       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
3037
3038       if (VPPCOM_DEBUG > 0)
3039         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: %s session is "
3040                       "not open! state 0x%x (%s), returning %d (%s)",
3041                       getpid (), vpp_handle, session_index, state,
3042                       vppcom_session_state_str (state),
3043                       rv, vppcom_retval_str (rv));
3044       goto done;
3045     }
3046
3047   clib_spinlock_unlock (&vcm->sessions_lockp);
3048
3049   do
3050     {
3051       if (peek)
3052         n_read = svm_fifo_peek (rx_fifo, 0, n, buf);
3053       else
3054         n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf);
3055     }
3056   while (!is_nonblocking && (n_read <= 0));
3057
3058   if (n_read <= 0)
3059     {
3060       VCL_LOCK_AND_GET_SESSION (session_index, &session);
3061
3062       poll_et = (((EPOLLET | EPOLLIN) & session->vep.ev.events) ==
3063                  (EPOLLET | EPOLLIN));
3064       if (poll_et)
3065         session->vep.et_mask |= EPOLLIN;
3066
3067       if (state & STATE_CLOSE_ON_EMPTY)
3068         {
3069           rv = VPPCOM_ECONNRESET;
3070
3071           if (VPPCOM_DEBUG > 1)
3072             {
3073               clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: Empty fifo "
3074                             "with session state 0x%x (%s)!"
3075                             "  Setting state to 0x%x (%s), returning %d (%s)",
3076                             getpid (), session->vpp_handle, session_index,
3077                             state, vppcom_session_state_str (state),
3078                             STATE_DISCONNECT,
3079                             vppcom_session_state_str (STATE_DISCONNECT), rv,
3080                             vppcom_retval_str (rv));
3081             }
3082
3083           session->state = STATE_DISCONNECT;
3084         }
3085       else
3086         rv = VPPCOM_EAGAIN;
3087
3088       clib_spinlock_unlock (&vcm->sessions_lockp);
3089     }
3090   else
3091     rv = n_read;
3092
3093   if (VPPCOM_DEBUG > 2)
3094     {
3095       if (rv > 0)
3096         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: read %d bytes "
3097                       "from (%p)", getpid (), vpp_handle,
3098                       session_index, n_read, rx_fifo);
3099       else
3100         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: nothing read! "
3101                       "returning %d (%s)", getpid (), vpp_handle,
3102                       session_index, rv, vppcom_retval_str (rv));
3103     }
3104 done:
3105   return rv;
3106 }
3107
3108 int
3109 vppcom_session_read (uint32_t session_index, void *buf, size_t n)
3110 {
3111   return (vppcom_session_read_internal (session_index, buf, n, 0));
3112 }
3113
3114 static int
3115 vppcom_session_peek (uint32_t session_index, void *buf, int n)
3116 {
3117   return (vppcom_session_read_internal (session_index, buf, n, 1));
3118 }
3119
3120 static inline int
3121 vppcom_session_read_ready (session_t * session, u32 session_index)
3122 {
3123   int ready = 0;
3124   u32 poll_et;
3125   int rv;
3126   session_state_t state = session->state;
3127   u64 vpp_handle = session->vpp_handle;
3128
3129   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3130   if (PREDICT_FALSE (session->is_vep))
3131     {
3132       clib_warning ("VCL<%d>: ERROR: sid %u: cannot read from an "
3133                     "epoll session!", getpid (), session_index);
3134       rv = VPPCOM_EBADFD;
3135       goto done;
3136     }
3137
3138   if (session->state & STATE_LISTEN)
3139     {
3140       ready = clib_fifo_elts (vcm->client_session_index_fifo);
3141     }
3142   else
3143     {
3144       if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN | STATE_LISTEN)))
3145         {
3146           rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3147                 VPPCOM_ENOTCONN);
3148
3149           if (VPPCOM_DEBUG > 1)
3150             clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session is "
3151                           "not open! state 0x%x (%s), returning %d (%s)",
3152                           getpid (), vpp_handle, session_index,
3153                           state, vppcom_session_state_str (state),
3154                           rv, vppcom_retval_str (rv));
3155           goto done;
3156         }
3157
3158       ready = svm_fifo_max_dequeue (session->rx_fifo);
3159     }
3160
3161   if (ready == 0)
3162     {
3163       poll_et =
3164         ((EPOLLET | EPOLLIN) & session->vep.ev.events) == (EPOLLET | EPOLLIN);
3165       if (poll_et)
3166         session->vep.et_mask |= EPOLLIN;
3167
3168       if (state & STATE_CLOSE_ON_EMPTY)
3169         {
3170           rv = VPPCOM_ECONNRESET;
3171
3172           if (VPPCOM_DEBUG > 1)
3173             {
3174               clib_warning ("VCL<%d>: vpp handle 0x%llx, "
3175                             "sid %u: Empty fifo with"
3176                             " session state 0x%x (%s)! Setting state to "
3177                             "0x%x (%s), returning %d (%s)",
3178                             getpid (), session_index, vpp_handle,
3179                             state, vppcom_session_state_str (state),
3180                             STATE_DISCONNECT,
3181                             vppcom_session_state_str (STATE_DISCONNECT), rv,
3182                             vppcom_retval_str (rv));
3183             }
3184           session->state = STATE_DISCONNECT;
3185           goto done;
3186         }
3187     }
3188   rv = ready;
3189
3190   if (vcm->app_event_queue->cursize &&
3191       !pthread_mutex_trylock (&vcm->app_event_queue->mutex))
3192     {
3193       u32 i, n_to_dequeue = vcm->app_event_queue->cursize;
3194       session_fifo_event_t e;
3195
3196       for (i = 0; i < n_to_dequeue; i++)
3197         svm_queue_sub_raw (vcm->app_event_queue, (u8 *) & e);
3198
3199       pthread_mutex_unlock (&vcm->app_event_queue->mutex);
3200     }
3201 done:
3202   return rv;
3203 }
3204
3205 int
3206 vppcom_session_write (uint32_t session_index, void *buf, size_t n)
3207 {
3208   session_t *session = 0;
3209   svm_fifo_t *tx_fifo = 0;
3210   svm_queue_t *q;
3211   session_fifo_event_t evt;
3212   session_state_t state;
3213   int rv, n_write, is_nonblocking;
3214   u32 poll_et;
3215   u64 vpp_handle;
3216
3217   ASSERT (buf);
3218
3219   VCL_LOCK_AND_GET_SESSION (session_index, &session);
3220
3221   tx_fifo = session->tx_fifo;
3222   is_nonblocking = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
3223   vpp_handle = session->vpp_handle;
3224   state = session->state;
3225
3226   if (PREDICT_FALSE (session->is_vep))
3227     {
3228       clib_spinlock_unlock (&vcm->sessions_lockp);
3229       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3230                     "cannot write to an epoll session!",
3231                     getpid (), vpp_handle, session_index);
3232
3233       rv = VPPCOM_EBADFD;
3234       goto done;
3235     }
3236
3237   if (!(session->state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3238     {
3239       rv =
3240         ((session->state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3241          VPPCOM_ENOTCONN);
3242
3243       clib_spinlock_unlock (&vcm->sessions_lockp);
3244       if (VPPCOM_DEBUG > 1)
3245         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3246                       "session is not open! state 0x%x (%s)",
3247                       getpid (), vpp_handle, session_index,
3248                       state, vppcom_session_state_str (state));
3249       goto done;
3250     }
3251
3252   clib_spinlock_unlock (&vcm->sessions_lockp);
3253
3254   do
3255     {
3256       n_write = svm_fifo_enqueue_nowait (tx_fifo, n, (void *) buf);
3257     }
3258   while (!is_nonblocking && (n_write <= 0));
3259
3260   /* If event wasn't set, add one */
3261   if ((n_write > 0) && svm_fifo_set_event (tx_fifo))
3262     {
3263       /* Fabricate TX event, send to vpp */
3264       evt.fifo = tx_fifo;
3265       evt.event_type = FIFO_EVENT_APP_TX;
3266
3267       VCL_LOCK_AND_GET_SESSION (session_index, &session);
3268       q = session->vpp_event_queue;
3269       ASSERT (q);
3270       svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
3271       clib_spinlock_unlock (&vcm->sessions_lockp);
3272       if (VPPCOM_DEBUG > 1)
3273         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3274                       "added FIFO_EVENT_APP_TX to "
3275                       "vpp_event_q %p, n_write %d", getpid (),
3276                       vpp_handle, session_index, q, n_write);
3277     }
3278
3279   if (n_write <= 0)
3280     {
3281       VCL_LOCK_AND_GET_SESSION (session_index, &session);
3282
3283       poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3284                  (EPOLLET | EPOLLOUT));
3285       if (poll_et)
3286         session->vep.et_mask |= EPOLLOUT;
3287
3288       if (session->state & STATE_CLOSE_ON_EMPTY)
3289         {
3290           rv = VPPCOM_ECONNRESET;
3291
3292           if (VPPCOM_DEBUG > 1)
3293             {
3294               clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3295                             "Empty fifo with session state 0x%x (%s)!"
3296                             "  Setting state to 0x%x (%s), returning %d (%s)",
3297                             getpid (), session->vpp_handle, session_index,
3298                             session->state,
3299                             vppcom_session_state_str (session->state),
3300                             STATE_DISCONNECT,
3301                             vppcom_session_state_str (STATE_DISCONNECT), rv,
3302                             vppcom_retval_str (rv));
3303             }
3304
3305           session->state = STATE_DISCONNECT;
3306         }
3307       else
3308         rv = VPPCOM_EAGAIN;
3309
3310       clib_spinlock_unlock (&vcm->sessions_lockp);
3311     }
3312   else
3313     rv = n_write;
3314
3315   if (VPPCOM_DEBUG > 2)
3316     {
3317       if (n_write <= 0)
3318         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3319                       "FIFO-FULL (%p)", getpid (), vpp_handle,
3320                       session_index, tx_fifo);
3321       else
3322         clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3323                       "wrote %d bytes tx-fifo: (%p)", getpid (),
3324                       vpp_handle, session_index, n_write, tx_fifo);
3325     }
3326 done:
3327   return rv;
3328 }
3329
3330 static inline int
3331 vppcom_session_write_ready (session_t * session, u32 session_index)
3332 {
3333   int ready;
3334   u32 poll_et;
3335   int rv;
3336
3337   ASSERT (session);
3338
3339   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3340   if (PREDICT_FALSE (session->is_vep))
3341     {
3342       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3343                     "cannot write to an epoll session!",
3344                     getpid (), session->vpp_handle, session_index);
3345       rv = VPPCOM_EBADFD;
3346       goto done;
3347     }
3348
3349   if (PREDICT_FALSE (session->state & STATE_LISTEN))
3350     {
3351       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3352                     "cannot write to a listen session!",
3353                     getpid (), session->vpp_handle, session_index);
3354       rv = VPPCOM_EBADFD;
3355       goto done;
3356     }
3357
3358   if (!(session->state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3359     {
3360       session_state_t state = session->state;
3361
3362       rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
3363
3364       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3365                     "session is not open! state 0x%x (%s), "
3366                     "returning %d (%s)", getpid (), session->vpp_handle,
3367                     session_index,
3368                     state, vppcom_session_state_str (state),
3369                     rv, vppcom_retval_str (rv));
3370       goto done;
3371     }
3372
3373   ready = svm_fifo_max_enqueue (session->tx_fifo);
3374
3375   if (VPPCOM_DEBUG > 3)
3376     clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3377                   "peek %s (%p), ready = %d", getpid (),
3378                   session->vpp_handle, session_index,
3379                   session->tx_fifo, ready);
3380
3381   if (ready == 0)
3382     {
3383       poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3384                  (EPOLLET | EPOLLOUT));
3385       if (poll_et)
3386         session->vep.et_mask |= EPOLLOUT;
3387
3388       if (session->state & STATE_CLOSE_ON_EMPTY)
3389         {
3390           rv = VPPCOM_ECONNRESET;
3391
3392           if (VPPCOM_DEBUG > 1)
3393             {
3394               clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3395                             "Empty fifo with session "
3396                             "state 0x%x (%s)! Setting state to 0x%x (%s), "
3397                             "returning %d (%s)", getpid (),
3398                             session->vpp_handle, session_index,
3399                             session->state,
3400                             vppcom_session_state_str (session->state),
3401                             STATE_DISCONNECT,
3402                             vppcom_session_state_str (STATE_DISCONNECT), rv,
3403                             vppcom_retval_str (rv));
3404             }
3405           session->state = STATE_DISCONNECT;
3406           goto done;
3407         }
3408     }
3409   rv = ready;
3410 done:
3411   return rv;
3412 }
3413
3414 int
3415 vppcom_select (unsigned long n_bits, unsigned long *read_map,
3416                unsigned long *write_map, unsigned long *except_map,
3417                double time_to_wait)
3418 {
3419   u32 session_index;
3420   session_t *session = 0;
3421   int rv, bits_set = 0;
3422   f64 timeout = clib_time_now (&vcm->clib_time) + time_to_wait;
3423   u32 minbits = clib_max (n_bits, BITS (uword));
3424
3425   ASSERT (sizeof (clib_bitmap_t) == sizeof (long int));
3426
3427   if (n_bits && read_map)
3428     {
3429       clib_bitmap_validate (vcm->rd_bitmap, minbits);
3430       clib_memcpy (vcm->rd_bitmap, read_map,
3431                    vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
3432       memset (read_map, 0, vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
3433     }
3434   if (n_bits && write_map)
3435     {
3436       clib_bitmap_validate (vcm->wr_bitmap, minbits);
3437       clib_memcpy (vcm->wr_bitmap, write_map,
3438                    vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
3439       memset (write_map, 0,
3440               vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
3441     }
3442   if (n_bits && except_map)
3443     {
3444       clib_bitmap_validate (vcm->ex_bitmap, minbits);
3445       clib_memcpy (vcm->ex_bitmap, except_map,
3446                    vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
3447       memset (except_map, 0,
3448               vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
3449     }
3450
3451   do
3452     {
3453       /* *INDENT-OFF* */
3454       if (n_bits)
3455         {
3456           if (read_map)
3457             {
3458               clib_bitmap_foreach (session_index, vcm->rd_bitmap,
3459                 ({
3460                   clib_spinlock_lock (&vcm->sessions_lockp);
3461                   rv = vppcom_session_at_index (session_index, &session);
3462                   if (rv < 0)
3463                     {
3464                       clib_spinlock_unlock (&vcm->sessions_lockp);
3465                       if (VPPCOM_DEBUG > 1)
3466                         clib_warning ("VCL<%d>: session %d specified in "
3467                                       "read_map is closed.", getpid (),
3468                                       session_index);
3469                       bits_set = VPPCOM_EBADFD;
3470                       goto select_done;
3471                     }
3472
3473                   rv = vppcom_session_read_ready (session, session_index);
3474                   clib_spinlock_unlock (&vcm->sessions_lockp);
3475                   if (except_map && vcm->ex_bitmap &&
3476                       clib_bitmap_get (vcm->ex_bitmap, session_index) &&
3477                       (rv < 0))
3478                     {
3479                       clib_bitmap_set_no_check (except_map, session_index, 1);
3480                       bits_set++;
3481                     }
3482                   else if (rv > 0)
3483                     {
3484                       clib_bitmap_set_no_check (read_map, session_index, 1);
3485                       bits_set++;
3486                     }
3487                 }));
3488             }
3489
3490           if (write_map)
3491             {
3492               clib_bitmap_foreach (session_index, vcm->wr_bitmap,
3493                 ({
3494                   clib_spinlock_lock (&vcm->sessions_lockp);
3495                   rv = vppcom_session_at_index (session_index, &session);
3496                   if (rv < 0)
3497                     {
3498                       clib_spinlock_unlock (&vcm->sessions_lockp);
3499                       if (VPPCOM_DEBUG > 0)
3500                         clib_warning ("VCL<%d>: session %d specified in "
3501                                       "write_map is closed.", getpid (),
3502                                       session_index);
3503                       bits_set = VPPCOM_EBADFD;
3504                       goto select_done;
3505                     }
3506
3507                   rv = vppcom_session_write_ready (session, session_index);
3508                   clib_spinlock_unlock (&vcm->sessions_lockp);
3509                   if (write_map && (rv > 0))
3510                     {
3511                       clib_bitmap_set_no_check (write_map, session_index, 1);
3512                       bits_set++;
3513                     }
3514                 }));
3515             }
3516
3517           if (except_map)
3518             {
3519               clib_bitmap_foreach (session_index, vcm->ex_bitmap,
3520                 ({
3521                   clib_spinlock_lock (&vcm->sessions_lockp);
3522                   rv = vppcom_session_at_index (session_index, &session);
3523                   if (rv < 0)
3524                     {
3525                       clib_spinlock_unlock (&vcm->sessions_lockp);
3526                       if (VPPCOM_DEBUG > 1)
3527                         clib_warning ("VCL<%d>: session %d specified in "
3528                                       "except_map is closed.", getpid (),
3529                                       session_index);
3530                       bits_set = VPPCOM_EBADFD;
3531                       goto select_done;
3532                     }
3533
3534                   rv = vppcom_session_read_ready (session, session_index);
3535                   clib_spinlock_unlock (&vcm->sessions_lockp);
3536                   if (rv < 0)
3537                     {
3538                       clib_bitmap_set_no_check (except_map, session_index, 1);
3539                       bits_set++;
3540                     }
3541                 }));
3542             }
3543         }
3544       /* *INDENT-ON* */
3545     }
3546   while ((time_to_wait == -1) || (clib_time_now (&vcm->clib_time) < timeout));
3547
3548 select_done:
3549   return (bits_set);
3550 }
3551
3552 static inline void
3553 vep_verify_epoll_chain (u32 vep_idx)
3554 {
3555   session_t *session;
3556   vppcom_epoll_t *vep;
3557   int rv;
3558   u32 sid = vep_idx;
3559
3560   if (VPPCOM_DEBUG <= 1)
3561     return;
3562
3563   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3564   rv = vppcom_session_at_index (vep_idx, &session);
3565   if (PREDICT_FALSE (rv))
3566     {
3567       clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!",
3568                     getpid (), vep_idx);
3569       goto done;
3570     }
3571   if (PREDICT_FALSE (!session->is_vep))
3572     {
3573       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
3574                     getpid (), vep_idx);
3575       goto done;
3576     }
3577   vep = &session->vep;
3578   clib_warning ("VCL<%d>: vep_idx (%u): Dumping epoll chain\n"
3579                 "{\n"
3580                 "   is_vep         = %u\n"
3581                 "   is_vep_session = %u\n"
3582                 "   next_sid       = 0x%x (%u)\n"
3583                 "   wait_cont_idx  = 0x%x (%u)\n"
3584                 "}\n", getpid (), vep_idx,
3585                 session->is_vep, session->is_vep_session,
3586                 vep->next_sid, vep->next_sid,
3587                 session->wait_cont_idx, session->wait_cont_idx);
3588
3589   for (sid = vep->next_sid; sid != ~0; sid = vep->next_sid)
3590     {
3591       rv = vppcom_session_at_index (sid, &session);
3592       if (PREDICT_FALSE (rv))
3593         {
3594           clib_warning ("VCL<%d>: ERROR: Invalid sid (%u)!", getpid (), sid);
3595           goto done;
3596         }
3597       if (PREDICT_FALSE (session->is_vep))
3598         clib_warning ("VCL<%d>: ERROR: sid (%u) is a vep!",
3599                       getpid (), vep_idx);
3600       else if (PREDICT_FALSE (!session->is_vep_session))
3601         {
3602           clib_warning ("VCL<%d>: ERROR: session (%u) "
3603                         "is not a vep session!", getpid (), sid);
3604           goto done;
3605         }
3606       vep = &session->vep;
3607       if (PREDICT_FALSE (vep->vep_idx != vep_idx))
3608         clib_warning ("VCL<%d>: ERROR: session (%u) vep_idx (%u) != "
3609                       "vep_idx (%u)!", getpid (),
3610                       sid, session->vep.vep_idx, vep_idx);
3611       if (session->is_vep_session)
3612         {
3613           clib_warning ("vep_idx[%u]: sid 0x%x (%u)\n"
3614                         "{\n"
3615                         "   next_sid       = 0x%x (%u)\n"
3616                         "   prev_sid       = 0x%x (%u)\n"
3617                         "   vep_idx        = 0x%x (%u)\n"
3618                         "   ev.events      = 0x%x\n"
3619                         "   ev.data.u64    = 0x%llx\n"
3620                         "   et_mask        = 0x%x\n"
3621                         "}\n",
3622                         vep_idx, sid, sid,
3623                         vep->next_sid, vep->next_sid,
3624                         vep->prev_sid, vep->prev_sid,
3625                         vep->vep_idx, vep->vep_idx,
3626                         vep->ev.events, vep->ev.data.u64, vep->et_mask);
3627         }
3628     }
3629
3630 done:
3631   clib_warning ("VCL<%d>: vep_idx (%u): Dump complete!\n",
3632                 getpid (), vep_idx);
3633 }
3634
3635 int
3636 vppcom_epoll_create (void)
3637 {
3638   session_t *vep_session;
3639   u32 vep_idx;
3640   elog_track_t vep_elog_track;
3641
3642   clib_spinlock_lock (&vcm->sessions_lockp);
3643   pool_get (vcm->sessions, vep_session);
3644   memset (vep_session, 0, sizeof (*vep_session));
3645   vep_idx = vep_session - vcm->sessions;
3646
3647   vep_session->is_vep = 1;
3648   vep_session->vep.vep_idx = ~0;
3649   vep_session->vep.next_sid = ~0;
3650   vep_session->vep.prev_sid = ~0;
3651   vep_session->wait_cont_idx = ~0;
3652   vep_session->vpp_handle = ~0;
3653   vep_session->poll_reg = 0;
3654
3655   if (VPPCOM_DEBUG > 0)
3656     {
3657       vep_session->elog_track.name =
3658         (char *) format (0, "C:%d:VEP:%d%c", vcm->my_client_index,
3659                          vep_idx, 0);
3660       elog_track_register (&vcm->elog_main, &vep_session->elog_track);
3661       vep_elog_track = vep_session->elog_track;
3662     }
3663
3664   clib_spinlock_unlock (&vcm->sessions_lockp);
3665
3666   if (VPPCOM_DEBUG > 0)
3667     clib_warning ("VCL<%d>: Created vep_idx %u / sid %u!",
3668                   getpid (), vep_idx, vep_idx);
3669
3670   if (VPPCOM_DEBUG > 0)
3671     {
3672
3673       /* *INDENT-OFF* */
3674       ELOG_TYPE_DECLARE (e) =
3675       {
3676         .format = "created epoll session:%d",
3677         .format_args = "i4",
3678       };
3679
3680       struct
3681       {
3682         u32 data;
3683       } *ed;
3684
3685       ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vep_elog_track);
3686       ed->data = vep_idx;
3687       /* *INDENT-ON* */
3688     }
3689
3690   return (vep_idx);
3691 }
3692
3693 int
3694 vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
3695                   struct epoll_event *event)
3696 {
3697   session_t *vep_session;
3698   session_t *session;
3699   vce_event_t *ev = 0;
3700   int rv;
3701
3702   if (vep_idx == session_index)
3703     {
3704       clib_warning ("VCL<%d>: ERROR: vep_idx == session_index (%u)!",
3705                     getpid (), vep_idx);
3706       return VPPCOM_EINVAL;
3707     }
3708
3709   clib_spinlock_lock (&vcm->sessions_lockp);
3710   rv = vppcom_session_at_index (vep_idx, &vep_session);
3711   if (PREDICT_FALSE (rv))
3712     {
3713       clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!", vep_idx);
3714       goto done;
3715     }
3716   if (PREDICT_FALSE (!vep_session->is_vep))
3717     {
3718       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
3719                     getpid (), vep_idx);
3720       rv = VPPCOM_EINVAL;
3721       goto done;
3722     }
3723
3724   ASSERT (vep_session->vep.vep_idx == ~0);
3725   ASSERT (vep_session->vep.prev_sid == ~0);
3726
3727   rv = vppcom_session_at_index (session_index, &session);
3728   if (PREDICT_FALSE (rv))
3729     {
3730       if (VPPCOM_DEBUG > 0)
3731         clib_warning ("VCL<%d>: ERROR: Invalid session_index (%u)!",
3732                       getpid (), session_index);
3733       goto done;
3734     }
3735   if (PREDICT_FALSE (session->is_vep))
3736     {
3737       clib_warning ("ERROR: session_index (%u) is a vep!", vep_idx);
3738       rv = VPPCOM_EINVAL;
3739       goto done;
3740     }
3741
3742   switch (op)
3743     {
3744     case EPOLL_CTL_ADD:
3745       if (PREDICT_FALSE (!event))
3746         {
3747           clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: NULL pointer to "
3748                         "epoll_event structure!", getpid ());
3749           rv = VPPCOM_EINVAL;
3750           goto done;
3751         }
3752       if (vep_session->vep.next_sid != ~0)
3753         {
3754           session_t *next_session;
3755           rv = vppcom_session_at_index (vep_session->vep.next_sid,
3756                                         &next_session);
3757           if (PREDICT_FALSE (rv))
3758             {
3759               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: Invalid "
3760                             "vep.next_sid (%u) on vep_idx (%u)!",
3761                             getpid (), vep_session->vep.next_sid, vep_idx);
3762               goto done;
3763             }
3764           ASSERT (next_session->vep.prev_sid == vep_idx);
3765           next_session->vep.prev_sid = session_index;
3766         }
3767       session->vep.next_sid = vep_session->vep.next_sid;
3768       session->vep.prev_sid = vep_idx;
3769       session->vep.vep_idx = vep_idx;
3770       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3771       session->vep.ev = *event;
3772       session->is_vep = 0;
3773       session->is_vep_session = 1;
3774       vep_session->vep.next_sid = session_index;
3775
3776       /* VCL Event Register handler */
3777       if (session->state & STATE_LISTEN)
3778         {
3779           /* Register handler for connect_request event on listen_session_index */
3780           vce_event_key_t evk;
3781           evk.session_index = session_index;
3782           evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
3783           vep_session->poll_reg =
3784             vce_register_handler (&vcm->event_thread, &evk,
3785                                   vce_epoll_wait_connect_request_handler_fn);
3786         }
3787       if (VPPCOM_DEBUG > 1)
3788         clib_warning ("VCL<%d>: EPOLL_CTL_ADD: vep_idx %u, "
3789                       "sid %u, events 0x%x, data 0x%llx!",
3790                       getpid (), vep_idx, session_index,
3791                       event->events, event->data.u64);
3792       if (VPPCOM_DEBUG > 0)
3793         {
3794           /* *INDENT-OFF* */
3795           ELOG_TYPE_DECLARE (e) =
3796             {
3797               .format = "epoll_ctladd: events:%x data:%x",
3798               .format_args = "i4i4i8",
3799             };
3800           struct
3801           {
3802             u32 events;
3803             u64 event_data;
3804           } *ed;
3805
3806           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
3807
3808           ed->events = event->events;
3809           ed->event_data = event->data.u64;
3810           /* *INDENT-ON* */
3811         }
3812       break;
3813
3814     case EPOLL_CTL_MOD:
3815       if (PREDICT_FALSE (!event))
3816         {
3817           clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_MOD: NULL pointer to "
3818                         "epoll_event structure!", getpid ());
3819           rv = VPPCOM_EINVAL;
3820           goto done;
3821         }
3822       else if (PREDICT_FALSE (!session->is_vep_session))
3823         {
3824           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
3825                         "not a vep session!", getpid (), session_index);
3826           rv = VPPCOM_EINVAL;
3827           goto done;
3828         }
3829       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3830         {
3831           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
3832                         "vep_idx (%u) != vep_idx (%u)!",
3833                         getpid (), session_index,
3834                         session->vep.vep_idx, vep_idx);
3835           rv = VPPCOM_EINVAL;
3836           goto done;
3837         }
3838       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3839       session->vep.ev = *event;
3840       if (VPPCOM_DEBUG > 1)
3841         clib_warning
3842           ("VCL<%d>: EPOLL_CTL_MOD: vep_idx %u, sid %u, events 0x%x,"
3843            " data 0x%llx!", getpid (), vep_idx, session_index, event->events,
3844            event->data.u64);
3845       break;
3846
3847     case EPOLL_CTL_DEL:
3848       if (PREDICT_FALSE (!session->is_vep_session))
3849         {
3850           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
3851                         "not a vep session!", getpid (), session_index);
3852           rv = VPPCOM_EINVAL;
3853           goto done;
3854         }
3855       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3856         {
3857           clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
3858                         "vep_idx (%u) != vep_idx (%u)!",
3859                         getpid (), session_index,
3860                         session->vep.vep_idx, vep_idx);
3861           rv = VPPCOM_EINVAL;
3862           goto done;
3863         }
3864
3865       /* VCL Event Un-register handler */
3866       if ((session->state & STATE_LISTEN) && vep_session->poll_reg)
3867         {
3868           ev = vce_get_event_from_index (&vcm->event_thread,
3869                                          vep_session->poll_reg->ev_idx);
3870           (void) vce_unregister_handler (&vcm->event_thread, ev);
3871         }
3872
3873       vep_session->wait_cont_idx =
3874         (vep_session->wait_cont_idx == session_index) ?
3875         session->vep.next_sid : vep_session->wait_cont_idx;
3876
3877       if (session->vep.prev_sid == vep_idx)
3878         vep_session->vep.next_sid = session->vep.next_sid;
3879       else
3880         {
3881           session_t *prev_session;
3882           rv = vppcom_session_at_index (session->vep.prev_sid, &prev_session);
3883           if (PREDICT_FALSE (rv))
3884             {
3885               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
3886                             "vep.prev_sid (%u) on sid (%u)!",
3887                             getpid (), session->vep.prev_sid, session_index);
3888               goto done;
3889             }
3890           ASSERT (prev_session->vep.next_sid == session_index);
3891           prev_session->vep.next_sid = session->vep.next_sid;
3892         }
3893       if (session->vep.next_sid != ~0)
3894         {
3895           session_t *next_session;
3896           rv = vppcom_session_at_index (session->vep.next_sid, &next_session);
3897           if (PREDICT_FALSE (rv))
3898             {
3899               clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
3900                             "vep.next_sid (%u) on sid (%u)!",
3901                             getpid (), session->vep.next_sid, session_index);
3902               goto done;
3903             }
3904           ASSERT (next_session->vep.prev_sid == session_index);
3905           next_session->vep.prev_sid = session->vep.prev_sid;
3906         }
3907
3908       memset (&session->vep, 0, sizeof (session->vep));
3909       session->vep.next_sid = ~0;
3910       session->vep.prev_sid = ~0;
3911       session->vep.vep_idx = ~0;
3912       session->is_vep_session = 0;
3913       if (VPPCOM_DEBUG > 1)
3914         clib_warning ("VCL<%d>: EPOLL_CTL_DEL: vep_idx %u, sid %u!",
3915                       getpid (), vep_idx, session_index);
3916       if (VPPCOM_DEBUG > 0)
3917         {
3918           /* *INDENT-OFF* */
3919           ELOG_TYPE_DECLARE (e) =
3920             {
3921               .format = "epoll_ctldel: vep:%d",
3922               .format_args = "i4",
3923             };
3924           struct
3925           {
3926             u32 data;
3927           } *ed;
3928
3929           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
3930
3931           ed->data = vep_idx;
3932           /* *INDENT-ON* */
3933         }
3934       break;
3935
3936     default:
3937       clib_warning ("VCL<%d>: ERROR: Invalid operation (%d)!", getpid (), op);
3938       rv = VPPCOM_EINVAL;
3939     }
3940
3941   vep_verify_epoll_chain (vep_idx);
3942
3943 done:
3944   clib_spinlock_unlock (&vcm->sessions_lockp);
3945   return rv;
3946 }
3947
3948 int
3949 vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
3950                    int maxevents, double wait_for_time)
3951 {
3952   session_t *vep_session;
3953   elog_track_t vep_elog_track;
3954   int rv;
3955   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
3956   u32 keep_trying = 1;
3957   int num_ev = 0;
3958   u32 vep_next_sid, wait_cont_idx;
3959   u8 is_vep;
3960
3961   if (PREDICT_FALSE (maxevents <= 0))
3962     {
3963       clib_warning ("VCL<%d>: ERROR: Invalid maxevents (%d)!",
3964                     getpid (), maxevents);
3965       return VPPCOM_EINVAL;
3966     }
3967   memset (events, 0, sizeof (*events) * maxevents);
3968
3969   VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
3970   vep_next_sid = vep_session->vep.next_sid;
3971   is_vep = vep_session->is_vep;
3972   wait_cont_idx = vep_session->wait_cont_idx;
3973   vep_elog_track = vep_session->elog_track;
3974   clib_spinlock_unlock (&vcm->sessions_lockp);
3975
3976   if (PREDICT_FALSE (!is_vep))
3977     {
3978       clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
3979                     getpid (), vep_idx);
3980       rv = VPPCOM_EINVAL;
3981       goto done;
3982     }
3983   if (PREDICT_FALSE (vep_next_sid == ~0))
3984     {
3985       if (VPPCOM_DEBUG > 1)
3986         clib_warning ("VCL<%d>: WARNING: vep_idx (%u) is empty!",
3987                       getpid (), vep_idx);
3988       if (VPPCOM_DEBUG > 1)
3989         {
3990           /* *INDENT-OFF* */
3991           ELOG_TYPE_DECLARE (e) =
3992             {
3993               .format = "WRN: vep_idx:%d empty",
3994               .format_args = "i4",
3995             };
3996           struct
3997           {
3998             u32 data;
3999           } *ed;
4000
4001           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vep_elog_track);
4002
4003           ed->data = vep_idx;
4004           /* *INDENT-ON* */
4005         }
4006       goto done;
4007     }
4008
4009   do
4010     {
4011       u32 sid;
4012       u32 next_sid = ~0;
4013       session_t *session;
4014       elog_track_t session_elog_track;
4015
4016       for (sid = (wait_cont_idx == ~0) ? vep_next_sid : wait_cont_idx;
4017            sid != ~0; sid = next_sid)
4018         {
4019           u32 session_events, et_mask, clear_et_mask, session_vep_idx;
4020           u8 add_event, is_vep_session;
4021           int ready;
4022           u64 session_ev_data;
4023
4024           VCL_LOCK_AND_GET_SESSION (sid, &session);
4025           next_sid = session->vep.next_sid;
4026           session_events = session->vep.ev.events;
4027           et_mask = session->vep.et_mask;
4028           is_vep = session->is_vep;
4029           is_vep_session = session->is_vep_session;
4030           session_vep_idx = session->vep.vep_idx;
4031           session_ev_data = session->vep.ev.data.u64;
4032
4033           if (VPPCOM_DEBUG > 0)
4034             {
4035               session_elog_track = session->elog_track;
4036             }
4037
4038           clib_spinlock_unlock (&vcm->sessions_lockp);
4039
4040           if (PREDICT_FALSE (is_vep))
4041             {
4042               if (VPPCOM_DEBUG > 0)
4043                 clib_warning ("VCL<%d>: ERROR: sid (%u) is a vep!",
4044                               getpid (), vep_idx);
4045               if (VPPCOM_DEBUG > 0)
4046                 {
4047                   /* *INDENT-OFF* */
4048                   ELOG_TYPE_DECLARE (e) =
4049                     {
4050                       .format = "ERR:vep_idx:%d is vep",
4051                       .format_args = "i4",
4052                     };
4053                   struct
4054                   {
4055                     u32 data;
4056                   } *ed;
4057
4058                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
4059
4060                   ed->data = vep_idx;
4061                   /* *INDENT-ON* */
4062                 }
4063
4064               rv = VPPCOM_EINVAL;
4065               goto done;
4066             }
4067           if (PREDICT_FALSE (!is_vep_session))
4068             {
4069               if (VPPCOM_DEBUG > 0)
4070                 clib_warning ("VCL<%d>: ERROR: session (%u) is not "
4071                               "a vep session!", getpid (), sid);
4072               if (VPPCOM_DEBUG > 0)
4073                 {
4074                   /* *INDENT-OFF* */
4075                   ELOG_TYPE_DECLARE (e) =
4076                     {
4077                       .format = "ERR:SID:%d not vep",
4078                       .format_args = "i4",
4079                     };
4080                   struct
4081                   {
4082                     u32 data;
4083                   } *ed;
4084
4085                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
4086
4087                   ed->data = sid;
4088                   /* *INDENT-ON* */
4089                 }
4090
4091               rv = VPPCOM_EINVAL;
4092               goto done;
4093             }
4094           if (PREDICT_FALSE (session_vep_idx != vep_idx))
4095             {
4096               clib_warning ("VCL<%d>: ERROR: session (%u) "
4097                             "vep_idx (%u) != vep_idx (%u)!",
4098                             getpid (), sid, session_vep_idx, vep_idx);
4099               rv = VPPCOM_EINVAL;
4100               goto done;
4101             }
4102
4103           add_event = clear_et_mask = 0;
4104
4105           if (EPOLLIN & session_events)
4106             {
4107               VCL_LOCK_AND_GET_SESSION (sid, &session);
4108               ready = vppcom_session_read_ready (session, sid);
4109               clib_spinlock_unlock (&vcm->sessions_lockp);
4110               if ((ready > 0) && (EPOLLIN & et_mask))
4111                 {
4112                   add_event = 1;
4113                   events[num_ev].events |= EPOLLIN;
4114                   if (((EPOLLET | EPOLLIN) & session_events) ==
4115                       (EPOLLET | EPOLLIN))
4116                     clear_et_mask |= EPOLLIN;
4117                 }
4118               else if (ready < 0)
4119                 {
4120                   add_event = 1;
4121                   switch (ready)
4122                     {
4123                     case VPPCOM_ECONNRESET:
4124                       events[num_ev].events |= EPOLLHUP | EPOLLRDHUP;
4125                       break;
4126
4127                     default:
4128                       events[num_ev].events |= EPOLLERR;
4129                       break;
4130                     }
4131                 }
4132             }
4133
4134           if (EPOLLOUT & session_events)
4135             {
4136               VCL_LOCK_AND_GET_SESSION (sid, &session);
4137               ready = vppcom_session_write_ready (session, sid);
4138               clib_spinlock_unlock (&vcm->sessions_lockp);
4139               if ((ready > 0) && (EPOLLOUT & et_mask))
4140                 {
4141                   add_event = 1;
4142                   events[num_ev].events |= EPOLLOUT;
4143                   if (((EPOLLET | EPOLLOUT) & session_events) ==
4144                       (EPOLLET | EPOLLOUT))
4145                     clear_et_mask |= EPOLLOUT;
4146                 }
4147               else if (ready < 0)
4148                 {
4149                   add_event = 1;
4150                   switch (ready)
4151                     {
4152                     case VPPCOM_ECONNRESET:
4153                       events[num_ev].events |= EPOLLHUP;
4154                       break;
4155
4156                     default:
4157                       events[num_ev].events |= EPOLLERR;
4158                       break;
4159                     }
4160                 }
4161             }
4162
4163           if (add_event)
4164             {
4165               events[num_ev].data.u64 = session_ev_data;
4166               if (EPOLLONESHOT & session_events)
4167                 {
4168                   VCL_LOCK_AND_GET_SESSION (sid, &session);
4169                   session->vep.ev.events = 0;
4170                   clib_spinlock_unlock (&vcm->sessions_lockp);
4171                 }
4172               num_ev++;
4173               if (num_ev == maxevents)
4174                 {
4175                   VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4176                   vep_session->wait_cont_idx = next_sid;
4177                   clib_spinlock_unlock (&vcm->sessions_lockp);
4178                   goto done;
4179                 }
4180             }
4181           if (wait_cont_idx != ~0)
4182             {
4183               if (next_sid == ~0)
4184                 next_sid = vep_next_sid;
4185               else if (next_sid == wait_cont_idx)
4186                 next_sid = ~0;
4187             }
4188         }
4189       if (wait_for_time != -1)
4190         keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
4191     }
4192   while ((num_ev == 0) && keep_trying);
4193
4194   if (wait_cont_idx != ~0)
4195     {
4196       VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4197       vep_session->wait_cont_idx = ~0;
4198       clib_spinlock_unlock (&vcm->sessions_lockp);
4199     }
4200 done:
4201   return (rv != VPPCOM_OK) ? rv : num_ev;
4202 }
4203
4204 int
4205 vppcom_session_attr (uint32_t session_index, uint32_t op,
4206                      void *buffer, uint32_t * buflen)
4207 {
4208   session_t *session;
4209   int rv = VPPCOM_OK;
4210   u32 *flags = buffer;
4211   vppcom_endpt_t *ep = buffer;
4212
4213   VCL_LOCK_AND_GET_SESSION (session_index, &session);
4214
4215   ASSERT (session);
4216
4217   switch (op)
4218     {
4219     case VPPCOM_ATTR_GET_NREAD:
4220       rv = vppcom_session_read_ready (session, session_index);
4221       if (VPPCOM_DEBUG > 2)
4222         clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
4223                       getpid (), rv);
4224       if (VPPCOM_DEBUG > 0)
4225         {
4226           /* *INDENT-OFF* */
4227           ELOG_TYPE_DECLARE (e) =
4228             {
4229               .format = "VPPCOM_ATTR_GET_NREAD: nread=%d",
4230               .format_args = "i4",
4231             };
4232           struct
4233           {
4234             u32 data;
4235           } *ed;
4236
4237           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4238
4239           ed->data = rv;
4240           /* *INDENT-ON* */
4241         }
4242
4243       break;
4244
4245     case VPPCOM_ATTR_GET_NWRITE:
4246       rv = vppcom_session_write_ready (session, session_index);
4247       if (VPPCOM_DEBUG > 2)
4248         clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
4249                       getpid (), session_index, rv);
4250       if (VPPCOM_DEBUG > 0)
4251         {
4252           /* *INDENT-OFF* */
4253           ELOG_TYPE_DECLARE (e) =
4254             {
4255               .format = "VPPCOM_ATTR_GET_NWRITE: nwrite=%d",
4256               .format_args = "i4",
4257             };
4258           struct
4259           {
4260             u32 data;
4261           } *ed;
4262
4263           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4264
4265           ed->data = rv;
4266           /* *INDENT-ON* */
4267         }
4268       break;
4269
4270     case VPPCOM_ATTR_GET_FLAGS:
4271       if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
4272         {
4273           *flags = O_RDWR | (VCL_SESS_ATTR_TEST (session->attr,
4274                                                  VCL_SESS_ATTR_NONBLOCK));
4275           *buflen = sizeof (*flags);
4276           if (VPPCOM_DEBUG > 2)
4277             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_FLAGS: sid %u, "
4278                           "flags = 0x%08x, is_nonblocking = %u", getpid (),
4279                           session_index, *flags,
4280                           VCL_SESS_ATTR_TEST (session->attr,
4281                                               VCL_SESS_ATTR_NONBLOCK));
4282           if (VPPCOM_DEBUG > 0)
4283             {
4284                 /* *INDENT-OFF* */
4285               ELOG_TYPE_DECLARE (e) =
4286                 {
4287                   .format = "VPPCOM_ATTR_GET_FLAGS: flags=%x is_nonblk=%d",
4288                   .format_args = "i4i4",
4289                 };
4290               struct
4291               {
4292                 u32 flags;
4293                 u32 is_nonblk;
4294               } *ed;
4295
4296               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4297
4298               ed->flags = *flags;
4299               ed->is_nonblk = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
4300               /* *INDENT-ON* */
4301             }
4302
4303         }
4304       else
4305         rv = VPPCOM_EINVAL;
4306       break;
4307
4308     case VPPCOM_ATTR_SET_FLAGS:
4309       if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
4310         {
4311           if (*flags & O_NONBLOCK)
4312             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
4313           else
4314             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
4315
4316           if (VPPCOM_DEBUG > 2)
4317             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_FLAGS: sid %u, "
4318                           "flags = 0x%08x, is_nonblocking = %u",
4319                           getpid (), session_index, *flags,
4320                           VCL_SESS_ATTR_TEST (session->attr,
4321                                               VCL_SESS_ATTR_NONBLOCK));
4322           if (VPPCOM_DEBUG > 0)
4323             {
4324                 /* *INDENT-OFF* */
4325               ELOG_TYPE_DECLARE (e) =
4326                 {
4327                   .format = "VPPCOM_ATTR_SET_FLAGS: flags=%x is_nonblk=%d",
4328                   .format_args = "i4i4",
4329                 };
4330               struct
4331               {
4332                 u32 flags;
4333                 u32 is_nonblk;
4334               } *ed;
4335
4336               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4337
4338               ed->flags = *flags;
4339               ed->is_nonblk = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
4340               /* *INDENT-ON* */
4341             }
4342         }
4343       else
4344         rv = VPPCOM_EINVAL;
4345       break;
4346
4347     case VPPCOM_ATTR_GET_PEER_ADDR:
4348       if (PREDICT_TRUE (buffer && buflen &&
4349                         (*buflen >= sizeof (*ep)) && ep->ip))
4350         {
4351           ep->is_ip4 = session->peer_addr.is_ip4;
4352           ep->port = session->peer_port;
4353           if (session->peer_addr.is_ip4)
4354             clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
4355                          sizeof (ip4_address_t));
4356           else
4357             clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
4358                          sizeof (ip6_address_t));
4359           *buflen = sizeof (*ep);
4360           if (VPPCOM_DEBUG > 1)
4361             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_PEER_ADDR: sid %u, "
4362                           "is_ip4 = %u, addr = %U, port %u", getpid (),
4363                           session_index, ep->is_ip4, format_ip46_address,
4364                           &session->peer_addr.ip46, ep->is_ip4,
4365                           clib_net_to_host_u16 (ep->port));
4366           if (VPPCOM_DEBUG > 0)
4367             {
4368               if (ep->is_ip4)
4369                 {
4370                     /* *INDENT-OFF* */
4371                   ELOG_TYPE_DECLARE (e) =
4372                     {
4373                       .format = "VPPCOM_ATTR_GET_PEER_ADDR: addr:%d.%d.%d.%d:%d",
4374                       .format_args = "i1i1i1i1i2",
4375                     };
4376                   CLIB_PACKED (struct {
4377                     u8 addr[4]; //4
4378                     u16 port;   //2
4379                   }) * ed;
4380
4381                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4382
4383                   ed->addr[0] = session->peer_addr.ip46.ip4.as_u8[0];
4384                   ed->addr[1] = session->peer_addr.ip46.ip4.as_u8[1];
4385                   ed->addr[2] = session->peer_addr.ip46.ip4.as_u8[2];
4386                   ed->addr[3] = session->peer_addr.ip46.ip4.as_u8[3];
4387                   ed->port = clib_net_to_host_u16 (session->peer_port);
4388                   /* *INDENT-ON* */
4389                 }
4390               else
4391                 {
4392                     /* *INDENT-OFF* */
4393                   ELOG_TYPE_DECLARE (e) =
4394                     {
4395                       .format = "VPPCOM_ATTR_GET_PEER_ADDR: addr:IP6:%d",
4396                       .format_args = "i2",
4397                     };
4398                   CLIB_PACKED (struct {
4399                     u16 port;   //2
4400                   }) * ed;
4401
4402                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4403
4404                   ed->port = clib_net_to_host_u16 (session->peer_port);
4405                   /* *INDENT-ON* */
4406                 }
4407             }
4408         }
4409       else
4410         rv = VPPCOM_EINVAL;
4411       break;
4412
4413     case VPPCOM_ATTR_GET_LCL_ADDR:
4414       if (PREDICT_TRUE (buffer && buflen &&
4415                         (*buflen >= sizeof (*ep)) && ep->ip))
4416         {
4417           ep->is_ip4 = session->lcl_addr.is_ip4;
4418           ep->port = session->lcl_port;
4419           if (session->lcl_addr.is_ip4)
4420             clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip4,
4421                          sizeof (ip4_address_t));
4422           else
4423             clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip6,
4424                          sizeof (ip6_address_t));
4425           *buflen = sizeof (*ep);
4426           if (VPPCOM_DEBUG > 1)
4427             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LCL_ADDR: sid %u, "
4428                           "is_ip4 = %u, addr = %U port %d", getpid (),
4429                           session_index, ep->is_ip4, format_ip46_address,
4430                           &session->lcl_addr.ip46, ep->is_ip4,
4431                           clib_net_to_host_u16 (ep->port));
4432           if (VPPCOM_DEBUG > 0)
4433             {
4434               if (ep->is_ip4)
4435                 {
4436                     /* *INDENT-OFF* */
4437                   ELOG_TYPE_DECLARE (e) =
4438                     {
4439                       .format = "VPPCOM_ATTR_GET_LCL_ADDR: addr:%d.%d.%d.%d:%d",
4440                       .format_args = "i1i1i1i1i2",
4441                     };
4442                   CLIB_PACKED (struct {
4443                     u8 addr[4]; //4
4444                     u16 port;   //2
4445                   }) * ed;
4446
4447                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4448
4449                   ed->addr[0] = session->lcl_addr.ip46.ip4.as_u8[0];
4450                   ed->addr[1] = session->lcl_addr.ip46.ip4.as_u8[1];
4451                   ed->addr[2] = session->lcl_addr.ip46.ip4.as_u8[2];
4452                   ed->addr[3] = session->lcl_addr.ip46.ip4.as_u8[3];
4453                   ed->port = clib_net_to_host_u16 (session->peer_port);
4454                   /* *INDENT-ON* */
4455                 }
4456               else
4457                 {
4458                     /* *INDENT-OFF* */
4459                   ELOG_TYPE_DECLARE (e) =
4460                     {
4461                       .format = "VPPCOM_ATTR_GET_LCL_ADDR: addr:IP6:%d",
4462                       .format_args = "i2",
4463                     };
4464                   CLIB_PACKED (struct {
4465                     u16 port;   //2
4466                   }) * ed;
4467
4468                   ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4469
4470                   ed->port = clib_net_to_host_u16 (session->peer_port);
4471                   /* *INDENT-ON* */
4472                 }
4473             }
4474         }
4475       else
4476         rv = VPPCOM_EINVAL;
4477       break;
4478
4479     case VPPCOM_ATTR_GET_LIBC_EPFD:
4480       rv = session->libc_epfd;
4481       if (VPPCOM_DEBUG > 2)
4482         clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d",
4483                       getpid (), rv);
4484       if (VPPCOM_DEBUG > 0)
4485         {
4486           /* *INDENT-OFF* */
4487           ELOG_TYPE_DECLARE (e) =
4488             {
4489               .format = "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd=%d",
4490               .format_args = "i4",
4491             };
4492           CLIB_PACKED (struct {
4493             i32 data;
4494           }) *ed;
4495
4496           ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4497           ed->data = session->libc_epfd;
4498           /* *INDENT-ON* */
4499         }
4500
4501       break;
4502
4503     case VPPCOM_ATTR_SET_LIBC_EPFD:
4504       if (PREDICT_TRUE (buffer && buflen &&
4505                         (*buflen == sizeof (session->libc_epfd))))
4506         {
4507           session->libc_epfd = *(int *) buffer;
4508           *buflen = sizeof (session->libc_epfd);
4509
4510           if (VPPCOM_DEBUG > 2)
4511             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, "
4512                           "buflen %d", getpid (), session->libc_epfd,
4513                           *buflen);
4514           if (VPPCOM_DEBUG > 0)
4515             {
4516                 /* *INDENT-OFF* */
4517               ELOG_TYPE_DECLARE (e) =
4518                 {
4519                   .format = "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd=%s%d buflen=%d",
4520                   .format_args = "t1i4i4",
4521                   .n_enum_strings = 2,
4522                   .enum_strings = {"", "-",},
4523                 };
4524               CLIB_PACKED (struct {
4525                 u8 sign;
4526                 u32 data[2];
4527               }) * ed;
4528
4529               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4530
4531               ed->sign = (session->libc_epfd < 0);
4532               ed->data[0] = abs(session->libc_epfd);
4533               ed->data[1] = *buflen;
4534               /* *INDENT-ON* */
4535             }
4536         }
4537       else
4538         rv = VPPCOM_EINVAL;
4539       break;
4540
4541     case VPPCOM_ATTR_GET_PROTOCOL:
4542       if (buffer && buflen && (*buflen >= sizeof (int)))
4543         {
4544           *(int *) buffer = session->proto;
4545           *buflen = sizeof (int);
4546
4547           if (VPPCOM_DEBUG > 2)
4548             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_PROTOCOL: %d (%s), "
4549                           "buflen %d", getpid (), *(int *) buffer,
4550                           *(int *) buffer ? "UDP" : "TCP", *buflen);
4551           if (VPPCOM_DEBUG > 0)
4552             {
4553                 /* *INDENT-OFF* */
4554               ELOG_TYPE_DECLARE (e) =
4555                 {
4556                   .format = "VPPCOM_ATTR_GET_PROTOCOL: %s buflen=%d",
4557                   .format_args = "t1i4",
4558                   .n_enum_strings = 2,
4559                   .enum_strings = {"TCP", "UDP",},
4560                 };
4561
4562               CLIB_PACKED (struct {
4563                 u8 proto;
4564                 u32 buflen;
4565               }) * ed;
4566
4567               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4568               ed->proto = session->proto;
4569               ed->buflen = *(int *) buffer;
4570               /* *INDENT-ON* */
4571             }
4572         }
4573       else
4574         rv = VPPCOM_EINVAL;
4575       break;
4576
4577     case VPPCOM_ATTR_GET_LISTEN:
4578       if (buffer && buflen && (*buflen >= sizeof (int)))
4579         {
4580           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
4581                                                 VCL_SESS_ATTR_LISTEN);
4582           *buflen = sizeof (int);
4583
4584           if (VPPCOM_DEBUG > 2)
4585             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LISTEN: %d, "
4586                           "buflen %d", getpid (), *(int *) buffer, *buflen);
4587           if (VPPCOM_DEBUG > 0)
4588             {
4589                 /* *INDENT-OFF* */
4590               ELOG_TYPE_DECLARE (e) =
4591                 {
4592                   .format = "VPPCOM_ATTR_GET_LISTEN: %d buflen=%d",
4593                   .format_args = "i4i4",
4594                 };
4595
4596               struct {
4597                 u32 data[2];
4598               } * ed;
4599
4600               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4601               ed->data[0] = *(int *) buffer;
4602               ed->data[1] = *buflen;
4603               /* *INDENT-ON* */
4604             }
4605         }
4606       else
4607         rv = VPPCOM_EINVAL;
4608       break;
4609
4610     case VPPCOM_ATTR_GET_ERROR:
4611       if (buffer && buflen && (*buflen >= sizeof (int)))
4612         {
4613           *(int *) buffer = 0;
4614           *buflen = sizeof (int);
4615
4616           if (VPPCOM_DEBUG > 2)
4617             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_ERROR: %d, "
4618                           "buflen %d, #VPP-TBD#", getpid (),
4619                           *(int *) buffer, *buflen);
4620           if (VPPCOM_DEBUG > 0)
4621             {
4622                 /* *INDENT-OFF* */
4623               ELOG_TYPE_DECLARE (e) =
4624                 {
4625                   .format = "VPPCOM_ATTR_GET_ERROR: %d buflen=%d",
4626                   .format_args = "i4i4",
4627                 };
4628
4629               struct {
4630                 u32 data[2];
4631               } * ed;
4632
4633               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4634               ed->data[0] = *(int *) buffer;
4635               ed->data[1] = *buflen;
4636               /* *INDENT-ON* */
4637             }
4638         }
4639       else
4640         rv = VPPCOM_EINVAL;
4641       break;
4642
4643     case VPPCOM_ATTR_GET_TX_FIFO_LEN:
4644       if (buffer && buflen && (*buflen >= sizeof (u32)))
4645         {
4646
4647           /* VPP-TBD */
4648           *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
4649                                 session->tx_fifo ? session->tx_fifo->nitems :
4650                                 vcm->cfg.tx_fifo_size);
4651           *buflen = sizeof (u32);
4652
4653           if (VPPCOM_DEBUG > 2)
4654             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), "
4655                           "buflen %d, #VPP-TBD#", getpid (),
4656                           *(size_t *) buffer, *(size_t *) buffer, *buflen);
4657           if (VPPCOM_DEBUG > 0)
4658             {
4659                 /* *INDENT-OFF* */
4660               ELOG_TYPE_DECLARE (e) =
4661                 {
4662                   .format = "VPPCOM_ATTR_GET_TX_FIFO_LEN: 0x%x buflen=%d",
4663                   .format_args = "i4i4",
4664                 };
4665
4666               struct {
4667                 u32 data[2];
4668               } * ed;
4669
4670               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4671               ed->data[0] = *(size_t *) buffer;
4672               ed->data[1] = *buflen;
4673               /* *INDENT-ON* */
4674             }
4675         }
4676       else
4677         rv = VPPCOM_EINVAL;
4678       break;
4679
4680     case VPPCOM_ATTR_SET_TX_FIFO_LEN:
4681       if (buffer && buflen && (*buflen == sizeof (u32)))
4682         {
4683           /* VPP-TBD */
4684           session->sndbuf_size = *(u32 *) buffer;
4685           if (VPPCOM_DEBUG > 2)
4686             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), "
4687                           "buflen %d, #VPP-TBD#", getpid (),
4688                           session->sndbuf_size, session->sndbuf_size,
4689                           *buflen);
4690           if (VPPCOM_DEBUG > 0)
4691             {
4692                 /* *INDENT-OFF* */
4693               ELOG_TYPE_DECLARE (e) =
4694                 {
4695                   .format = "VPPCOM_ATTR_SET_TX_FIFO_LEN: 0x%x buflen=%d",
4696                   .format_args = "i4i4",
4697                 };
4698
4699               struct {
4700                 u32 data[2];
4701               } * ed;
4702
4703               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4704               ed->data[0] = session->sndbuf_size;
4705               ed->data[1] = *buflen;
4706               /* *INDENT-ON* */
4707             }
4708         }
4709       else
4710         rv = VPPCOM_EINVAL;
4711       break;
4712
4713     case VPPCOM_ATTR_GET_RX_FIFO_LEN:
4714       if (buffer && buflen && (*buflen >= sizeof (u32)))
4715         {
4716
4717           /* VPP-TBD */
4718           *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
4719                                 session->rx_fifo ? session->rx_fifo->nitems :
4720                                 vcm->cfg.rx_fifo_size);
4721           *buflen = sizeof (u32);
4722
4723           if (VPPCOM_DEBUG > 2)
4724             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), "
4725                           "buflen %d, #VPP-TBD#", getpid (),
4726                           *(size_t *) buffer, *(size_t *) buffer, *buflen);
4727           if (VPPCOM_DEBUG > 0)
4728             {
4729                 /* *INDENT-OFF* */
4730               ELOG_TYPE_DECLARE (e) =
4731                 {
4732                   .format = "VPPCOM_ATTR_GET_RX_FIFO_LEN: 0x%x buflen=%d",
4733                   .format_args = "i4i4",
4734                 };
4735
4736               struct {
4737                 u32 data[2];
4738               } * ed;
4739
4740               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4741               ed->data[0] = *(size_t *) buffer;
4742               ed->data[1] = *buflen;
4743               /* *INDENT-ON* */
4744             }
4745         }
4746       else
4747         rv = VPPCOM_EINVAL;
4748       break;
4749
4750     case VPPCOM_ATTR_SET_RX_FIFO_LEN:
4751       if (buffer && buflen && (*buflen == sizeof (u32)))
4752         {
4753           /* VPP-TBD */
4754           session->rcvbuf_size = *(u32 *) buffer;
4755           if (VPPCOM_DEBUG > 2)
4756             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), "
4757                           "buflen %d, #VPP-TBD#", getpid (),
4758                           session->sndbuf_size, session->sndbuf_size,
4759                           *buflen);
4760           if (VPPCOM_DEBUG > 0)
4761             {
4762                 /* *INDENT-OFF* */
4763               ELOG_TYPE_DECLARE (e) =
4764                 {
4765                   .format = "VPPCOM_ATTR_SET_RX_FIFO_LEN: 0x%x buflen=%d",
4766                   .format_args = "i4i4",
4767                 };
4768
4769               struct {
4770                 u32 data[2];
4771               } * ed;
4772
4773               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4774               ed->data[0] = session->sndbuf_size;
4775               ed->data[1] = *buflen;
4776               /* *INDENT-ON* */
4777             }
4778         }
4779       else
4780         rv = VPPCOM_EINVAL;
4781       break;
4782
4783     case VPPCOM_ATTR_GET_REUSEADDR:
4784       if (buffer && buflen && (*buflen >= sizeof (int)))
4785         {
4786           /* VPP-TBD */
4787           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
4788                                                 VCL_SESS_ATTR_REUSEADDR);
4789           *buflen = sizeof (int);
4790
4791           if (VPPCOM_DEBUG > 2)
4792             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_REUSEADDR: %d, "
4793                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
4794                           *buflen);
4795           if (VPPCOM_DEBUG > 0)
4796             {
4797                 /* *INDENT-OFF* */
4798               ELOG_TYPE_DECLARE (e) =
4799                 {
4800                   .format = "VPPCOM_ATTR_GET_REUSEADDR: %d buflen=%d",
4801                   .format_args = "i4i4",
4802                 };
4803
4804               struct {
4805                 u32 data[2];
4806               } * ed;
4807
4808               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4809               ed->data[0] = *(int *) buffer;
4810               ed->data[1] = *buflen;
4811               /* *INDENT-ON* */
4812             }
4813         }
4814       else
4815         rv = VPPCOM_EINVAL;
4816       break;
4817
4818     case VPPCOM_ATTR_SET_REUSEADDR:
4819       if (buffer && buflen && (*buflen == sizeof (int)) &&
4820           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
4821         {
4822           /* VPP-TBD */
4823           if (*(int *) buffer)
4824             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEADDR);
4825           else
4826             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEADDR);
4827
4828           if (VPPCOM_DEBUG > 2)
4829             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_REUSEADDR: %d, "
4830                           "buflen %d, #VPP-TBD#", getpid (),
4831                           VCL_SESS_ATTR_TEST (session->attr,
4832                                               VCL_SESS_ATTR_REUSEADDR),
4833                           *buflen);
4834           if (VPPCOM_DEBUG > 0)
4835             {
4836                 /* *INDENT-OFF* */
4837               ELOG_TYPE_DECLARE (e) =
4838                 {
4839                   .format = "VPPCOM_ATTR_SET_REUSEADDR: %d buflen=%d",
4840                   .format_args = "i4i4",
4841                 };
4842
4843               struct {
4844                 u32 data[2];
4845               } * ed;
4846
4847               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4848               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
4849                                                 VCL_SESS_ATTR_REUSEADDR);
4850               ed->data[1] = *buflen;
4851               /* *INDENT-ON* */
4852             }
4853         }
4854       else
4855         rv = VPPCOM_EINVAL;
4856       break;
4857
4858     case VPPCOM_ATTR_GET_REUSEPORT:
4859       if (buffer && buflen && (*buflen >= sizeof (int)))
4860         {
4861           /* VPP-TBD */
4862           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
4863                                                 VCL_SESS_ATTR_REUSEPORT);
4864           *buflen = sizeof (int);
4865
4866           if (VPPCOM_DEBUG > 2)
4867             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_REUSEPORT: %d, "
4868                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
4869                           *buflen);
4870           if (VPPCOM_DEBUG > 0)
4871             {
4872                 /* *INDENT-OFF* */
4873               ELOG_TYPE_DECLARE (e) =
4874                 {
4875                   .format = "VPPCOM_ATTR_GET_REUSEPORT: %d buflen=%d",
4876                   .format_args = "i4i4",
4877                 };
4878
4879               struct {
4880                 u32 data[2];
4881               } * ed;
4882
4883               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4884               ed->data[0] = *(int *) buffer;
4885               ed->data[1] = *buflen;
4886               /* *INDENT-ON* */
4887             }
4888         }
4889       else
4890         rv = VPPCOM_EINVAL;
4891       break;
4892
4893     case VPPCOM_ATTR_SET_REUSEPORT:
4894       if (buffer && buflen && (*buflen == sizeof (int)) &&
4895           !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
4896         {
4897           /* VPP-TBD */
4898           if (*(int *) buffer)
4899             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEPORT);
4900           else
4901             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEPORT);
4902
4903           if (VPPCOM_DEBUG > 2)
4904             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_REUSEPORT: %d, "
4905                           "buflen %d, #VPP-TBD#", getpid (),
4906                           VCL_SESS_ATTR_TEST (session->attr,
4907                                               VCL_SESS_ATTR_REUSEPORT),
4908                           *buflen);
4909           if (VPPCOM_DEBUG > 0)
4910             {
4911                 /* *INDENT-OFF* */
4912               ELOG_TYPE_DECLARE (e) =
4913                 {
4914                   .format = "VPPCOM_ATTR_SET_REUSEPORT: %d buflen=%d",
4915                   .format_args = "i4i4",
4916                 };
4917
4918               struct {
4919                 u32 data[2];
4920               } * ed;
4921
4922               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4923               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
4924                                                 VCL_SESS_ATTR_REUSEPORT);
4925               ed->data[1] = *buflen;
4926               /* *INDENT-ON* */
4927             }
4928         }
4929       else
4930         rv = VPPCOM_EINVAL;
4931       break;
4932
4933     case VPPCOM_ATTR_GET_BROADCAST:
4934       if (buffer && buflen && (*buflen >= sizeof (int)))
4935         {
4936           /* VPP-TBD */
4937           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
4938                                                 VCL_SESS_ATTR_BROADCAST);
4939           *buflen = sizeof (int);
4940
4941           if (VPPCOM_DEBUG > 2)
4942             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_BROADCAST: %d, "
4943                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
4944                           *buflen);
4945           if (VPPCOM_DEBUG > 0)
4946             {
4947                 /* *INDENT-OFF* */
4948               ELOG_TYPE_DECLARE (e) =
4949                 {
4950                   .format = "VPPCOM_ATTR_GET_BROADCAST: %d buflen=%d",
4951                   .format_args = "i4i4",
4952                 };
4953
4954               struct {
4955                 u32 data[2];
4956               } * ed;
4957
4958               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4959               ed->data[0] = *(int *) buffer;
4960               ed->data[1] = *buflen;
4961               /* *INDENT-ON* */
4962             }
4963         }
4964       else
4965         rv = VPPCOM_EINVAL;
4966       break;
4967
4968     case VPPCOM_ATTR_SET_BROADCAST:
4969       if (buffer && buflen && (*buflen == sizeof (int)))
4970         {
4971           /* VPP-TBD */
4972           if (*(int *) buffer)
4973             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_BROADCAST);
4974           else
4975             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_BROADCAST);
4976
4977           if (VPPCOM_DEBUG > 2)
4978             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_BROADCAST: %d, "
4979                           "buflen %d, #VPP-TBD#", getpid (),
4980                           VCL_SESS_ATTR_TEST (session->attr,
4981                                               VCL_SESS_ATTR_BROADCAST),
4982                           *buflen);
4983           if (VPPCOM_DEBUG > 0)
4984             {
4985                 /* *INDENT-OFF* */
4986               ELOG_TYPE_DECLARE (e) =
4987                 {
4988                   .format = "VPPCOM_ATTR_SET_BROADCAST: %d buflen=%d",
4989                   .format_args = "i4i4",
4990                 };
4991
4992               struct {
4993                 u32 data[2];
4994               } * ed;
4995
4996               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4997               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
4998                                                 VCL_SESS_ATTR_BROADCAST);
4999               ed->data[1] = *buflen;
5000               /* *INDENT-ON* */
5001             }
5002         }
5003       else
5004         rv = VPPCOM_EINVAL;
5005       break;
5006
5007     case VPPCOM_ATTR_GET_V6ONLY:
5008       if (buffer && buflen && (*buflen >= sizeof (int)))
5009         {
5010           /* VPP-TBD */
5011           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5012                                                 VCL_SESS_ATTR_V6ONLY);
5013           *buflen = sizeof (int);
5014
5015           if (VPPCOM_DEBUG > 2)
5016             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_V6ONLY: %d, "
5017                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5018                           *buflen);
5019           if (VPPCOM_DEBUG > 0)
5020             {
5021                 /* *INDENT-OFF* */
5022               ELOG_TYPE_DECLARE (e) =
5023                 {
5024                   .format = "VPPCOM_ATTR_GET_V6ONLY: %d buflen=%d",
5025                   .format_args = "i4i4",
5026                 };
5027
5028               struct {
5029                 u32 data[2];
5030               } * ed;
5031
5032               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5033               ed->data[0] = *(int *) buffer;
5034               ed->data[1] = *buflen;
5035               /* *INDENT-ON* */
5036             }
5037         }
5038       else
5039         rv = VPPCOM_EINVAL;
5040       break;
5041
5042     case VPPCOM_ATTR_SET_V6ONLY:
5043       if (buffer && buflen && (*buflen == sizeof (int)))
5044         {
5045           /* VPP-TBD */
5046           if (*(int *) buffer)
5047             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_V6ONLY);
5048           else
5049             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_V6ONLY);
5050
5051           if (VPPCOM_DEBUG > 2)
5052             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_V6ONLY: %d, "
5053                           "buflen %d, #VPP-TBD#", getpid (),
5054                           VCL_SESS_ATTR_TEST (session->attr,
5055                                               VCL_SESS_ATTR_V6ONLY), *buflen);
5056           if (VPPCOM_DEBUG > 0)
5057             {
5058                 /* *INDENT-OFF* */
5059               ELOG_TYPE_DECLARE (e) =
5060                 {
5061                   .format = "VPPCOM_ATTR_SET_V6ONLY: %d buflen=%d",
5062                   .format_args = "i4i4",
5063                 };
5064
5065               struct {
5066                 u32 data[2];
5067               } * ed;
5068
5069               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5070               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5071                                                 VCL_SESS_ATTR_V6ONLY);
5072               ed->data[1] = *buflen;
5073               /* *INDENT-ON* */
5074             }
5075         }
5076       else
5077         rv = VPPCOM_EINVAL;
5078       break;
5079
5080     case VPPCOM_ATTR_GET_KEEPALIVE:
5081       if (buffer && buflen && (*buflen >= sizeof (int)))
5082         {
5083           /* VPP-TBD */
5084           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5085                                                 VCL_SESS_ATTR_KEEPALIVE);
5086           *buflen = sizeof (int);
5087
5088           if (VPPCOM_DEBUG > 2)
5089             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_KEEPALIVE: %d, "
5090                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5091                           *buflen);
5092           if (VPPCOM_DEBUG > 0)
5093             {
5094                 /* *INDENT-OFF* */
5095               ELOG_TYPE_DECLARE (e) =
5096                 {
5097                   .format = "VPPCOM_ATTR_GET_KEEPALIVE: %d buflen=%d",
5098                   .format_args = "i4i4",
5099                 };
5100
5101               struct {
5102                 u32 data[2];
5103               } * ed;
5104
5105               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5106               ed->data[0] = *(int *) buffer;
5107               ed->data[1] = *buflen;
5108               /* *INDENT-ON* */
5109             }
5110         }
5111       else
5112         rv = VPPCOM_EINVAL;
5113       break;
5114
5115     case VPPCOM_ATTR_SET_KEEPALIVE:
5116       if (buffer && buflen && (*buflen == sizeof (int)))
5117         {
5118           /* VPP-TBD */
5119           if (*(int *) buffer)
5120             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_KEEPALIVE);
5121           else
5122             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_KEEPALIVE);
5123
5124           if (VPPCOM_DEBUG > 2)
5125             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_KEEPALIVE: %d, "
5126                           "buflen %d, #VPP-TBD#", getpid (),
5127                           VCL_SESS_ATTR_TEST (session->attr,
5128                                               VCL_SESS_ATTR_KEEPALIVE),
5129                           *buflen);
5130           if (VPPCOM_DEBUG > 0)
5131             {
5132                 /* *INDENT-OFF* */
5133               ELOG_TYPE_DECLARE (e) =
5134                 {
5135                   .format = "VPPCOM_ATTR_SET_KEEPALIVE: %d buflen=%d",
5136                   .format_args = "i4i4",
5137                 };
5138
5139               struct {
5140                 u32 data[2];
5141               } * ed;
5142
5143               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5144               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5145                                                 VCL_SESS_ATTR_KEEPALIVE);
5146               ed->data[1] = *buflen;
5147               /* *INDENT-ON* */
5148             }
5149         }
5150       else
5151         rv = VPPCOM_EINVAL;
5152       break;
5153
5154     case VPPCOM_ATTR_GET_TCP_NODELAY:
5155       if (buffer && buflen && (*buflen >= sizeof (int)))
5156         {
5157           /* VPP-TBD */
5158           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5159                                                 VCL_SESS_ATTR_TCP_NODELAY);
5160           *buflen = sizeof (int);
5161
5162           if (VPPCOM_DEBUG > 2)
5163             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_NODELAY: %d, "
5164                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5165                           *buflen);
5166           if (VPPCOM_DEBUG > 0)
5167             {
5168                 /* *INDENT-OFF* */
5169               ELOG_TYPE_DECLARE (e) =
5170                 {
5171                   .format = "VPPCOM_ATTR_GET_TCP_NODELAY: %d buflen=%d",
5172                   .format_args = "i4i4",
5173                 };
5174
5175               struct {
5176                 u32 data[2];
5177               } * ed;
5178
5179               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5180               ed->data[0] = *(int *) buffer;
5181               ed->data[1] = *buflen;
5182               /* *INDENT-ON* */
5183             }
5184         }
5185       else
5186         rv = VPPCOM_EINVAL;
5187       break;
5188
5189     case VPPCOM_ATTR_SET_TCP_NODELAY:
5190       if (buffer && buflen && (*buflen == sizeof (int)))
5191         {
5192           /* VPP-TBD */
5193           if (*(int *) buffer)
5194             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
5195           else
5196             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
5197
5198           if (VPPCOM_DEBUG > 2)
5199             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_NODELAY: %d, "
5200                           "buflen %d, #VPP-TBD#", getpid (),
5201                           VCL_SESS_ATTR_TEST (session->attr,
5202                                               VCL_SESS_ATTR_TCP_NODELAY),
5203                           *buflen);
5204           if (VPPCOM_DEBUG > 0)
5205             {
5206                 /* *INDENT-OFF* */
5207               ELOG_TYPE_DECLARE (e) =
5208                 {
5209                   .format = "VPPCOM_ATTR_SET_TCP_NODELAY: %d buflen=%d",
5210                   .format_args = "i4i4",
5211                 };
5212
5213               struct {
5214                 u32 data[2];
5215               } * ed;
5216
5217               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5218               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5219                                                 VCL_SESS_ATTR_TCP_NODELAY);
5220               ed->data[1] = *buflen;
5221               /* *INDENT-ON* */
5222             }
5223         }
5224       else
5225         rv = VPPCOM_EINVAL;
5226       break;
5227
5228     case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
5229       if (buffer && buflen && (*buflen >= sizeof (int)))
5230         {
5231           /* VPP-TBD */
5232           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5233                                                 VCL_SESS_ATTR_TCP_KEEPIDLE);
5234           *buflen = sizeof (int);
5235
5236           if (VPPCOM_DEBUG > 2)
5237             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, "
5238                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5239                           *buflen);
5240           if (VPPCOM_DEBUG > 0)
5241             {
5242                 /* *INDENT-OFF* */
5243               ELOG_TYPE_DECLARE (e) =
5244                 {
5245                   .format = "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d buflen=%d",
5246                   .format_args = "i4i4",
5247                 };
5248
5249               struct {
5250                 u32 data[2];
5251               } * ed;
5252
5253               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5254               ed->data[0] = *(int *) buffer;
5255               ed->data[1] = *buflen;
5256               /* *INDENT-ON* */
5257             }
5258         }
5259       else
5260         rv = VPPCOM_EINVAL;
5261       break;
5262
5263     case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
5264       if (buffer && buflen && (*buflen == sizeof (int)))
5265         {
5266           /* VPP-TBD */
5267           if (*(int *) buffer)
5268             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
5269           else
5270             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
5271
5272           if (VPPCOM_DEBUG > 2)
5273             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, "
5274                           "buflen %d, #VPP-TBD#", getpid (),
5275                           VCL_SESS_ATTR_TEST (session->attr,
5276                                               VCL_SESS_ATTR_TCP_KEEPIDLE),
5277                           *buflen);
5278           if (VPPCOM_DEBUG > 0)
5279             {
5280                 /* *INDENT-OFF* */
5281               ELOG_TYPE_DECLARE (e) =
5282                 {
5283                   .format = "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d buflen=%d",
5284                   .format_args = "i4i4",
5285                 };
5286
5287               struct {
5288                 u32 data[2];
5289               } * ed;
5290
5291               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5292               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5293                                                 VCL_SESS_ATTR_TCP_KEEPIDLE);
5294               ed->data[1] = *buflen;
5295               /* *INDENT-ON* */
5296             }
5297         }
5298       else
5299         rv = VPPCOM_EINVAL;
5300       break;
5301
5302     case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
5303       if (buffer && buflen && (*buflen >= sizeof (int)))
5304         {
5305           /* VPP-TBD */
5306           *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5307                                                 VCL_SESS_ATTR_TCP_KEEPINTVL);
5308           *buflen = sizeof (int);
5309
5310           if (VPPCOM_DEBUG > 2)
5311             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, "
5312                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5313                           *buflen);
5314           if (VPPCOM_DEBUG > 0)
5315             {
5316                 /* *INDENT-OFF* */
5317               ELOG_TYPE_DECLARE (e) =
5318                 {
5319                   .format = "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d buflen=%d",
5320                   .format_args = "i4i4",
5321                 };
5322
5323               struct {
5324                 u32 data[2];
5325               } * ed;
5326
5327               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5328               ed->data[0] = *(int *) buffer;
5329               ed->data[1] = *buflen;
5330               /* *INDENT-ON* */
5331             }
5332         }
5333       else
5334         rv = VPPCOM_EINVAL;
5335       break;
5336
5337     case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
5338       if (buffer && buflen && (*buflen == sizeof (int)))
5339         {
5340           /* VPP-TBD */
5341           if (*(int *) buffer)
5342             VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
5343           else
5344             VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
5345
5346           if (VPPCOM_DEBUG > 2)
5347             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, "
5348                           "buflen %d, #VPP-TBD#", getpid (),
5349                           VCL_SESS_ATTR_TEST (session->attr,
5350                                               VCL_SESS_ATTR_TCP_KEEPINTVL),
5351                           *buflen);
5352           if (VPPCOM_DEBUG > 0)
5353             {
5354                 /* *INDENT-OFF* */
5355               ELOG_TYPE_DECLARE (e) =
5356                 {
5357                   .format = "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d buflen=%d",
5358                   .format_args = "i4i4",
5359                 };
5360
5361               struct {
5362                 u32 data[2];
5363               } * ed;
5364
5365               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5366               ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5367                                                 VCL_SESS_ATTR_TCP_KEEPINTVL);
5368               ed->data[1] = *buflen;
5369               /* *INDENT-ON* */
5370             }
5371         }
5372       else
5373         rv = VPPCOM_EINVAL;
5374       break;
5375
5376     case VPPCOM_ATTR_GET_TCP_USER_MSS:
5377       if (buffer && buflen && (*buflen >= sizeof (u32)))
5378         {
5379           /* VPP-TBD */
5380           *(u32 *) buffer = session->user_mss;
5381           *buflen = sizeof (int);
5382
5383           if (VPPCOM_DEBUG > 2)
5384             clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_USER_MSS: %d, "
5385                           "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5386                           *buflen);
5387           if (VPPCOM_DEBUG > 0)
5388             {
5389                 /* *INDENT-OFF* */
5390               ELOG_TYPE_DECLARE (e) =
5391                 {
5392                   .format = "VPPCOM_ATTR_GET_TCP_USER_MSS: %d buflen=%d",
5393                   .format_args = "i4i4",
5394                 };
5395
5396               struct {
5397                 u32 data[2];
5398               } * ed;
5399
5400               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5401               ed->data[0] = *(int *) buffer;
5402               ed->data[1] = *buflen;
5403               /* *INDENT-ON* */
5404             }
5405         }
5406       else
5407         rv = VPPCOM_EINVAL;
5408       break;
5409
5410     case VPPCOM_ATTR_SET_TCP_USER_MSS:
5411       if (buffer && buflen && (*buflen == sizeof (u32)))
5412         {
5413           /* VPP-TBD */
5414           session->user_mss = *(u32 *) buffer;
5415
5416           if (VPPCOM_DEBUG > 2)
5417             clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_USER_MSS: %u, "
5418                           "buflen %d, #VPP-TBD#", getpid (),
5419                           session->user_mss, *buflen);
5420           if (VPPCOM_DEBUG > 0)
5421             {
5422                 /* *INDENT-OFF* */
5423               ELOG_TYPE_DECLARE (e) =
5424                 {
5425                   .format = "VPPCOM_ATTR_SET_TCP_USER_MSS: %d buflen=%d",
5426                   .format_args = "i4i4",
5427                 };
5428
5429               struct {
5430                 u32 data[2];
5431               } * ed;
5432
5433               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5434               ed->data[0] = session->user_mss;
5435               ed->data[1] = *buflen;
5436               /* *INDENT-ON* */
5437             }
5438         }
5439       else
5440         rv = VPPCOM_EINVAL;
5441       break;
5442
5443     default:
5444       rv = VPPCOM_EINVAL;
5445       break;
5446     }
5447
5448 done:
5449   clib_spinlock_unlock (&vcm->sessions_lockp);
5450   return rv;
5451 }
5452
5453 int
5454 vppcom_session_recvfrom (uint32_t session_index, void *buffer,
5455                          uint32_t buflen, int flags, vppcom_endpt_t * ep)
5456 {
5457   int rv = VPPCOM_OK;
5458   session_t *session = 0;
5459
5460   if (ep)
5461     {
5462       clib_spinlock_lock (&vcm->sessions_lockp);
5463       rv = vppcom_session_at_index (session_index, &session);
5464       if (PREDICT_FALSE (rv))
5465         {
5466           clib_spinlock_unlock (&vcm->sessions_lockp);
5467           if (VPPCOM_DEBUG > 0)
5468             clib_warning ("VCL<%d>: invalid session, "
5469                           "sid (%u) has been closed!",
5470                           getpid (), session_index);
5471           if (VPPCOM_DEBUG > 0)
5472             {
5473               /* *INDENT-OFF* */
5474               ELOG_TYPE_DECLARE (e) =
5475                 {
5476                   .format = "invalid session: %d closed",
5477                   .format_args = "i4",
5478                 };
5479
5480               struct {
5481                 u32 data;
5482               } * ed;
5483
5484               ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
5485               ed->data = session_index;
5486               /* *INDENT-ON* */
5487             }
5488           rv = VPPCOM_EBADFD;
5489           clib_spinlock_unlock (&vcm->sessions_lockp);
5490           goto done;
5491         }
5492       ep->is_ip4 = session->peer_addr.is_ip4;
5493       ep->port = session->peer_port;
5494       if (session->peer_addr.is_ip4)
5495         clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
5496                      sizeof (ip4_address_t));
5497       else
5498         clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
5499                      sizeof (ip6_address_t));
5500       clib_spinlock_unlock (&vcm->sessions_lockp);
5501     }
5502
5503   if (flags == 0)
5504     rv = vppcom_session_read (session_index, buffer, buflen);
5505   else if (flags & MSG_PEEK)
5506     rv = vppcom_session_peek (session_index, buffer, buflen);
5507   else
5508     {
5509       clib_warning ("VCL<%d>: Unsupport flags for recvfrom %d",
5510                     getpid (), flags);
5511       rv = VPPCOM_EAFNOSUPPORT;
5512     }
5513
5514 done:
5515   return rv;
5516 }
5517
5518 int
5519 vppcom_session_sendto (uint32_t session_index, void *buffer,
5520                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
5521 {
5522   if (!buffer)
5523     return VPPCOM_EINVAL;
5524
5525   if (ep)
5526     {
5527       // TBD
5528       return VPPCOM_EINVAL;
5529     }
5530
5531   if (flags)
5532     {
5533       // TBD check the flags and do the right thing
5534       if (VPPCOM_DEBUG > 2)
5535         clib_warning ("VCL<%d>: handling flags 0x%u (%d) "
5536                       "not implemented yet.", getpid (), flags, flags);
5537     }
5538
5539   return (vppcom_session_write (session_index, buffer, buflen));
5540 }
5541
5542 int
5543 vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
5544 {
5545   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
5546   u32 i, keep_trying = 1;
5547   int rv, num_ev = 0;
5548
5549   if (VPPCOM_DEBUG > 3)
5550     clib_warning ("VCL<%d>: vp %p, nsids %u, wait_for_time %f",
5551                   getpid (), vp, n_sids, wait_for_time);
5552
5553   if (!vp)
5554     return VPPCOM_EFAULT;
5555
5556   do
5557     {
5558       session_t *session;
5559
5560       for (i = 0; i < n_sids; i++)
5561         {
5562           ASSERT (vp[i].revents);
5563
5564           VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5565           clib_spinlock_unlock (&vcm->sessions_lockp);
5566
5567           if (*vp[i].revents)
5568             *vp[i].revents = 0;
5569
5570           if (POLLIN & vp[i].events)
5571             {
5572               VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5573               rv = vppcom_session_read_ready (session, vp[i].sid);
5574               clib_spinlock_unlock (&vcm->sessions_lockp);
5575               if (rv > 0)
5576                 {
5577                   *vp[i].revents |= POLLIN;
5578                   num_ev++;
5579                 }
5580               else if (rv < 0)
5581                 {
5582                   switch (rv)
5583                     {
5584                     case VPPCOM_ECONNRESET:
5585                       *vp[i].revents = POLLHUP;
5586                       break;
5587
5588                     default:
5589                       *vp[i].revents = POLLERR;
5590                       break;
5591                     }
5592                   num_ev++;
5593                 }
5594             }
5595
5596           if (POLLOUT & vp[i].events)
5597             {
5598               VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5599               rv = vppcom_session_write_ready (session, vp[i].sid);
5600               clib_spinlock_unlock (&vcm->sessions_lockp);
5601               if (rv > 0)
5602                 {
5603                   *vp[i].revents |= POLLOUT;
5604                   num_ev++;
5605                 }
5606               else if (rv < 0)
5607                 {
5608                   switch (rv)
5609                     {
5610                     case VPPCOM_ECONNRESET:
5611                       *vp[i].revents = POLLHUP;
5612                       break;
5613
5614                     default:
5615                       *vp[i].revents = POLLERR;
5616                       break;
5617                     }
5618                   num_ev++;
5619                 }
5620             }
5621
5622           if (0)                // Note "done:" label used by VCL_LOCK_AND_GET_SESSION()
5623             {
5624             done:
5625               *vp[i].revents = POLLNVAL;
5626               num_ev++;
5627             }
5628         }
5629       if (wait_for_time != -1)
5630         keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
5631     }
5632   while ((num_ev == 0) && keep_trying);
5633
5634   if (VPPCOM_DEBUG > 3)
5635     {
5636       clib_warning ("VCL<%d>: returning %d", getpid (), num_ev);
5637       for (i = 0; i < n_sids; i++)
5638         {
5639           clib_warning ("VCL<%d>: vp[%d].sid %d (0x%x), .events 0x%x, "
5640                         ".revents 0x%x", getpid (), i, vp[i].sid, vp[i].sid,
5641                         vp[i].events, *vp[i].revents);
5642         }
5643     }
5644   return num_ev;
5645 }
5646
5647 /*
5648  * fd.io coding-style-patch-verification: ON
5649  *
5650  * Local Variables:
5651  * eval: (c-set-style "gnu")
5652  * End:
5653  */