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