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