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