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