VPP-659 TCP improvements
[vpp.git] / src / vnet / session / session_api.c
1 /*
2  * Copyright (c) 2015-2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
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 <vnet/vnet.h>
17 #include <vlibmemory/api.h>
18 #include <vnet/session/application.h>
19
20 #include <vnet/vnet_msg_enum.h>
21 #include "application_interface.h"
22
23 #define vl_typedefs             /* define message structures */
24 #include <vnet/vnet_all_api_h.h>
25 #undef vl_typedefs
26
27 #define vl_endianfun            /* define message structures */
28 #include <vnet/vnet_all_api_h.h>
29 #undef vl_endianfun
30
31 /* instantiate all the print functions we know about */
32 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
33 #define vl_printfun
34 #include <vnet/vnet_all_api_h.h>
35 #undef vl_printfun
36
37 #include <vlibapi/api_helper_macros.h>
38
39 #define foreach_session_api_msg                                         \
40 _(MAP_ANOTHER_SEGMENT_REPLY, map_another_segment_reply)                 \
41 _(BIND_URI, bind_uri)                                                   \
42 _(UNBIND_URI, unbind_uri)                                               \
43 _(CONNECT_URI, connect_uri)                                             \
44 _(DISCONNECT_SESSION, disconnect_session)                               \
45 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)                   \
46 _(ACCEPT_SESSION_REPLY, accept_session_reply)                           \
47 _(RESET_SESSION_REPLY, reset_session_reply)                             \
48 _(BIND_SOCK, bind_sock)                                                 \
49 _(UNBIND_SOCK, unbind_sock)                                             \
50 _(CONNECT_SOCK, connect_sock)                                           \
51 _(DISCONNECT_SOCK, disconnect_sock)                                     \
52 _(DISCONNECT_SOCK_REPLY, disconnect_sock_reply)                         \
53 _(ACCEPT_SOCK_REPLY, accept_sock_reply)                                 \
54 _(RESET_SOCK_REPLY, reset_sock_reply)                                   \
55 _(SESSION_ENABLE_DISABLE, session_enable_disable)                       \
56
57
58 static int
59 send_add_segment_callback (u32 api_client_index, const u8 * segment_name,
60                            u32 segment_size)
61 {
62   vl_api_map_another_segment_t *mp;
63   unix_shared_memory_queue_t *q;
64
65   q = vl_api_client_index_to_input_queue (api_client_index);
66
67   if (!q)
68     return -1;
69
70   mp = vl_msg_api_alloc (sizeof (*mp));
71   memset (mp, 0, sizeof (*mp));
72   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
73   mp->segment_size = segment_size;
74   strncpy ((char *) mp->segment_name, (char *) segment_name,
75            sizeof (mp->segment_name) - 1);
76
77   vl_msg_api_send_shmem (q, (u8 *) & mp);
78
79   return 0;
80 }
81
82 static int
83 send_session_accept_uri_callback (stream_session_t * s)
84 {
85   vl_api_accept_session_t *mp;
86   unix_shared_memory_queue_t *q, *vpp_queue;
87   application_t *server = application_get (s->app_index);
88
89   q = vl_api_client_index_to_input_queue (server->api_client_index);
90   vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
91
92   if (!q)
93     return -1;
94
95   mp = vl_msg_api_alloc (sizeof (*mp));
96   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION);
97
98   /* Note: session_type is the first octet in all types of sessions */
99
100   mp->accept_cookie = server->accept_cookie;
101   mp->server_rx_fifo = (u64) s->server_rx_fifo;
102   mp->server_tx_fifo = (u64) s->server_tx_fifo;
103   mp->session_thread_index = s->thread_index;
104   mp->session_index = s->session_index;
105   mp->session_type = s->session_type;
106   mp->vpp_event_queue_address = (u64) vpp_queue;
107   vl_msg_api_send_shmem (q, (u8 *) & mp);
108
109   return 0;
110 }
111
112 static void
113 send_session_disconnect_uri_callback (stream_session_t * s)
114 {
115   vl_api_disconnect_session_t *mp;
116   unix_shared_memory_queue_t *q;
117   application_t *app = application_get (s->app_index);
118
119   q = vl_api_client_index_to_input_queue (app->api_client_index);
120
121   if (!q)
122     return;
123
124   mp = vl_msg_api_alloc (sizeof (*mp));
125   memset (mp, 0, sizeof (*mp));
126   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
127
128   mp->session_thread_index = s->thread_index;
129   mp->session_index = s->session_index;
130   vl_msg_api_send_shmem (q, (u8 *) & mp);
131 }
132
133 static void
134 send_session_reset_uri_callback (stream_session_t * s)
135 {
136   vl_api_reset_session_t *mp;
137   unix_shared_memory_queue_t *q;
138   application_t *app = application_get (s->app_index);
139
140   q = vl_api_client_index_to_input_queue (app->api_client_index);
141
142   if (!q)
143     return;
144
145   mp = vl_msg_api_alloc (sizeof (*mp));
146   memset (mp, 0, sizeof (*mp));
147   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SESSION);
148
149   mp->session_thread_index = s->thread_index;
150   mp->session_index = s->session_index;
151   vl_msg_api_send_shmem (q, (u8 *) & mp);
152 }
153
154 static int
155 send_session_connected_uri_callback (u32 api_client_index,
156                                      stream_session_t * s, u8 is_fail)
157 {
158   vl_api_connect_uri_reply_t *mp;
159   unix_shared_memory_queue_t *q;
160   application_t *app = application_lookup (api_client_index);
161   u8 *seg_name;
162   unix_shared_memory_queue_t *vpp_queue;
163
164   q = vl_api_client_index_to_input_queue (app->api_client_index);
165
166   if (!q)
167     return -1;
168
169   mp = vl_msg_api_alloc (sizeof (*mp));
170   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_URI_REPLY);
171   mp->context = app->api_context;
172   if (!is_fail)
173     {
174       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
175       mp->server_rx_fifo = (u64) s->server_rx_fifo;
176       mp->server_tx_fifo = (u64) s->server_tx_fifo;
177       mp->session_thread_index = s->thread_index;
178       mp->session_index = s->session_index;
179       mp->session_type = s->session_type;
180       mp->vpp_event_queue_address = (u64) vpp_queue;
181       mp->client_event_queue_address = (u64) app->event_queue;
182       mp->retval = 0;
183
184       session_manager_get_segment_info (s->server_segment_index, &seg_name,
185                                         &mp->segment_size);
186       mp->segment_name_length = vec_len (seg_name);
187       if (mp->segment_name_length)
188         clib_memcpy (mp->segment_name, seg_name, mp->segment_name_length);
189     }
190   else
191     {
192       mp->retval = VNET_API_ERROR_SESSION_CONNECT_FAIL;
193     }
194
195   vl_msg_api_send_shmem (q, (u8 *) & mp);
196
197   /* Remove client if connect failed */
198   if (is_fail)
199     {
200       application_del (app);
201     }
202   else
203     {
204       s->session_state = SESSION_STATE_READY;
205     }
206
207   return 0;
208 }
209
210 /**
211  * Redirect a connect_uri message to the indicated server.
212  * Only sent if the server has bound the related port with
213  * URI_OPTIONS_FLAGS_USE_FIFO
214  */
215 static int
216 redirect_connect_uri_callback (u32 server_api_client_index, void *mp_arg)
217 {
218   vl_api_connect_uri_t *mp = mp_arg;
219   unix_shared_memory_queue_t *server_q, *client_q;
220   vlib_main_t *vm = vlib_get_main ();
221   f64 timeout = vlib_time_now (vm) + 0.5;
222   int rv = 0;
223
224   server_q = vl_api_client_index_to_input_queue (server_api_client_index);
225
226   if (!server_q)
227     {
228       rv = VNET_API_ERROR_INVALID_VALUE;
229       goto out;
230     }
231
232   client_q = vl_api_client_index_to_input_queue (mp->client_index);
233   if (!client_q)
234     {
235       rv = VNET_API_ERROR_INVALID_VALUE_2;
236       goto out;
237     }
238
239   /* Tell the server the client's API queue address, so it can reply */
240   mp->client_queue_address = (u64) client_q;
241
242   /*
243    * Bounce message handlers MUST NOT block the data-plane.
244    * Spin waiting for the queue lock, but
245    */
246
247   while (vlib_time_now (vm) < timeout)
248     {
249       rv =
250         unix_shared_memory_queue_add (server_q, (u8 *) & mp, 1 /*nowait */ );
251       switch (rv)
252         {
253           /* correctly enqueued */
254         case 0:
255           return VNET_CONNECT_REDIRECTED;
256
257           /* continue spinning, wait for pthread_mutex_trylock to work */
258         case -1:
259           continue;
260
261           /* queue stuffed, drop the msg */
262         case -2:
263           rv = VNET_API_ERROR_QUEUE_FULL;
264           goto out;
265         }
266     }
267 out:
268   /* Dispose of the message */
269   vl_msg_api_free (mp);
270   return rv;
271 }
272
273 static u64
274 make_session_handle (stream_session_t * s)
275 {
276   return (u64) s->session_index << 32 | (u64) s->thread_index;
277 }
278
279 static int
280 send_session_accept_callback (stream_session_t * s)
281 {
282   vl_api_accept_sock_t *mp;
283   unix_shared_memory_queue_t *q, *vpp_queue;
284   application_t *server = application_get (s->app_index);
285
286   q = vl_api_client_index_to_input_queue (server->api_client_index);
287   vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
288
289   if (!q)
290     return -1;
291
292   mp = vl_msg_api_alloc (sizeof (*mp));
293   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SOCK);
294
295   /* Note: session_type is the first octet in all types of sessions */
296
297   mp->accept_cookie = server->accept_cookie;
298   mp->server_rx_fifo = (u64) s->server_rx_fifo;
299   mp->server_tx_fifo = (u64) s->server_tx_fifo;
300   mp->handle = make_session_handle (s);
301   mp->vpp_event_queue_address = (u64) vpp_queue;
302   vl_msg_api_send_shmem (q, (u8 *) & mp);
303
304   return 0;
305 }
306
307 static int
308 send_session_connected_callback (u32 api_client_index, stream_session_t * s,
309                                  u8 is_fail)
310 {
311   vl_api_connect_sock_reply_t *mp;
312   unix_shared_memory_queue_t *q;
313   application_t *app = application_lookup (api_client_index);
314   u8 *seg_name;
315   unix_shared_memory_queue_t *vpp_queue;
316
317   q = vl_api_client_index_to_input_queue (app->api_client_index);
318
319   if (!q)
320     return -1;
321
322   mp = vl_msg_api_alloc (sizeof (*mp));
323   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SOCK_REPLY);
324   mp->context = app->api_context;
325   mp->retval = is_fail;
326   if (!is_fail)
327     {
328       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
329       mp->server_rx_fifo = (u64) s->server_rx_fifo;
330       mp->server_tx_fifo = (u64) s->server_tx_fifo;
331       mp->handle = make_session_handle (s);
332       mp->vpp_event_queue_address = (u64) vpp_queue;
333       mp->client_event_queue_address = (u64) app->event_queue;
334
335       session_manager_get_segment_info (s->server_segment_index, &seg_name,
336                                         &mp->segment_size);
337       mp->segment_name_length = vec_len (seg_name);
338       if (mp->segment_name_length)
339         clib_memcpy (mp->segment_name, seg_name, mp->segment_name_length);
340     }
341
342   vl_msg_api_send_shmem (q, (u8 *) & mp);
343
344   /* Remove client if connect failed */
345   if (is_fail)
346     application_del (app);
347
348   return 0;
349 }
350
351 static void
352 send_session_disconnect_callback (stream_session_t * s)
353 {
354   vl_api_disconnect_sock_t *mp;
355   unix_shared_memory_queue_t *q;
356   application_t *app = application_get (s->app_index);
357
358   q = vl_api_client_index_to_input_queue (app->api_client_index);
359
360   if (!q)
361     return;
362
363   mp = vl_msg_api_alloc (sizeof (*mp));
364   memset (mp, 0, sizeof (*mp));
365   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SOCK);
366
367   mp->handle = make_session_handle (s);
368   vl_msg_api_send_shmem (q, (u8 *) & mp);
369 }
370
371 static void
372 send_session_reset_callback (stream_session_t * s)
373 {
374   vl_api_reset_sock_t *mp;
375   unix_shared_memory_queue_t *q;
376   application_t *app = application_get (s->app_index);
377
378   q = vl_api_client_index_to_input_queue (app->api_client_index);
379
380   if (!q)
381     return;
382
383   mp = vl_msg_api_alloc (sizeof (*mp));
384   memset (mp, 0, sizeof (*mp));
385   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SOCK);
386
387   mp->handle = make_session_handle (s);
388   vl_msg_api_send_shmem (q, (u8 *) & mp);
389 }
390
391 /**
392  * Redirect a connect_uri message to the indicated server.
393  * Only sent if the server has bound the related port with
394  * URI_OPTIONS_FLAGS_USE_FIFO
395  */
396 static int
397 redirect_connect_callback (u32 server_api_client_index, void *mp_arg)
398 {
399   vl_api_connect_sock_t *mp = mp_arg;
400   unix_shared_memory_queue_t *server_q, *client_q;
401   vlib_main_t *vm = vlib_get_main ();
402   f64 timeout = vlib_time_now (vm) + 0.5;
403   int rv = 0;
404
405   server_q = vl_api_client_index_to_input_queue (server_api_client_index);
406
407   if (!server_q)
408     {
409       rv = VNET_API_ERROR_INVALID_VALUE;
410       goto out;
411     }
412
413   client_q = vl_api_client_index_to_input_queue (mp->client_index);
414   if (!client_q)
415     {
416       rv = VNET_API_ERROR_INVALID_VALUE_2;
417       goto out;
418     }
419
420   /* Tell the server the client's API queue address, so it can reply */
421   mp->client_queue_address = (u64) client_q;
422
423   /*
424    * Bounce message handlers MUST NOT block the data-plane.
425    * Spin waiting for the queue lock, but
426    */
427
428   while (vlib_time_now (vm) < timeout)
429     {
430       rv =
431         unix_shared_memory_queue_add (server_q, (u8 *) & mp, 1 /*nowait */ );
432       switch (rv)
433         {
434           /* correctly enqueued */
435         case 0:
436           return VNET_CONNECT_REDIRECTED;
437
438           /* continue spinning, wait for pthread_mutex_trylock to work */
439         case -1:
440           continue;
441
442           /* queue stuffed, drop the msg */
443         case -2:
444           rv = VNET_API_ERROR_QUEUE_FULL;
445           goto out;
446         }
447     }
448 out:
449   /* Dispose of the message */
450   vl_msg_api_free (mp);
451   return rv;
452 }
453
454 static session_cb_vft_t uri_session_cb_vft = {
455   .session_accept_callback = send_session_accept_uri_callback,
456   .session_disconnect_callback = send_session_disconnect_uri_callback,
457   .session_connected_callback = send_session_connected_uri_callback,
458   .session_reset_callback = send_session_reset_uri_callback,
459   .add_segment_callback = send_add_segment_callback,
460   .redirect_connect_callback = redirect_connect_uri_callback
461 };
462
463 static session_cb_vft_t session_cb_vft = {
464   .session_accept_callback = send_session_accept_callback,
465   .session_disconnect_callback = send_session_disconnect_callback,
466   .session_connected_callback = send_session_connected_callback,
467   .session_reset_callback = send_session_reset_callback,
468   .add_segment_callback = send_add_segment_callback,
469   .redirect_connect_callback = redirect_connect_callback
470 };
471
472 static int
473 api_session_not_valid (u32 session_index, u32 thread_index)
474 {
475   session_manager_main_t *smm = vnet_get_session_manager_main ();
476   stream_session_t *pool;
477
478   if (thread_index >= vec_len (smm->sessions))
479     return VNET_API_ERROR_INVALID_VALUE;
480
481   pool = smm->sessions[thread_index];
482
483   if (pool_is_free_index (pool, session_index))
484     return VNET_API_ERROR_INVALID_VALUE_2;
485
486   return 0;
487 }
488
489 static void
490 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
491 {
492   vl_api_session_enable_disable_reply_t *rmp;
493   vlib_main_t *vm = vlib_get_main ();
494   int rv = 0;
495
496   vnet_session_enable_disable (vm, mp->is_enable);
497   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
498 }
499
500 static void
501 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
502 {
503   vl_api_bind_uri_reply_t *rmp;
504   vnet_bind_args_t _a, *a = &_a;
505   char segment_name[128];
506   u32 segment_name_length;
507   int rv;
508
509   _Static_assert (sizeof (u64) * SESSION_OPTIONS_N_OPTIONS <=
510                   sizeof (mp->options),
511                   "Out of options, fix api message definition");
512
513   segment_name_length = ARRAY_LEN (segment_name);
514
515   memset (a, 0, sizeof (*a));
516
517   a->uri = (char *) mp->uri;
518   a->api_client_index = mp->client_index;
519   a->options = mp->options;
520   a->segment_name = segment_name;
521   a->segment_name_length = segment_name_length;
522   a->session_cb_vft = &uri_session_cb_vft;
523
524   a->options[SESSION_OPTIONS_SEGMENT_SIZE] = mp->initial_segment_size;
525   a->options[SESSION_OPTIONS_ACCEPT_COOKIE] = mp->accept_cookie;
526   rv = vnet_bind_uri (a);
527
528   /* *INDENT-OFF* */
529   REPLY_MACRO2 (VL_API_BIND_URI_REPLY, ({
530     rmp->retval = rv;
531     if (!rv)
532       {
533         rmp->segment_name_length = 0;
534         /* $$$$ policy? */
535         rmp->segment_size = mp->initial_segment_size;
536         if (segment_name_length)
537           {
538             memcpy (rmp->segment_name, segment_name, segment_name_length);
539             rmp->segment_name_length = segment_name_length;
540           }
541         rmp->server_event_queue_address = a->server_event_queue_address;
542       }
543   }));
544   /* *INDENT-ON* */
545 }
546
547 static void
548 vl_api_unbind_uri_t_handler (vl_api_unbind_uri_t * mp)
549 {
550   vl_api_unbind_uri_reply_t *rmp;
551   int rv;
552
553   rv = vnet_unbind_uri ((char *) mp->uri, mp->client_index);
554
555   REPLY_MACRO (VL_API_UNBIND_URI_REPLY);
556 }
557
558 static void
559 vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
560 {
561   vl_api_connect_uri_reply_t *rmp;
562   vnet_connect_args_t _a, *a = &_a;
563   int rv;
564
565   a->uri = (char *) mp->uri;
566   a->api_client_index = mp->client_index;
567   a->api_context = mp->context;
568   a->options = mp->options;
569   a->session_cb_vft = &uri_session_cb_vft;
570   a->mp = mp;
571
572   rv = vnet_connect_uri (a);
573
574   if (rv == 0 || rv == VNET_CONNECT_REDIRECTED)
575     return;
576
577   /* Got some error, relay it */
578
579   /* *INDENT-OFF* */
580   REPLY_MACRO2 (VL_API_CONNECT_URI_REPLY, ({
581     rmp->retval = rv;
582   }));
583   /* *INDENT-ON* */
584 }
585
586 static void
587 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
588 {
589   vl_api_disconnect_session_reply_t *rmp;
590   int rv;
591
592   rv = api_session_not_valid (mp->session_index, mp->session_thread_index);
593   if (!rv)
594     rv =
595       vnet_disconnect_session (mp->session_index, mp->session_thread_index);
596
597   REPLY_MACRO (VL_API_DISCONNECT_SESSION_REPLY);
598 }
599
600 static void
601 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
602                                            mp)
603 {
604   if (api_session_not_valid (mp->session_index, mp->session_thread_index))
605     {
606       clib_warning ("Invalid session!");
607       return;
608     }
609
610   /* Client objected to disconnecting the session, log and continue */
611   if (mp->retval)
612     {
613       clib_warning ("client retval %d", mp->retval);
614       return;
615     }
616
617   /* Disconnect has been confirmed. Confirm close to transport */
618   vnet_disconnect_session (mp->session_index, mp->session_thread_index);
619 }
620
621 static void
622 vl_api_reset_session_reply_t_handler (vl_api_reset_session_reply_t * mp)
623 {
624   stream_session_t *s;
625
626   if (api_session_not_valid (mp->session_index, mp->session_thread_index))
627     {
628       clib_warning ("Invalid session!");
629       return;
630     }
631
632   /* Client objected to resetting the session, log and continue */
633   if (mp->retval)
634     {
635       clib_warning ("client retval %d", mp->retval);
636       return;
637     }
638
639   s = stream_session_get (mp->session_index, mp->session_thread_index);
640
641   /* This comes as a response to a reset, transport only waiting for
642    * confirmation to remove connection state, no need to disconnect */
643   stream_session_cleanup (s);
644 }
645
646 static void
647 vl_api_accept_session_reply_t_handler (vl_api_accept_session_reply_t * mp)
648 {
649   stream_session_t *s;
650   int rv;
651
652   if (api_session_not_valid (mp->session_index, mp->session_thread_index))
653     return;
654
655   s = stream_session_get (mp->session_index, mp->session_thread_index);
656   rv = mp->retval;
657
658   if (rv)
659     {
660       /* Server isn't interested, kill the session */
661       stream_session_disconnect (s);
662       return;
663     }
664
665   s->session_state = SESSION_STATE_READY;
666 }
667
668 static void
669 vl_api_map_another_segment_reply_t_handler (vl_api_map_another_segment_reply_t
670                                             * mp)
671 {
672   clib_warning ("not implemented");
673 }
674
675 static void
676 vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
677 {
678   vl_api_bind_sock_reply_t *rmp;
679   vnet_bind_args_t _a, *a = &_a;
680   char segment_name[128];
681   u32 segment_name_length;
682   int rv;
683
684   STATIC_ASSERT (sizeof (u64) * SESSION_OPTIONS_N_OPTIONS <=
685                  sizeof (mp->options),
686                  "Out of options, fix api message definition");
687
688   segment_name_length = ARRAY_LEN (segment_name);
689
690   memset (a, 0, sizeof (*a));
691
692   clib_memcpy (&a->tep.ip, mp->ip,
693                (mp->is_ip4 ? sizeof (ip4_address_t) :
694                 sizeof (ip6_address_t)));
695   a->tep.is_ip4 = mp->is_ip4;
696   a->tep.port = mp->port;
697   a->tep.vrf = mp->vrf;
698
699   a->api_client_index = mp->client_index;
700   a->options = mp->options;
701   a->segment_name = segment_name;
702   a->segment_name_length = segment_name_length;
703   a->session_cb_vft = &session_cb_vft;
704
705   rv = vnet_bind_uri (a);
706
707   /* *INDENT-OFF* */
708   REPLY_MACRO2 (VL_API_BIND_SOCK_REPLY, ({
709     rmp->retval = rv;
710     if (!rv)
711       {
712         rmp->segment_name_length = 0;
713         rmp->segment_size = mp->options[SESSION_OPTIONS_SEGMENT_SIZE];
714         if (segment_name_length)
715           {
716             memcpy(rmp->segment_name, segment_name, segment_name_length);
717             rmp->segment_name_length = segment_name_length;
718           }
719         rmp->server_event_queue_address = a->server_event_queue_address;
720       }
721   }));
722   /* *INDENT-ON* */
723 }
724
725 static void
726 vl_api_unbind_sock_t_handler (vl_api_unbind_sock_t * mp)
727 {
728   vl_api_unbind_sock_reply_t *rmp;
729   vnet_unbind_args_t _a, *a = &_a;
730   int rv;
731
732   a->api_client_index = mp->client_index;
733   a->handle = mp->handle;
734
735   rv = vnet_unbind (a);
736
737   REPLY_MACRO (VL_API_UNBIND_SOCK_REPLY);
738 }
739
740 static void
741 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
742 {
743   vl_api_connect_sock_reply_t *rmp;
744   vnet_connect_args_t _a, *a = &_a;
745   int rv;
746
747   clib_memcpy (&a->tep.ip, mp->ip,
748                (mp->is_ip4 ? sizeof (ip4_address_t) :
749                 sizeof (ip6_address_t)));
750   a->tep.is_ip4 = mp->is_ip4;
751   a->tep.port = mp->port;
752   a->tep.vrf = mp->vrf;
753   a->options = mp->options;
754   a->session_cb_vft = &session_cb_vft;
755   a->api_context = mp->context;
756   a->mp = mp;
757
758   rv = vnet_connect (a);
759
760   if (rv == 0 || rv == VNET_CONNECT_REDIRECTED)
761     return;
762
763   /* Got some error, relay it */
764
765   /* *INDENT-OFF* */
766   REPLY_MACRO2 (VL_API_CONNECT_URI_REPLY, ({
767     rmp->retval = rv;
768   }));
769   /* *INDENT-ON* */
770 }
771
772 static void
773 vl_api_disconnect_sock_t_handler (vl_api_disconnect_sock_t * mp)
774 {
775   vnet_disconnect_args_t _a, *a = &_a;
776   vl_api_disconnect_sock_reply_t *rmp;
777   int rv;
778
779   a->api_client_index = mp->client_index;
780   a->handle = mp->handle;
781   rv = vnet_disconnect (a);
782
783   REPLY_MACRO (VL_API_DISCONNECT_SOCK_REPLY);
784 }
785
786 static void
787 vl_api_disconnect_sock_reply_t_handler (vl_api_disconnect_sock_reply_t * mp)
788 {
789   vnet_disconnect_args_t _a, *a = &_a;
790
791   /* Client objected to disconnecting the session, log and continue */
792   if (mp->retval)
793     {
794       clib_warning ("client retval %d", mp->retval);
795       return;
796     }
797
798   a->api_client_index = mp->client_index;
799   a->handle = mp->handle;
800
801   vnet_disconnect (a);
802 }
803
804 static void
805 vl_api_reset_sock_reply_t_handler (vl_api_reset_sock_reply_t * mp)
806 {
807   stream_session_t *s;
808   u32 session_index, thread_index;
809
810   /* Client objected to resetting the session, log and continue */
811   if (mp->retval)
812     {
813       clib_warning ("client retval %d", mp->retval);
814       return;
815     }
816
817   if (api_parse_session_handle (mp->handle, &session_index, &thread_index))
818     {
819       clib_warning ("Invalid handle");
820       return;
821     }
822
823   s = stream_session_get (session_index, thread_index);
824
825   /* This comes as a response to a reset, transport only waiting for
826    * confirmation to remove connection state, no need to disconnect */
827   stream_session_cleanup (s);
828 }
829
830 static void
831 vl_api_accept_sock_reply_t_handler (vl_api_accept_sock_reply_t * mp)
832 {
833   stream_session_t *s;
834   u32 session_index, thread_index;
835
836   if (api_parse_session_handle (mp->handle, &session_index, &thread_index))
837     {
838       clib_warning ("Invalid handle");
839       return;
840     }
841   s = stream_session_get (session_index, thread_index);
842
843   if (mp->retval)
844     {
845       /* Server isn't interested, kill the session */
846       stream_session_disconnect (s);
847       return;
848     }
849
850   s->session_state = SESSION_STATE_READY;
851 }
852
853 #define vl_msg_name_crc_list
854 #include <vnet/vnet_all_api_h.h>
855 #undef vl_msg_name_crc_list
856
857 static void
858 setup_message_id_table (api_main_t * am)
859 {
860 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
861   foreach_vl_msg_name_crc_session;
862 #undef _
863 }
864
865 /*
866  * session_api_hookup
867  * Add uri's API message handlers to the table.
868  * vlib has alread mapped shared memory and
869  * added the client registration handlers.
870  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
871  */
872 static clib_error_t *
873 session_api_hookup (vlib_main_t * vm)
874 {
875   api_main_t *am = &api_main;
876
877 #define _(N,n)                                                  \
878     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
879                            vl_api_##n##_t_handler,              \
880                            vl_noop_handler,                     \
881                            vl_api_##n##_t_endian,               \
882                            vl_api_##n##_t_print,                \
883                            sizeof(vl_api_##n##_t), 1);
884   foreach_session_api_msg;
885 #undef _
886
887   /*
888    * Messages which bounce off the data-plane to
889    * an API client. Simply tells the message handling infra not
890    * to free the message.
891    *
892    * Bounced message handlers MUST NOT block the data plane
893    */
894   am->message_bounce[VL_API_CONNECT_URI] = 1;
895   am->message_bounce[VL_API_CONNECT_SOCK] = 1;
896
897   /*
898    * Set up the (msg_name, crc, message-id) table
899    */
900   setup_message_id_table (am);
901
902   return 0;
903 }
904
905 VLIB_API_INIT_FUNCTION (session_api_hookup);
906 /*
907  * fd.io coding-style-patch-verification: ON
908  *
909  * Local Variables:
910  * eval: (c-set-style "gnu")
911  * End:
912  */