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