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