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