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