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