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