VCL: add vpp api q length to config file.
[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
27 #define vl_typedefs             /* define message structures */
28 #include <vpp/api/vpe_all_api_h.h>
29 #undef vl_typedefs
30
31 /* declare message handlers for each api */
32
33 #define vl_endianfun            /* define message structures */
34 #include <vpp/api/vpe_all_api_h.h>
35 #undef vl_endianfun
36
37 /* instantiate all the print functions we know about */
38 #define vl_print(handle, ...)
39 #define vl_printfun
40 #include <vpp/api/vpe_all_api_h.h>
41 #undef vl_printfun
42
43 #if (CLIB_DEBUG > 0)
44 /* Set VPPCOM_DEBUG_INIT 2 for connection debug,
45  *                       3 for read/write debug output
46  * or
47  *    export VCL_DEBUG=<#> to set dynamically.
48  */
49 #define VPPCOM_DEBUG_INIT 1
50 #else
51 #define VPPCOM_DEBUG_INIT 0
52 #endif
53
54 #define VPPCOM_DEBUG vcm->debug
55
56 /*
57  * VPPCOM Private definitions and functions.
58  */
59 typedef enum
60 {
61   STATE_APP_START,
62   STATE_APP_CONN_VPP,
63   STATE_APP_ENABLED,
64   STATE_APP_ATTACHED,
65 } app_state_t;
66
67 typedef enum
68 {
69   STATE_START = 0x01,
70   STATE_CONNECT = 0x02,
71   STATE_LISTEN = 0x04,
72   STATE_ACCEPT = 0x08,
73   STATE_CLOSE_ON_EMPTY = 0x10,
74   STATE_DISCONNECT = 0x20,
75   STATE_FAILED = 0x40
76 } session_state_t;
77
78 #define SERVER_STATE_OPEN  (STATE_ACCEPT|STATE_CLOSE_ON_EMPTY)
79 #define CLIENT_STATE_OPEN  (STATE_CONNECT|STATE_CLOSE_ON_EMPTY)
80
81 typedef struct epoll_event vppcom_epoll_event_t;
82
83 typedef struct
84 {
85   u32 next_sid;
86   u32 prev_sid;
87   u32 vep_idx;
88   vppcom_epoll_event_t ev;
89 #define VEP_DEFAULT_ET_MASK  (EPOLLIN|EPOLLOUT)
90 #define VEP_UNSUPPORTED_EVENTS (EPOLLONESHOT|EPOLLEXCLUSIVE)
91   u32 et_mask;
92 } vppcom_epoll_t;
93
94 typedef struct
95 {
96   u8 is_ip4;
97   ip46_address_t ip46;
98 } vppcom_ip46_t;
99
100 typedef struct
101 {
102   volatile session_state_t state;
103
104   svm_fifo_t *server_rx_fifo;
105   svm_fifo_t *server_tx_fifo;
106   u8 *segment_name;
107   u32 sm_seg_index;
108   u32 client_context;
109   u64 vpp_handle;
110   unix_shared_memory_queue_t *vpp_event_queue;
111
112   /* Socket configuration state */
113   /* TBD: covert 'is_*' vars to bit in u8 flags; */
114   u8 is_server;
115   u8 is_listen;
116   u8 is_cut_thru;
117   u8 is_nonblocking;
118   u8 is_vep;
119   u8 is_vep_session;
120   u32 wait_cont_idx;
121   vppcom_epoll_t vep;
122   u32 vrf;
123   vppcom_ip46_t lcl_addr;
124   vppcom_ip46_t peer_addr;
125   u16 lcl_port;                 // network order
126   u16 peer_port;                // network order
127   u8 proto;
128   u64 client_queue_address;
129   u64 options[16];
130 } session_t;
131
132 typedef struct vppcom_cfg_t_
133 {
134   u64 heapsize;
135   u32 vpp_api_q_length;
136   u64 segment_baseva;
137   u32 segment_size;
138   u32 add_segment_size;
139   u32 preallocated_fifo_pairs;
140   u32 rx_fifo_size;
141   u32 tx_fifo_size;
142   u32 event_queue_size;
143   u32 listen_queue_size;
144   u8 app_proxy_transport_tcp;
145   u8 app_proxy_transport_udp;
146   u8 app_scope_local;
147   u8 app_scope_global;
148   u8 *namespace_id;
149   u64 namespace_secret;
150   f64 app_timeout;
151   f64 session_timeout;
152   f64 accept_timeout;
153 } vppcom_cfg_t;
154
155 typedef struct vppcom_main_t_
156 {
157   u8 init;
158   u32 debug;
159   u32 *client_session_index_fifo;
160   int main_cpu;
161
162   /* vpe input queue */
163   unix_shared_memory_queue_t *vl_input_queue;
164
165   /* API client handle */
166   u32 my_client_index;
167
168   /* Session pool */
169   clib_spinlock_t sessions_lockp;
170   session_t *sessions;
171
172   /* Hash table for disconnect processing */
173   uword *session_index_by_vpp_handles;
174
175   /* Select bitmaps */
176   clib_bitmap_t *rd_bitmap;
177   clib_bitmap_t *wr_bitmap;
178   clib_bitmap_t *ex_bitmap;
179
180   /* Our event queue */
181   unix_shared_memory_queue_t *app_event_queue;
182
183   /* unique segment name counter */
184   u32 unique_segment_index;
185
186   /* For deadman timers */
187   clib_time_t clib_time;
188
189   /* State of the connection, shared between msg RX thread and main thread */
190   volatile app_state_t app_state;
191
192   vppcom_cfg_t cfg;
193
194   /* VNET_API_ERROR_FOO -> "Foo" hash table */
195   uword *error_string_by_error_number;
196 } vppcom_main_t;
197
198 /* NOTE: _vppcom_main is only used until the heap is allocated.
199  *       Do not access it directly -- use vcm which will point to
200  *       the heap allocated copy after init.
201  */
202 static vppcom_main_t _vppcom_main = {
203   .debug = VPPCOM_DEBUG_INIT,
204   .my_client_index = ~0
205 };
206
207 static vppcom_main_t *vcm = &_vppcom_main;
208
209 #define VCL_LOCK_AND_GET_SESSION(I, S)                  \
210 do {                                                    \
211   clib_spinlock_lock (&vcm->sessions_lockp);            \
212   rv = vppcom_session_at_index (I, S);                  \
213   if (PREDICT_FALSE (rv))                               \
214     {                                                   \
215       clib_spinlock_unlock (&vcm->sessions_lockp);      \
216       clib_warning ("[%s] ERROR: Invalid ##I (%u)!",    \
217                     getpid (), I);                      \
218       goto done;                                        \
219     }                                                   \
220 } while (0)
221
222 static const char *
223 vppcom_app_state_str (app_state_t state)
224 {
225   char *st;
226
227   switch (state)
228     {
229     case STATE_APP_START:
230       st = "STATE_APP_START";
231       break;
232
233     case STATE_APP_CONN_VPP:
234       st = "STATE_APP_CONN_VPP";
235       break;
236
237     case STATE_APP_ENABLED:
238       st = "STATE_APP_ENABLED";
239       break;
240
241     case STATE_APP_ATTACHED:
242       st = "STATE_APP_ATTACHED";
243       break;
244
245     default:
246       st = "UNKNOWN_APP_STATE";
247       break;
248     }
249
250   return st;
251 }
252
253 static const char *
254 vppcom_session_state_str (session_state_t state)
255 {
256   char *st;
257
258   switch (state)
259     {
260     case STATE_START:
261       st = "STATE_START";
262       break;
263
264     case STATE_CONNECT:
265       st = "STATE_CONNECT";
266       break;
267
268     case STATE_LISTEN:
269       st = "STATE_LISTEN";
270       break;
271
272     case STATE_ACCEPT:
273       st = "STATE_ACCEPT";
274       break;
275
276     case STATE_CLOSE_ON_EMPTY:
277       st = "STATE_CLOSE_ON_EMPTY";
278       break;
279
280     case STATE_DISCONNECT:
281       st = "STATE_DISCONNECT";
282       break;
283
284     case STATE_FAILED:
285       st = "STATE_FAILED";
286       break;
287
288     default:
289       st = "UNKNOWN_STATE";
290       break;
291     }
292
293   return st;
294 }
295
296 /*
297  * VPPCOM Utility Functions
298  */
299 static inline int
300 vppcom_session_at_index (u32 session_index, session_t * volatile *sess)
301 {
302   /* Assumes that caller has acquired spinlock: vcm->sessions_lockp */
303   if (PREDICT_FALSE ((session_index == ~0) ||
304                      pool_is_free_index (vcm->sessions, session_index)))
305     {
306       clib_warning ("[%d] invalid session, sid (%u) has been closed!",
307                     getpid (), session_index);
308       return VPPCOM_EBADFD;
309     }
310   *sess = pool_elt_at_index (vcm->sessions, session_index);
311   return VPPCOM_OK;
312 }
313
314 static inline void
315 vppcom_session_table_add_listener (u64 listener_handle, u32 value)
316 {
317   /* Session and listener handles have different formats. The latter has
318    * the thread index in the upper 32 bits while the former has the session
319    * type. Knowing that, for listeners we just flip the MSB to 1 */
320   listener_handle |= 1ULL << 63;
321   hash_set (vcm->session_index_by_vpp_handles, listener_handle, value);
322 }
323
324 static inline session_t *
325 vppcom_session_table_lookup_listener (u64 listener_handle)
326 {
327   uword *p;
328   u64 handle = listener_handle | (1ULL << 63);
329   session_t *session;
330
331   p = hash_get (vcm->session_index_by_vpp_handles, handle);
332   if (!p)
333     {
334       clib_warning ("[%d] couldn't find listen session: unknown vpp "
335                     "listener handle %llx", getpid (), listener_handle);
336       return 0;
337     }
338   if (pool_is_free_index (vcm->sessions, p[0]))
339     {
340       if (VPPCOM_DEBUG > 1)
341         clib_warning ("[%d] invalid listen session, sid (%u)", getpid (),
342                       p[0]);
343       return 0;
344     }
345
346   session = pool_elt_at_index (vcm->sessions, p[0]);
347   ASSERT (session->is_listen);
348   return session;
349 }
350
351 static inline void
352 vppcom_session_table_del_listener (u64 listener_handle)
353 {
354   listener_handle |= 1ULL << 63;
355   hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
356 }
357
358 static int
359 vppcom_connect_to_vpp (char *app_name)
360 {
361   api_main_t *am = &api_main;
362
363   if (VPPCOM_DEBUG > 0)
364     printf ("\nConnecting to VPP api...");
365   if (vl_client_connect_to_vlib ("/vpe-api", app_name,
366                                  vcm->cfg.vpp_api_q_length) < 0)
367     {
368       clib_warning ("[%d] connect to vpp (%s) failed!", getpid (), app_name);
369       return VPPCOM_ECONNREFUSED;
370     }
371
372   vcm->vl_input_queue = am->shmem_hdr->vl_input_queue;
373   vcm->my_client_index = am->my_client_index;
374   if (VPPCOM_DEBUG > 0)
375     printf (" connected!\n");
376
377   vcm->app_state = STATE_APP_CONN_VPP;
378   return VPPCOM_OK;
379 }
380
381 static u8 *
382 format_api_error (u8 * s, va_list * args)
383 {
384   i32 error = va_arg (*args, u32);
385   uword *p;
386
387   p = hash_get (vcm->error_string_by_error_number, -error);
388
389   if (p)
390     s = format (s, "%s (%d)", p[0], error);
391   else
392     s = format (s, "%d", error);
393   return s;
394 }
395
396 static void
397 vppcom_init_error_string_table (void)
398 {
399   vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
400
401 #define _(n,v,s) hash_set (vcm->error_string_by_error_number, -v, s);
402   foreach_vnet_api_error;
403 #undef _
404
405   hash_set (vcm->error_string_by_error_number, 99, "Misc");
406 }
407
408 static inline int
409 vppcom_wait_for_app_state_change (app_state_t app_state)
410 {
411   f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout;
412
413   while (clib_time_now (&vcm->clib_time) < timeout)
414     {
415       if (vcm->app_state == app_state)
416         return VPPCOM_OK;
417     }
418   if (VPPCOM_DEBUG > 0)
419     clib_warning ("[%d] timeout waiting for state %s (%d)", getpid (),
420                   vppcom_app_state_str (app_state), app_state);
421   return VPPCOM_ETIMEDOUT;
422 }
423
424 static inline int
425 vppcom_wait_for_session_state_change (u32 session_index,
426                                       session_state_t state,
427                                       f64 wait_for_time)
428 {
429   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
430   session_t *volatile session;
431   int rv;
432
433   do
434     {
435       clib_spinlock_lock (&vcm->sessions_lockp);
436       rv = vppcom_session_at_index (session_index, &session);
437       if (PREDICT_FALSE (rv))
438         {
439           clib_spinlock_unlock (&vcm->sessions_lockp);
440           return rv;
441         }
442       if (session->state == state)
443         {
444           clib_spinlock_unlock (&vcm->sessions_lockp);
445           return VPPCOM_OK;
446         }
447       if (session->state == STATE_FAILED)
448         {
449           clib_spinlock_unlock (&vcm->sessions_lockp);
450           return VPPCOM_ECONNREFUSED;
451         }
452
453       clib_spinlock_unlock (&vcm->sessions_lockp);
454     }
455   while (clib_time_now (&vcm->clib_time) < timeout);
456
457   if (VPPCOM_DEBUG > 0)
458     clib_warning ("[%d] timeout waiting for state 0x%x (%s)", getpid (),
459                   state, vppcom_session_state_str (state));
460   return VPPCOM_ETIMEDOUT;
461 }
462
463 static inline int
464 vppcom_wait_for_client_session_index (f64 wait_for_time)
465 {
466   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
467
468   do
469     {
470       if (clib_fifo_elts (vcm->client_session_index_fifo))
471         return VPPCOM_OK;
472     }
473   while (clib_time_now (&vcm->clib_time) < timeout);
474
475   if (wait_for_time == 0)
476     return VPPCOM_EAGAIN;
477
478   if (VPPCOM_DEBUG > 0)
479     clib_warning ("[%d] timeout waiting for client_session_index", getpid ());
480   return VPPCOM_ETIMEDOUT;
481 }
482
483 /*
484  * VPP-API message functions
485  */
486 static void
487 vppcom_send_session_enable_disable (u8 is_enable)
488 {
489   vl_api_session_enable_disable_t *bmp;
490   bmp = vl_msg_api_alloc (sizeof (*bmp));
491   memset (bmp, 0, sizeof (*bmp));
492
493   bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
494   bmp->client_index = vcm->my_client_index;
495   bmp->context = htonl (0xfeedface);
496   bmp->is_enable = is_enable;
497   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
498 }
499
500 static int
501 vppcom_app_session_enable (void)
502 {
503   int rv;
504
505   if (vcm->app_state != STATE_APP_ENABLED)
506     {
507       vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
508       rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
509       if (PREDICT_FALSE (rv))
510         {
511           if (VPPCOM_DEBUG > 0)
512             clib_warning ("[%d] application session enable timed out! "
513                           "returning %d (%s)",
514                           getpid (), rv, vppcom_retval_str (rv));
515           return rv;
516         }
517     }
518   return VPPCOM_OK;
519 }
520
521 static void
522   vl_api_session_enable_disable_reply_t_handler
523   (vl_api_session_enable_disable_reply_t * mp)
524 {
525   if (mp->retval)
526     {
527       clib_warning ("[%d] session_enable_disable failed: %U", getpid (),
528                     format_api_error, ntohl (mp->retval));
529     }
530   else
531     vcm->app_state = STATE_APP_ENABLED;
532 }
533
534 static void
535 vppcom_app_send_attach (void)
536 {
537   vl_api_application_attach_t *bmp;
538   u8 nsid_len = vec_len (vcm->cfg.namespace_id);
539   u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
540                      vcm->cfg.app_proxy_transport_udp);
541
542   bmp = vl_msg_api_alloc (sizeof (*bmp));
543   memset (bmp, 0, sizeof (*bmp));
544
545   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
546   bmp->client_index = vcm->my_client_index;
547   bmp->context = htonl (0xfeedface);
548   bmp->options[APP_OPTIONS_FLAGS] =
549     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
550     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
551     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
552     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0);
553   bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
554     (vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
555     (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0);
556   bmp->options[SESSION_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
557   bmp->options[SESSION_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
558   bmp->options[SESSION_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
559   bmp->options[SESSION_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
560   if (nsid_len)
561     {
562       bmp->namespace_id_len = nsid_len;
563       clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
564       bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
565     }
566   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
567 }
568
569 static int
570 vppcom_app_attach (void)
571 {
572   int rv;
573
574   vppcom_app_send_attach ();
575   rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED);
576   if (PREDICT_FALSE (rv))
577     {
578       if (VPPCOM_DEBUG > 0)
579         clib_warning ("[%d] application attach timed out! returning %d (%s)",
580                       getpid (), rv, vppcom_retval_str (rv));
581       return rv;
582     }
583   return VPPCOM_OK;
584 }
585
586 static void
587 vppcom_app_detach (void)
588 {
589   vl_api_application_detach_t *bmp;
590   bmp = vl_msg_api_alloc (sizeof (*bmp));
591   memset (bmp, 0, sizeof (*bmp));
592
593   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
594   bmp->client_index = vcm->my_client_index;
595   bmp->context = htonl (0xfeedface);
596   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
597 }
598
599 static void
600 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
601                                            mp)
602 {
603   static svm_fifo_segment_create_args_t _a;
604   svm_fifo_segment_create_args_t *a = &_a;
605   int rv;
606
607   memset (a, 0, sizeof (*a));
608   if (mp->retval)
609     {
610       clib_warning ("[%d] attach failed: %U", getpid (),
611                     format_api_error, ntohl (mp->retval));
612       return;
613     }
614
615   if (mp->segment_name_length == 0)
616     {
617       clib_warning ("[%d] segment_name_length zero", getpid ());
618       return;
619     }
620
621   a->segment_name = (char *) mp->segment_name;
622   a->segment_size = mp->segment_size;
623
624   ASSERT (mp->app_event_queue_address);
625
626   /* Attach to the segment vpp created */
627   rv = svm_fifo_segment_attach (a);
628   vec_reset_length (a->new_segment_indices);
629   if (PREDICT_FALSE (rv))
630     {
631       clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed", getpid (),
632                     mp->segment_name);
633       return;
634     }
635
636   vcm->app_event_queue =
637     uword_to_pointer (mp->app_event_queue_address,
638                       unix_shared_memory_queue_t *);
639
640   vcm->app_state = STATE_APP_ATTACHED;
641 }
642
643 static void
644 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
645                                            mp)
646 {
647   if (mp->retval)
648     clib_warning ("[%d] detach failed: %U", getpid (), format_api_error,
649                   ntohl (mp->retval));
650
651   vcm->app_state = STATE_APP_ENABLED;
652 }
653
654 static void
655 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
656                                            mp)
657 {
658   if (mp->retval)
659     clib_warning ("[%d] vpp handle 0x%llx: disconnect session failed: %U",
660                   getpid (), mp->handle, format_api_error,
661                   ntohl (mp->retval));
662 }
663
664 static void
665 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
666 {
667   static svm_fifo_segment_create_args_t _a;
668   svm_fifo_segment_create_args_t *a = &_a;
669   int rv;
670
671   memset (a, 0, sizeof (*a));
672   a->segment_name = (char *) mp->segment_name;
673   a->segment_size = mp->segment_size;
674   /* Attach to the segment vpp created */
675   rv = svm_fifo_segment_attach (a);
676   vec_reset_length (a->new_segment_indices);
677   if (PREDICT_FALSE (rv))
678     {
679       clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed",
680                     getpid (), mp->segment_name);
681       return;
682     }
683   if (VPPCOM_DEBUG > 1)
684     clib_warning ("[%d] mapped new segment '%s' size %d", getpid (),
685                   mp->segment_name, mp->segment_size);
686 }
687
688 static void
689 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
690 {
691   uword *p;
692
693   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
694   if (p)
695     {
696       int rv;
697       session_t *session = 0;
698       u32 session_index = p[0];
699
700       VCL_LOCK_AND_GET_SESSION (session_index, &session);
701       session->state = STATE_CLOSE_ON_EMPTY;
702
703       if (VPPCOM_DEBUG > 1)
704         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
705                       "setting state to 0x%x (%s)",
706                       getpid (), mp->handle, session_index, session->state,
707                       vppcom_session_state_str (session->state));
708       clib_spinlock_unlock (&vcm->sessions_lockp);
709       return;
710
711     done:
712       if (VPPCOM_DEBUG > 1)
713         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
714                       "session lookup failed!",
715                       getpid (), mp->handle, session_index);
716     }
717   else
718     clib_warning ("[%d] vpp handle 0x%llx: session lookup by "
719                   "handle failed!", getpid (), mp->handle);
720 }
721
722 static void
723 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
724 {
725   session_t *session = 0;
726   vl_api_reset_session_reply_t *rmp;
727   uword *p;
728   int rv = 0;
729
730   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
731   if (p)
732     {
733       int rval;
734       clib_spinlock_lock (&vcm->sessions_lockp);
735       rval = vppcom_session_at_index (p[0], &session);
736       if (PREDICT_FALSE (rval))
737         {
738           rv = VNET_API_ERROR_INVALID_VALUE_2;
739           clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
740                         "session lookup failed! returning %d %U",
741                         getpid (), mp->handle, p[0],
742                         rv, format_api_error, rv);
743         }
744       else
745         {
746           /* TBD: should this disconnect immediately and
747            * flush the fifos?
748            */
749           session->state = STATE_CLOSE_ON_EMPTY;
750
751           if (VPPCOM_DEBUG > 1)
752             clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
753                           "state set to %d (%s)!", getpid (),
754                           mp->handle, p[0], session->state,
755                           vppcom_session_state_str (session->state));
756         }
757       clib_spinlock_unlock (&vcm->sessions_lockp);
758     }
759   else
760     {
761       rv = VNET_API_ERROR_INVALID_VALUE;
762       clib_warning ("[%d] ERROR: vpp handle 0x%llx: session lookup "
763                     "failed! returning %d %U",
764                     getpid (), mp->handle, rv, format_api_error, rv);
765     }
766
767   rmp = vl_msg_api_alloc (sizeof (*rmp));
768   memset (rmp, 0, sizeof (*rmp));
769   rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
770   rmp->retval = htonl (rv);
771   rmp->handle = mp->handle;
772   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
773 }
774
775 static void
776 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
777 {
778   session_t *session = 0;
779   u32 session_index;
780   svm_fifo_t *rx_fifo, *tx_fifo;
781   u8 is_cut_thru = 0;
782   int rv;
783
784   session_index = mp->context;
785   VCL_LOCK_AND_GET_SESSION (session_index, &session);
786 done:
787   if (mp->retval)
788     {
789       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
790                     "connect failed! %U",
791                     getpid (), mp->handle, session_index,
792                     format_api_error, ntohl (mp->retval));
793       if (rv == VPPCOM_OK)
794         {
795           session->state = STATE_FAILED;
796           session->vpp_handle = mp->handle;
797         }
798       else
799         {
800           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
801                         "Invalid session index (%u)!",
802                         getpid (), mp->handle, session_index);
803         }
804       goto done_unlock;
805     }
806
807   if (rv)
808     goto done_unlock;
809
810   /* We've been redirected */
811   if (mp->segment_name_length > 0)
812     {
813       static svm_fifo_segment_create_args_t _a;
814       svm_fifo_segment_create_args_t *a = &_a;
815
816       is_cut_thru = 1;
817       memset (a, 0, sizeof (*a));
818       a->segment_name = (char *) mp->segment_name;
819       if (VPPCOM_DEBUG > 1)
820         clib_warning ("[%d] cut-thru segment: %s\n",
821                       getpid (), a->segment_name);
822
823       rv = svm_fifo_segment_attach (a);
824       vec_reset_length (a->new_segment_indices);
825       if (PREDICT_FALSE (rv))
826         {
827           clib_warning ("[%d] sm_fifo_segment_attach ('%s') failed",
828                         getpid (), a->segment_name);
829           goto done_unlock;
830         }
831     }
832
833   /*
834    * Setup session
835    */
836   session->is_cut_thru = is_cut_thru;
837   session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
838                                                unix_shared_memory_queue_t *);
839
840   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
841   rx_fifo->client_session_index = session_index;
842   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
843   tx_fifo->client_session_index = session_index;
844
845   session->server_rx_fifo = rx_fifo;
846   session->server_tx_fifo = tx_fifo;
847   session->vpp_handle = mp->handle;
848   session->lcl_addr.is_ip4 = mp->is_ip4;
849   clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
850                sizeof (session->peer_addr.ip46));
851   session->lcl_port = mp->lcl_port;
852   session->state = STATE_CONNECT;
853
854   /* Add it to lookup table */
855   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
856
857   if (VPPCOM_DEBUG > 1)
858     clib_warning ("[%d] vpp handle 0x%llx, sid %u: connect succeeded!"
859                   " session_rx_fifo %p, refcnt %d,"
860                   " session_tx_fifo %p, refcnt %d",
861                   getpid (), mp->handle, session_index,
862                   session->server_rx_fifo,
863                   session->server_rx_fifo->refcnt,
864                   session->server_tx_fifo, session->server_tx_fifo->refcnt);
865 done_unlock:
866   clib_spinlock_unlock (&vcm->sessions_lockp);
867 }
868
869 static void
870 vppcom_send_connect_sock (session_t * session, u32 session_index)
871 {
872   vl_api_connect_sock_t *cmp;
873
874   /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */
875   session->is_server = 0;
876   cmp = vl_msg_api_alloc (sizeof (*cmp));
877   memset (cmp, 0, sizeof (*cmp));
878   cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK);
879   cmp->client_index = vcm->my_client_index;
880   cmp->context = session_index;
881
882   cmp->vrf = session->vrf;
883   cmp->is_ip4 = session->peer_addr.is_ip4;
884   clib_memcpy (cmp->ip, &session->peer_addr.ip46, sizeof (cmp->ip));
885   cmp->port = session->peer_port;
886   cmp->proto = session->proto;
887   clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
888   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
889 }
890
891 static inline void
892 vppcom_send_disconnect_session_reply (u64 vpp_handle, u32 session_index,
893                                       int rv)
894 {
895   vl_api_disconnect_session_reply_t *rmp;
896
897   if (VPPCOM_DEBUG > 1)
898     clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending disconnect msg",
899                   getpid (), vpp_handle, session_index);
900
901   rmp = vl_msg_api_alloc (sizeof (*rmp));
902   memset (rmp, 0, sizeof (*rmp));
903
904   rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
905   rmp->retval = htonl (rv);
906   rmp->handle = vpp_handle;
907   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
908 }
909
910 static inline void
911 vppcom_send_disconnect_session (u64 vpp_handle, u32 session_index)
912 {
913   vl_api_disconnect_session_t *dmp;
914
915   if (VPPCOM_DEBUG > 1)
916     clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending disconnect msg",
917                   getpid (), vpp_handle, session_index);
918
919   dmp = vl_msg_api_alloc (sizeof (*dmp));
920   memset (dmp, 0, sizeof (*dmp));
921   dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
922   dmp->client_index = vcm->my_client_index;
923   dmp->handle = vpp_handle;
924   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp);
925 }
926
927 static void
928 vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
929 {
930   session_t *session = 0;
931   u32 session_index = mp->context;
932   int rv;
933
934   VCL_LOCK_AND_GET_SESSION (session_index, &session);
935 done:
936   if (mp->retval)
937     {
938       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: bind failed: %U",
939                     getpid (), mp->handle, session_index, format_api_error,
940                     ntohl (mp->retval));
941       rv = vppcom_session_at_index (session_index, &session);
942       if (rv == VPPCOM_OK)
943         {
944           session->state = STATE_FAILED;
945           session->vpp_handle = mp->handle;
946         }
947       else
948         {
949           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
950                         "Invalid session index (%u)!",
951                         getpid (), mp->handle, session_index);
952         }
953       goto done_unlock;
954     }
955
956   session->vpp_handle = mp->handle;
957   session->lcl_addr.is_ip4 = mp->lcl_is_ip4;
958   clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
959                sizeof (session->peer_addr.ip46));
960   session->lcl_port = mp->lcl_port;
961   vppcom_session_table_add_listener (mp->handle, session_index);
962   session->is_listen = 1;
963   session->state = STATE_LISTEN;
964
965   if (VPPCOM_DEBUG > 1)
966     clib_warning ("[%d] vpp handle 0x%llx, sid %u: bind succeeded!",
967                   getpid (), mp->handle, mp->context);
968 done_unlock:
969   clib_spinlock_unlock (&vcm->sessions_lockp);
970 }
971
972 static void
973 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
974 {
975   if (mp->retval)
976     clib_warning ("[%d] ERROR: sid %u: unbind failed: %U",
977                   getpid (), mp->context, format_api_error,
978                   ntohl (mp->retval));
979
980   else if (VPPCOM_DEBUG > 1)
981     clib_warning ("[%d] sid %u: unbind succeeded!", getpid (), mp->context);
982 }
983
984 u8 *
985 format_ip4_address (u8 * s, va_list * args)
986 {
987   u8 *a = va_arg (*args, u8 *);
988   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
989 }
990
991 u8 *
992 format_ip6_address (u8 * s, va_list * args)
993 {
994   ip6_address_t *a = va_arg (*args, ip6_address_t *);
995   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
996
997   i_max_n_zero = ARRAY_LEN (a->as_u16);
998   max_n_zeros = 0;
999   i_first_zero = i_max_n_zero;
1000   n_zeros = 0;
1001   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1002     {
1003       u32 is_zero = a->as_u16[i] == 0;
1004       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
1005         {
1006           i_first_zero = i;
1007           n_zeros = 0;
1008         }
1009       n_zeros += is_zero;
1010       if ((!is_zero && n_zeros > max_n_zeros)
1011           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
1012         {
1013           i_max_n_zero = i_first_zero;
1014           max_n_zeros = n_zeros;
1015           i_first_zero = ARRAY_LEN (a->as_u16);
1016           n_zeros = 0;
1017         }
1018     }
1019
1020   last_double_colon = 0;
1021   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1022     {
1023       if (i == i_max_n_zero && max_n_zeros > 1)
1024         {
1025           s = format (s, "::");
1026           i += max_n_zeros - 1;
1027           last_double_colon = 1;
1028         }
1029       else
1030         {
1031           s = format (s, "%s%x",
1032                       (last_double_colon || i == 0) ? "" : ":",
1033                       clib_net_to_host_u16 (a->as_u16[i]));
1034           last_double_colon = 0;
1035         }
1036     }
1037
1038   return s;
1039 }
1040
1041 /* Format an IP46 address. */
1042 u8 *
1043 format_ip46_address (u8 * s, va_list * args)
1044 {
1045   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1046   ip46_type_t type = va_arg (*args, ip46_type_t);
1047   int is_ip4 = 1;
1048
1049   switch (type)
1050     {
1051     case IP46_TYPE_ANY:
1052       is_ip4 = ip46_address_is_ip4 (ip46);
1053       break;
1054     case IP46_TYPE_IP4:
1055       is_ip4 = 1;
1056       break;
1057     case IP46_TYPE_IP6:
1058       is_ip4 = 0;
1059       break;
1060     }
1061
1062   return is_ip4 ?
1063     format (s, "%U", format_ip4_address, &ip46->ip4) :
1064     format (s, "%U", format_ip6_address, &ip46->ip6);
1065 }
1066
1067 static inline void
1068 vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
1069 {
1070   vl_api_accept_session_reply_t *rmp;
1071
1072   rmp = vl_msg_api_alloc (sizeof (*rmp));
1073   memset (rmp, 0, sizeof (*rmp));
1074   rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
1075   rmp->retval = htonl (retval);
1076   rmp->context = context;
1077   rmp->handle = handle;
1078   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1079 }
1080
1081 static void
1082 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
1083 {
1084   svm_fifo_t *rx_fifo, *tx_fifo;
1085   session_t *session, *listen_session;
1086   u32 session_index;
1087
1088   clib_spinlock_lock (&vcm->sessions_lockp);
1089   if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
1090     {
1091       clib_warning ("[%d] client session queue is full!", getpid ());
1092       vppcom_send_accept_session_reply (mp->handle, mp->context,
1093                                         VNET_API_ERROR_QUEUE_FULL);
1094       clib_spinlock_unlock (&vcm->sessions_lockp);
1095       return;
1096     }
1097
1098   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1099   if (!listen_session)
1100     {
1101       clib_warning ("[%d] ERROR: couldn't find listen session: unknown vpp "
1102                     "listener handle %llx", getpid (), mp->listener_handle);
1103       clib_spinlock_unlock (&vcm->sessions_lockp);
1104       return;
1105     }
1106
1107   /* Allocate local session and set it up */
1108   pool_get (vcm->sessions, session);
1109   memset (session, 0, sizeof (*session));
1110   session_index = session - vcm->sessions;
1111
1112   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1113   rx_fifo->client_session_index = session_index;
1114   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1115   tx_fifo->client_session_index = session_index;
1116
1117   session->vpp_handle = mp->handle;
1118   session->client_context = mp->context;
1119   session->server_rx_fifo = rx_fifo;
1120   session->server_tx_fifo = tx_fifo;
1121   session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1122                                                unix_shared_memory_queue_t *);
1123   session->state = STATE_ACCEPT;
1124   session->is_cut_thru = 0;
1125   session->is_server = 1;
1126   session->peer_port = mp->port;
1127   session->peer_addr.is_ip4 = mp->is_ip4;
1128   clib_memcpy (&session->peer_addr.ip46, mp->ip,
1129                sizeof (session->peer_addr.ip46));
1130
1131   /* Add it to lookup table */
1132   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1133   session->lcl_port = listen_session->lcl_port;
1134   session->lcl_addr = listen_session->lcl_addr;
1135
1136   /* TBD: move client_session_index_fifo into listener session */
1137   clib_fifo_add1 (vcm->client_session_index_fifo, session_index);
1138
1139   clib_spinlock_unlock (&vcm->sessions_lockp);
1140
1141   if (VPPCOM_DEBUG > 1)
1142     clib_warning ("[%d] vpp handle 0x%llx, sid %u: client accept "
1143                   "request from %s address %U port %d queue %p!", getpid (),
1144                   mp->handle, session_index, mp->is_ip4 ? "IPv4" : "IPv6",
1145                   format_ip46_address, &mp->ip, mp->is_ip4,
1146                   clib_net_to_host_u16 (mp->port), session->vpp_event_queue);
1147 }
1148
1149 static void
1150 vppcom_send_connect_session_reply (session_t * session, u32 session_index,
1151                                    u64 vpp_handle, u32 context, int retval)
1152 {
1153   vl_api_connect_session_reply_t *rmp;
1154   u32 len;
1155   unix_shared_memory_queue_t *client_q;
1156
1157   rmp = vl_msg_api_alloc (sizeof (*rmp));
1158   memset (rmp, 0, sizeof (*rmp));
1159   rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY);
1160
1161   if (!session)
1162     {
1163       rmp->context = context;
1164       rmp->handle = vpp_handle;
1165       rmp->retval = htonl (retval);
1166       vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1167       return;
1168     }
1169
1170   rmp->context = session->client_context;
1171   rmp->retval = htonl (retval);
1172   rmp->handle = session->vpp_handle;
1173   rmp->server_rx_fifo = pointer_to_uword (session->server_rx_fifo);
1174   rmp->server_tx_fifo = pointer_to_uword (session->server_tx_fifo);
1175   rmp->vpp_event_queue_address = pointer_to_uword (session->vpp_event_queue);
1176   rmp->segment_size = vcm->cfg.segment_size;
1177   len = vec_len (session->segment_name);
1178   rmp->segment_name_length = clib_min (len, sizeof (rmp->segment_name));
1179   clib_memcpy (rmp->segment_name, session->segment_name,
1180                rmp->segment_name_length - 1);
1181   clib_memcpy (rmp->lcl_ip, session->peer_addr.ip46.as_u8,
1182                sizeof (rmp->lcl_ip));
1183   rmp->is_ip4 = session->peer_addr.is_ip4;
1184   rmp->lcl_port = session->peer_port;
1185   client_q = uword_to_pointer (session->client_queue_address,
1186                                unix_shared_memory_queue_t *);
1187   ASSERT (client_q);
1188   vl_msg_api_send_shmem (client_q, (u8 *) & rmp);
1189 }
1190
1191 /*
1192  * Acting as server for redirected connect requests
1193  */
1194 static void
1195 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
1196 {
1197   u32 session_index;
1198   session_t *session = 0;
1199
1200   clib_spinlock_lock (&vcm->sessions_lockp);
1201   if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
1202     {
1203       clib_spinlock_unlock (&vcm->sessions_lockp);
1204
1205       if (VPPCOM_DEBUG > 1)
1206         clib_warning ("[%d] client session queue is full!", getpid ());
1207
1208       /* TBD: Fix api to include vpp handle */
1209       vppcom_send_connect_session_reply (0 /* session */ , 0 /* sid */ ,
1210                                          0 /* handle */ , mp->context,
1211                                          VNET_API_ERROR_QUEUE_FULL);
1212       return;
1213     }
1214
1215   pool_get (vcm->sessions, session);
1216   memset (session, 0, sizeof (*session));
1217   session_index = session - vcm->sessions;
1218
1219   session->client_context = mp->context;
1220   session->vpp_handle = session_index;
1221   session->client_queue_address = mp->client_queue_address;
1222   session->is_cut_thru = 1;
1223   session->is_server = 1;
1224   session->lcl_port = mp->port;
1225   session->lcl_addr.is_ip4 = mp->is_ip4;
1226   clib_memcpy (&session->lcl_addr.ip46, mp->ip,
1227                sizeof (session->lcl_addr.ip46));
1228
1229   /* TBD: missing peer info in api msg.
1230    */
1231   session->peer_addr.is_ip4 = mp->is_ip4;
1232   ASSERT (session->lcl_addr.is_ip4 == session->peer_addr.is_ip4);
1233
1234   session->state = STATE_ACCEPT;
1235   clib_fifo_add1 (vcm->client_session_index_fifo, session_index);
1236   if (VPPCOM_DEBUG > 1)
1237     clib_warning ("[%d] sid %u: Got a cut-thru connect request! "
1238                   "clib_fifo_elts %u!\n", getpid (), session_index,
1239                   clib_fifo_elts (vcm->client_session_index_fifo));
1240   clib_spinlock_unlock (&vcm->sessions_lockp);
1241 }
1242
1243 static void
1244 vppcom_send_bind_sock (session_t * session, u32 session_index)
1245 {
1246   vl_api_bind_sock_t *bmp;
1247
1248   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1249   session->is_server = 1;
1250   bmp = vl_msg_api_alloc (sizeof (*bmp));
1251   memset (bmp, 0, sizeof (*bmp));
1252
1253   bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK);
1254   bmp->client_index = vcm->my_client_index;
1255   bmp->context = session_index;
1256   bmp->vrf = session->vrf;
1257   bmp->is_ip4 = session->lcl_addr.is_ip4;
1258   clib_memcpy (bmp->ip, &session->lcl_addr.ip46, sizeof (bmp->ip));
1259   bmp->port = session->lcl_port;
1260   bmp->proto = session->proto;
1261   clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
1262   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
1263 }
1264
1265 static void
1266 vppcom_send_unbind_sock (u64 vpp_handle)
1267 {
1268   vl_api_unbind_sock_t *ump;
1269
1270   ump = vl_msg_api_alloc (sizeof (*ump));
1271   memset (ump, 0, sizeof (*ump));
1272
1273   ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK);
1274   ump->client_index = vcm->my_client_index;
1275   ump->handle = vpp_handle;
1276   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump);
1277 }
1278
1279 static int
1280 vppcom_session_unbind (u32 session_index)
1281 {
1282   session_t *session = 0;
1283   int rv;
1284   u64 vpp_handle;
1285
1286   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1287
1288   vpp_handle = session->vpp_handle;
1289   vppcom_session_table_del_listener (vpp_handle);
1290   session->vpp_handle = ~0;
1291   session->state = STATE_DISCONNECT;
1292
1293   clib_spinlock_unlock (&vcm->sessions_lockp);
1294
1295   if (VPPCOM_DEBUG > 1)
1296     clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1297                   "sending unbind msg! new state 0x%x (%s)",
1298                   getpid (), vpp_handle, session_index,
1299                   session->state, vppcom_session_state_str (session->state));
1300
1301   vppcom_send_unbind_sock (vpp_handle);
1302
1303 done:
1304   return rv;
1305 }
1306
1307 static inline int
1308 vppcom_session_disconnect (u32 session_index)
1309 {
1310   int rv;
1311   session_t *session;
1312   u8 is_cut_thru, is_listen, is_server;
1313   u64 vpp_handle;
1314   session_state_t state;
1315
1316   VCL_LOCK_AND_GET_SESSION (session_index, &session);
1317
1318   vpp_handle = session->vpp_handle;
1319   is_server = session->is_server;
1320   is_listen = session->is_listen;
1321   is_cut_thru = session->is_cut_thru;
1322   state = session->state;
1323   clib_spinlock_unlock (&vcm->sessions_lockp);
1324
1325   if (VPPCOM_DEBUG > 1)
1326     {
1327       clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s state 0x%x (%s), "
1328                     "is_cut_thru %d, is_listen %d",
1329                     getpid (), vpp_handle, session_index,
1330                     is_server ? "server" : "client",
1331                     state, vppcom_session_state_str (state),
1332                     is_cut_thru, is_listen);
1333     }
1334
1335   if (PREDICT_FALSE (is_listen))
1336     {
1337       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
1338                     "Cannot disconnect a listen socket!",
1339                     getpid (), vpp_handle, session_index);
1340       rv = VPPCOM_EBADFD;
1341       goto done;
1342     }
1343
1344   /* Through the VPP host stack...
1345    */
1346   else if (!is_cut_thru)
1347     {
1348       /* The peer has already initiated the close,
1349        * so send the disconnect session reply.
1350        */
1351       if (state & STATE_CLOSE_ON_EMPTY)
1352         {
1353           vppcom_send_disconnect_session_reply (vpp_handle,
1354                                                 session_index, 0 /* rv */ );
1355           if (VPPCOM_DEBUG > 1)
1356             clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1357                           "sending disconnect REPLY...",
1358                           getpid (), vpp_handle, session_index);
1359         }
1360
1361       /* Otherwise, send a disconnect session msg...
1362        */
1363       else
1364         {
1365           if (VPPCOM_DEBUG > 1)
1366             clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1367                           "sending disconnect...",
1368                           getpid (), vpp_handle, session_index);
1369
1370           vppcom_send_disconnect_session (vpp_handle, session_index);
1371         }
1372     }
1373
1374   /* Cut-thru connections...
1375    *
1376    *   server: free fifos and segment allocated during connect/redirect
1377    *   client: no cleanup required
1378    */
1379   else
1380     {
1381       if (is_server)
1382         {
1383           svm_fifo_segment_main_t *sm = &svm_fifo_segment_main;
1384           svm_fifo_segment_private_t *seg;
1385
1386           VCL_LOCK_AND_GET_SESSION (session_index, &session);
1387
1388           if (VPPCOM_DEBUG > 1)
1389             clib_warning ("[%d] sid %d: freeing cut-thru fifos in "
1390                           "sm_seg_index %d! "
1391                           " server_rx_fifo %p, refcnt = %d"
1392                           " server_tx_fifo %p, refcnt = %d",
1393                           getpid (), session_index, session->sm_seg_index,
1394                           session->server_rx_fifo,
1395                           session->server_rx_fifo->refcnt,
1396                           session->server_tx_fifo,
1397                           session->server_tx_fifo->refcnt);
1398
1399           seg = vec_elt_at_index (sm->segments, session->sm_seg_index);
1400           svm_fifo_segment_free_fifo (seg, session->server_rx_fifo,
1401                                       FIFO_SEGMENT_RX_FREELIST);
1402           svm_fifo_segment_free_fifo (seg, session->server_tx_fifo,
1403                                       FIFO_SEGMENT_TX_FREELIST);
1404           svm_fifo_segment_delete (seg);
1405
1406           /* TBD: Send cut-thru disconnect event to client */
1407
1408           clib_spinlock_unlock (&vcm->sessions_lockp);
1409         }
1410       else
1411         {
1412           /* TBD: Send cut-thru disconnect event to server */
1413         }
1414     }
1415
1416 done:
1417   return rv;
1418 }
1419
1420 #define foreach_sock_msg                                        \
1421 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply)   \
1422 _(BIND_SOCK_REPLY, bind_sock_reply)                             \
1423 _(UNBIND_SOCK_REPLY, unbind_sock_reply)                         \
1424 _(ACCEPT_SESSION, accept_session)                               \
1425 _(CONNECT_SOCK, connect_sock)                                   \
1426 _(CONNECT_SESSION_REPLY, connect_session_reply)                 \
1427 _(DISCONNECT_SESSION, disconnect_session)                       \
1428 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)           \
1429 _(RESET_SESSION, reset_session)                                 \
1430 _(APPLICATION_ATTACH_REPLY, application_attach_reply)           \
1431 _(APPLICATION_DETACH_REPLY, application_detach_reply)           \
1432 _(MAP_ANOTHER_SEGMENT, map_another_segment)
1433
1434 static void
1435 vppcom_api_hookup (void)
1436 {
1437 #define _(N,n)                                                  \
1438     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1439                            vl_api_##n##_t_handler,              \
1440                            vl_noop_handler,                     \
1441                            vl_api_##n##_t_endian,               \
1442                            vl_api_##n##_t_print,                \
1443                            sizeof(vl_api_##n##_t), 1);
1444   foreach_sock_msg;
1445 #undef _
1446 }
1447
1448 static void
1449 vppcom_cfg_init (vppcom_cfg_t * vcl_cfg)
1450 {
1451   ASSERT (vcl_cfg);
1452
1453   vcl_cfg->heapsize = (256ULL << 20);
1454   vcl_cfg->vpp_api_q_length = 1024;
1455   vcl_cfg->segment_baseva = 0x200000000ULL;
1456   vcl_cfg->segment_size = (256 << 20);
1457   vcl_cfg->add_segment_size = (128 << 20);
1458   vcl_cfg->preallocated_fifo_pairs = 8;
1459   vcl_cfg->rx_fifo_size = (1 << 20);
1460   vcl_cfg->tx_fifo_size = (1 << 20);
1461   vcl_cfg->event_queue_size = 2048;
1462   vcl_cfg->listen_queue_size = CLIB_CACHE_LINE_BYTES / sizeof (u32);
1463   vcl_cfg->app_timeout = 10 * 60.0;
1464   vcl_cfg->session_timeout = 10 * 60.0;
1465   vcl_cfg->accept_timeout = 60.0;
1466 }
1467
1468 static void
1469 vppcom_cfg_heapsize (char *conf_fname)
1470 {
1471   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1472   FILE *fp;
1473   char inbuf[4096];
1474   int argc = 1;
1475   char **argv = NULL;
1476   char *arg = NULL;
1477   char *p;
1478   int i;
1479   u8 *sizep;
1480   u32 size;
1481   void *vcl_mem;
1482   void *heap;
1483
1484   fp = fopen (conf_fname, "r");
1485   if (fp == NULL)
1486     {
1487       if (VPPCOM_DEBUG > 0)
1488         fprintf (stderr, "open configuration file '%s' failed\n", conf_fname);
1489       goto defaulted;
1490     }
1491   argv = calloc (1, sizeof (char *));
1492   if (argv == NULL)
1493     goto defaulted;
1494
1495   while (1)
1496     {
1497       if (fgets (inbuf, 4096, fp) == 0)
1498         break;
1499       p = strtok (inbuf, " \t\n");
1500       while (p != NULL)
1501         {
1502           if (*p == '#')
1503             break;
1504           argc++;
1505           char **tmp = realloc (argv, argc * sizeof (char *));
1506           if (tmp == NULL)
1507             goto defaulted;
1508           argv = tmp;
1509           arg = strndup (p, 1024);
1510           if (arg == NULL)
1511             goto defaulted;
1512           argv[argc - 1] = arg;
1513           p = strtok (NULL, " \t\n");
1514         }
1515     }
1516
1517   fclose (fp);
1518   fp = NULL;
1519
1520   char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
1521   if (tmp == NULL)
1522     goto defaulted;
1523   argv = tmp;
1524   argv[argc] = NULL;
1525
1526   /*
1527    * Look for and parse the "heapsize" config parameter.
1528    * Manual since none of the clib infra has been bootstrapped yet.
1529    *
1530    * Format: heapsize <nn>[mM][gG]
1531    */
1532
1533   for (i = 1; i < (argc - 1); i++)
1534     {
1535       if (!strncmp (argv[i], "heapsize", 8))
1536         {
1537           sizep = (u8 *) argv[i + 1];
1538           size = 0;
1539           while (*sizep >= '0' && *sizep <= '9')
1540             {
1541               size *= 10;
1542               size += *sizep++ - '0';
1543             }
1544           if (size == 0)
1545             {
1546               if (VPPCOM_DEBUG > 0)
1547                 clib_warning ("[%d] parse error '%s %s', "
1548                               "using default heapsize %lld (0x%llx)",
1549                               getpid (), argv[i], argv[i + 1],
1550                               vcl_cfg->heapsize, vcl_cfg->heapsize);
1551               goto defaulted;
1552             }
1553
1554           if (*sizep == 'g' || *sizep == 'G')
1555             vcl_cfg->heapsize = size << 30;
1556           else if (*sizep == 'm' || *sizep == 'M')
1557             vcl_cfg->heapsize = size << 20;
1558           else
1559             {
1560               if (VPPCOM_DEBUG > 0)
1561                 clib_warning ("[%d] parse error '%s %s', "
1562                               "using default heapsize %lld (0x%llx)",
1563                               getpid (), argv[i], argv[i + 1],
1564                               vcl_cfg->heapsize, vcl_cfg->heapsize);
1565               goto defaulted;
1566             }
1567         }
1568     }
1569
1570 defaulted:
1571   if (fp != NULL)
1572     fclose (fp);
1573   if (argv != NULL)
1574     free (argv);
1575
1576   vcl_mem = mmap (0, vcl_cfg->heapsize, PROT_READ | PROT_WRITE,
1577                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1578   if (vcl_mem == MAP_FAILED)
1579     {
1580       clib_unix_error ("[%d] ERROR: mmap(0, %lld == 0x%llx, "
1581                        "PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, "
1582                        "-1, 0) failed!",
1583                        getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1584       return;
1585     }
1586   heap = clib_mem_init (vcl_mem, vcl_cfg->heapsize);
1587   if (!heap)
1588     {
1589       clib_warning ("[%d] ERROR: clib_mem_init() failed!", getpid ());
1590       return;
1591     }
1592   vcl_mem = clib_mem_alloc (sizeof (_vppcom_main));
1593   if (!vcl_mem)
1594     {
1595       clib_warning ("[%d] ERROR: clib_mem_alloc() failed!", getpid ());
1596       return;
1597     }
1598
1599   clib_memcpy (vcl_mem, &_vppcom_main, sizeof (_vppcom_main));
1600   vcm = vcl_mem;
1601
1602   if (VPPCOM_DEBUG > 0)
1603     clib_warning ("[%d] allocated VCL heap = %p, size %lld (0x%llx)",
1604                   getpid (), heap, vcl_cfg->heapsize, vcl_cfg->heapsize);
1605 }
1606
1607 static void
1608 vppcom_cfg_read (char *conf_fname)
1609 {
1610   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1611   int fd;
1612   unformat_input_t _input, *input = &_input;
1613   unformat_input_t _line_input, *line_input = &_line_input;
1614   u8 vc_cfg_input = 0;
1615   u8 *chroot_path;
1616   struct stat s;
1617   u32 uid, gid, q_len;
1618
1619   fd = open (conf_fname, O_RDONLY);
1620   if (fd < 0)
1621     {
1622       if (VPPCOM_DEBUG > 0)
1623         clib_warning ("[%d] open configuration file '%s' failed!",
1624                       getpid (), conf_fname);
1625       goto file_done;
1626     }
1627
1628   if (fstat (fd, &s) < 0)
1629     {
1630       if (VPPCOM_DEBUG > 0)
1631         clib_warning ("[%d] failed to stat `%s'", getpid (), conf_fname);
1632       goto file_done;
1633     }
1634
1635   if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
1636     {
1637       if (VPPCOM_DEBUG > 0)
1638         clib_warning ("[%d] not a regular file `%s'", getpid (), conf_fname);
1639       goto file_done;
1640     }
1641
1642   unformat_init_clib_file (input, fd);
1643
1644   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1645     {
1646       (void) unformat_user (input, unformat_line_input, line_input);
1647       unformat_skip_white_space (line_input);
1648
1649       if (unformat (line_input, "vcl {"))
1650         {
1651           vc_cfg_input = 1;
1652           continue;
1653         }
1654
1655       if (vc_cfg_input)
1656         {
1657           if (unformat (line_input, "heapsize %s", &chroot_path))
1658             {
1659               vec_terminate_c_string (chroot_path);
1660               if (VPPCOM_DEBUG > 0)
1661                 clib_warning ("[%d] configured heapsize %s, "
1662                               "actual heapsize %lld (0x%llx)",
1663                               getpid (), chroot_path, vcl_cfg->heapsize,
1664                               vcl_cfg->heapsize);
1665               vec_free (chroot_path);
1666             }
1667           else if (unformat (line_input, "api-prefix %s", &chroot_path))
1668             {
1669               vec_terminate_c_string (chroot_path);
1670               vl_set_memory_root_path ((char *) chroot_path);
1671               if (VPPCOM_DEBUG > 0)
1672                 clib_warning ("[%d] configured api-prefix %s",
1673                               getpid (), chroot_path);
1674               chroot_path = 0;  /* Don't vec_free() it! */
1675             }
1676           else if (unformat (line_input, "vpp-api-q-length %d", &q_len))
1677             {
1678               if (q_len < vcl_cfg->vpp_api_q_length)
1679                 {
1680                   clib_warning ("[%d] ERROR: configured vpp-api-q-length "
1681                                 "(%u) is too small! Using default: %u ",
1682                                 getpid (), q_len, vcl_cfg->vpp_api_q_length);
1683                 }
1684               else
1685                 {
1686                   vcl_cfg->vpp_api_q_length = q_len;
1687
1688                   if (VPPCOM_DEBUG > 0)
1689                     clib_warning ("[%d] configured vpp-api-q-length %u",
1690                                   getpid (), vcl_cfg->vpp_api_q_length);
1691                 }
1692             }
1693           else if (unformat (line_input, "uid %d", &uid))
1694             {
1695               vl_set_memory_uid (uid);
1696               if (VPPCOM_DEBUG > 0)
1697                 clib_warning ("[%d] configured uid %d", getpid (), uid);
1698             }
1699           else if (unformat (line_input, "gid %d", &gid))
1700             {
1701               vl_set_memory_gid (gid);
1702               if (VPPCOM_DEBUG > 0)
1703                 clib_warning ("[%d] configured gid %d", getpid (), gid);
1704             }
1705           else if (unformat (line_input, "segment-baseva 0x%lx",
1706                              &vcl_cfg->segment_baseva))
1707             {
1708               if (VPPCOM_DEBUG > 0)
1709                 clib_warning ("[%d] configured segment_baseva 0x%lx",
1710                               getpid (), vcl_cfg->segment_baseva);
1711             }
1712           else if (unformat (line_input, "segment-size 0x%lx",
1713                              &vcl_cfg->segment_size))
1714             {
1715               if (VPPCOM_DEBUG > 0)
1716                 clib_warning ("[%d] configured segment_size 0x%lx (%ld)",
1717                               getpid (), vcl_cfg->segment_size,
1718                               vcl_cfg->segment_size);
1719             }
1720           else if (unformat (line_input, "segment-size %ld",
1721                              &vcl_cfg->segment_size))
1722             {
1723               if (VPPCOM_DEBUG > 0)
1724                 clib_warning ("[%d] configured segment_size %ld (0x%lx)",
1725                               getpid (), vcl_cfg->segment_size,
1726                               vcl_cfg->segment_size);
1727             }
1728           else if (unformat (line_input, "add-segment-size 0x%lx",
1729                              &vcl_cfg->add_segment_size))
1730             {
1731               if (VPPCOM_DEBUG > 0)
1732                 clib_warning
1733                   ("[%d] configured add_segment_size 0x%lx (%ld)",
1734                    getpid (), vcl_cfg->add_segment_size,
1735                    vcl_cfg->add_segment_size);
1736             }
1737           else if (unformat (line_input, "add-segment-size %ld",
1738                              &vcl_cfg->add_segment_size))
1739             {
1740               if (VPPCOM_DEBUG > 0)
1741                 clib_warning
1742                   ("[%d] configured add_segment_size %ld (0x%lx)",
1743                    getpid (), vcl_cfg->add_segment_size,
1744                    vcl_cfg->add_segment_size);
1745             }
1746           else if (unformat (line_input, "preallocated-fifo-pairs %d",
1747                              &vcl_cfg->preallocated_fifo_pairs))
1748             {
1749               if (VPPCOM_DEBUG > 0)
1750                 clib_warning ("[%d] configured preallocated_fifo_pairs "
1751                               "%d (0x%x)", getpid (),
1752                               vcl_cfg->preallocated_fifo_pairs,
1753                               vcl_cfg->preallocated_fifo_pairs);
1754             }
1755           else if (unformat (line_input, "rx-fifo-size 0x%lx",
1756                              &vcl_cfg->rx_fifo_size))
1757             {
1758               if (VPPCOM_DEBUG > 0)
1759                 clib_warning ("[%d] configured rx_fifo_size 0x%lx (%ld)",
1760                               getpid (), vcl_cfg->rx_fifo_size,
1761                               vcl_cfg->rx_fifo_size);
1762             }
1763           else if (unformat (line_input, "rx-fifo-size %ld",
1764                              &vcl_cfg->rx_fifo_size))
1765             {
1766               if (VPPCOM_DEBUG > 0)
1767                 clib_warning ("[%d] configured rx_fifo_size %ld (0x%lx)",
1768                               getpid (), vcl_cfg->rx_fifo_size,
1769                               vcl_cfg->rx_fifo_size);
1770             }
1771           else if (unformat (line_input, "tx-fifo-size 0x%lx",
1772                              &vcl_cfg->tx_fifo_size))
1773             {
1774               if (VPPCOM_DEBUG > 0)
1775                 clib_warning ("[%d] configured tx_fifo_size 0x%lx (%ld)",
1776                               getpid (), vcl_cfg->tx_fifo_size,
1777                               vcl_cfg->tx_fifo_size);
1778             }
1779           else if (unformat (line_input, "tx-fifo-size %ld",
1780                              &vcl_cfg->tx_fifo_size))
1781             {
1782               if (VPPCOM_DEBUG > 0)
1783                 clib_warning ("[%d] configured tx_fifo_size %ld (0x%lx)",
1784                               getpid (), vcl_cfg->tx_fifo_size,
1785                               vcl_cfg->tx_fifo_size);
1786             }
1787           else if (unformat (line_input, "event-queue-size 0x%lx",
1788                              &vcl_cfg->event_queue_size))
1789             {
1790               if (VPPCOM_DEBUG > 0)
1791                 clib_warning ("[%d] configured event_queue_size 0x%lx (%ld)",
1792                               getpid (), vcl_cfg->event_queue_size,
1793                               vcl_cfg->event_queue_size);
1794             }
1795           else if (unformat (line_input, "event-queue-size %ld",
1796                              &vcl_cfg->event_queue_size))
1797             {
1798               if (VPPCOM_DEBUG > 0)
1799                 clib_warning ("[%d] configured event_queue_size %ld (0x%lx)",
1800                               getpid (), vcl_cfg->event_queue_size,
1801                               vcl_cfg->event_queue_size);
1802             }
1803           else if (unformat (line_input, "listen-queue-size 0x%lx",
1804                              &vcl_cfg->listen_queue_size))
1805             {
1806               if (VPPCOM_DEBUG > 0)
1807                 clib_warning ("[%d] configured listen_queue_size 0x%lx (%ld)",
1808                               getpid (), vcl_cfg->listen_queue_size,
1809                               vcl_cfg->listen_queue_size);
1810             }
1811           else if (unformat (line_input, "listen-queue-size %ld",
1812                              &vcl_cfg->listen_queue_size))
1813             {
1814               if (VPPCOM_DEBUG > 0)
1815                 clib_warning ("[%d] configured listen_queue_size %ld (0x%lx)",
1816                               getpid (), vcl_cfg->listen_queue_size,
1817                               vcl_cfg->listen_queue_size);
1818             }
1819           else if (unformat (line_input, "app-timeout %f",
1820                              &vcl_cfg->app_timeout))
1821             {
1822               if (VPPCOM_DEBUG > 0)
1823                 clib_warning ("[%d] configured app_timeout %f",
1824                               getpid (), vcl_cfg->app_timeout);
1825             }
1826           else if (unformat (line_input, "session-timeout %f",
1827                              &vcl_cfg->session_timeout))
1828             {
1829               if (VPPCOM_DEBUG > 0)
1830                 clib_warning ("[%d] configured session_timeout %f",
1831                               getpid (), vcl_cfg->session_timeout);
1832             }
1833           else if (unformat (line_input, "accept-timeout %f",
1834                              &vcl_cfg->accept_timeout))
1835             {
1836               if (VPPCOM_DEBUG > 0)
1837                 clib_warning ("[%d] configured accept_timeout %f",
1838                               getpid (), vcl_cfg->accept_timeout);
1839             }
1840           else if (unformat (line_input, "app-proxy-transport-tcp"))
1841             {
1842               vcl_cfg->app_proxy_transport_tcp = 1;
1843               if (VPPCOM_DEBUG > 0)
1844                 clib_warning ("[%d] configured app_proxy_transport_tcp (%d)",
1845                               getpid (), vcl_cfg->app_proxy_transport_tcp);
1846             }
1847           else if (unformat (line_input, "app-proxy-transport-udp"))
1848             {
1849               vcl_cfg->app_proxy_transport_udp = 1;
1850               if (VPPCOM_DEBUG > 0)
1851                 clib_warning ("[%d] configured app_proxy_transport_udp (%d)",
1852                               getpid (), vcl_cfg->app_proxy_transport_udp);
1853             }
1854           else if (unformat (line_input, "app-scope-local"))
1855             {
1856               vcl_cfg->app_scope_local = 1;
1857               if (VPPCOM_DEBUG > 0)
1858                 clib_warning ("[%d] configured app_scope_local (%d)",
1859                               getpid (), vcl_cfg->app_scope_local);
1860             }
1861           else if (unformat (line_input, "app-scope-global"))
1862             {
1863               vcl_cfg->app_scope_global = 1;
1864               if (VPPCOM_DEBUG > 0)
1865                 clib_warning ("[%d] configured app_scope_global (%d)",
1866                               getpid (), vcl_cfg->app_scope_global);
1867             }
1868           else if (unformat (line_input, "namespace-secret %lu",
1869                              &vcl_cfg->namespace_secret))
1870             {
1871               if (VPPCOM_DEBUG > 0)
1872                 clib_warning
1873                   ("[%d] configured namespace_secret %lu (0x%lx)",
1874                    getpid (), vcl_cfg->namespace_secret,
1875                    vcl_cfg->namespace_secret);
1876             }
1877           else if (unformat (line_input, "namespace-id %v",
1878                              &vcl_cfg->namespace_id))
1879             {
1880               vl_api_application_attach_t *mp;
1881               u32 max_nsid_vec_len = sizeof (mp->namespace_id) - 1;
1882               u32 nsid_vec_len = vec_len (vcl_cfg->namespace_id);
1883               if (nsid_vec_len > max_nsid_vec_len)
1884                 {
1885                   _vec_len (vcl_cfg->namespace_id) = max_nsid_vec_len;
1886                   if (VPPCOM_DEBUG > 0)
1887                     clib_warning ("[%d] configured namespace_id is too long,"
1888                                   " truncated to %d characters!", getpid (),
1889                                   max_nsid_vec_len);
1890                 }
1891
1892               if (VPPCOM_DEBUG > 0)
1893                 clib_warning ("[%d] configured namespace_id %v",
1894                               getpid (), vcl_cfg->namespace_id);
1895             }
1896           else if (unformat (line_input, "}"))
1897             {
1898               vc_cfg_input = 0;
1899               if (VPPCOM_DEBUG > 0)
1900                 clib_warning ("[%d] completed parsing vppcom config!",
1901                               getpid ());
1902               goto input_done;
1903             }
1904           else
1905             {
1906               if (line_input->buffer[line_input->index] != '#')
1907                 {
1908                   clib_warning ("[%d] Unknown vppcom config option: '%s'",
1909                                 getpid (), (char *)
1910                                 &line_input->buffer[line_input->index]);
1911                 }
1912             }
1913         }
1914     }
1915
1916 input_done:
1917   unformat_free (input);
1918
1919 file_done:
1920   if (fd >= 0)
1921     close (fd);
1922 }
1923
1924 /*
1925  * VPPCOM Public API functions
1926  */
1927 int
1928 vppcom_app_create (char *app_name)
1929 {
1930   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1931   u8 *heap;
1932   mheap_t *h;
1933   int rv;
1934
1935   if (!vcm->init)
1936     {
1937       char *conf_fname;
1938       char *env_var_str;
1939
1940       vcm->init = 1;
1941       vppcom_cfg_init (vcl_cfg);
1942       env_var_str = getenv (VPPCOM_ENV_DEBUG);
1943       if (env_var_str)
1944         {
1945           u32 tmp;
1946           if (sscanf (env_var_str, "%u", &tmp) != 1)
1947             clib_warning ("[%d] Invalid debug level specified in "
1948                           "the environment variable "
1949                           VPPCOM_ENV_DEBUG
1950                           " (%s)!\n", getpid (), env_var_str);
1951           else
1952             {
1953               vcm->debug = tmp;
1954               clib_warning ("[%d] configured debug level (%u) from "
1955                             VPPCOM_ENV_DEBUG "!", getpid (), vcm->debug);
1956             }
1957         }
1958       conf_fname = getenv (VPPCOM_ENV_CONF);
1959       if (!conf_fname)
1960         {
1961           conf_fname = VPPCOM_CONF_DEFAULT;
1962           if (VPPCOM_DEBUG > 0)
1963             clib_warning ("[%d] getenv '%s' failed!", getpid (),
1964                           VPPCOM_ENV_CONF);
1965         }
1966       vppcom_cfg_heapsize (conf_fname);
1967       clib_fifo_validate (vcm->client_session_index_fifo,
1968                           vcm->cfg.listen_queue_size);
1969       vppcom_cfg_read (conf_fname);
1970       env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_ID);
1971       if (env_var_str)
1972         {
1973           u32 ns_id_vec_len = strlen (env_var_str);
1974
1975           vec_reset_length (vcm->cfg.namespace_id);
1976           vec_validate (vcm->cfg.namespace_id, ns_id_vec_len - 1);
1977           clib_memcpy (vcm->cfg.namespace_id, env_var_str, ns_id_vec_len);
1978
1979           if (VPPCOM_DEBUG > 0)
1980             clib_warning ("[%d] configured namespace_id (%v) from "
1981                           VPPCOM_ENV_APP_NAMESPACE_ID "!", getpid (),
1982                           vcm->cfg.namespace_id);
1983         }
1984       env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
1985       if (env_var_str)
1986         {
1987           u64 tmp;
1988           if (sscanf (env_var_str, "%lu", &tmp) != 1)
1989             clib_warning ("[%d] Invalid namespace secret specified in "
1990                           "the environment variable "
1991                           VPPCOM_ENV_APP_NAMESPACE_SECRET
1992                           " (%s)!\n", getpid (), env_var_str);
1993           else
1994             {
1995               vcm->cfg.namespace_secret = tmp;
1996               if (VPPCOM_DEBUG > 0)
1997                 clib_warning ("[%d] configured namespace secret (%lu) from "
1998                               VPPCOM_ENV_APP_NAMESPACE_ID "!", getpid (),
1999                               vcm->cfg.namespace_secret);
2000             }
2001         }
2002       if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP))
2003         {
2004           vcm->cfg.app_proxy_transport_tcp = 1;
2005           if (VPPCOM_DEBUG > 0)
2006             clib_warning ("[%d] configured app_proxy_transport_tcp (%u) from "
2007                           VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP "!", getpid (),
2008                           vcm->cfg.app_proxy_transport_tcp);
2009         }
2010       if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP))
2011         {
2012           vcm->cfg.app_proxy_transport_udp = 1;
2013           if (VPPCOM_DEBUG > 0)
2014             clib_warning ("[%d] configured app_proxy_transport_udp (%u) from "
2015                           VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP "!", getpid (),
2016                           vcm->cfg.app_proxy_transport_udp);
2017         }
2018       if (getenv (VPPCOM_ENV_APP_SCOPE_LOCAL))
2019         {
2020           vcm->cfg.app_scope_local = 1;
2021           if (VPPCOM_DEBUG > 0)
2022             clib_warning ("[%d] configured app_scope_local (%u) from "
2023                           VPPCOM_ENV_APP_SCOPE_LOCAL "!", getpid (),
2024                           vcm->cfg.app_scope_local);
2025         }
2026       if (getenv (VPPCOM_ENV_APP_SCOPE_GLOBAL))
2027         {
2028           vcm->cfg.app_scope_global = 1;
2029           if (VPPCOM_DEBUG > 0)
2030             clib_warning ("[%d] configured app_scope_global (%u) from "
2031                           VPPCOM_ENV_APP_SCOPE_GLOBAL "!", getpid (),
2032                           vcm->cfg.app_scope_global);
2033         }
2034
2035       vcm->main_cpu = os_get_thread_index ();
2036       heap = clib_mem_get_per_cpu_heap ();
2037       h = mheap_header (heap);
2038
2039       /* make the main heap thread-safe */
2040       h->flags |= MHEAP_FLAG_THREAD_SAFE;
2041
2042       vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
2043
2044       clib_time_init (&vcm->clib_time);
2045       vppcom_init_error_string_table ();
2046       svm_fifo_segment_init (vcl_cfg->segment_baseva,
2047                              20 /* timeout in secs */ );
2048       clib_spinlock_init (&vcm->sessions_lockp);
2049       vppcom_api_hookup ();
2050     }
2051
2052   if (vcm->my_client_index == ~0)
2053     {
2054       vcm->app_state = STATE_APP_START;
2055       rv = vppcom_connect_to_vpp (app_name);
2056       if (rv)
2057         {
2058           clib_warning ("[%d] ERROR: couldn't connect to VPP!", getpid ());
2059           return rv;
2060         }
2061
2062       if (VPPCOM_DEBUG > 0)
2063         clib_warning ("[%d] sending session enable", getpid ());
2064
2065       rv = vppcom_app_session_enable ();
2066       if (rv)
2067         {
2068           clib_warning ("[%d] ERROR: vppcom_app_session_enable() failed!",
2069                         getpid ());
2070           return rv;
2071         }
2072
2073       if (VPPCOM_DEBUG > 0)
2074         clib_warning ("[%d] sending app attach", getpid ());
2075
2076       rv = vppcom_app_attach ();
2077       if (rv)
2078         {
2079           clib_warning ("[%d] ERROR: vppcom_app_attach() failed!", getpid ());
2080           return rv;
2081         }
2082
2083       if (VPPCOM_DEBUG > 0)
2084         clib_warning ("[%d] app_name '%s', my_client_index %d (0x%x)",
2085                       getpid (), app_name, vcm->my_client_index,
2086                       vcm->my_client_index);
2087     }
2088
2089   return VPPCOM_OK;
2090 }
2091
2092 void
2093 vppcom_app_destroy (void)
2094 {
2095   int rv;
2096
2097   if (vcm->my_client_index == ~0)
2098     return;
2099
2100   if (VPPCOM_DEBUG > 0)
2101     clib_warning ("[%d] detaching from VPP, my_client_index %d (0x%x)",
2102                   getpid (), vcm->my_client_index, vcm->my_client_index);
2103
2104   vppcom_app_detach ();
2105   rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
2106   if (PREDICT_FALSE (rv))
2107     {
2108       if (VPPCOM_DEBUG > 0)
2109         clib_warning ("[%d] application detach timed out! returning %d (%s)",
2110                       getpid (), rv, vppcom_retval_str (rv));
2111     }
2112   vl_client_disconnect_from_vlib ();
2113   vcm->my_client_index = ~0;
2114   vcm->app_state = STATE_APP_START;
2115 }
2116
2117 int
2118 vppcom_session_create (u32 vrf, u8 proto, u8 is_nonblocking)
2119 {
2120   session_t *session;
2121   u32 session_index;
2122
2123   clib_spinlock_lock (&vcm->sessions_lockp);
2124   pool_get (vcm->sessions, session);
2125   memset (session, 0, sizeof (*session));
2126   session_index = session - vcm->sessions;
2127
2128   session->vrf = vrf;
2129   session->proto = proto;
2130   session->state = STATE_START;
2131   session->is_nonblocking = is_nonblocking ? 1 : 0;
2132   session->vpp_handle = ~0;
2133   clib_spinlock_unlock (&vcm->sessions_lockp);
2134
2135   if (VPPCOM_DEBUG > 0)
2136     clib_warning ("[%d] sid %u", getpid (), session_index);
2137
2138   return (int) session_index;
2139 }
2140
2141 int
2142 vppcom_session_close (uint32_t session_index)
2143 {
2144   session_t *session = 0;
2145   int rv;
2146   u8 is_listen;
2147   u8 is_vep;
2148   u8 is_vep_session;
2149   u32 next_sid;
2150   u32 vep_idx;
2151   u64 vpp_handle;
2152   uword *p;
2153   session_state_t state;
2154
2155   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2156   is_listen = session->is_listen;
2157   is_vep = session->is_vep;
2158   is_vep_session = session->is_vep_session;
2159   next_sid = session->vep.next_sid;
2160   vep_idx = session->vep.vep_idx;
2161   state = session->state;
2162   vpp_handle = session->vpp_handle;
2163   clib_spinlock_unlock (&vcm->sessions_lockp);
2164
2165   if (VPPCOM_DEBUG > 0)
2166     {
2167       if (is_vep)
2168         clib_warning ("[%d] vep_idx %u / sid %u: closing epoll session...",
2169                       getpid (), session_index, session_index);
2170       else
2171         clib_warning ("[%d] vpp handle 0x%llx, sid %d: closing session...",
2172                       getpid (), vpp_handle, session_index);
2173     }
2174
2175   if (is_vep)
2176     {
2177       while (next_sid != ~0)
2178         {
2179           rv = vppcom_epoll_ctl (session_index, EPOLL_CTL_DEL, next_sid, 0);
2180           if ((VPPCOM_DEBUG > 0) && PREDICT_FALSE (rv < 0))
2181             clib_warning ("[%d] vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
2182                           "vep_idx %u failed! rv %d (%s)", getpid (),
2183                           vpp_handle, next_sid, vep_idx,
2184                           rv, vppcom_retval_str (rv));
2185
2186           VCL_LOCK_AND_GET_SESSION (session_index, &session);
2187           next_sid = session->vep.next_sid;
2188           clib_spinlock_unlock (&vcm->sessions_lockp);
2189         }
2190     }
2191   else
2192     {
2193       if (is_vep_session)
2194         {
2195           rv = vppcom_epoll_ctl (vep_idx, EPOLL_CTL_DEL, session_index, 0);
2196           if ((VPPCOM_DEBUG > 0) && (rv < 0))
2197             clib_warning ("[%d] vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
2198                           "vep_idx %u failed! rv %d (%s)",
2199                           getpid (), vpp_handle, session_index,
2200                           vep_idx, rv, vppcom_retval_str (rv));
2201         }
2202
2203       if (is_listen)
2204         {
2205           if (state == STATE_LISTEN)
2206             {
2207               rv = vppcom_session_unbind (session_index);
2208               if (PREDICT_FALSE (rv < 0))
2209                 {
2210                   if (VPPCOM_DEBUG > 0)
2211                     clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2212                                   "listener unbind failed! rv %d (%s)",
2213                                   getpid (), vpp_handle, session_index,
2214                                   rv, vppcom_retval_str (rv));
2215                 }
2216             }
2217         }
2218
2219       else if (state & (CLIENT_STATE_OPEN | SERVER_STATE_OPEN))
2220         {
2221           rv = vppcom_session_disconnect (session_index);
2222           if (PREDICT_FALSE (rv < 0))
2223             clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2224                           "session disconnect failed! rv %d (%s)",
2225                           getpid (), vpp_handle, session_index,
2226                           rv, vppcom_retval_str (rv));
2227         }
2228     }
2229
2230   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2231   vpp_handle = session->vpp_handle;
2232   if (vpp_handle != ~0)
2233     {
2234       p = hash_get (vcm->session_index_by_vpp_handles, vpp_handle);
2235       if (p)
2236         hash_unset (vcm->session_index_by_vpp_handles, vpp_handle);
2237     }
2238   pool_put_index (vcm->sessions, session_index);
2239   clib_spinlock_unlock (&vcm->sessions_lockp);
2240
2241   if (VPPCOM_DEBUG > 0)
2242     {
2243       if (is_vep)
2244         clib_warning ("[%d] vep_idx %u / sid %u: epoll session removed.",
2245                       getpid (), session_index, session_index);
2246       else
2247         clib_warning ("[%d] vpp handle 0x%llx, sid %u: session removed.",
2248                       getpid (), vpp_handle, session_index);
2249     }
2250 done:
2251   return rv;
2252 }
2253
2254 int
2255 vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
2256 {
2257   session_t *session = 0;
2258   int rv;
2259
2260   if (!ep || !ep->ip)
2261     return VPPCOM_EINVAL;
2262
2263   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2264
2265   if (session->is_vep)
2266     {
2267       clib_spinlock_unlock (&vcm->sessions_lockp);
2268       clib_warning ("[%d] ERROR: sid %u: cannot bind to an epoll session!",
2269                     getpid (), session_index);
2270       rv = VPPCOM_EBADFD;
2271       goto done;
2272     }
2273
2274   session->vrf = ep->vrf;
2275   session->lcl_addr.is_ip4 = ep->is_ip4;
2276   session->lcl_addr.ip46 = to_ip46 (!ep->is_ip4, ep->ip);
2277   session->lcl_port = ep->port;
2278
2279   if (VPPCOM_DEBUG > 0)
2280     clib_warning ("[%d] sid %u: binding to local %s address %U "
2281                   "port %u, proto %s", getpid (), session_index,
2282                   session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2283                   format_ip46_address, &session->lcl_addr.ip46,
2284                   session->lcl_addr.is_ip4,
2285                   clib_net_to_host_u16 (session->lcl_port),
2286                   session->proto ? "UDP" : "TCP");
2287
2288   clib_spinlock_unlock (&vcm->sessions_lockp);
2289 done:
2290   return rv;
2291 }
2292
2293 int
2294 vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
2295 {
2296   session_t *listen_session = 0;
2297   u64 listen_vpp_handle;
2298   int rv, retval;
2299
2300   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2301
2302   if (listen_session->is_vep)
2303     {
2304       clib_spinlock_unlock (&vcm->sessions_lockp);
2305       clib_warning ("[%d] ERROR: sid %u: cannot listen on an "
2306                     "epoll session!", getpid (), listen_session_index);
2307       rv = VPPCOM_EBADFD;
2308       goto done;
2309     }
2310
2311   listen_vpp_handle = listen_session->vpp_handle;
2312   if (listen_session->is_listen)
2313     {
2314       clib_spinlock_unlock (&vcm->sessions_lockp);
2315       if (VPPCOM_DEBUG > 0)
2316         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2317                       "already in listen state!",
2318                       getpid (), listen_vpp_handle, listen_session_index);
2319       rv = VPPCOM_OK;
2320       goto done;
2321     }
2322
2323   if (VPPCOM_DEBUG > 0)
2324     clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending bind request...",
2325                   getpid (), listen_vpp_handle, listen_session_index);
2326
2327   vppcom_send_bind_sock (listen_session, listen_session_index);
2328   clib_spinlock_unlock (&vcm->sessions_lockp);
2329   retval =
2330     vppcom_wait_for_session_state_change (listen_session_index, STATE_LISTEN,
2331                                           vcm->cfg.session_timeout);
2332
2333   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2334   if (PREDICT_FALSE (retval))
2335     {
2336       if (VPPCOM_DEBUG > 0)
2337         clib_warning ("[%d] vpp handle 0x%llx, sid %u: bind failed! "
2338                       "returning %d (%s)", getpid (),
2339                       listen_session->vpp_handle, listen_session_index,
2340                       retval, vppcom_retval_str (retval));
2341       clib_spinlock_unlock (&vcm->sessions_lockp);
2342       rv = retval;
2343       goto done;
2344     }
2345
2346   clib_fifo_validate (vcm->client_session_index_fifo, q_len);
2347   clib_spinlock_unlock (&vcm->sessions_lockp);
2348 done:
2349   return rv;
2350 }
2351
2352 int
2353 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
2354                        uint32_t flags, double wait_for_time)
2355 {
2356   session_t *listen_session = 0;
2357   session_t *client_session = 0;
2358   u32 client_session_index = ~0;
2359   int rv;
2360   f64 wait_for;
2361   char *cut_thru_str;
2362   u64 listen_vpp_handle;
2363
2364   VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2365
2366   if (listen_session->is_vep)
2367     {
2368       clib_spinlock_unlock (&vcm->sessions_lockp);
2369       clib_warning ("[%d] ERROR: sid %u: cannot accept on an "
2370                     "epoll session!", getpid (), listen_session_index);
2371       rv = VPPCOM_EBADFD;
2372       goto done;
2373     }
2374
2375   listen_vpp_handle = listen_session->vpp_handle;
2376   if (listen_session->state != STATE_LISTEN)
2377     {
2378       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2379                     "not in listen state! state 0x%x (%s)", getpid (),
2380                     listen_vpp_handle, listen_session_index,
2381                     listen_session->state,
2382                     vppcom_session_state_str (listen_session->state));
2383       clib_spinlock_unlock (&vcm->sessions_lockp);
2384       rv = VPPCOM_EBADFD;
2385       goto done;
2386     }
2387   wait_for = ((listen_session->is_nonblocking) ? 0 :
2388               (wait_for_time < 0) ? vcm->cfg.accept_timeout : wait_for_time);
2389
2390   clib_spinlock_unlock (&vcm->sessions_lockp);
2391
2392   while (1)
2393     {
2394       rv = vppcom_wait_for_client_session_index (wait_for);
2395       if (rv)
2396         {
2397           if ((VPPCOM_DEBUG > 0))
2398             clib_warning ("[%d] vpp handle 0x%llx, sid %u: accept failed! "
2399                           "returning %d (%s)", getpid (),
2400                           listen_vpp_handle, listen_session_index,
2401                           rv, vppcom_retval_str (rv));
2402           if ((wait_for == 0) || (wait_for_time > 0))
2403             goto done;
2404         }
2405       else
2406         break;
2407     }
2408
2409   clib_spinlock_lock (&vcm->sessions_lockp);
2410   clib_fifo_sub1 (vcm->client_session_index_fifo, client_session_index);
2411   rv = vppcom_session_at_index (client_session_index, &client_session);
2412   if (PREDICT_FALSE (rv))
2413     {
2414       rv = VPPCOM_ECONNABORTED;
2415       clib_warning ("[%d] vpp handle 0x%llx, sid %u: client sid %u "
2416                     "lookup failed! returning %d (%s)", getpid (),
2417                     listen_vpp_handle, listen_session_index,
2418                     client_session_index, rv, vppcom_retval_str (rv));
2419       goto done;
2420     }
2421
2422   client_session->is_nonblocking = (flags & O_NONBLOCK) ? 1 : 0;
2423   if (VPPCOM_DEBUG > 0)
2424     clib_warning ("[%d] vpp handle 0x%llx, sid %u: Got a client request! "
2425                   "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
2426                   getpid (), listen_vpp_handle, listen_session_index,
2427                   client_session->vpp_handle, client_session_index,
2428                   flags, client_session->is_nonblocking);
2429
2430   ep->vrf = client_session->vrf;
2431   ep->is_cut_thru = client_session->is_cut_thru;
2432   ep->is_ip4 = client_session->peer_addr.is_ip4;
2433   ep->port = client_session->peer_port;
2434   if (client_session->peer_addr.is_ip4)
2435     clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip4,
2436                  sizeof (ip4_address_t));
2437   else
2438     clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip6,
2439                  sizeof (ip6_address_t));
2440
2441   if (client_session->is_server && client_session->is_cut_thru)
2442     {
2443       static svm_fifo_segment_create_args_t _a;
2444       svm_fifo_segment_create_args_t *a = &_a;
2445       svm_fifo_segment_private_t *seg;
2446
2447       cut_thru_str = " cut-thru ";
2448
2449       /* Create the segment */
2450       memset (a, 0, sizeof (*a));
2451       a->segment_name = (char *)
2452         format ((u8 *) a->segment_name, "%d:segment%d%c",
2453                 getpid (), vcm->unique_segment_index++, 0);
2454       a->segment_size = vcm->cfg.segment_size;
2455       a->preallocated_fifo_pairs = vcm->cfg.preallocated_fifo_pairs;
2456       a->rx_fifo_size = vcm->cfg.rx_fifo_size;
2457       a->tx_fifo_size = vcm->cfg.tx_fifo_size;
2458
2459       rv = svm_fifo_segment_create (a);
2460       if (PREDICT_FALSE (rv))
2461         {
2462           clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2463                         "client sid %u svm_fifo_segment_create ('%s') "
2464                         "failed! rv %d", getpid (), listen_vpp_handle,
2465                         listen_session_index, client_session_index,
2466                         a->segment_name, rv);
2467           vec_reset_length (a->new_segment_indices);
2468           rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2469           vppcom_send_connect_session_reply (client_session,
2470                                              client_session_index,
2471                                              client_session->vpp_handle,
2472                                              client_session->client_context,
2473                                              rv);
2474           clib_spinlock_unlock (&vcm->sessions_lockp);
2475           rv = VPPCOM_ENOMEM;
2476           goto done;
2477         }
2478
2479       client_session->segment_name = vec_dup ((u8 *) a->segment_name);
2480       client_session->sm_seg_index = a->new_segment_indices[0];
2481       vec_free (a->new_segment_indices);
2482
2483       seg = svm_fifo_segment_get_segment (client_session->sm_seg_index);
2484       client_session->server_rx_fifo =
2485         svm_fifo_segment_alloc_fifo (seg, vcm->cfg.rx_fifo_size,
2486                                      FIFO_SEGMENT_RX_FREELIST);
2487       if (PREDICT_FALSE (!client_session->server_rx_fifo))
2488         {
2489           svm_fifo_segment_delete (seg);
2490           clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2491                         "client sid %u rx fifo alloc failed! "
2492                         "size %ld (0x%lx)", getpid (), listen_vpp_handle,
2493                         listen_session_index, client_session_index,
2494                         vcm->cfg.rx_fifo_size, vcm->cfg.rx_fifo_size);
2495           rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2496           vppcom_send_connect_session_reply (client_session,
2497                                              client_session_index,
2498                                              client_session->vpp_handle,
2499                                              client_session->client_context,
2500                                              rv);
2501           clib_spinlock_unlock (&vcm->sessions_lockp);
2502           rv = VPPCOM_ENOMEM;
2503           goto done;
2504         }
2505       client_session->server_rx_fifo->master_session_index =
2506         client_session_index;
2507
2508       client_session->server_tx_fifo =
2509         svm_fifo_segment_alloc_fifo (seg, vcm->cfg.tx_fifo_size,
2510                                      FIFO_SEGMENT_TX_FREELIST);
2511       if (PREDICT_FALSE (!client_session->server_tx_fifo))
2512         {
2513           svm_fifo_segment_delete (seg);
2514           clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2515                         "client sid %u tx fifo alloc failed! "
2516                         "size %ld (0x%lx)", getpid (), listen_vpp_handle,
2517                         listen_session_index, client_session_index,
2518                         vcm->cfg.tx_fifo_size, vcm->cfg.tx_fifo_size);
2519           rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2520           vppcom_send_connect_session_reply (client_session,
2521                                              client_session_index,
2522                                              client_session->vpp_handle,
2523                                              client_session->client_context,
2524                                              rv);
2525           clib_spinlock_unlock (&vcm->sessions_lockp);
2526           rv = VPPCOM_ENOMEM;
2527           goto done;
2528         }
2529       client_session->server_tx_fifo->master_session_index =
2530         client_session_index;
2531
2532       if (VPPCOM_DEBUG > 1)
2533         clib_warning ("[%d] vpp handle 0x%llx, sid %u: client sid %u "
2534                       "created segment '%s', rx_fifo %p, tx_fifo %p",
2535                       getpid (), listen_vpp_handle, listen_session_index,
2536                       client_session_index, client_session->segment_name,
2537                       client_session->server_rx_fifo,
2538                       client_session->server_tx_fifo);
2539
2540 #ifdef CUT_THRU_EVENT_QUEUE     /* TBD */
2541       {
2542         void *oldheap;
2543         ssvm_shared_header_t *sh = seg->ssvm.sh;
2544
2545         ssvm_lock_non_recursive (sh, 1);
2546         oldheap = ssvm_push_heap (sh);
2547         event_q = client_session->vpp_event_queue =
2548           unix_shared_memory_queue_init (vcm->cfg.event_queue_size,
2549                                          sizeof (session_fifo_event_t),
2550                                          getpid (), 0 /* signal not sent */ );
2551         ssvm_pop_heap (oldheap);
2552         ssvm_unlock_non_recursive (sh);
2553       }
2554 #endif
2555       vppcom_send_connect_session_reply (client_session,
2556                                          client_session_index,
2557                                          client_session->vpp_handle,
2558                                          client_session->client_context,
2559                                          0 /* retval OK */ );
2560     }
2561   else
2562     {
2563       cut_thru_str = " ";
2564       vppcom_send_accept_session_reply (client_session->vpp_handle,
2565                                         client_session->client_context,
2566                                         0 /* retval OK */ );
2567     }
2568
2569   if (VPPCOM_DEBUG > 0)
2570     clib_warning ("[%d] vpp handle 0x%llx, sid %u: accepted vpp handle "
2571                   "0x%llx, sid %u%sconnection to local %s address "
2572                   "%U port %u", getpid (), listen_vpp_handle,
2573                   listen_session_index, client_session->vpp_handle,
2574                   client_session_index, cut_thru_str,
2575                   client_session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2576                   format_ip46_address, &client_session->lcl_addr.ip46,
2577                   client_session->lcl_addr.is_ip4,
2578                   clib_net_to_host_u16 (client_session->lcl_port));
2579
2580   clib_spinlock_unlock (&vcm->sessions_lockp);
2581   rv = (int) client_session_index;
2582 done:
2583   return rv;
2584 }
2585
2586 int
2587 vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
2588 {
2589   session_t *session = 0;
2590   int rv, retval = VPPCOM_OK;
2591   u64 vpp_handle = ~0;
2592
2593   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2594
2595   if (PREDICT_FALSE (session->is_vep))
2596     {
2597       clib_spinlock_unlock (&vcm->sessions_lockp);
2598       clib_warning ("[%d] ERROR: sid %u: cannot connect on an epoll session!",
2599                     getpid (), session_index);
2600       rv = VPPCOM_EBADFD;
2601       goto done;
2602     }
2603
2604   vpp_handle = session->vpp_handle;
2605   if (PREDICT_FALSE (session->is_server))
2606     {
2607       clib_spinlock_unlock (&vcm->sessions_lockp);
2608       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: is in use "
2609                     "as a server session!", getpid (), vpp_handle,
2610                     session_index);
2611       rv = VPPCOM_EBADFD;
2612       goto done;
2613     }
2614
2615   if (PREDICT_FALSE (session->state & CLIENT_STATE_OPEN))
2616     {
2617       if (VPPCOM_DEBUG > 0)
2618         clib_warning ("[%d] vpp handle 0x%llx, sid %u: session already "
2619                       "connected to %s %U port %d proto %s, state 0x%x (%s)",
2620                       getpid (), vpp_handle, session_index,
2621                       session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
2622                       format_ip46_address,
2623                       &session->peer_addr.ip46, session->peer_addr.is_ip4,
2624                       clib_net_to_host_u16 (session->peer_port),
2625                       session->proto ? "UDP" : "TCP", session->state,
2626                       vppcom_session_state_str (session->state));
2627
2628       clib_spinlock_unlock (&vcm->sessions_lockp);
2629       goto done;
2630     }
2631
2632   session->vrf = server_ep->vrf;
2633   session->peer_addr.is_ip4 = server_ep->is_ip4;
2634   session->peer_addr.ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip);
2635   session->peer_port = server_ep->port;
2636
2637   if (VPPCOM_DEBUG > 0)
2638     clib_warning ("[%d] vpp handle 0x%llx, sid %u: connecting to server "
2639                   "%s %U port %d proto %s",
2640                   getpid (), vpp_handle, session_index,
2641                   session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
2642                   format_ip46_address,
2643                   &session->peer_addr.ip46, session->peer_addr.is_ip4,
2644                   clib_net_to_host_u16 (session->peer_port),
2645                   session->proto ? "UDP" : "TCP");
2646
2647   vppcom_send_connect_sock (session, session_index);
2648   clib_spinlock_unlock (&vcm->sessions_lockp);
2649
2650   retval =
2651     vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
2652                                           vcm->cfg.session_timeout);
2653
2654   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2655   vpp_handle = session->vpp_handle;
2656   clib_spinlock_unlock (&vcm->sessions_lockp);
2657
2658 done:
2659   if (PREDICT_FALSE (retval))
2660     {
2661       rv = retval;
2662       if (VPPCOM_DEBUG > 0)
2663         clib_warning ("[%d] vpp handle 0x%llx, sid %u: connect failed! "
2664                       "returning %d (%s)", getpid (), vpp_handle,
2665                       session_index, rv, vppcom_retval_str (rv));
2666     }
2667   else if (VPPCOM_DEBUG > 0)
2668     clib_warning ("[%d] vpp handle 0x%llx, sid %u: connected!",
2669                   getpid (), vpp_handle, session_index);
2670
2671   return rv;
2672 }
2673
2674 static inline int
2675 vppcom_session_read_internal (uint32_t session_index, void *buf, int n,
2676                               u8 peek)
2677 {
2678   session_t *session = 0;
2679   svm_fifo_t *rx_fifo;
2680   int n_read = 0;
2681   int rv;
2682   char *fifo_str;
2683   u32 poll_et;
2684   session_state_t state;
2685   u8 is_server;
2686   u8 is_nonblocking;
2687   u64 vpp_handle;
2688
2689   ASSERT (buf);
2690
2691   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2692
2693   if (PREDICT_FALSE (session->is_vep))
2694     {
2695       clib_spinlock_unlock (&vcm->sessions_lockp);
2696       clib_warning ("[%d] ERROR: sid %u: cannot read from an epoll session!",
2697                     getpid (), session_index);
2698       rv = VPPCOM_EBADFD;
2699       goto done;
2700     }
2701
2702   vpp_handle = session->vpp_handle;
2703   is_server = session->is_server;
2704   is_nonblocking = session->is_nonblocking;
2705   state = session->state;
2706   if (PREDICT_FALSE (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN))))
2707     {
2708       clib_spinlock_unlock (&vcm->sessions_lockp);
2709       rv = ((state == STATE_DISCONNECT) ?
2710             VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
2711
2712       if (VPPCOM_DEBUG > 0)
2713         clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s session is "
2714                       "not open! state 0x%x (%s), returning %d (%s)",
2715                       getpid (), vpp_handle, session_index,
2716                       is_server ? "server" : "client", state,
2717                       vppcom_session_state_str (state),
2718                       rv, vppcom_retval_str (rv));
2719       goto done;
2720     }
2721
2722   rx_fifo = ((!session->is_cut_thru || is_server) ?
2723              session->server_rx_fifo : session->server_tx_fifo);
2724   fifo_str = ((!session->is_cut_thru || is_server) ?
2725               "server_rx_fifo" : "server_tx_fifo");
2726   clib_spinlock_unlock (&vcm->sessions_lockp);
2727
2728   do
2729     {
2730       if (peek)
2731         n_read = svm_fifo_peek (rx_fifo, 0, n, buf);
2732       else
2733         n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf);
2734     }
2735   while (!is_nonblocking && (n_read <= 0));
2736
2737   if (n_read <= 0)
2738     {
2739       VCL_LOCK_AND_GET_SESSION (session_index, &session);
2740
2741       poll_et = (((EPOLLET | EPOLLIN) & session->vep.ev.events) ==
2742                  (EPOLLET | EPOLLIN));
2743       if (poll_et)
2744         session->vep.et_mask |= EPOLLIN;
2745
2746       if (state == STATE_CLOSE_ON_EMPTY)
2747         {
2748           session_state_t new_state = STATE_DISCONNECT;
2749           rv = VPPCOM_ECONNRESET;
2750
2751           if (VPPCOM_DEBUG > 1)
2752             {
2753               clib_warning ("[%d] vpp handle 0x%llx, sid %u: Empty fifo "
2754                             "with %s session state 0x%x (%s)!"
2755                             "  Setting state to 0x%x (%s), returning %d (%s)",
2756                             getpid (), vpp_handle, session_index,
2757                             is_server ? "server" : "client",
2758                             state, vppcom_session_state_str (state),
2759                             new_state, vppcom_session_state_str (new_state),
2760                             rv, vppcom_retval_str (rv));
2761             }
2762
2763           session->state = new_state;
2764         }
2765       else
2766         rv = VPPCOM_EAGAIN;
2767
2768       clib_spinlock_unlock (&vcm->sessions_lockp);
2769     }
2770   else
2771     rv = n_read;
2772
2773   if (VPPCOM_DEBUG > 2)
2774     {
2775       if (rv > 0)
2776         clib_warning ("[%d] vpp handle 0x%llx, sid %u: read %d bytes "
2777                       "from %s (%p)", getpid (), vpp_handle,
2778                       session_index, n_read, fifo_str, rx_fifo);
2779       else
2780         clib_warning ("[%d] vpp handle 0x%llx, sid %u: nothing read! "
2781                       "returning %d (%s)", getpid (), vpp_handle,
2782                       session_index, rv, vppcom_retval_str (rv));
2783     }
2784 done:
2785   return rv;
2786 }
2787
2788 int
2789 vppcom_session_read (uint32_t session_index, void *buf, int n)
2790 {
2791   return (vppcom_session_read_internal (session_index, buf, n, 0));
2792 }
2793
2794 static int
2795 vppcom_session_peek (uint32_t session_index, void *buf, int n)
2796 {
2797   return (vppcom_session_read_internal (session_index, buf, n, 1));
2798 }
2799
2800 static inline int
2801 vppcom_session_read_ready (session_t * session, u32 session_index)
2802 {
2803   svm_fifo_t *rx_fifo = 0;
2804   int ready = 0;
2805   u32 poll_et;
2806   int rv;
2807   u8 is_server = session->is_server;
2808   session_state_t state = session->state;
2809   u64 vpp_handle = session->vpp_handle;
2810
2811   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
2812   if (PREDICT_FALSE (session->is_vep))
2813     {
2814       clib_warning ("[%d] ERROR: sid %u: cannot read from an "
2815                     "epoll session!", getpid (), session_index);
2816       rv = VPPCOM_EBADFD;
2817       goto done;
2818     }
2819
2820   if (session->is_listen)
2821     ready = clib_fifo_elts (vcm->client_session_index_fifo);
2822   else
2823     {
2824       if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN | STATE_LISTEN)))
2825         {
2826           rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
2827                 VPPCOM_ENOTCONN);
2828
2829           if (VPPCOM_DEBUG > 1)
2830             clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s session is "
2831                           "not open! state 0x%x (%s), returning %d (%s)",
2832                           getpid (), vpp_handle, session_index,
2833                           is_server ? "server" : "client",
2834                           state, vppcom_session_state_str (state),
2835                           rv, vppcom_retval_str (rv));
2836           goto done;
2837         }
2838
2839       rx_fifo = ((!session->is_cut_thru || is_server) ?
2840                  session->server_rx_fifo : session->server_tx_fifo);
2841
2842       ready = svm_fifo_max_dequeue (rx_fifo);
2843     }
2844
2845   if (ready == 0)
2846     {
2847       poll_et =
2848         ((EPOLLET | EPOLLIN) & session->vep.ev.events) == (EPOLLET | EPOLLIN);
2849       if (poll_et)
2850         session->vep.et_mask |= EPOLLIN;
2851
2852       if (state == STATE_CLOSE_ON_EMPTY)
2853         {
2854           rv = VPPCOM_ECONNRESET;
2855           session_state_t new_state = STATE_DISCONNECT;
2856
2857           if (VPPCOM_DEBUG > 1)
2858             {
2859               clib_warning ("[%d] vpp handle 0x%llx, sid %u: Empty fifo with"
2860                             " %s session state 0x%x (%s)! Setting state to "
2861                             "0x%x (%s), returning %d (%s)",
2862                             getpid (), session_index, vpp_handle,
2863                             is_server ? "server" : "client",
2864                             state, vppcom_session_state_str (state),
2865                             new_state, vppcom_session_state_str (new_state),
2866                             rv, vppcom_retval_str (rv));
2867             }
2868           session->state = new_state;
2869           goto done;
2870         }
2871     }
2872   rv = ready;
2873
2874   if (vcm->app_event_queue->cursize &&
2875       !pthread_mutex_trylock (&vcm->app_event_queue->mutex))
2876     {
2877       u32 i, n_to_dequeue = vcm->app_event_queue->cursize;
2878       session_fifo_event_t e;
2879
2880       for (i = 0; i < n_to_dequeue; i++)
2881         unix_shared_memory_queue_sub_raw (vcm->app_event_queue, (u8 *) & e);
2882
2883       pthread_mutex_unlock (&vcm->app_event_queue->mutex);
2884     }
2885
2886 done:
2887   return rv;
2888 }
2889
2890 int
2891 vppcom_session_write (uint32_t session_index, void *buf, int n)
2892 {
2893   session_t *session = 0;
2894   svm_fifo_t *tx_fifo;
2895   unix_shared_memory_queue_t *q;
2896   session_fifo_event_t evt;
2897   int rv, n_write;
2898   char *fifo_str;
2899   u32 poll_et;
2900   u8 is_server;
2901   u8 is_nonblocking;
2902   session_state_t state;
2903   u64 vpp_handle;
2904
2905   ASSERT (buf);
2906
2907   VCL_LOCK_AND_GET_SESSION (session_index, &session);
2908
2909   if (PREDICT_FALSE (session->is_vep))
2910     {
2911       clib_spinlock_unlock (&vcm->sessions_lockp);
2912       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2913                     "cannot write to an epoll session!",
2914                     getpid (), session->vpp_handle, session_index);
2915
2916       rv = VPPCOM_EBADFD;
2917       goto done;
2918     }
2919
2920   is_server = session->is_server;
2921   is_nonblocking = session->is_nonblocking;
2922   vpp_handle = session->vpp_handle;
2923   state = session->state;
2924   if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
2925     {
2926       rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
2927             VPPCOM_ENOTCONN);
2928
2929       clib_spinlock_unlock (&vcm->sessions_lockp);
2930       if (VPPCOM_DEBUG > 1)
2931         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2932                       "%s session is not open! state 0x%x (%s)",
2933                       getpid (), vpp_handle, session_index,
2934                       is_server ? "server" : "client", state,
2935                       vppcom_session_state_str (state));
2936       goto done;
2937     }
2938
2939   tx_fifo = ((!session->is_cut_thru || is_server) ?
2940              session->server_tx_fifo : session->server_rx_fifo);
2941   fifo_str = ((!session->is_cut_thru || is_server) ?
2942               "server_tx_fifo" : "server_rx_fifo");
2943   clib_spinlock_unlock (&vcm->sessions_lockp);
2944
2945   do
2946     {
2947       n_write = svm_fifo_enqueue_nowait (tx_fifo, n, buf);
2948     }
2949   while (!is_nonblocking && (n_write <= 0));
2950
2951   /* If event wasn't set, add one */
2952   if (!session->is_cut_thru && (n_write > 0) && svm_fifo_set_event (tx_fifo))
2953     {
2954       /* Fabricate TX event, send to vpp */
2955       evt.fifo = tx_fifo;
2956       evt.event_type = FIFO_EVENT_APP_TX;
2957
2958       VCL_LOCK_AND_GET_SESSION (session_index, &session);
2959       q = session->vpp_event_queue;
2960       ASSERT (q);
2961       unix_shared_memory_queue_add (q, (u8 *) & evt,
2962                                     0 /* do wait for mutex */ );
2963       clib_spinlock_unlock (&vcm->sessions_lockp);
2964       if (VPPCOM_DEBUG > 1)
2965         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2966                       "added FIFO_EVENT_APP_TX to "
2967                       "vpp_event_q %p, n_write %d", getpid (),
2968                       vpp_handle, session_index, q, n_write);
2969     }
2970
2971   if (n_write <= 0)
2972     {
2973       VCL_LOCK_AND_GET_SESSION (session_index, &session);
2974
2975       poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
2976                  (EPOLLET | EPOLLOUT));
2977       if (poll_et)
2978         session->vep.et_mask |= EPOLLOUT;
2979
2980       if (state == STATE_CLOSE_ON_EMPTY)
2981         {
2982           session_state_t new_state = STATE_DISCONNECT;
2983           rv = VPPCOM_ECONNRESET;
2984
2985           if (VPPCOM_DEBUG > 1)
2986             {
2987               clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2988                             "Empty fifo with %s session state 0x%x (%s)!"
2989                             "  Setting state to 0x%x (%s), returning %d (%s)",
2990                             getpid (), vpp_handle, session_index,
2991                             is_server ? "server" : "client",
2992                             state, vppcom_session_state_str (state),
2993                             new_state, vppcom_session_state_str (new_state),
2994                             rv, vppcom_retval_str (rv));
2995             }
2996
2997           session->state = new_state;
2998         }
2999       else
3000         rv = VPPCOM_EAGAIN;
3001
3002       clib_spinlock_unlock (&vcm->sessions_lockp);
3003     }
3004   else
3005     rv = n_write;
3006
3007   if (VPPCOM_DEBUG > 2)
3008     {
3009       if (n_write <= 0)
3010         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3011                       "FIFO-FULL %s (%p)", getpid (), vpp_handle,
3012                       session_index, fifo_str, tx_fifo);
3013       else
3014         clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3015                       "wrote %d bytes to %s (%p)", getpid (), vpp_handle,
3016                       session_index, n_write, fifo_str, tx_fifo);
3017     }
3018 done:
3019   return rv;
3020 }
3021
3022 static inline int
3023 vppcom_session_write_ready (session_t * session, u32 session_index)
3024 {
3025   svm_fifo_t *tx_fifo;
3026   char *fifo_str;
3027   int ready;
3028   u32 poll_et;
3029   int rv;
3030   u8 is_server = session->is_server;
3031   session_state_t state = session->state;
3032
3033   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3034   if (PREDICT_FALSE (session->is_vep))
3035     {
3036       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3037                     "cannot write to an epoll session!",
3038                     getpid (), session->vpp_handle, session_index);
3039       rv = VPPCOM_EBADFD;
3040       goto done;
3041     }
3042
3043   if (PREDICT_FALSE (session->is_listen))
3044     {
3045       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3046                     "cannot write to a listen session!",
3047                     getpid (), session->vpp_handle, session_index);
3048       rv = VPPCOM_EBADFD;
3049       goto done;
3050     }
3051
3052   if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3053     {
3054       session_state_t state = session->state;
3055
3056       rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3057             VPPCOM_ENOTCONN);
3058
3059       clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3060                     "%s session is not open! state 0x%x (%s), "
3061                     "returning %d (%s)", getpid (), session->vpp_handle,
3062                     session_index, is_server ? "server" : "client",
3063                     state, vppcom_session_state_str (state),
3064                     rv, vppcom_retval_str (rv));
3065       goto done;
3066     }
3067
3068   tx_fifo = ((!session->is_cut_thru || session->is_server) ?
3069              session->server_tx_fifo : session->server_rx_fifo);
3070   fifo_str = ((!session->is_cut_thru || session->is_server) ?
3071               "server_tx_fifo" : "server_rx_fifo");
3072
3073   ready = svm_fifo_max_enqueue (tx_fifo);
3074
3075   if (VPPCOM_DEBUG > 3)
3076     clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3077                   "peek %s (%p), ready = %d", getpid (),
3078                   session->vpp_handle, session_index,
3079                   fifo_str, tx_fifo, ready);
3080
3081   if (ready == 0)
3082     {
3083       poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3084                  (EPOLLET | EPOLLOUT));
3085       if (poll_et)
3086         session->vep.et_mask |= EPOLLOUT;
3087
3088       if (state == STATE_CLOSE_ON_EMPTY)
3089         {
3090           rv = VPPCOM_ECONNRESET;
3091           session_state_t new_state = STATE_DISCONNECT;
3092
3093           if (VPPCOM_DEBUG > 1)
3094             {
3095               clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3096                             "Empty fifo with %s session "
3097                             "state 0x%x (%s)! Setting state to 0x%x (%s), "
3098                             "returning %d (%s)", getpid (),
3099                             session->vpp_handle, session_index,
3100                             is_server ? "server" : "client",
3101                             state, vppcom_session_state_str (state),
3102                             new_state, vppcom_session_state_str (new_state),
3103                             rv, vppcom_retval_str (rv));
3104             }
3105           session->state = new_state;
3106           goto done;
3107         }
3108     }
3109   rv = ready;
3110 done:
3111   return rv;
3112 }
3113
3114 int
3115 vppcom_select (unsigned long n_bits, unsigned long *read_map,
3116                unsigned long *write_map, unsigned long *except_map,
3117                double time_to_wait)
3118 {
3119   u32 session_index;
3120   session_t *session = 0;
3121   int rv, bits_set = 0;
3122   f64 timeout = clib_time_now (&vcm->clib_time) + time_to_wait;
3123   u32 minbits = clib_max (n_bits, BITS (uword));
3124
3125   ASSERT (sizeof (clib_bitmap_t) == sizeof (long int));
3126
3127   if (n_bits && read_map)
3128     {
3129       clib_bitmap_validate (vcm->rd_bitmap, minbits);
3130       clib_memcpy (vcm->rd_bitmap, read_map, vec_len (vcm->rd_bitmap));
3131       memset (read_map, 0, vec_len (vcm->rd_bitmap));
3132     }
3133   if (n_bits && write_map)
3134     {
3135       clib_bitmap_validate (vcm->wr_bitmap, minbits);
3136       clib_memcpy (vcm->wr_bitmap, write_map, vec_len (vcm->wr_bitmap));
3137       memset (write_map, 0, vec_len (vcm->wr_bitmap));
3138     }
3139   if (n_bits && except_map)
3140     {
3141       clib_bitmap_validate (vcm->ex_bitmap, minbits);
3142       clib_memcpy (vcm->ex_bitmap, except_map, vec_len (vcm->ex_bitmap));
3143       memset (except_map, 0, vec_len (vcm->ex_bitmap));
3144     }
3145
3146   do
3147     {
3148       /* *INDENT-OFF* */
3149       if (n_bits)
3150         {
3151           if (read_map)
3152             {
3153               clib_bitmap_foreach (session_index, vcm->rd_bitmap,
3154                 ({
3155                   clib_spinlock_lock (&vcm->sessions_lockp);
3156                   rv = vppcom_session_at_index (session_index, &session);
3157                   if (rv < 0)
3158                     {
3159                       clib_spinlock_unlock (&vcm->sessions_lockp);
3160                       if (VPPCOM_DEBUG > 1)
3161                         clib_warning ("[%d] session %d specified in "
3162                                       "read_map is closed.", getpid (),
3163                                       session_index);
3164                       bits_set = VPPCOM_EBADFD;
3165                       goto select_done;
3166                     }
3167
3168                   rv = vppcom_session_read_ready (session, session_index);
3169                   clib_spinlock_unlock (&vcm->sessions_lockp);
3170                   if (except_map && vcm->ex_bitmap &&
3171                       clib_bitmap_get (vcm->ex_bitmap, session_index) &&
3172                       (rv < 0))
3173                     {
3174                       // TBD: clib_warning
3175                       clib_bitmap_set_no_check (except_map, session_index, 1);
3176                       bits_set++;
3177                     }
3178                   else if (rv > 0)
3179                     {
3180                       // TBD: clib_warning
3181                       clib_bitmap_set_no_check (read_map, session_index, 1);
3182                       bits_set++;
3183                     }
3184                 }));
3185             }
3186
3187           if (write_map)
3188             {
3189               clib_bitmap_foreach (session_index, vcm->wr_bitmap,
3190                 ({
3191                   clib_spinlock_lock (&vcm->sessions_lockp);
3192                   rv = vppcom_session_at_index (session_index, &session);
3193                   if (rv < 0)
3194                     {
3195                       clib_spinlock_unlock (&vcm->sessions_lockp);
3196                       if (VPPCOM_DEBUG > 0)
3197                         clib_warning ("[%d] session %d specified in "
3198                                       "write_map is closed.", getpid (),
3199                                       session_index);
3200                       bits_set = VPPCOM_EBADFD;
3201                       goto select_done;
3202                     }
3203
3204                   rv = vppcom_session_write_ready (session, session_index);
3205                   clib_spinlock_unlock (&vcm->sessions_lockp);
3206                   if (write_map && (rv > 0))
3207                     {
3208                       // TBD: clib_warning
3209                       clib_bitmap_set_no_check (write_map, session_index, 1);
3210                       bits_set++;
3211                     }
3212                 }));
3213             }
3214
3215           if (except_map)
3216             {
3217               clib_bitmap_foreach (session_index, vcm->ex_bitmap,
3218                 ({
3219                   clib_spinlock_lock (&vcm->sessions_lockp);
3220                   rv = vppcom_session_at_index (session_index, &session);
3221                   if (rv < 0)
3222                     {
3223                       clib_spinlock_unlock (&vcm->sessions_lockp);
3224                       if (VPPCOM_DEBUG > 1)
3225                         clib_warning ("[%d] session %d specified in "
3226                                       "except_map is closed.", getpid (),
3227                                       session_index);
3228                       bits_set = VPPCOM_EBADFD;
3229                       goto select_done;
3230                     }
3231
3232                   rv = vppcom_session_read_ready (session, session_index);
3233                   clib_spinlock_unlock (&vcm->sessions_lockp);
3234                   if (rv < 0)
3235                     {
3236                       // TBD: clib_warning
3237                       clib_bitmap_set_no_check (except_map, session_index, 1);
3238                       bits_set++;
3239                     }
3240                 }));
3241             }
3242         }
3243       /* *INDENT-ON* */
3244     }
3245   while (clib_time_now (&vcm->clib_time) < timeout);
3246
3247 select_done:
3248   return (bits_set);
3249 }
3250
3251 static inline void
3252 vep_verify_epoll_chain (u32 vep_idx)
3253 {
3254   session_t *session;
3255   vppcom_epoll_t *vep;
3256   int rv;
3257   u32 sid = vep_idx;
3258
3259   if (VPPCOM_DEBUG <= 1)
3260     return;
3261
3262   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3263   rv = vppcom_session_at_index (vep_idx, &session);
3264   if (PREDICT_FALSE (rv))
3265     {
3266       clib_warning ("[%d] ERROR: Invalid vep_idx (%u)!", getpid (), vep_idx);
3267       goto done;
3268     }
3269   if (PREDICT_FALSE (!session->is_vep))
3270     {
3271       clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!", getpid (),
3272                     vep_idx);
3273       goto done;
3274     }
3275   vep = &session->vep;
3276   clib_warning ("[%d] vep_idx (%u): Dumping epoll chain\n"
3277                 "{\n"
3278                 "   is_vep         = %u\n"
3279                 "   is_vep_session = %u\n"
3280                 "   next_sid       = 0x%x (%u)\n"
3281                 "   wait_cont_idx  = 0x%x (%u)\n"
3282                 "}\n", getpid (), vep_idx,
3283                 session->is_vep, session->is_vep_session,
3284                 vep->next_sid, vep->next_sid,
3285                 session->wait_cont_idx, session->wait_cont_idx);
3286
3287   for (sid = vep->next_sid; sid != ~0; sid = vep->next_sid)
3288     {
3289       rv = vppcom_session_at_index (sid, &session);
3290       if (PREDICT_FALSE (rv))
3291         {
3292           clib_warning ("[%d] ERROR: Invalid sid (%u)!", getpid (), sid);
3293           goto done;
3294         }
3295       if (PREDICT_FALSE (session->is_vep))
3296         clib_warning ("[%d] ERROR: sid (%u) is a vep!", getpid (), vep_idx);
3297       else if (PREDICT_FALSE (!session->is_vep_session))
3298         {
3299           clib_warning ("[%d] ERROR: session (%u) is not a vep session!",
3300                         getpid (), sid);
3301           goto done;
3302         }
3303       vep = &session->vep;
3304       if (PREDICT_FALSE (vep->vep_idx != vep_idx))
3305         clib_warning ("[%d] ERROR: session (%u) vep_idx (%u) != "
3306                       "vep_idx (%u)!", getpid (),
3307                       sid, session->vep.vep_idx, vep_idx);
3308       if (session->is_vep_session)
3309         {
3310           clib_warning ("vep_idx[%u]: sid 0x%x (%u)\n"
3311                         "{\n"
3312                         "   next_sid       = 0x%x (%u)\n"
3313                         "   prev_sid       = 0x%x (%u)\n"
3314                         "   vep_idx        = 0x%x (%u)\n"
3315                         "   ev.events      = 0x%x\n"
3316                         "   ev.data.u64    = 0x%llx\n"
3317                         "   et_mask        = 0x%x\n"
3318                         "}\n",
3319                         vep_idx, sid, sid,
3320                         vep->next_sid, vep->next_sid,
3321                         vep->prev_sid, vep->prev_sid,
3322                         vep->vep_idx, vep->vep_idx,
3323                         vep->ev.events, vep->ev.data.u64, vep->et_mask);
3324         }
3325     }
3326
3327 done:
3328   clib_warning ("[%d] vep_idx (%u): Dump complete!\n", getpid (), vep_idx);
3329 }
3330
3331 int
3332 vppcom_epoll_create (void)
3333 {
3334   session_t *vep_session;
3335   u32 vep_idx;
3336
3337   clib_spinlock_lock (&vcm->sessions_lockp);
3338   pool_get (vcm->sessions, vep_session);
3339   memset (vep_session, 0, sizeof (*vep_session));
3340   vep_idx = vep_session - vcm->sessions;
3341
3342   vep_session->is_vep = 1;
3343   vep_session->vep.vep_idx = ~0;
3344   vep_session->vep.next_sid = ~0;
3345   vep_session->vep.prev_sid = ~0;
3346   vep_session->wait_cont_idx = ~0;
3347   vep_session->vpp_handle = ~0;
3348   clib_spinlock_unlock (&vcm->sessions_lockp);
3349
3350   if (VPPCOM_DEBUG > 0)
3351     clib_warning ("[%d] Created vep_idx %u / sid %u!",
3352                   getpid (), vep_idx, vep_idx);
3353
3354   return (vep_idx);
3355 }
3356
3357 int
3358 vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
3359                   struct epoll_event *event)
3360 {
3361   session_t *vep_session;
3362   session_t *session;
3363   int rv;
3364
3365   if (vep_idx == session_index)
3366     {
3367       clib_warning ("[%d] ERROR: vep_idx == session_index (%u)!",
3368                     getpid (), vep_idx);
3369       return VPPCOM_EINVAL;
3370     }
3371
3372   clib_spinlock_lock (&vcm->sessions_lockp);
3373   rv = vppcom_session_at_index (vep_idx, &vep_session);
3374   if (PREDICT_FALSE (rv))
3375     {
3376       clib_warning ("[%d] ERROR: Invalid vep_idx (%u)!", vep_idx);
3377       goto done;
3378     }
3379   if (PREDICT_FALSE (!vep_session->is_vep))
3380     {
3381       clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!",
3382                     getpid (), vep_idx);
3383       rv = VPPCOM_EINVAL;
3384       goto done;
3385     }
3386
3387   ASSERT (vep_session->vep.vep_idx == ~0);
3388   ASSERT (vep_session->vep.prev_sid == ~0);
3389
3390   rv = vppcom_session_at_index (session_index, &session);
3391   if (PREDICT_FALSE (rv))
3392     {
3393       if (VPPCOM_DEBUG > 0)
3394         clib_warning ("[%d] ERROR: Invalid session_index (%u)!",
3395                       getpid (), session_index);
3396       goto done;
3397     }
3398   if (PREDICT_FALSE (session->is_vep))
3399     {
3400       clib_warning ("ERROR: session_index (%u) is a vep!", vep_idx);
3401       rv = VPPCOM_EINVAL;
3402       goto done;
3403     }
3404
3405   switch (op)
3406     {
3407     case EPOLL_CTL_ADD:
3408       if (PREDICT_FALSE (!event))
3409         {
3410           clib_warning ("[%d] ERROR: EPOLL_CTL_ADD: NULL pointer to "
3411                         "epoll_event structure!", getpid ());
3412           rv = VPPCOM_EINVAL;
3413           goto done;
3414         }
3415       if (vep_session->vep.next_sid != ~0)
3416         {
3417           session_t *next_session;
3418           rv = vppcom_session_at_index (vep_session->vep.next_sid,
3419                                         &next_session);
3420           if (PREDICT_FALSE (rv))
3421             {
3422               clib_warning ("[%d] ERROR: EPOLL_CTL_ADD: Invalid "
3423                             "vep.next_sid (%u) on vep_idx (%u)!",
3424                             getpid (), vep_session->vep.next_sid, vep_idx);
3425               goto done;
3426             }
3427           ASSERT (next_session->vep.prev_sid == vep_idx);
3428           next_session->vep.prev_sid = session_index;
3429         }
3430       session->vep.next_sid = vep_session->vep.next_sid;
3431       session->vep.prev_sid = vep_idx;
3432       session->vep.vep_idx = vep_idx;
3433       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3434       session->vep.ev = *event;
3435       session->is_vep = 0;
3436       session->is_vep_session = 1;
3437       vep_session->vep.next_sid = session_index;
3438       if (VPPCOM_DEBUG > 1)
3439         clib_warning ("[%d] EPOLL_CTL_ADD: vep_idx %u, sid %u, events 0x%x,"
3440                       " data 0x%llx!", getpid (), vep_idx, session_index,
3441                       event->events, event->data.u64);
3442       break;
3443
3444     case EPOLL_CTL_MOD:
3445       if (PREDICT_FALSE (!event))
3446         {
3447           clib_warning ("[%d] ERROR: EPOLL_CTL_MOD: NULL pointer to "
3448                         "epoll_event structure!", getpid ());
3449           rv = VPPCOM_EINVAL;
3450           goto done;
3451         }
3452       else if (PREDICT_FALSE (!session->is_vep_session))
3453         {
3454           clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_MOD: "
3455                         "not a vep session!", getpid (), session_index);
3456           rv = VPPCOM_EINVAL;
3457           goto done;
3458         }
3459       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3460         {
3461           clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_MOD: "
3462                         "vep_idx (%u) != vep_idx (%u)!",
3463                         getpid (), session_index,
3464                         session->vep.vep_idx, vep_idx);
3465           rv = VPPCOM_EINVAL;
3466           goto done;
3467         }
3468       session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3469       session->vep.ev = *event;
3470       if (VPPCOM_DEBUG > 1)
3471         clib_warning ("[%d] EPOLL_CTL_MOD: vep_idx %u, sid %u, events 0x%x,"
3472                       " data 0x%llx!", getpid (), vep_idx, session_index,
3473                       event->events, event->data.u64);
3474       break;
3475
3476     case EPOLL_CTL_DEL:
3477       if (PREDICT_FALSE (!session->is_vep_session))
3478         {
3479           clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_DEL: "
3480                         "not a vep session!", getpid (), session_index);
3481           rv = VPPCOM_EINVAL;
3482           goto done;
3483         }
3484       else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3485         {
3486           clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_DEL: "
3487                         "vep_idx (%u) != vep_idx (%u)!",
3488                         getpid (), session_index,
3489                         session->vep.vep_idx, vep_idx);
3490           rv = VPPCOM_EINVAL;
3491           goto done;
3492         }
3493
3494       vep_session->wait_cont_idx =
3495         (vep_session->wait_cont_idx == session_index) ?
3496         session->vep.next_sid : vep_session->wait_cont_idx;
3497
3498       if (session->vep.prev_sid == vep_idx)
3499         vep_session->vep.next_sid = session->vep.next_sid;
3500       else
3501         {
3502           session_t *prev_session;
3503           rv = vppcom_session_at_index (session->vep.prev_sid, &prev_session);
3504           if (PREDICT_FALSE (rv))
3505             {
3506               clib_warning ("[%d] ERROR: EPOLL_CTL_DEL: Invalid "
3507                             "vep.prev_sid (%u) on sid (%u)!",
3508                             getpid (), session->vep.prev_sid, session_index);
3509               goto done;
3510             }
3511           ASSERT (prev_session->vep.next_sid == session_index);
3512           prev_session->vep.next_sid = session->vep.next_sid;
3513         }
3514       if (session->vep.next_sid != ~0)
3515         {
3516           session_t *next_session;
3517           rv = vppcom_session_at_index (session->vep.next_sid, &next_session);
3518           if (PREDICT_FALSE (rv))
3519             {
3520               clib_warning ("[%d] ERROR: EPOLL_CTL_DEL: Invalid "
3521                             "vep.next_sid (%u) on sid (%u)!",
3522                             getpid (), session->vep.next_sid, session_index);
3523               goto done;
3524             }
3525           ASSERT (next_session->vep.prev_sid == session_index);
3526           next_session->vep.prev_sid = session->vep.prev_sid;
3527         }
3528
3529       memset (&session->vep, 0, sizeof (session->vep));
3530       session->vep.next_sid = ~0;
3531       session->vep.prev_sid = ~0;
3532       session->vep.vep_idx = ~0;
3533       session->is_vep_session = 0;
3534       if (VPPCOM_DEBUG > 1)
3535         clib_warning ("[%d] EPOLL_CTL_DEL: vep_idx %u, sid %u!",
3536                       getpid (), vep_idx, session_index);
3537       break;
3538
3539     default:
3540       clib_warning ("[%d] ERROR: Invalid operation (%d)!", getpid (), op);
3541       rv = VPPCOM_EINVAL;
3542     }
3543
3544   vep_verify_epoll_chain (vep_idx);
3545
3546 done:
3547   clib_spinlock_unlock (&vcm->sessions_lockp);
3548   return rv;
3549 }
3550
3551 int
3552 vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
3553                    int maxevents, double wait_for_time)
3554 {
3555   session_t *vep_session;
3556   int rv;
3557   f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
3558   u32 keep_trying = 1;
3559   int num_ev = 0;
3560   u32 vep_next_sid, wait_cont_idx;
3561   u8 is_vep;
3562
3563   if (PREDICT_FALSE (maxevents <= 0))
3564     {
3565       clib_warning ("[%d] ERROR: Invalid maxevents (%d)!",
3566                     getpid (), maxevents);
3567       return VPPCOM_EINVAL;
3568     }
3569   memset (events, 0, sizeof (*events) * maxevents);
3570
3571   VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
3572   vep_next_sid = vep_session->vep.next_sid;
3573   is_vep = vep_session->is_vep;
3574   wait_cont_idx = vep_session->wait_cont_idx;
3575   clib_spinlock_unlock (&vcm->sessions_lockp);
3576
3577   if (PREDICT_FALSE (!is_vep))
3578     {
3579       clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!",
3580                     getpid (), vep_idx);
3581       rv = VPPCOM_EINVAL;
3582       goto done;
3583     }
3584   if (PREDICT_FALSE (vep_next_sid == ~0))
3585     {
3586       if (VPPCOM_DEBUG > 0)
3587         clib_warning ("[%d] WARNING: vep_idx (%u) is empty!",
3588                       getpid (), vep_idx);
3589       goto done;
3590     }
3591
3592   do
3593     {
3594       u32 sid;
3595       u32 next_sid = ~0;
3596       session_t *session;
3597
3598       for (sid = (wait_cont_idx == ~0) ? vep_next_sid : wait_cont_idx;
3599            sid != ~0; sid = next_sid)
3600         {
3601           u32 session_events, et_mask, clear_et_mask, session_vep_idx;
3602           u8 add_event, is_vep_session;
3603           int ready;
3604           u64 session_ev_data;
3605
3606           VCL_LOCK_AND_GET_SESSION (sid, &session);
3607           next_sid = session->vep.next_sid;
3608           session_events = session->vep.ev.events;
3609           et_mask = session->vep.et_mask;
3610           is_vep = session->is_vep;
3611           is_vep_session = session->is_vep_session;
3612           session_vep_idx = session->vep.vep_idx;
3613           session_ev_data = session->vep.ev.data.u64;
3614           clib_spinlock_unlock (&vcm->sessions_lockp);
3615
3616           if (PREDICT_FALSE (is_vep))
3617             {
3618               if (VPPCOM_DEBUG > 0)
3619                 clib_warning ("[%d] ERROR: sid (%u) is a vep!",
3620                               getpid (), vep_idx);
3621               rv = VPPCOM_EINVAL;
3622               goto done;
3623             }
3624           if (PREDICT_FALSE (!is_vep_session))
3625             {
3626               if (VPPCOM_DEBUG > 0)
3627                 clib_warning ("[%d] ERROR: session (%u) is not "
3628                               "a vep session!", getpid (), sid);
3629               rv = VPPCOM_EINVAL;
3630               goto done;
3631             }
3632           if (PREDICT_FALSE (session_vep_idx != vep_idx))
3633             {
3634               clib_warning ("[%d] ERROR: session (%u) "
3635                             "vep_idx (%u) != vep_idx (%u)!",
3636                             getpid (), sid, session->vep.vep_idx, vep_idx);
3637               rv = VPPCOM_EINVAL;
3638               goto done;
3639             }
3640
3641           add_event = clear_et_mask = 0;
3642
3643           if (EPOLLIN & session_events)
3644             {
3645               VCL_LOCK_AND_GET_SESSION (sid, &session);
3646               ready = vppcom_session_read_ready (session, sid);
3647               clib_spinlock_unlock (&vcm->sessions_lockp);
3648               if ((ready > 0) && (EPOLLIN & et_mask))
3649                 {
3650                   add_event = 1;
3651                   events[num_ev].events |= EPOLLIN;
3652                   if (((EPOLLET | EPOLLIN) & session_events) ==
3653                       (EPOLLET | EPOLLIN))
3654                     clear_et_mask |= EPOLLIN;
3655                 }
3656               else if (ready < 0)
3657                 {
3658                   add_event = 1;
3659                   switch (ready)
3660                     {
3661                     case VPPCOM_ECONNRESET:
3662                       events[num_ev].events |= EPOLLHUP | EPOLLRDHUP;
3663                       break;
3664
3665                     default:
3666                       events[num_ev].events |= EPOLLERR;
3667                       break;
3668                     }
3669                 }
3670             }
3671
3672           if (EPOLLOUT & session_events)
3673             {
3674               VCL_LOCK_AND_GET_SESSION (sid, &session);
3675               ready = vppcom_session_write_ready (session, sid);
3676               clib_spinlock_unlock (&vcm->sessions_lockp);
3677               if ((ready > 0) && (EPOLLOUT & et_mask))
3678                 {
3679                   add_event = 1;
3680                   events[num_ev].events |= EPOLLOUT;
3681                   if (((EPOLLET | EPOLLOUT) & session_events) ==
3682                       (EPOLLET | EPOLLOUT))
3683                     clear_et_mask |= EPOLLOUT;
3684                 }
3685               else if (ready < 0)
3686                 {
3687                   add_event = 1;
3688                   switch (ready)
3689                     {
3690                     case VPPCOM_ECONNRESET:
3691                       events[num_ev].events |= EPOLLHUP;
3692                       break;
3693
3694                     default:
3695                       events[num_ev].events |= EPOLLERR;
3696                       break;
3697                     }
3698                 }
3699             }
3700
3701           if (add_event)
3702             {
3703               events[num_ev].data.u64 = session_ev_data;
3704               if (EPOLLONESHOT & session_events)
3705                 {
3706                   VCL_LOCK_AND_GET_SESSION (sid, &session);
3707                   session->vep.ev.events = 0;
3708                   clib_spinlock_unlock (&vcm->sessions_lockp);
3709                 }
3710               num_ev++;
3711               if (num_ev == maxevents)
3712                 {
3713                   VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
3714                   vep_session->wait_cont_idx = next_sid;
3715                   clib_spinlock_unlock (&vcm->sessions_lockp);
3716                   goto done;
3717                 }
3718             }
3719           if (wait_cont_idx != ~0)
3720             {
3721               if (next_sid == ~0)
3722                 next_sid = vep_next_sid;
3723               else if (next_sid == wait_cont_idx)
3724                 next_sid = ~0;
3725             }
3726         }
3727       if (wait_for_time != -1)
3728         keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
3729     }
3730   while ((num_ev == 0) && keep_trying);
3731
3732   if (wait_cont_idx != ~0)
3733     {
3734       VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
3735       vep_session->wait_cont_idx = ~0;
3736       clib_spinlock_unlock (&vcm->sessions_lockp);
3737     }
3738 done:
3739   return (rv != VPPCOM_OK) ? rv : num_ev;
3740 }
3741
3742 int
3743 vppcom_session_attr (uint32_t session_index, uint32_t op,
3744                      void *buffer, uint32_t * buflen)
3745 {
3746   session_t *session;
3747   int rv = VPPCOM_OK;
3748   u32 *flags = buffer;
3749   vppcom_endpt_t *ep = buffer;
3750
3751   VCL_LOCK_AND_GET_SESSION (session_index, &session);
3752   switch (op)
3753     {
3754     case VPPCOM_ATTR_GET_NREAD:
3755       rv = vppcom_session_read_ready (session, session_index);
3756       if (VPPCOM_DEBUG > 2)
3757         clib_warning ("[%d] VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
3758                       getpid (), rv);
3759       break;
3760
3761     case VPPCOM_ATTR_GET_NWRITE:
3762       rv = vppcom_session_write_ready (session, session_index);
3763       if (VPPCOM_DEBUG > 2)
3764         clib_warning ("[%d] VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
3765                       getpid (), session_index, rv);
3766       break;
3767
3768     case VPPCOM_ATTR_GET_FLAGS:
3769       if (buffer && buflen && (*buflen >= sizeof (*flags)))
3770         {
3771           *flags = O_RDWR | ((session->is_nonblocking) ? O_NONBLOCK : 0);
3772           *buflen = sizeof (*flags);
3773           if (VPPCOM_DEBUG > 2)
3774             clib_warning ("[%d] VPPCOM_ATTR_GET_FLAGS: sid %u, "
3775                           "flags = 0x%08x, is_nonblocking = %u", getpid (),
3776                           session_index, *flags, session->is_nonblocking);
3777         }
3778       else
3779         rv = VPPCOM_EINVAL;
3780       break;
3781
3782     case VPPCOM_ATTR_SET_FLAGS:
3783       if (buffer && buflen && (*buflen >= sizeof (*flags)))
3784         {
3785           session->is_nonblocking = (*flags & O_NONBLOCK) ? 1 : 0;
3786           if (VPPCOM_DEBUG > 2)
3787             clib_warning ("[%d] VPPCOM_ATTR_SET_FLAGS: sid %u, "
3788                           "flags = 0x%08x, is_nonblocking = %u",
3789                           getpid (), session_index, *flags,
3790                           session->is_nonblocking);
3791         }
3792       else
3793         rv = VPPCOM_EINVAL;
3794       break;
3795
3796     case VPPCOM_ATTR_GET_PEER_ADDR:
3797       if (buffer && buflen && (*buflen >= sizeof (*ep)))
3798         {
3799           ep->vrf = session->vrf;
3800           ep->is_ip4 = session->peer_addr.is_ip4;
3801           ep->port = session->peer_port;
3802           if (session->peer_addr.is_ip4)
3803             clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
3804                          sizeof (ip4_address_t));
3805           else
3806             clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
3807                          sizeof (ip6_address_t));
3808           *buflen = sizeof (*ep);
3809           if (VPPCOM_DEBUG > 1)
3810             clib_warning ("[%d] VPPCOM_ATTR_GET_PEER_ADDR: sid %u, is_ip4 = "
3811                           "%u, addr = %U, port %u", getpid (),
3812                           session_index, ep->is_ip4, format_ip46_address,
3813                           &session->peer_addr.ip46, ep->is_ip4,
3814                           clib_net_to_host_u16 (ep->port));
3815         }
3816       else
3817         rv = VPPCOM_EINVAL;
3818       break;
3819
3820     case VPPCOM_ATTR_GET_LCL_ADDR:
3821       if (buffer && buflen && (*buflen >= sizeof (*ep)))
3822         {
3823           ep->vrf = session->vrf;
3824           ep->is_ip4 = session->lcl_addr.is_ip4;
3825           ep->port = session->lcl_port;
3826           if (session->lcl_addr.is_ip4)
3827             clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip4,
3828                          sizeof (ip4_address_t));
3829           else
3830             clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip6,
3831                          sizeof (ip6_address_t));
3832           *buflen = sizeof (*ep);
3833           if (VPPCOM_DEBUG > 1)
3834             clib_warning ("[%d] VPPCOM_ATTR_GET_LCL_ADDR: sid %u, is_ip4 = "
3835                           "%u, addr = %U port %d", getpid (),
3836                           session_index, ep->is_ip4, format_ip46_address,
3837                           &session->lcl_addr.ip46, ep->is_ip4,
3838                           clib_net_to_host_u16 (ep->port));
3839         }
3840       else
3841         rv = VPPCOM_EINVAL;
3842       break;
3843
3844     case VPPCOM_ATTR_SET_REUSEADDR:
3845       break;
3846
3847     case VPPCOM_ATTR_SET_BROADCAST:
3848       break;
3849
3850     case VPPCOM_ATTR_SET_V6ONLY:
3851       break;
3852
3853     case VPPCOM_ATTR_SET_KEEPALIVE:
3854       break;
3855
3856     case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
3857       break;
3858
3859     case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
3860       break;
3861
3862     default:
3863       rv = VPPCOM_EINVAL;
3864       break;
3865     }
3866
3867 done:
3868   clib_spinlock_unlock (&vcm->sessions_lockp);
3869   return rv;
3870 }
3871
3872 int
3873 vppcom_session_recvfrom (uint32_t session_index, void *buffer,
3874                          uint32_t buflen, int flags, vppcom_endpt_t * ep)
3875 {
3876   int rv = VPPCOM_OK;
3877   session_t *session = 0;
3878
3879   if (ep)
3880     {
3881       clib_spinlock_lock (&vcm->sessions_lockp);
3882       rv = vppcom_session_at_index (session_index, &session);
3883       if (PREDICT_FALSE (rv))
3884         {
3885           clib_spinlock_unlock (&vcm->sessions_lockp);
3886           if (VPPCOM_DEBUG > 0)
3887             clib_warning ("[%d] invalid session, sid (%u) has been closed!",
3888                           getpid (), session_index);
3889           rv = VPPCOM_EBADFD;
3890           clib_spinlock_unlock (&vcm->sessions_lockp);
3891           goto done;
3892         }
3893       ep->vrf = session->vrf;
3894       ep->is_ip4 = session->peer_addr.is_ip4;
3895       ep->port = session->peer_port;
3896       if (session->peer_addr.is_ip4)
3897         clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
3898                      sizeof (ip4_address_t));
3899       else
3900         clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
3901                      sizeof (ip6_address_t));
3902       clib_spinlock_unlock (&vcm->sessions_lockp);
3903     }
3904
3905   if (flags == 0)
3906     rv = vppcom_session_read (session_index, buffer, buflen);
3907   else if (flags & MSG_PEEK)
3908     rv = vppcom_session_peek (session_index, buffer, buflen);
3909   else
3910     {
3911       clib_warning ("[%d] Unsupport flags for recvfrom %d", getpid (), flags);
3912       rv = VPPCOM_EAFNOSUPPORT;
3913     }
3914
3915 done:
3916   return rv;
3917 }
3918
3919 int
3920 vppcom_session_sendto (uint32_t session_index, void *buffer,
3921                        uint32_t buflen, int flags, vppcom_endpt_t * ep)
3922 {
3923   if (!buffer)
3924     return VPPCOM_EINVAL;
3925
3926   if (ep)
3927     {
3928       // TBD
3929       return VPPCOM_EINVAL;
3930     }
3931
3932   if (flags)
3933     {
3934       // TBD check the flags and do the right thing
3935       if (VPPCOM_DEBUG > 2)
3936         clib_warning ("[%d] handling flags 0x%u (%d) not implemented yet.",
3937                       getpid (), flags, flags);
3938     }
3939
3940   return (vppcom_session_write (session_index, buffer, buflen));
3941 }
3942
3943 /*
3944  * fd.io coding-style-patch-verification: ON
3945  *
3946  * Local Variables:
3947  * eval: (c-set-style "gnu")
3948  * End:
3949  */