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