api: refactor vlibmemory
[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
60 static int
61 send_add_segment_callback (u32 api_client_index, const u8 * segment_name,
62                            u32 segment_size)
63 {
64   vl_api_map_another_segment_t *mp;
65   svm_queue_t *q;
66
67   q = vl_api_client_index_to_input_queue (api_client_index);
68
69   if (!q)
70     return -1;
71
72   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
73   memset (mp, 0, sizeof (*mp));
74   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
75   mp->segment_size = segment_size;
76   strncpy ((char *) mp->segment_name, (char *) segment_name,
77            sizeof (mp->segment_name) - 1);
78
79   vl_msg_api_send_shmem (q, (u8 *) & mp);
80
81   return 0;
82 }
83
84 static int
85 send_session_accept_callback (stream_session_t * s)
86 {
87   vl_api_accept_session_t *mp;
88   svm_queue_t *q, *vpp_queue;
89   application_t *server = application_get (s->app_index);
90   transport_connection_t *tc;
91   transport_proto_vft_t *tp_vft;
92   stream_session_t *listener;
93
94   q = vl_api_client_index_to_input_queue (server->api_client_index);
95   vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
96
97   if (!q)
98     return -1;
99
100   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
101   memset (mp, 0, sizeof (*mp));
102
103   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION);
104   mp->context = server->index;
105   listener = listen_session_get (s->session_type, s->listener_index);
106   tp_vft = transport_protocol_get_vft (session_get_transport_proto (s));
107   tc = tp_vft->get_connection (s->connection_index, s->thread_index);
108   mp->listener_handle = listen_session_get_handle (listener);
109
110   if (application_is_proxy (server))
111     {
112       listener =
113         application_first_listener (server,
114                                     transport_connection_fib_proto (tc),
115                                     tc->proto);
116       if (listener)
117         mp->listener_handle = listen_session_get_handle (listener);
118     }
119   mp->handle = session_handle (s);
120   mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
121   mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
122   mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
123   mp->port = tc->rmt_port;
124   mp->is_ip4 = tc->is_ip4;
125   clib_memcpy (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
126   vl_msg_api_send_shmem (q, (u8 *) & mp);
127
128   return 0;
129 }
130
131 static void
132 send_session_disconnect_callback (stream_session_t * s)
133 {
134   vl_api_disconnect_session_t *mp;
135   svm_queue_t *q;
136   application_t *app = application_get (s->app_index);
137
138   q = vl_api_client_index_to_input_queue (app->api_client_index);
139
140   if (!q)
141     return;
142
143   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
144   memset (mp, 0, sizeof (*mp));
145   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
146   mp->handle = session_handle (s);
147   vl_msg_api_send_shmem (q, (u8 *) & mp);
148 }
149
150 static void
151 send_session_reset_callback (stream_session_t * s)
152 {
153   vl_api_reset_session_t *mp;
154   svm_queue_t *q;
155   application_t *app = application_get (s->app_index);
156
157   q = vl_api_client_index_to_input_queue (app->api_client_index);
158
159   if (!q)
160     return;
161
162   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
163   memset (mp, 0, sizeof (*mp));
164   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SESSION);
165   mp->handle = session_handle (s);
166   vl_msg_api_send_shmem (q, (u8 *) & mp);
167 }
168
169 int
170 send_session_connected_callback (u32 app_index, u32 api_context,
171                                  stream_session_t * s, u8 is_fail)
172 {
173   vl_api_connect_session_reply_t *mp;
174   svm_queue_t *q;
175   application_t *app;
176   svm_queue_t *vpp_queue;
177   transport_connection_t *tc;
178
179   app = application_get (app_index);
180   q = vl_api_client_index_to_input_queue (app->api_client_index);
181
182   if (!q)
183     return -1;
184
185   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
186   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SESSION_REPLY);
187   mp->context = api_context;
188
189   if (is_fail)
190     goto done;
191
192   tc = session_get_transport (s);
193   if (!tc)
194     {
195       is_fail = 1;
196       goto done;
197     }
198
199   vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
200   mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
201   mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
202   mp->handle = session_handle (s);
203   mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
204   clib_memcpy (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
205   mp->is_ip4 = tc->is_ip4;
206   mp->lcl_port = tc->lcl_port;
207
208 done:
209   mp->retval = is_fail ?
210     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
211   vl_msg_api_send_shmem (q, (u8 *) & mp);
212   return 0;
213 }
214
215 /**
216  * Redirect a connect_uri message to the indicated server.
217  * Only sent if the server has bound the related port with
218  * URI_OPTIONS_FLAGS_USE_FIFO
219  */
220 static int
221 redirect_connect_callback (u32 server_api_client_index, void *mp_arg)
222 {
223   vl_api_connect_sock_t *mp = mp_arg;
224   svm_queue_t *server_q, *client_q;
225   segment_manager_properties_t *props;
226   vlib_main_t *vm = vlib_get_main ();
227   f64 timeout = vlib_time_now (vm) + 0.5;
228   application_t *app;
229   int rv = 0;
230
231   server_q = vl_api_client_index_to_input_queue (server_api_client_index);
232
233   if (!server_q)
234     {
235       rv = VNET_API_ERROR_INVALID_VALUE;
236       goto out;
237     }
238
239   client_q = vl_api_client_index_to_input_queue (mp->client_index);
240   if (!client_q)
241     {
242       rv = VNET_API_ERROR_INVALID_VALUE_2;
243       goto out;
244     }
245
246   /* Tell the server the client's API queue address, so it can reply */
247   mp->client_queue_address = pointer_to_uword (client_q);
248   app = application_lookup (mp->client_index);
249   if (!app)
250     {
251       clib_warning ("no client application");
252       return -1;
253     }
254
255   props = segment_manager_properties_get (app->sm_properties);
256   mp->options[APP_OPTIONS_RX_FIFO_SIZE] = props->rx_fifo_size;
257   mp->options[APP_OPTIONS_TX_FIFO_SIZE] = props->tx_fifo_size;
258
259   /*
260    * Bounce message handlers MUST NOT block the data-plane.
261    * Spin waiting for the queue lock, but
262    */
263
264   while (vlib_time_now (vm) < timeout)
265     {
266       rv = svm_queue_add (server_q, (u8 *) & mp, 1 /*nowait */ );
267       switch (rv)
268         {
269           /* correctly enqueued */
270         case 0:
271           return VNET_API_ERROR_SESSION_REDIRECT;
272
273           /* continue spinning, wait for pthread_mutex_trylock to work */
274         case -1:
275           continue;
276
277           /* queue stuffed, drop the msg */
278         case -2:
279           rv = VNET_API_ERROR_QUEUE_FULL;
280           goto out;
281         }
282     }
283 out:
284   /* Dispose of the message */
285   vl_msg_api_free (mp);
286   return rv;
287 }
288
289 static session_cb_vft_t session_cb_vft = {
290   .session_accept_callback = send_session_accept_callback,
291   .session_disconnect_callback = send_session_disconnect_callback,
292   .session_connected_callback = send_session_connected_callback,
293   .session_reset_callback = send_session_reset_callback,
294   .add_segment_callback = send_add_segment_callback,
295   .redirect_connect_callback = redirect_connect_callback
296 };
297
298 static void
299 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
300 {
301   vl_api_session_enable_disable_reply_t *rmp;
302   vlib_main_t *vm = vlib_get_main ();
303   int rv = 0;
304
305   vnet_session_enable_disable (vm, mp->is_enable);
306   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
307 }
308
309 static void
310 vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
311 {
312   vl_api_application_attach_reply_t *rmp;
313   vnet_app_attach_args_t _a, *a = &_a;
314   clib_error_t *error = 0;
315   int rv = 0;
316
317   if (session_manager_is_enabled () == 0)
318     {
319       rv = VNET_API_ERROR_FEATURE_DISABLED;
320       goto done;
321     }
322
323   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
324                  sizeof (mp->options),
325                  "Out of options, fix api message definition");
326
327   memset (a, 0, sizeof (*a));
328   a->api_client_index = mp->client_index;
329   a->options = mp->options;
330   a->session_cb_vft = &session_cb_vft;
331
332   if (mp->namespace_id_len > 64)
333     {
334       rv = VNET_API_ERROR_INVALID_VALUE;
335       goto done;
336     }
337
338   if (mp->namespace_id_len)
339     {
340       vec_validate (a->namespace_id, mp->namespace_id_len - 1);
341       clib_memcpy (a->namespace_id, mp->namespace_id, mp->namespace_id_len);
342     }
343
344   if ((error = vnet_application_attach (a)))
345     {
346       rv = clib_error_get_code (error);
347       clib_error_report (error);
348     }
349   vec_free (a->namespace_id);
350
351 done:
352
353   /* *INDENT-OFF* */
354   REPLY_MACRO2 (VL_API_APPLICATION_ATTACH_REPLY, ({
355     if (!rv)
356       {
357         rmp->segment_name_length = 0;
358         rmp->segment_size = a->segment_size;
359         if (a->segment_name_length)
360           {
361             memcpy (rmp->segment_name, a->segment_name,
362                     a->segment_name_length);
363             rmp->segment_name_length = a->segment_name_length;
364           }
365         rmp->app_event_queue_address = a->app_event_queue_address;
366       }
367   }));
368   /* *INDENT-ON* */
369 }
370
371 static void
372 vl_api_application_detach_t_handler (vl_api_application_detach_t * mp)
373 {
374   vl_api_application_detach_reply_t *rmp;
375   int rv = VNET_API_ERROR_INVALID_VALUE_2;
376   vnet_app_detach_args_t _a, *a = &_a;
377   application_t *app;
378
379   if (session_manager_is_enabled () == 0)
380     {
381       rv = VNET_API_ERROR_FEATURE_DISABLED;
382       goto done;
383     }
384
385   app = application_lookup (mp->client_index);
386   if (app)
387     {
388       a->app_index = app->index;
389       rv = vnet_application_detach (a);
390     }
391
392 done:
393   REPLY_MACRO (VL_API_APPLICATION_DETACH_REPLY);
394 }
395
396 static void
397 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
398 {
399   vl_api_bind_uri_reply_t *rmp;
400   vnet_bind_args_t _a, *a = &_a;
401   application_t *app;
402   int rv;
403
404   if (session_manager_is_enabled () == 0)
405     {
406       rv = VNET_API_ERROR_FEATURE_DISABLED;
407       goto done;
408     }
409
410   app = application_lookup (mp->client_index);
411   if (app)
412     {
413       memset (a, 0, sizeof (*a));
414       a->uri = (char *) mp->uri;
415       a->app_index = app->index;
416       rv = vnet_bind_uri (a);
417     }
418   else
419     {
420       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
421     }
422
423 done:
424   REPLY_MACRO (VL_API_BIND_URI_REPLY);
425 }
426
427 static void
428 vl_api_unbind_uri_t_handler (vl_api_unbind_uri_t * mp)
429 {
430   vl_api_unbind_uri_reply_t *rmp;
431   application_t *app;
432   vnet_unbind_args_t _a, *a = &_a;
433   int rv;
434
435   if (session_manager_is_enabled () == 0)
436     {
437       rv = VNET_API_ERROR_FEATURE_DISABLED;
438       goto done;
439     }
440
441   app = application_lookup (mp->client_index);
442   if (app)
443     {
444       a->uri = (char *) mp->uri;
445       a->app_index = app->index;
446       rv = vnet_unbind_uri (a);
447     }
448   else
449     {
450       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
451     }
452
453 done:
454   REPLY_MACRO (VL_API_UNBIND_URI_REPLY);
455 }
456
457 static void
458 vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
459 {
460   vl_api_connect_session_reply_t *rmp;
461   vnet_connect_args_t _a, *a = &_a;
462   application_t *app;
463   clib_error_t *error = 0;
464   int rv = 0;
465
466   if (session_manager_is_enabled () == 0)
467     {
468       rv = VNET_API_ERROR_FEATURE_DISABLED;
469       goto done;
470     }
471
472   app = application_lookup (mp->client_index);
473   if (app)
474     {
475       a->uri = (char *) mp->uri;
476       a->api_context = mp->context;
477       a->app_index = app->index;
478       a->mp = mp;
479       if ((error = vnet_connect_uri (a)))
480         {
481           rv = clib_error_get_code (error);
482           if (rv != VNET_API_ERROR_SESSION_REDIRECT)
483             clib_error_report (error);
484         }
485     }
486   else
487     {
488       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
489     }
490
491   /*
492    * Don't reply to stream (tcp) connects. The reply will come once
493    * the connection is established. In case of the redirects, the reply
494    * will come from the server app.
495    */
496   if (rv == 0 || rv == VNET_API_ERROR_SESSION_REDIRECT)
497     return;
498
499 done:
500   /* *INDENT-OFF* */
501   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
502   /* *INDENT-ON* */
503 }
504
505 static void
506 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
507 {
508   vl_api_disconnect_session_reply_t *rmp;
509   vnet_disconnect_args_t _a, *a = &_a;
510   application_t *app;
511   int rv = 0;
512
513   if (session_manager_is_enabled () == 0)
514     {
515       rv = VNET_API_ERROR_FEATURE_DISABLED;
516       goto done;
517     }
518
519   app = application_lookup (mp->client_index);
520   if (app)
521     {
522       a->handle = mp->handle;
523       a->app_index = app->index;
524       rv = vnet_disconnect_session (a);
525     }
526   else
527     {
528       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
529     }
530
531 done:
532   REPLY_MACRO2 (VL_API_DISCONNECT_SESSION_REPLY, rmp->handle = mp->handle);
533 }
534
535 static void
536 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
537                                            mp)
538 {
539   vnet_disconnect_args_t _a, *a = &_a;
540   application_t *app;
541
542   /* Client objected to disconnecting the session, log and continue */
543   if (mp->retval)
544     {
545       clib_warning ("client retval %d", mp->retval);
546       return;
547     }
548
549   /* Disconnect has been confirmed. Confirm close to transport */
550   app = application_lookup (mp->client_index);
551   if (app)
552     {
553       a->handle = mp->handle;
554       a->app_index = app->index;
555       vnet_disconnect_session (a);
556     }
557 }
558
559 static void
560 vl_api_reset_session_reply_t_handler (vl_api_reset_session_reply_t * mp)
561 {
562   application_t *app;
563   stream_session_t *s;
564   u32 index, thread_index;
565
566   app = application_lookup (mp->client_index);
567   if (!app)
568     return;
569
570   session_parse_handle (mp->handle, &index, &thread_index);
571   s = session_get_if_valid (index, thread_index);
572   if (s == 0 || app->index != s->app_index)
573     {
574       clib_warning ("Invalid session!");
575       return;
576     }
577
578   /* Client objected to resetting the session, log and continue */
579   if (mp->retval)
580     {
581       clib_warning ("client retval %d", mp->retval);
582       return;
583     }
584
585   /* This comes as a response to a reset, transport only waiting for
586    * confirmation to remove connection state, no need to disconnect */
587   stream_session_cleanup (s);
588 }
589
590 static void
591 vl_api_accept_session_reply_t_handler (vl_api_accept_session_reply_t * mp)
592 {
593   stream_session_t *s;
594   u32 session_index, thread_index;
595   vnet_disconnect_args_t _a, *a = &_a;
596
597   /* Server isn't interested, kill the session */
598   if (mp->retval)
599     {
600       a->app_index = mp->context;
601       a->handle = mp->handle;
602       vnet_disconnect_session (a);
603     }
604   else
605     {
606       session_parse_handle (mp->handle, &session_index, &thread_index);
607       s = session_get_if_valid (session_index, thread_index);
608       if (!s)
609         {
610           clib_warning ("session doesn't exist");
611           return;
612         }
613       if (s->app_index != mp->context)
614         {
615           clib_warning ("app doesn't own session");
616           return;
617         }
618       s->session_state = SESSION_STATE_READY;
619     }
620 }
621
622 static void
623 vl_api_map_another_segment_reply_t_handler (vl_api_map_another_segment_reply_t
624                                             * mp)
625 {
626   clib_warning ("not implemented");
627 }
628
629 static void
630 vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
631 {
632   vl_api_bind_sock_reply_t *rmp;
633   vnet_bind_args_t _a, *a = &_a;
634   int rv = 0;
635   clib_error_t *error;
636   application_t *app = 0;
637   stream_session_t *s;
638   transport_connection_t *tc = 0;
639   ip46_address_t *ip46;
640
641   if (session_manager_is_enabled () == 0)
642     {
643       rv = VNET_API_ERROR_FEATURE_DISABLED;
644       goto done;
645     }
646
647   app = application_lookup (mp->client_index);
648   if (!app)
649     {
650       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
651       goto done;
652     }
653
654   ip46 = (ip46_address_t *) mp->ip;
655   memset (a, 0, sizeof (*a));
656   a->sep.is_ip4 = mp->is_ip4;
657   a->sep.ip = *ip46;
658   a->sep.port = mp->port;
659   a->sep.fib_index = mp->vrf;
660   a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
661   a->sep.transport_proto = mp->proto;
662   a->app_index = app->index;
663
664   if ((error = vnet_bind (a)))
665     {
666       rv = clib_error_get_code (error);
667       clib_error_report (error);
668     }
669
670 done:
671   /* *INDENT-OFF* */
672   REPLY_MACRO2 (VL_API_BIND_SOCK_REPLY,({
673     if (!rv)
674       {
675         rmp->handle = a->handle;
676         rmp->lcl_port = mp->port;
677         if (app && application_has_global_scope (app))
678           {
679             s = listen_session_get_from_handle (a->handle);
680             tc = listen_session_get_transport (s);
681             rmp->lcl_is_ip4 = tc->is_ip4;
682             clib_memcpy (rmp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
683           }
684       }
685   }));
686   /* *INDENT-ON* */
687 }
688
689 static void
690 vl_api_unbind_sock_t_handler (vl_api_unbind_sock_t * mp)
691 {
692   vl_api_unbind_sock_reply_t *rmp;
693   vnet_unbind_args_t _a, *a = &_a;
694   application_t *app;
695   clib_error_t *error;
696   int rv = 0;
697
698   if (session_manager_is_enabled () == 0)
699     {
700       rv = VNET_API_ERROR_FEATURE_DISABLED;
701       goto done;
702     }
703
704   app = application_lookup (mp->client_index);
705   if (app)
706     {
707       a->app_index = app->index;
708       a->handle = mp->handle;
709       if ((error = vnet_unbind (a)))
710         {
711           rv = clib_error_get_code (error);
712           clib_error_report (error);
713         }
714     }
715
716 done:
717   REPLY_MACRO (VL_API_UNBIND_SOCK_REPLY);
718 }
719
720 static void
721 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
722 {
723   vl_api_connect_session_reply_t *rmp;
724   vnet_connect_args_t _a, *a = &_a;
725   application_t *app;
726   clib_error_t *error = 0;
727   int rv = 0;
728
729   if (session_manager_is_enabled () == 0)
730     {
731       rv = VNET_API_ERROR_FEATURE_DISABLED;
732       goto done;
733     }
734
735   app = application_lookup (mp->client_index);
736   if (app)
737     {
738       svm_queue_t *client_q;
739       ip46_address_t *ip46 = (ip46_address_t *) mp->ip;
740
741       client_q = vl_api_client_index_to_input_queue (mp->client_index);
742       mp->client_queue_address = pointer_to_uword (client_q);
743       a->sep.is_ip4 = mp->is_ip4;
744       a->sep.ip = *ip46;
745       a->sep.port = mp->port;
746       a->sep.transport_proto = mp->proto;
747       a->sep.fib_index = mp->vrf;
748       a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
749       a->api_context = mp->context;
750       a->app_index = app->index;
751       a->mp = mp;
752       if ((error = vnet_connect (a)))
753         {
754           rv = clib_error_get_code (error);
755           if (rv != VNET_API_ERROR_SESSION_REDIRECT)
756             clib_error_report (error);
757         }
758     }
759   else
760     {
761       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
762     }
763
764   if (rv == 0 || rv == VNET_API_ERROR_SESSION_REDIRECT)
765     return;
766
767   /* Got some error, relay it */
768
769 done:
770   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
771 }
772
773 static void
774 vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp)
775 {
776   vl_api_app_namespace_add_del_reply_t *rmp;
777   clib_error_t *error = 0;
778   u32 appns_index = 0;
779   u8 *ns_id = 0;
780   int rv = 0;
781   if (!session_manager_is_enabled ())
782     {
783       rv = VNET_API_ERROR_FEATURE_DISABLED;
784       goto done;
785     }
786
787   if (mp->namespace_id_len > ARRAY_LEN (mp->namespace_id))
788     {
789       rv = VNET_API_ERROR_INVALID_VALUE;
790       goto done;
791     }
792
793   vec_validate (ns_id, mp->namespace_id_len - 1);
794   clib_memcpy (ns_id, mp->namespace_id, mp->namespace_id_len);
795   vnet_app_namespace_add_del_args_t args = {
796     .ns_id = ns_id,
797     .secret = clib_net_to_host_u64 (mp->secret),
798     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
799     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
800     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
801     .is_add = 1
802   };
803   error = vnet_app_namespace_add_del (&args);
804   if (error)
805     {
806       rv = clib_error_get_code (error);
807       clib_error_report (error);
808     }
809   else
810     {
811       appns_index = app_namespace_index_from_id (ns_id);
812       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
813         {
814           clib_warning ("app ns lookup failed");
815           rv = VNET_API_ERROR_UNSPECIFIED;
816         }
817     }
818   vec_free (ns_id);
819
820   /* *INDENT-OFF* */
821 done:
822   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
823     if (!rv)
824       rmp->appns_index = clib_host_to_net_u32 (appns_index);
825   }));
826   /* *INDENT-ON* */
827 }
828
829 static void
830 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
831 {
832   vl_api_session_rule_add_del_reply_t *rmp;
833   session_rule_add_del_args_t args;
834   session_rule_table_add_del_args_t *table_args = &args.table_args;
835   clib_error_t *error;
836   u8 fib_proto;
837   int rv = 0;
838
839   memset (&args, 0, sizeof (args));
840   fib_proto = mp->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
841
842   table_args->lcl.fp_len = mp->lcl_plen;
843   table_args->lcl.fp_proto = fib_proto;
844   table_args->rmt.fp_len = mp->rmt_plen;
845   table_args->rmt.fp_proto = fib_proto;
846   table_args->lcl_port = mp->lcl_port;
847   table_args->rmt_port = mp->rmt_port;
848   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
849   table_args->is_add = mp->is_add;
850   mp->tag[sizeof (mp->tag) - 1] = 0;
851   table_args->tag = format (0, "%s", mp->tag);
852   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
853   args.scope = mp->scope;
854   args.transport_proto = mp->transport_proto;
855
856   memset (&table_args->lcl.fp_addr, 0, sizeof (table_args->lcl.fp_addr));
857   memset (&table_args->rmt.fp_addr, 0, sizeof (table_args->rmt.fp_addr));
858   ip_set (&table_args->lcl.fp_addr, mp->lcl_ip, mp->is_ip4);
859   ip_set (&table_args->rmt.fp_addr, mp->rmt_ip, mp->is_ip4);
860   error = vnet_session_rule_add_del (&args);
861   if (error)
862     {
863       rv = clib_error_get_code (error);
864       clib_error_report (error);
865     }
866   vec_free (table_args->tag);
867   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
868 }
869
870 static void
871 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
872                             u8 transport_proto, u32 appns_index, u8 * tag,
873                             svm_queue_t * q, u32 context)
874 {
875   vl_api_session_rules_details_t *rmp = 0;
876   session_mask_or_match_4_t *match =
877     (session_mask_or_match_4_t *) & rule->match;
878   session_mask_or_match_4_t *mask =
879     (session_mask_or_match_4_t *) & rule->mask;
880
881   rmp = vl_msg_api_alloc (sizeof (*rmp));
882   memset (rmp, 0, sizeof (*rmp));
883   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
884   rmp->context = context;
885
886   rmp->is_ip4 = 1;
887   clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
888   clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
889   rmp->lcl_plen = ip4_mask_to_preflen (&mask->lcl_ip);
890   rmp->rmt_plen = ip4_mask_to_preflen (&mask->rmt_ip);
891   rmp->lcl_port = match->lcl_port;
892   rmp->rmt_port = match->rmt_port;
893   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
894   rmp->scope =
895     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
896   rmp->transport_proto = transport_proto;
897   rmp->appns_index = clib_host_to_net_u32 (appns_index);
898   if (tag)
899     {
900       clib_memcpy (rmp->tag, tag, vec_len (tag));
901       rmp->tag[vec_len (tag)] = 0;
902     }
903
904   vl_msg_api_send_shmem (q, (u8 *) & rmp);
905 }
906
907 static void
908 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
909                             u8 transport_proto, u32 appns_index, u8 * tag,
910                             svm_queue_t * q, u32 context)
911 {
912   vl_api_session_rules_details_t *rmp = 0;
913   session_mask_or_match_6_t *match =
914     (session_mask_or_match_6_t *) & rule->match;
915   session_mask_or_match_6_t *mask =
916     (session_mask_or_match_6_t *) & rule->mask;
917
918   rmp = vl_msg_api_alloc (sizeof (*rmp));
919   memset (rmp, 0, sizeof (*rmp));
920   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
921   rmp->context = context;
922
923   rmp->is_ip4 = 0;
924   clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
925   clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
926   rmp->lcl_plen = ip6_mask_to_preflen (&mask->lcl_ip);
927   rmp->rmt_plen = ip6_mask_to_preflen (&mask->rmt_ip);
928   rmp->lcl_port = match->lcl_port;
929   rmp->rmt_port = match->rmt_port;
930   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
931   rmp->scope =
932     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
933   rmp->transport_proto = transport_proto;
934   rmp->appns_index = clib_host_to_net_u32 (appns_index);
935   if (tag)
936     {
937       clib_memcpy (rmp->tag, tag, vec_len (tag));
938       rmp->tag[vec_len (tag)] = 0;
939     }
940
941   vl_msg_api_send_shmem (q, (u8 *) & rmp);
942 }
943
944 static void
945 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
946                                   u8 tp, u8 is_local, u32 appns_index,
947                                   svm_queue_t * q, u32 context)
948 {
949   mma_rule_16_t *rule16;
950   mma_rule_40_t *rule40;
951   mma_rules_table_16_t *srt16;
952   mma_rules_table_40_t *srt40;
953   u32 ri;
954
955   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
956     {
957       u8 *tag = 0;
958       /* *INDENT-OFF* */
959       srt16 = &srt->session_rules_tables_16;
960       pool_foreach (rule16, srt16->rules, ({
961         ri = mma_rules_table_rule_index_16 (srt16, rule16);
962         tag = session_rules_table_rule_tag (srt, ri, 1);
963         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
964                                     q, context);
965       }));
966       /* *INDENT-ON* */
967     }
968   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
969     {
970       u8 *tag = 0;
971       /* *INDENT-OFF* */
972       srt40 = &srt->session_rules_tables_40;
973       pool_foreach (rule40, srt40->rules, ({
974         ri = mma_rules_table_rule_index_40 (srt40, rule40);
975         tag = session_rules_table_rule_tag (srt, ri, 1);
976         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
977                                     q, context);
978       }));
979       /* *INDENT-ON* */
980     }
981 }
982
983 static void
984 vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
985 {
986   svm_queue_t *q = NULL;
987   session_table_t *st;
988   u8 tp;
989
990   q = vl_api_client_index_to_input_queue (mp->client_index);
991   if (q == 0)
992     return;
993
994   /* *INDENT-OFF* */
995   session_table_foreach (st, ({
996     for (tp = 0; tp < TRANSPORT_N_PROTO; tp++)
997       {
998         send_session_rules_table_details (&st->session_rules[tp],
999                                           st->active_fib_proto, tp,
1000                                           st->is_local, st->appns_index, q,
1001                                           mp->context);
1002       }
1003   }));
1004   /* *INDENT-ON* */
1005 }
1006
1007 static clib_error_t *
1008 application_reaper_cb (u32 client_index)
1009 {
1010   application_t *app = application_lookup (client_index);
1011   vnet_app_detach_args_t _a, *a = &_a;
1012   if (app)
1013     {
1014       a->app_index = app->index;
1015       vnet_application_detach (a);
1016     }
1017   return 0;
1018 }
1019
1020 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1021
1022 #define vl_msg_name_crc_list
1023 #include <vnet/vnet_all_api_h.h>
1024 #undef vl_msg_name_crc_list
1025
1026 static void
1027 setup_message_id_table (api_main_t * am)
1028 {
1029 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1030   foreach_vl_msg_name_crc_session;
1031 #undef _
1032 }
1033
1034 /*
1035  * session_api_hookup
1036  * Add uri's API message handlers to the table.
1037  * vlib has alread mapped shared memory and
1038  * added the client registration handlers.
1039  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
1040  */
1041 static clib_error_t *
1042 session_api_hookup (vlib_main_t * vm)
1043 {
1044   api_main_t *am = &api_main;
1045
1046 #define _(N,n)                                                  \
1047     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1048                            vl_api_##n##_t_handler,              \
1049                            vl_noop_handler,                     \
1050                            vl_api_##n##_t_endian,               \
1051                            vl_api_##n##_t_print,                \
1052                            sizeof(vl_api_##n##_t), 1);
1053   foreach_session_api_msg;
1054 #undef _
1055
1056   /*
1057    * Messages which bounce off the data-plane to
1058    * an API client. Simply tells the message handling infra not
1059    * to free the message.
1060    *
1061    * Bounced message handlers MUST NOT block the data plane
1062    */
1063   am->message_bounce[VL_API_CONNECT_URI] = 1;
1064   am->message_bounce[VL_API_CONNECT_SOCK] = 1;
1065
1066   /*
1067    * Set up the (msg_name, crc, message-id) table
1068    */
1069   setup_message_id_table (am);
1070
1071   return 0;
1072 }
1073
1074 VLIB_API_INIT_FUNCTION (session_api_hookup);
1075
1076 /*
1077  * fd.io coding-style-patch-verification: ON
1078  *
1079  * Local Variables:
1080  * eval: (c-set-style "gnu")
1081  * End:
1082  */