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