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