udp/session: refactor to support dgram mode
[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 #include <vnet/session/application_interface.h>
20 #include <vnet/session/session_rules_table.h>
21 #include <vnet/session/session_table.h>
22
23 #include <vnet/vnet_msg_enum.h>
24
25 #define vl_typedefs             /* define message structures */
26 #include <vnet/vnet_all_api_h.h>
27 #undef vl_typedefs
28
29 #define vl_endianfun            /* define message structures */
30 #include <vnet/vnet_all_api_h.h>
31 #undef vl_endianfun
32
33 /* instantiate all the print functions we know about */
34 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
35 #define vl_printfun
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_printfun
38
39 #include <vlibapi/api_helper_macros.h>
40
41 #define foreach_session_api_msg                                         \
42 _(MAP_ANOTHER_SEGMENT_REPLY, map_another_segment_reply)                 \
43 _(APPLICATION_ATTACH, application_attach)                               \
44 _(APPLICATION_DETACH, application_detach)                               \
45 _(BIND_URI, bind_uri)                                                   \
46 _(UNBIND_URI, unbind_uri)                                               \
47 _(CONNECT_URI, connect_uri)                                             \
48 _(DISCONNECT_SESSION, disconnect_session)                               \
49 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)                   \
50 _(ACCEPT_SESSION_REPLY, accept_session_reply)                           \
51 _(RESET_SESSION_REPLY, reset_session_reply)                             \
52 _(BIND_SOCK, bind_sock)                                                 \
53 _(UNBIND_SOCK, unbind_sock)                                             \
54 _(CONNECT_SOCK, connect_sock)                                           \
55 _(SESSION_ENABLE_DISABLE, session_enable_disable)                       \
56 _(APP_NAMESPACE_ADD_DEL, app_namespace_add_del)                         \
57 _(SESSION_RULE_ADD_DEL, session_rule_add_del)                           \
58 _(SESSION_RULES_DUMP, session_rules_dump)                               \
59 _(APPLICATION_TLS_CERT_ADD, application_tls_cert_add)                   \
60 _(APPLICATION_TLS_KEY_ADD, application_tls_key_add)                     \
61
62 static int
63 session_send_memfd_fd (vl_api_registration_t * reg, const ssvm_private_t * sp)
64 {
65   clib_error_t *error;
66   if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
67     {
68       clib_warning ("can't send memfd fd");
69       return -1;
70     }
71   error = vl_api_send_fd_msg (reg, sp->fd);
72   if (error)
73     {
74       clib_error_report (error);
75       return -1;
76     }
77   return 0;
78 }
79
80 static int
81 send_add_segment_callback (u32 api_client_index, const ssvm_private_t * sp)
82 {
83   vl_api_map_another_segment_t *mp;
84   vl_api_registration_t *reg;
85
86   reg = vl_mem_api_client_index_to_registration (api_client_index);
87   if (!reg)
88     {
89       clib_warning ("no registration: %u", api_client_index);
90       return -1;
91     }
92
93   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD
94       && vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
95     {
96       clib_warning ("can't send memfd fd");
97       return -1;
98     }
99
100   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
101   memset (mp, 0, sizeof (*mp));
102   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
103   mp->segment_size = sp->ssvm_size;
104   strncpy ((char *) mp->segment_name, (char *) sp->name,
105            sizeof (mp->segment_name) - 1);
106
107   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
108
109   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
110     return session_send_memfd_fd (reg, sp);
111
112   return 0;
113 }
114
115 static int
116 send_del_segment_callback (u32 api_client_index, const ssvm_private_t * fs)
117 {
118   vl_api_unmap_segment_t *mp;
119   vl_api_registration_t *reg;
120
121   reg = vl_mem_api_client_index_to_registration (api_client_index);
122   if (!reg)
123     {
124       clib_warning ("no registration: %u", api_client_index);
125       return -1;
126     }
127
128   if (ssvm_type (fs) == SSVM_SEGMENT_MEMFD
129       && vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
130     {
131       clib_warning ("can't send memfd fd");
132       return -1;
133     }
134
135   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
136   memset (mp, 0, sizeof (*mp));
137   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_UNMAP_SEGMENT);
138   strncpy ((char *) mp->segment_name, (char *) fs->name,
139            sizeof (mp->segment_name) - 1);
140
141   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
142
143   if (ssvm_type (fs) == SSVM_SEGMENT_MEMFD)
144     return session_send_memfd_fd (reg, fs);
145
146   return 0;
147 }
148
149 static int
150 send_session_accept_callback (stream_session_t * s)
151 {
152   application_t *server = application_get (s->app_index);
153   transport_proto_vft_t *tp_vft;
154   vl_api_accept_session_t *mp;
155   vl_api_registration_t *reg;
156   transport_connection_t *tc;
157   stream_session_t *listener;
158   svm_queue_t *vpp_queue;
159
160   reg = vl_mem_api_client_index_to_registration (server->api_client_index);
161   if (!reg)
162     {
163       clib_warning ("no registration: %u", server->api_client_index);
164       return -1;
165     }
166
167   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
168   memset (mp, 0, sizeof (*mp));
169
170   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION);
171   mp->context = server->index;
172   mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
173   mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
174
175   if (session_has_transport (s))
176     {
177       listener = listen_session_get (s->listener_index);
178       mp->listener_handle = listen_session_get_handle (listener);
179       if (application_is_proxy (server))
180         {
181           listener =
182             application_first_listener (server, session_get_fib_proto (s),
183                                         session_get_transport_proto (s));
184           if (listener)
185             mp->listener_handle = listen_session_get_handle (listener);
186         }
187       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
188       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
189       mp->handle = session_handle (s);
190       tp_vft = transport_protocol_get_vft (session_get_transport_proto (s));
191       tc = tp_vft->get_connection (s->connection_index, s->thread_index);
192       mp->port = tc->rmt_port;
193       mp->is_ip4 = tc->is_ip4;
194       clib_memcpy (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
195     }
196   else
197     {
198       local_session_t *ls = (local_session_t *) s;
199       local_session_t *ll;
200       if (application_local_session_listener_has_transport (ls))
201         {
202           listener = listen_session_get (ls->listener_index);
203           mp->listener_handle = listen_session_get_handle (listener);
204           mp->is_ip4 = session_type_is_ip4 (listener->session_type);
205         }
206       else
207         {
208           ll = application_get_local_listen_session (server,
209                                                      ls->listener_index);
210           if (ll->transport_listener_index != ~0)
211             {
212               listener = listen_session_get (ll->transport_listener_index);
213               mp->listener_handle = listen_session_get_handle (listener);
214             }
215           else
216             {
217               mp->listener_handle = application_local_session_handle (ll);
218             }
219           mp->is_ip4 = session_type_is_ip4 (ll->listener_session_type);
220         }
221       mp->handle = application_local_session_handle (ls);
222       mp->port = ls->port;
223       mp->vpp_event_queue_address = ls->client_evt_q;
224       mp->server_event_queue_address = ls->server_evt_q;
225     }
226   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
227
228   return 0;
229 }
230
231 void
232 send_local_session_disconnect_callback (u32 app_index, local_session_t * ls)
233 {
234   application_t *app = application_get (app_index);
235   vl_api_disconnect_session_t *mp;
236   vl_api_registration_t *reg;
237
238   reg = vl_mem_api_client_index_to_registration (app->api_client_index);
239   if (!reg)
240     {
241       clib_warning ("no registration: %u", app->api_client_index);
242       return;
243     }
244
245   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
246   memset (mp, 0, sizeof (*mp));
247   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
248   mp->handle = application_local_session_handle (ls);
249   mp->context = app->api_client_index;
250   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
251 }
252
253 static void
254 send_session_disconnect_callback (stream_session_t * s)
255 {
256   application_t *app = application_get (s->app_index);
257   vl_api_disconnect_session_t *mp;
258   vl_api_registration_t *reg;
259
260   reg = vl_mem_api_client_index_to_registration (app->api_client_index);
261   if (!reg)
262     {
263       clib_warning ("no registration: %u", app->api_client_index);
264       return;
265     }
266
267   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
268   memset (mp, 0, sizeof (*mp));
269   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
270   mp->handle = session_handle (s);
271   mp->context = app->api_client_index;
272   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
273 }
274
275 static void
276 send_session_reset_callback (stream_session_t * s)
277 {
278   application_t *app = application_get (s->app_index);
279   vl_api_registration_t *reg;
280   vl_api_reset_session_t *mp;
281
282   reg = vl_mem_api_client_index_to_registration (app->api_client_index);
283   if (!reg)
284     {
285       clib_warning ("no registration: %u", app->api_client_index);
286       return;
287     }
288
289   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
290   memset (mp, 0, sizeof (*mp));
291   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SESSION);
292   mp->handle = session_handle (s);
293   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
294 }
295
296 int
297 send_session_connected_callback (u32 app_index, u32 api_context,
298                                  stream_session_t * s, u8 is_fail)
299 {
300   vl_api_connect_session_reply_t *mp;
301   transport_connection_t *tc;
302   vl_api_registration_t *reg;
303   svm_queue_t *vpp_queue;
304   application_t *app;
305
306   app = application_get (app_index);
307   reg = vl_mem_api_client_index_to_registration (app->api_client_index);
308   if (!reg)
309     {
310       clib_warning ("no registration: %u", app->api_client_index);
311       return -1;
312     }
313
314   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
315   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SESSION_REPLY);
316   mp->context = api_context;
317
318   if (is_fail)
319     goto done;
320
321   if (session_has_transport (s))
322     {
323       tc = session_get_transport (s);
324       if (!tc)
325         {
326           is_fail = 1;
327           goto done;
328         }
329
330       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
331       mp->handle = session_handle (s);
332       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
333       clib_memcpy (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
334       mp->is_ip4 = tc->is_ip4;
335       mp->lcl_port = tc->lcl_port;
336       mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
337       mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
338     }
339   else
340     {
341       local_session_t *ls = (local_session_t *) s;
342       mp->handle = application_local_session_handle (ls);
343       mp->lcl_port = ls->port;
344       mp->vpp_event_queue_address = ls->server_evt_q;
345       mp->client_event_queue_address = ls->client_evt_q;
346       mp->server_rx_fifo = pointer_to_uword (s->server_tx_fifo);
347       mp->server_tx_fifo = pointer_to_uword (s->server_rx_fifo);
348     }
349
350 done:
351   mp->retval = is_fail ?
352     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
353   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
354   return 0;
355 }
356
357 static session_cb_vft_t session_cb_vft = {
358   .session_accept_callback = send_session_accept_callback,
359   .session_disconnect_callback = send_session_disconnect_callback,
360   .session_connected_callback = send_session_connected_callback,
361   .session_reset_callback = send_session_reset_callback,
362   .add_segment_callback = send_add_segment_callback,
363   .del_segment_callback = send_del_segment_callback,
364 };
365
366 static void
367 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
368 {
369   vl_api_session_enable_disable_reply_t *rmp;
370   vlib_main_t *vm = vlib_get_main ();
371   int rv = 0;
372
373   vnet_session_enable_disable (vm, mp->is_enable);
374   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
375 }
376
377 static void
378 vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
379 {
380   vl_api_application_attach_reply_t *rmp;
381   ssvm_private_t *segp, *evt_q_segment;
382   vnet_app_attach_args_t _a, *a = &_a;
383   vl_api_registration_t *reg;
384   clib_error_t *error = 0;
385   int rv = 0;
386
387   reg = vl_api_client_index_to_registration (mp->client_index);
388   if (!reg)
389     return;
390
391   if (session_manager_is_enabled () == 0)
392     {
393       rv = VNET_API_ERROR_FEATURE_DISABLED;
394       goto done;
395     }
396
397   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
398                  sizeof (mp->options),
399                  "Out of options, fix api message definition");
400
401   memset (a, 0, sizeof (*a));
402   a->api_client_index = mp->client_index;
403   a->options = mp->options;
404   a->session_cb_vft = &session_cb_vft;
405
406   if (mp->namespace_id_len > 64)
407     {
408       rv = VNET_API_ERROR_INVALID_VALUE;
409       goto done;
410     }
411
412   if (mp->namespace_id_len)
413     {
414       vec_validate (a->namespace_id, mp->namespace_id_len - 1);
415       clib_memcpy (a->namespace_id, mp->namespace_id, mp->namespace_id_len);
416     }
417
418   if ((error = vnet_application_attach (a)))
419     {
420       rv = clib_error_get_code (error);
421       clib_error_report (error);
422     }
423   vec_free (a->namespace_id);
424
425 done:
426
427   /* *INDENT-OFF* */
428   REPLY_MACRO2 (VL_API_APPLICATION_ATTACH_REPLY, ({
429     if (!rv)
430       {
431         segp = a->segment;
432         rmp->segment_name_length = 0;
433         rmp->segment_size = segp->ssvm_size;
434         if (vec_len (segp->name))
435           {
436             memcpy (rmp->segment_name, segp->name, vec_len (segp->name));
437             rmp->segment_name_length = vec_len (segp->name);
438           }
439         rmp->app_event_queue_address = a->app_event_queue_address;
440       }
441   }));
442   /* *INDENT-ON* */
443
444   if (rv)
445     return;
446
447   /* Send fifo segment fd if needed */
448   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
449     session_send_memfd_fd (reg, a->segment);
450   /* Send event queues segment */
451   if ((evt_q_segment = session_manager_get_evt_q_segment ()))
452     session_send_memfd_fd (reg, evt_q_segment);
453 }
454
455 static void
456 vl_api_application_detach_t_handler (vl_api_application_detach_t * mp)
457 {
458   vl_api_application_detach_reply_t *rmp;
459   int rv = VNET_API_ERROR_INVALID_VALUE_2;
460   vnet_app_detach_args_t _a, *a = &_a;
461   application_t *app;
462
463   if (session_manager_is_enabled () == 0)
464     {
465       rv = VNET_API_ERROR_FEATURE_DISABLED;
466       goto done;
467     }
468
469   app = application_lookup (mp->client_index);
470   if (app)
471     {
472       a->app_index = app->index;
473       rv = vnet_application_detach (a);
474     }
475
476 done:
477   REPLY_MACRO (VL_API_APPLICATION_DETACH_REPLY);
478 }
479
480 static void
481 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
482 {
483   transport_connection_t *tc = 0;
484   vnet_bind_args_t _a, *a = &_a;
485   vl_api_bind_uri_reply_t *rmp;
486   stream_session_t *s;
487   application_t *app = 0;
488   svm_queue_t *vpp_evt_q;
489   int rv;
490
491   if (session_manager_is_enabled () == 0)
492     {
493       rv = VNET_API_ERROR_FEATURE_DISABLED;
494       goto done;
495     }
496
497   app = application_lookup (mp->client_index);
498   if (app)
499     {
500       memset (a, 0, sizeof (*a));
501       a->uri = (char *) mp->uri;
502       a->app_index = app->index;
503       rv = vnet_bind_uri (a);
504     }
505   else
506     {
507       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
508     }
509
510 done:
511
512   /* *INDENT-OFF* */
513   REPLY_MACRO2 (VL_API_BIND_URI_REPLY, ({
514     if (!rv)
515       {
516         rmp->handle = a->handle;
517         rmp->lcl_is_ip4 = tc->is_ip4;
518         rmp->lcl_port = tc->lcl_port;
519         if (app && application_has_global_scope (app))
520             {
521               s = listen_session_get_from_handle (a->handle);
522               tc = listen_session_get_transport (s);
523               clib_memcpy (rmp->lcl_ip, &tc->lcl_ip, sizeof(tc->lcl_ip));
524               if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
525                 {
526                   rmp->rx_fifo = pointer_to_uword (s->server_rx_fifo);
527                   rmp->tx_fifo = pointer_to_uword (s->server_tx_fifo);
528                   vpp_evt_q = session_manager_get_vpp_event_queue (0);
529                   rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
530                 }
531             }
532       }
533   }));
534   /* *INDENT-ON* */
535 }
536
537 static void
538 vl_api_unbind_uri_t_handler (vl_api_unbind_uri_t * mp)
539 {
540   vl_api_unbind_uri_reply_t *rmp;
541   application_t *app;
542   vnet_unbind_args_t _a, *a = &_a;
543   int rv;
544
545   if (session_manager_is_enabled () == 0)
546     {
547       rv = VNET_API_ERROR_FEATURE_DISABLED;
548       goto done;
549     }
550
551   app = application_lookup (mp->client_index);
552   if (app)
553     {
554       a->uri = (char *) mp->uri;
555       a->app_index = app->index;
556       rv = vnet_unbind_uri (a);
557     }
558   else
559     {
560       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
561     }
562
563 done:
564   REPLY_MACRO (VL_API_UNBIND_URI_REPLY);
565 }
566
567 static void
568 vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
569 {
570   vl_api_connect_session_reply_t *rmp;
571   vnet_connect_args_t _a, *a = &_a;
572   application_t *app;
573   clib_error_t *error = 0;
574   int rv = 0;
575
576   if (session_manager_is_enabled () == 0)
577     {
578       rv = VNET_API_ERROR_FEATURE_DISABLED;
579       goto done;
580     }
581
582   app = application_lookup (mp->client_index);
583   if (app)
584     {
585       a->uri = (char *) mp->uri;
586       a->api_context = mp->context;
587       a->app_index = app->index;
588       if ((error = vnet_connect_uri (a)))
589         {
590           rv = clib_error_get_code (error);
591           clib_error_report (error);
592         }
593     }
594   else
595     {
596       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
597     }
598
599   /*
600    * Don't reply to stream (tcp) connects. The reply will come once
601    * the connection is established. In case of the redirects, the reply
602    * will come from the server app.
603    */
604   if (rv == 0)
605     return;
606
607 done:
608   /* *INDENT-OFF* */
609   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
610   /* *INDENT-ON* */
611 }
612
613 static void
614 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
615 {
616   vl_api_disconnect_session_reply_t *rmp;
617   vnet_disconnect_args_t _a, *a = &_a;
618   application_t *app;
619   int rv = 0;
620
621   if (session_manager_is_enabled () == 0)
622     {
623       rv = VNET_API_ERROR_FEATURE_DISABLED;
624       goto done;
625     }
626
627   app = application_lookup (mp->client_index);
628   if (app)
629     {
630       a->handle = mp->handle;
631       a->app_index = app->index;
632       rv = vnet_disconnect_session (a);
633     }
634   else
635     {
636       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
637     }
638
639 done:
640   REPLY_MACRO2 (VL_API_DISCONNECT_SESSION_REPLY, rmp->handle = mp->handle);
641 }
642
643 static void
644 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
645                                            mp)
646 {
647   vnet_disconnect_args_t _a, *a = &_a;
648   application_t *app;
649
650   /* Client objected to disconnecting the session, log and continue */
651   if (mp->retval)
652     {
653       clib_warning ("client retval %d", mp->retval);
654       return;
655     }
656
657   /* Disconnect has been confirmed. Confirm close to transport */
658   app = application_lookup (mp->context);
659   if (app)
660     {
661       a->handle = mp->handle;
662       a->app_index = app->index;
663       vnet_disconnect_session (a);
664     }
665 }
666
667 static void
668 vl_api_reset_session_reply_t_handler (vl_api_reset_session_reply_t * mp)
669 {
670   application_t *app;
671   stream_session_t *s;
672   u32 index, thread_index;
673
674   app = application_lookup (mp->client_index);
675   if (!app)
676     return;
677
678   session_parse_handle (mp->handle, &index, &thread_index);
679   s = session_get_if_valid (index, thread_index);
680   if (s == 0 || app->index != s->app_index)
681     {
682       clib_warning ("Invalid session!");
683       return;
684     }
685
686   /* Client objected to resetting the session, log and continue */
687   if (mp->retval)
688     {
689       clib_warning ("client retval %d", mp->retval);
690       return;
691     }
692
693   /* This comes as a response to a reset, transport only waiting for
694    * confirmation to remove connection state, no need to disconnect */
695   stream_session_cleanup (s);
696 }
697
698 static void
699 vl_api_accept_session_reply_t_handler (vl_api_accept_session_reply_t * mp)
700 {
701   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
702   local_session_t *ls;
703   stream_session_t *s;
704
705   /* Server isn't interested, kill the session */
706   if (mp->retval)
707     {
708       a->app_index = mp->context;
709       a->handle = mp->handle;
710       vnet_disconnect_session (a);
711       return;
712     }
713
714   if (session_handle_is_local (mp->handle))
715     {
716       ls = application_get_local_session_from_handle (mp->handle);
717       if (!ls || ls->app_index != mp->context)
718         {
719           clib_warning ("server %u doesn't own local handle %llu",
720                         mp->context, mp->handle);
721           return;
722         }
723       if (application_local_session_connect_notify (ls))
724         return;
725       ls->session_state = SESSION_STATE_READY;
726     }
727   else
728     {
729       s = session_get_from_handle_if_valid (mp->handle);
730       if (!s)
731         {
732           clib_warning ("session doesn't exist");
733           return;
734         }
735       if (s->app_index != mp->context)
736         {
737           clib_warning ("app doesn't own session");
738           return;
739         }
740       s->session_state = SESSION_STATE_READY;
741     }
742 }
743
744 static void
745 vl_api_map_another_segment_reply_t_handler (vl_api_map_another_segment_reply_t
746                                             * mp)
747 {
748   clib_warning ("not implemented");
749 }
750
751 static void
752 vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
753 {
754   vl_api_bind_sock_reply_t *rmp;
755   vnet_bind_args_t _a, *a = &_a;
756   int rv = 0;
757   clib_error_t *error;
758   application_t *app = 0;
759   stream_session_t *s;
760   transport_connection_t *tc = 0;
761   ip46_address_t *ip46;
762   svm_queue_t *vpp_evt_q;
763
764   if (session_manager_is_enabled () == 0)
765     {
766       rv = VNET_API_ERROR_FEATURE_DISABLED;
767       goto done;
768     }
769
770   app = application_lookup (mp->client_index);
771   if (!app)
772     {
773       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
774       goto done;
775     }
776
777   ip46 = (ip46_address_t *) mp->ip;
778   memset (a, 0, sizeof (*a));
779   a->sep.is_ip4 = mp->is_ip4;
780   a->sep.ip = *ip46;
781   a->sep.port = mp->port;
782   a->sep.fib_index = mp->vrf;
783   a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
784   a->sep.transport_proto = mp->proto;
785   a->app_index = app->index;
786
787   if ((error = vnet_bind (a)))
788     {
789       rv = clib_error_get_code (error);
790       clib_error_report (error);
791     }
792
793 done:
794   /* *INDENT-OFF* */
795   REPLY_MACRO2 (VL_API_BIND_SOCK_REPLY,({
796     if (!rv)
797       {
798         rmp->handle = a->handle;
799         rmp->lcl_port = mp->port;
800         rmp->lcl_is_ip4 = mp->is_ip4;
801         if (app && application_has_global_scope (app))
802           {
803             s = listen_session_get_from_handle (a->handle);
804             tc = listen_session_get_transport (s);
805             clib_memcpy (rmp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
806             if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
807               {
808                 rmp->rx_fifo = pointer_to_uword (s->server_rx_fifo);
809                 rmp->tx_fifo = pointer_to_uword (s->server_tx_fifo);
810                 vpp_evt_q = session_manager_get_vpp_event_queue (0);
811                 rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
812               }
813           }
814       }
815   }));
816   /* *INDENT-ON* */
817 }
818
819 static void
820 vl_api_unbind_sock_t_handler (vl_api_unbind_sock_t * mp)
821 {
822   vl_api_unbind_sock_reply_t *rmp;
823   vnet_unbind_args_t _a, *a = &_a;
824   application_t *app;
825   clib_error_t *error;
826   int rv = 0;
827
828   if (session_manager_is_enabled () == 0)
829     {
830       rv = VNET_API_ERROR_FEATURE_DISABLED;
831       goto done;
832     }
833
834   app = application_lookup (mp->client_index);
835   if (app)
836     {
837       a->app_index = app->index;
838       a->handle = mp->handle;
839       if ((error = vnet_unbind (a)))
840         {
841           rv = clib_error_get_code (error);
842           clib_error_report (error);
843         }
844     }
845
846 done:
847   REPLY_MACRO (VL_API_UNBIND_SOCK_REPLY);
848 }
849
850 static void
851 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
852 {
853   vl_api_connect_session_reply_t *rmp;
854   vnet_connect_args_t _a, *a = &_a;
855   application_t *app;
856   clib_error_t *error = 0;
857   int rv = 0;
858
859   if (session_manager_is_enabled () == 0)
860     {
861       rv = VNET_API_ERROR_FEATURE_DISABLED;
862       goto done;
863     }
864
865   app = application_lookup (mp->client_index);
866   if (app)
867     {
868       svm_queue_t *client_q;
869       ip46_address_t *ip46 = (ip46_address_t *) mp->ip;
870
871       memset (a, 0, sizeof (*a));
872       client_q = vl_api_client_index_to_input_queue (mp->client_index);
873       mp->client_queue_address = pointer_to_uword (client_q);
874       a->sep.is_ip4 = mp->is_ip4;
875       a->sep.ip = *ip46;
876       a->sep.port = mp->port;
877       a->sep.transport_proto = mp->proto;
878       a->sep.fib_index = mp->vrf;
879       a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
880       if (mp->hostname_len)
881         {
882           vec_validate (a->sep.hostname, mp->hostname_len - 1);
883           clib_memcpy (a->sep.hostname, mp->hostname, mp->hostname_len);
884         }
885       a->api_context = mp->context;
886       a->app_index = app->index;
887       if ((error = vnet_connect (a)))
888         {
889           rv = clib_error_get_code (error);
890           clib_error_report (error);
891         }
892       vec_free (a->sep.hostname);
893     }
894   else
895     {
896       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
897     }
898
899   if (rv == 0)
900     return;
901
902   /* Got some error, relay it */
903
904 done:
905   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
906 }
907
908 static void
909 vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp)
910 {
911   vl_api_app_namespace_add_del_reply_t *rmp;
912   clib_error_t *error = 0;
913   u32 appns_index = 0;
914   u8 *ns_id = 0;
915   int rv = 0;
916   if (!session_manager_is_enabled ())
917     {
918       rv = VNET_API_ERROR_FEATURE_DISABLED;
919       goto done;
920     }
921
922   if (mp->namespace_id_len > ARRAY_LEN (mp->namespace_id))
923     {
924       rv = VNET_API_ERROR_INVALID_VALUE;
925       goto done;
926     }
927
928   vec_validate (ns_id, mp->namespace_id_len - 1);
929   clib_memcpy (ns_id, mp->namespace_id, mp->namespace_id_len);
930   vnet_app_namespace_add_del_args_t args = {
931     .ns_id = ns_id,
932     .secret = clib_net_to_host_u64 (mp->secret),
933     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
934     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
935     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
936     .is_add = 1
937   };
938   error = vnet_app_namespace_add_del (&args);
939   if (error)
940     {
941       rv = clib_error_get_code (error);
942       clib_error_report (error);
943     }
944   else
945     {
946       appns_index = app_namespace_index_from_id (ns_id);
947       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
948         {
949           clib_warning ("app ns lookup failed");
950           rv = VNET_API_ERROR_UNSPECIFIED;
951         }
952     }
953   vec_free (ns_id);
954
955   /* *INDENT-OFF* */
956 done:
957   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
958     if (!rv)
959       rmp->appns_index = clib_host_to_net_u32 (appns_index);
960   }));
961   /* *INDENT-ON* */
962 }
963
964 static void
965 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
966 {
967   vl_api_session_rule_add_del_reply_t *rmp;
968   session_rule_add_del_args_t args;
969   session_rule_table_add_del_args_t *table_args = &args.table_args;
970   clib_error_t *error;
971   u8 fib_proto;
972   int rv = 0;
973
974   memset (&args, 0, sizeof (args));
975   fib_proto = mp->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
976
977   table_args->lcl.fp_len = mp->lcl_plen;
978   table_args->lcl.fp_proto = fib_proto;
979   table_args->rmt.fp_len = mp->rmt_plen;
980   table_args->rmt.fp_proto = fib_proto;
981   table_args->lcl_port = mp->lcl_port;
982   table_args->rmt_port = mp->rmt_port;
983   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
984   table_args->is_add = mp->is_add;
985   mp->tag[sizeof (mp->tag) - 1] = 0;
986   table_args->tag = format (0, "%s", mp->tag);
987   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
988   args.scope = mp->scope;
989   args.transport_proto = mp->transport_proto;
990
991   memset (&table_args->lcl.fp_addr, 0, sizeof (table_args->lcl.fp_addr));
992   memset (&table_args->rmt.fp_addr, 0, sizeof (table_args->rmt.fp_addr));
993   ip_set (&table_args->lcl.fp_addr, mp->lcl_ip, mp->is_ip4);
994   ip_set (&table_args->rmt.fp_addr, mp->rmt_ip, mp->is_ip4);
995   error = vnet_session_rule_add_del (&args);
996   if (error)
997     {
998       rv = clib_error_get_code (error);
999       clib_error_report (error);
1000     }
1001   vec_free (table_args->tag);
1002   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
1003 }
1004
1005 static void
1006 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
1007                             u8 transport_proto, u32 appns_index, u8 * tag,
1008                             vl_api_registration_t * reg, u32 context)
1009 {
1010   vl_api_session_rules_details_t *rmp = 0;
1011   session_mask_or_match_4_t *match =
1012     (session_mask_or_match_4_t *) & rule->match;
1013   session_mask_or_match_4_t *mask =
1014     (session_mask_or_match_4_t *) & rule->mask;
1015
1016   rmp = vl_msg_api_alloc (sizeof (*rmp));
1017   memset (rmp, 0, sizeof (*rmp));
1018   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1019   rmp->context = context;
1020
1021   rmp->is_ip4 = 1;
1022   clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
1023   clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
1024   rmp->lcl_plen = ip4_mask_to_preflen (&mask->lcl_ip);
1025   rmp->rmt_plen = ip4_mask_to_preflen (&mask->rmt_ip);
1026   rmp->lcl_port = match->lcl_port;
1027   rmp->rmt_port = match->rmt_port;
1028   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1029   rmp->scope =
1030     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
1031   rmp->transport_proto = transport_proto;
1032   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1033   if (tag)
1034     {
1035       clib_memcpy (rmp->tag, tag, vec_len (tag));
1036       rmp->tag[vec_len (tag)] = 0;
1037     }
1038
1039   vl_api_send_msg (reg, (u8 *) rmp);
1040 }
1041
1042 static void
1043 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
1044                             u8 transport_proto, u32 appns_index, u8 * tag,
1045                             vl_api_registration_t * reg, u32 context)
1046 {
1047   vl_api_session_rules_details_t *rmp = 0;
1048   session_mask_or_match_6_t *match =
1049     (session_mask_or_match_6_t *) & rule->match;
1050   session_mask_or_match_6_t *mask =
1051     (session_mask_or_match_6_t *) & rule->mask;
1052
1053   rmp = vl_msg_api_alloc (sizeof (*rmp));
1054   memset (rmp, 0, sizeof (*rmp));
1055   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1056   rmp->context = context;
1057
1058   rmp->is_ip4 = 0;
1059   clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
1060   clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
1061   rmp->lcl_plen = ip6_mask_to_preflen (&mask->lcl_ip);
1062   rmp->rmt_plen = ip6_mask_to_preflen (&mask->rmt_ip);
1063   rmp->lcl_port = match->lcl_port;
1064   rmp->rmt_port = match->rmt_port;
1065   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1066   rmp->scope =
1067     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
1068   rmp->transport_proto = transport_proto;
1069   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1070   if (tag)
1071     {
1072       clib_memcpy (rmp->tag, tag, vec_len (tag));
1073       rmp->tag[vec_len (tag)] = 0;
1074     }
1075
1076   vl_api_send_msg (reg, (u8 *) rmp);
1077 }
1078
1079 static void
1080 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
1081                                   u8 tp, u8 is_local, u32 appns_index,
1082                                   vl_api_registration_t * reg, u32 context)
1083 {
1084   mma_rule_16_t *rule16;
1085   mma_rule_40_t *rule40;
1086   mma_rules_table_16_t *srt16;
1087   mma_rules_table_40_t *srt40;
1088   u32 ri;
1089
1090   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
1091     {
1092       u8 *tag = 0;
1093       /* *INDENT-OFF* */
1094       srt16 = &srt->session_rules_tables_16;
1095       pool_foreach (rule16, srt16->rules, ({
1096         ri = mma_rules_table_rule_index_16 (srt16, rule16);
1097         tag = session_rules_table_rule_tag (srt, ri, 1);
1098         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
1099                                     reg, context);
1100       }));
1101       /* *INDENT-ON* */
1102     }
1103   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
1104     {
1105       u8 *tag = 0;
1106       /* *INDENT-OFF* */
1107       srt40 = &srt->session_rules_tables_40;
1108       pool_foreach (rule40, srt40->rules, ({
1109         ri = mma_rules_table_rule_index_40 (srt40, rule40);
1110         tag = session_rules_table_rule_tag (srt, ri, 1);
1111         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
1112                                     reg, context);
1113       }));
1114       /* *INDENT-ON* */
1115     }
1116 }
1117
1118 static void
1119 vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
1120 {
1121   vl_api_registration_t *reg;
1122   session_table_t *st;
1123   u8 tp;
1124
1125   reg = vl_api_client_index_to_registration (mp->client_index);
1126   if (!reg)
1127     return;
1128
1129   /* *INDENT-OFF* */
1130   session_table_foreach (st, ({
1131     for (tp = 0; tp < TRANSPORT_N_PROTO; tp++)
1132       {
1133         send_session_rules_table_details (&st->session_rules[tp],
1134                                           st->active_fib_proto, tp,
1135                                           st->is_local, st->appns_index, reg,
1136                                           mp->context);
1137       }
1138   }));
1139   /* *INDENT-ON* */
1140 }
1141
1142 static void
1143 vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t *
1144                                            mp)
1145 {
1146   vl_api_app_namespace_add_del_reply_t *rmp;
1147   vnet_app_add_tls_cert_args_t _a, *a = &_a;
1148   clib_error_t *error;
1149   application_t *app;
1150   u32 cert_len;
1151   int rv = 0;
1152   if (!session_manager_is_enabled ())
1153     {
1154       rv = VNET_API_ERROR_FEATURE_DISABLED;
1155       goto done;
1156     }
1157   if (!(app = application_lookup (mp->client_index)))
1158     {
1159       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1160       goto done;
1161     }
1162   memset (a, 0, sizeof (*a));
1163   a->app_index = app->index;
1164   cert_len = clib_net_to_host_u16 (mp->cert_len);
1165   if (cert_len > 10000)
1166     {
1167       rv = VNET_API_ERROR_INVALID_VALUE;
1168       goto done;
1169     }
1170   vec_validate (a->cert, cert_len);
1171   clib_memcpy (a->cert, mp->cert, cert_len);
1172   if ((error = vnet_app_add_tls_cert (a)))
1173     {
1174       rv = clib_error_get_code (error);
1175       clib_error_report (error);
1176     }
1177   vec_free (a->cert);
1178 done:
1179   REPLY_MACRO (VL_API_APPLICATION_TLS_CERT_ADD_REPLY);
1180 }
1181
1182 static void
1183 vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t *
1184                                           mp)
1185 {
1186   vl_api_app_namespace_add_del_reply_t *rmp;
1187   vnet_app_add_tls_key_args_t _a, *a = &_a;
1188   clib_error_t *error;
1189   application_t *app;
1190   u32 key_len;
1191   int rv = 0;
1192   if (!session_manager_is_enabled ())
1193     {
1194       rv = VNET_API_ERROR_FEATURE_DISABLED;
1195       goto done;
1196     }
1197   if (!(app = application_lookup (mp->client_index)))
1198     {
1199       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1200       goto done;
1201     }
1202   memset (a, 0, sizeof (*a));
1203   a->app_index = app->index;
1204   key_len = clib_net_to_host_u16 (mp->key_len);
1205   if (key_len > 10000)
1206     {
1207       rv = VNET_API_ERROR_INVALID_VALUE;
1208       goto done;
1209     }
1210   vec_validate (a->key, key_len);
1211   clib_memcpy (a->key, mp->key, key_len);
1212   if ((error = vnet_app_add_tls_key (a)))
1213     {
1214       rv = clib_error_get_code (error);
1215       clib_error_report (error);
1216     }
1217   vec_free (a->key);
1218 done:
1219   REPLY_MACRO (VL_API_APPLICATION_TLS_KEY_ADD_REPLY);
1220 }
1221
1222 static clib_error_t *
1223 application_reaper_cb (u32 client_index)
1224 {
1225   application_t *app = application_lookup (client_index);
1226   vnet_app_detach_args_t _a, *a = &_a;
1227   if (app)
1228     {
1229       a->app_index = app->index;
1230       vnet_application_detach (a);
1231     }
1232   return 0;
1233 }
1234
1235 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1236
1237 #define vl_msg_name_crc_list
1238 #include <vnet/vnet_all_api_h.h>
1239 #undef vl_msg_name_crc_list
1240
1241 static void
1242 setup_message_id_table (api_main_t * am)
1243 {
1244 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1245   foreach_vl_msg_name_crc_session;
1246 #undef _
1247 }
1248
1249 /*
1250  * session_api_hookup
1251  * Add uri's API message handlers to the table.
1252  * vlib has alread mapped shared memory and
1253  * added the client registration handlers.
1254  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
1255  */
1256 static clib_error_t *
1257 session_api_hookup (vlib_main_t * vm)
1258 {
1259   api_main_t *am = &api_main;
1260
1261 #define _(N,n)                                                  \
1262     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1263                            vl_api_##n##_t_handler,              \
1264                            vl_noop_handler,                     \
1265                            vl_api_##n##_t_endian,               \
1266                            vl_api_##n##_t_print,                \
1267                            sizeof(vl_api_##n##_t), 1);
1268   foreach_session_api_msg;
1269 #undef _
1270
1271   /*
1272    * Messages which bounce off the data-plane to
1273    * an API client. Simply tells the message handling infra not
1274    * to free the message.
1275    *
1276    * Bounced message handlers MUST NOT block the data plane
1277    */
1278   am->message_bounce[VL_API_CONNECT_URI] = 1;
1279   am->message_bounce[VL_API_CONNECT_SOCK] = 1;
1280
1281   /*
1282    * Set up the (msg_name, crc, message-id) table
1283    */
1284   setup_message_id_table (am);
1285
1286   return 0;
1287 }
1288
1289 VLIB_API_INIT_FUNCTION (session_api_hookup);
1290
1291 /*
1292  * fd.io coding-style-patch-verification: ON
1293  *
1294  * Local Variables:
1295  * eval: (c-set-style "gnu")
1296  * End:
1297  */