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