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