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