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