session: api to add new transport types
[vpp.git] / src / vnet / session / session_api.c
1 /*
2  * Copyright (c) 2015-2019 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/application_local.h>
21 #include <vnet/session/session_rules_table.h>
22 #include <vnet/session/session_table.h>
23 #include <vnet/session/session.h>
24
25 #include <vnet/ip/ip_types_api.h>
26
27 #include <vnet/vnet_msg_enum.h>
28
29 #define vl_typedefs             /* define message structures */
30 #include <vnet/vnet_all_api_h.h>
31 #undef vl_typedefs
32
33 #define vl_endianfun            /* define message structures */
34 #include <vnet/vnet_all_api_h.h>
35 #undef vl_endianfun
36
37 /* instantiate all the print functions we know about */
38 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
39 #define vl_printfun
40 #include <vnet/vnet_all_api_h.h>
41 #undef vl_printfun
42
43 #include <vlibapi/api_helper_macros.h>
44
45 #define foreach_session_api_msg                                         \
46 _(MAP_ANOTHER_SEGMENT_REPLY, map_another_segment_reply)                 \
47 _(APPLICATION_ATTACH, application_attach)                               \
48 _(APP_ATTACH, app_attach)                                               \
49 _(APPLICATION_DETACH, application_detach)                               \
50 _(BIND_URI, bind_uri)                                                   \
51 _(UNBIND_URI, unbind_uri)                                               \
52 _(CONNECT_URI, connect_uri)                                             \
53 _(DISCONNECT_SESSION, disconnect_session)                               \
54 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)                   \
55 _(BIND_SOCK, bind_sock)                                                 \
56 _(UNBIND_SOCK, unbind_sock)                                             \
57 _(CONNECT_SOCK, connect_sock)                                           \
58 _(SESSION_ENABLE_DISABLE, session_enable_disable)                       \
59 _(APP_NAMESPACE_ADD_DEL, app_namespace_add_del)                         \
60 _(SESSION_RULE_ADD_DEL, session_rule_add_del)                           \
61 _(SESSION_RULES_DUMP, session_rules_dump)                               \
62 _(APPLICATION_TLS_CERT_ADD, application_tls_cert_add)                   \
63 _(APPLICATION_TLS_KEY_ADD, application_tls_key_add)                     \
64 _(APP_ADD_CERT_KEY_PAIR, app_add_cert_key_pair)                         \
65 _(APP_DEL_CERT_KEY_PAIR, app_del_cert_key_pair)                         \
66 _(APP_WORKER_ADD_DEL, app_worker_add_del)                               \
67
68 static transport_proto_t
69 api_session_transport_proto_decode (const vl_api_transport_proto_t * api_tp)
70 {
71   switch (*api_tp)
72     {
73     case TRANSPORT_PROTO_API_TCP:
74       return TRANSPORT_PROTO_TCP;
75     case TRANSPORT_PROTO_API_UDP:
76       return TRANSPORT_PROTO_UDP;
77     case TRANSPORT_PROTO_API_TLS:
78       return TRANSPORT_PROTO_TLS;
79     case TRANSPORT_PROTO_API_UDPC:
80       return TRANSPORT_PROTO_UDPC;
81     case TRANSPORT_PROTO_API_QUIC:
82       return TRANSPORT_PROTO_QUIC;
83     default:
84       return TRANSPORT_PROTO_NONE;
85     }
86 }
87
88 static vl_api_transport_proto_t
89 api_session_transport_proto_encode (const transport_proto_t tp)
90 {
91   switch (tp)
92     {
93     case TRANSPORT_PROTO_TCP:
94       return TRANSPORT_PROTO_API_TCP;
95     case TRANSPORT_PROTO_UDP:
96       return TRANSPORT_PROTO_API_UDP;
97     case TRANSPORT_PROTO_TLS:
98       return TRANSPORT_PROTO_API_TLS;
99     case TRANSPORT_PROTO_UDPC:
100       return TRANSPORT_PROTO_API_UDPC;
101     case TRANSPORT_PROTO_QUIC:
102       return TRANSPORT_PROTO_API_QUIC;
103     default:
104       return TRANSPORT_PROTO_API_NONE;
105     }
106 }
107
108 static int
109 session_send_fds (vl_api_registration_t * reg, int fds[], int n_fds)
110 {
111   clib_error_t *error;
112   if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
113     {
114       clib_warning ("can't send memfd fd");
115       return -1;
116     }
117   error = vl_api_send_fd_msg (reg, fds, n_fds);
118   if (error)
119     {
120       clib_error_report (error);
121       return -1;
122     }
123   return 0;
124 }
125
126 /* ### WILL BE DEPRECATED POST 20.01 ### */
127 static int
128 send_add_segment_callback (u32 api_client_index, u64 segment_handle)
129 {
130   int fds[SESSION_N_FD_TYPE], n_fds = 0;
131   vl_api_map_another_segment_t *mp;
132   vl_api_registration_t *reg;
133   fifo_segment_t *fs;
134   ssvm_private_t *sp;
135   u8 fd_flags = 0;
136
137   reg = vl_mem_api_client_index_to_registration (api_client_index);
138   if (!reg)
139     {
140       clib_warning ("no api registration for client: %u", api_client_index);
141       return -1;
142     }
143
144   fs = segment_manager_get_segment_w_handle (segment_handle);
145   sp = &fs->ssvm;
146   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
147     {
148       if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
149         {
150           clib_warning ("can't send memfd fd");
151           return -1;
152         }
153
154       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
155       fds[n_fds] = sp->fd;
156       n_fds += 1;
157     }
158
159   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
160   clib_memset (mp, 0, sizeof (*mp));
161   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
162   mp->segment_size = sp->ssvm_size;
163   mp->fd_flags = fd_flags;
164   mp->segment_handle = clib_host_to_net_u64 (segment_handle);
165   strncpy ((char *) mp->segment_name, (char *) sp->name,
166            sizeof (mp->segment_name) - 1);
167
168   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
169
170   if (n_fds)
171     return session_send_fds (reg, fds, n_fds);
172
173   return 0;
174 }
175
176 /* ### WILL BE DEPRECATED POST 20.01 ### */
177 static int
178 send_del_segment_callback (u32 api_client_index, u64 segment_handle)
179 {
180   vl_api_unmap_segment_t *mp;
181   vl_api_registration_t *reg;
182
183   reg = vl_mem_api_client_index_to_registration (api_client_index);
184   if (!reg)
185     {
186       clib_warning ("no registration: %u", api_client_index);
187       return -1;
188     }
189
190   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
191   clib_memset (mp, 0, sizeof (*mp));
192   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_UNMAP_SEGMENT);
193   mp->segment_handle = clib_host_to_net_u64 (segment_handle);
194   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
195
196   return 0;
197 }
198
199 static int
200 mq_try_lock_and_alloc_msg (svm_msg_q_t * app_mq, svm_msg_q_msg_t * msg)
201 {
202   int rv;
203   u8 try = 0;
204   while (try < 100)
205     {
206       rv = svm_msg_q_lock_and_alloc_msg_w_ring (app_mq,
207                                                 SESSION_MQ_CTRL_EVT_RING,
208                                                 SVM_Q_NOWAIT, msg);
209       if (!rv)
210         return 0;
211       try++;
212       usleep (1);
213     }
214   clib_warning ("failed to alloc msg");
215   return -1;
216 }
217
218 static int
219 mq_send_session_accepted_cb (session_t * s)
220 {
221   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
222   svm_msg_q_msg_t _msg, *msg = &_msg;
223   svm_msg_q_t *vpp_queue, *app_mq;
224   session_t *listener;
225   session_accepted_msg_t *mp;
226   session_event_t *evt;
227   application_t *app;
228
229   app = application_get (app_wrk->app_index);
230   app_mq = app_wrk->event_queue;
231   if (mq_try_lock_and_alloc_msg (app_mq, msg))
232     return -1;
233
234   evt = svm_msg_q_msg_data (app_mq, msg);
235   clib_memset (evt, 0, sizeof (*evt));
236   evt->event_type = SESSION_CTRL_EVT_ACCEPTED;
237   mp = (session_accepted_msg_t *) evt->data;
238   clib_memset (mp, 0, sizeof (*mp));
239   mp->context = app->app_index;
240   mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
241   mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
242   mp->segment_handle = session_segment_handle (s);
243   mp->flags = s->flags;
244
245   if (session_has_transport (s))
246     {
247       listener = listen_session_get_from_handle (s->listener_handle);
248       mp->listener_handle = app_listen_session_handle (listener);
249       if (application_is_proxy (app))
250         {
251           listener =
252             app_worker_first_listener (app_wrk, session_get_fib_proto (s),
253                                        session_get_transport_proto (s));
254           if (listener)
255             mp->listener_handle = listen_session_get_handle (listener);
256         }
257       vpp_queue = session_main_get_vpp_event_queue (s->thread_index);
258       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
259       mp->handle = session_handle (s);
260
261       session_get_endpoint (s, &mp->rmt, 0 /* is_lcl */ );
262     }
263   else
264     {
265       ct_connection_t *ct;
266
267       ct = (ct_connection_t *) session_get_transport (s);
268       listener = listen_session_get_from_handle (s->listener_handle);
269       mp->listener_handle = app_listen_session_handle (listener);
270       mp->rmt.is_ip4 = session_type_is_ip4 (listener->session_type);
271       mp->rmt.port = ct->c_rmt_port;
272       mp->handle = session_handle (s);
273       vpp_queue = session_main_get_vpp_event_queue (0);
274       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
275     }
276   svm_msg_q_add_and_unlock (app_mq, msg);
277
278   return 0;
279 }
280
281 static inline void
282 mq_send_session_close_evt (app_worker_t * app_wrk, session_handle_t sh,
283                            session_evt_type_t evt_type)
284 {
285   svm_msg_q_msg_t _msg, *msg = &_msg;
286   session_disconnected_msg_t *mp;
287   svm_msg_q_t *app_mq;
288   session_event_t *evt;
289
290   app_mq = app_wrk->event_queue;
291   if (mq_try_lock_and_alloc_msg (app_mq, msg))
292     return;
293   evt = svm_msg_q_msg_data (app_mq, msg);
294   clib_memset (evt, 0, sizeof (*evt));
295   evt->event_type = evt_type;
296   mp = (session_disconnected_msg_t *) evt->data;
297   mp->handle = sh;
298   mp->context = app_wrk->api_client_index;
299   svm_msg_q_add_and_unlock (app_mq, msg);
300 }
301
302 static inline void
303 mq_notify_close_subscribers (u32 app_index, session_handle_t sh,
304                              svm_fifo_t * f, session_evt_type_t evt_type)
305 {
306   app_worker_t *app_wrk;
307   application_t *app;
308   int i;
309
310   app = application_get (app_index);
311   if (!app)
312     return;
313
314   for (i = 0; i < f->n_subscribers; i++)
315     {
316       if (!(app_wrk = application_get_worker (app, f->subscribers[i])))
317         continue;
318       mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_DISCONNECTED);
319     }
320 }
321
322 static void
323 mq_send_session_disconnected_cb (session_t * s)
324 {
325   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
326   session_handle_t sh = session_handle (s);
327
328   mq_send_session_close_evt (app_wrk, session_handle (s),
329                              SESSION_CTRL_EVT_DISCONNECTED);
330
331   if (svm_fifo_n_subscribers (s->rx_fifo))
332     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
333                                  SESSION_CTRL_EVT_DISCONNECTED);
334 }
335
336 static void
337 mq_send_session_reset_cb (session_t * s)
338 {
339   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
340   session_handle_t sh = session_handle (s);
341
342   mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_RESET);
343
344   if (svm_fifo_n_subscribers (s->rx_fifo))
345     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
346                                  SESSION_CTRL_EVT_RESET);
347 }
348
349 int
350 mq_send_session_connected_cb (u32 app_wrk_index, u32 api_context,
351                               session_t * s, u8 is_fail)
352 {
353   svm_msg_q_msg_t _msg, *msg = &_msg;
354   session_connected_msg_t *mp;
355   svm_msg_q_t *vpp_mq, *app_mq;
356   transport_connection_t *tc;
357   app_worker_t *app_wrk;
358   session_event_t *evt;
359
360   app_wrk = app_worker_get (app_wrk_index);
361   app_mq = app_wrk->event_queue;
362   if (!app_mq)
363     {
364       clib_warning ("app %u with api index: %u not attached",
365                     app_wrk->app_index, app_wrk->api_client_index);
366       return -1;
367     }
368
369   if (mq_try_lock_and_alloc_msg (app_mq, msg))
370     return -1;
371
372   evt = svm_msg_q_msg_data (app_mq, msg);
373   clib_memset (evt, 0, sizeof (*evt));
374   evt->event_type = SESSION_CTRL_EVT_CONNECTED;
375   mp = (session_connected_msg_t *) evt->data;
376   clib_memset (mp, 0, sizeof (*mp));
377   mp->context = api_context;
378
379   if (is_fail)
380     goto done;
381
382   if (session_has_transport (s))
383     {
384       tc = session_get_transport (s);
385       if (!tc)
386         {
387           is_fail = 1;
388           goto done;
389         }
390
391       vpp_mq = session_main_get_vpp_event_queue (s->thread_index);
392       mp->handle = session_handle (s);
393       mp->vpp_event_queue_address = pointer_to_uword (vpp_mq);
394
395       session_get_endpoint (s, &mp->lcl, 1 /* is_lcl */ );
396
397       mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
398       mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
399       mp->segment_handle = session_segment_handle (s);
400     }
401   else
402     {
403       ct_connection_t *cct;
404       session_t *ss;
405
406       cct = (ct_connection_t *) session_get_transport (s);
407       mp->handle = session_handle (s);
408       mp->lcl.port = cct->c_lcl_port;
409       mp->lcl.is_ip4 = cct->c_is_ip4;
410       vpp_mq = session_main_get_vpp_event_queue (0);
411       mp->vpp_event_queue_address = pointer_to_uword (vpp_mq);
412       mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
413       mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
414       mp->segment_handle = session_segment_handle (s);
415       ss = ct_session_get_peer (s);
416       mp->ct_rx_fifo = pointer_to_uword (ss->tx_fifo);
417       mp->ct_tx_fifo = pointer_to_uword (ss->rx_fifo);
418       mp->ct_segment_handle = session_segment_handle (ss);
419     }
420
421 done:
422   mp->retval = is_fail ?
423     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
424
425   svm_msg_q_add_and_unlock (app_mq, msg);
426   return 0;
427 }
428
429 int
430 mq_send_session_bound_cb (u32 app_wrk_index, u32 api_context,
431                           session_handle_t handle, int rv)
432 {
433   svm_msg_q_msg_t _msg, *msg = &_msg;
434   svm_msg_q_t *app_mq, *vpp_evt_q;
435   transport_endpoint_t tep;
436   session_bound_msg_t *mp;
437   app_worker_t *app_wrk;
438   session_event_t *evt;
439   app_listener_t *al;
440   session_t *ls = 0;
441   app_wrk = app_worker_get (app_wrk_index);
442   app_mq = app_wrk->event_queue;
443   if (!app_mq)
444     {
445       clib_warning ("app %u with api index: %u not attached",
446                     app_wrk->app_index, app_wrk->api_client_index);
447       return -1;
448     }
449
450   if (mq_try_lock_and_alloc_msg (app_mq, msg))
451     return -1;
452
453   evt = svm_msg_q_msg_data (app_mq, msg);
454   clib_memset (evt, 0, sizeof (*evt));
455   evt->event_type = SESSION_CTRL_EVT_BOUND;
456   mp = (session_bound_msg_t *) evt->data;
457   mp->context = api_context;
458
459   if (rv)
460     goto done;
461
462   mp->handle = handle;
463   al = app_listener_get_w_handle (handle);
464   if (al->session_index != SESSION_INVALID_INDEX)
465     ls = app_listener_get_session (al);
466   else
467     ls = app_listener_get_local_session (al);
468
469   session_get_endpoint (ls, &tep, 1 /* is_lcl */ );
470   mp->lcl_port = tep.port;
471   mp->lcl_is_ip4 = tep.is_ip4;
472   clib_memcpy_fast (mp->lcl_ip, &tep.ip, sizeof (tep.ip));
473
474   vpp_evt_q = session_main_get_vpp_event_queue (0);
475   mp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
476
477   if (session_transport_service_type (ls) == TRANSPORT_SERVICE_CL)
478     {
479       mp->rx_fifo = pointer_to_uword (ls->rx_fifo);
480       mp->tx_fifo = pointer_to_uword (ls->tx_fifo);
481     }
482
483 done:
484   mp->retval = rv;
485   svm_msg_q_add_and_unlock (app_mq, msg);
486   return 0;
487 }
488
489 void
490 mq_send_unlisten_reply (app_worker_t * app_wrk, session_handle_t sh,
491                         u32 context, int rv)
492 {
493   svm_msg_q_msg_t _msg, *msg = &_msg;
494   session_unlisten_reply_msg_t *ump;
495   svm_msg_q_t *app_mq;
496   session_event_t *evt;
497
498   app_mq = app_wrk->event_queue;
499   if (mq_try_lock_and_alloc_msg (app_mq, msg))
500     return;
501
502   evt = svm_msg_q_msg_data (app_mq, msg);
503   clib_memset (evt, 0, sizeof (*evt));
504   evt->event_type = SESSION_CTRL_EVT_UNLISTEN_REPLY;
505   ump = (session_unlisten_reply_msg_t *) evt->data;
506   ump->context = context;
507   ump->handle = sh;
508   ump->retval = rv;
509   svm_msg_q_add_and_unlock (app_mq, msg);
510 }
511
512 static void
513 mq_send_session_migrate_cb (session_t * s, session_handle_t new_sh)
514 {
515   svm_msg_q_msg_t _msg, *msg = &_msg;
516   session_migrated_msg_t *mp;
517   svm_msg_q_t *vpp_evt_q;
518   app_worker_t *app_wrk;
519   session_event_t *evt;
520   svm_msg_q_t *app_mq;
521
522   app_wrk = app_worker_get (s->app_wrk_index);
523   app_mq = app_wrk->event_queue;
524   if (mq_try_lock_and_alloc_msg (app_mq, msg))
525     return;
526
527   evt = svm_msg_q_msg_data (app_mq, msg);
528   clib_memset (evt, 0, sizeof (*evt));
529   evt->event_type = SESSION_CTRL_EVT_MIGRATED;
530   mp = (session_migrated_msg_t *) evt->data;
531   mp->handle = session_handle (s);
532   mp->new_handle = new_sh;
533   mp->vpp_thread_index = session_thread_from_handle (new_sh);
534   vpp_evt_q = session_main_get_vpp_event_queue (mp->vpp_thread_index);
535   mp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
536   svm_msg_q_add_and_unlock (app_mq, msg);
537 }
538
539 static int
540 mq_send_add_segment_cb (u32 app_wrk_index, u64 segment_handle)
541 {
542   int fds[SESSION_N_FD_TYPE], n_fds = 0;
543   svm_msg_q_msg_t _msg, *msg = &_msg;
544   session_app_add_segment_msg_t *mp;
545   vl_api_registration_t *reg;
546   app_worker_t *app_wrk;
547   session_event_t *evt;
548   svm_msg_q_t *app_mq;
549   fifo_segment_t *fs;
550   ssvm_private_t *sp;
551   u8 fd_flags = 0;
552
553   app_wrk = app_worker_get (app_wrk_index);
554
555   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
556   if (!reg)
557     {
558       clib_warning ("no api registration for client: %u",
559                     app_wrk->api_client_index);
560       return -1;
561     }
562
563   fs = segment_manager_get_segment_w_handle (segment_handle);
564   sp = &fs->ssvm;
565   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
566     {
567       if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
568         {
569           clib_warning ("can't send memfd fd");
570           return -1;
571         }
572
573       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
574       fds[n_fds] = sp->fd;
575       n_fds += 1;
576     }
577
578   app_mq = app_wrk->event_queue;
579   if (mq_try_lock_and_alloc_msg (app_mq, msg))
580     return -1;
581
582   if (n_fds)
583     session_send_fds (reg, fds, n_fds);
584
585   evt = svm_msg_q_msg_data (app_mq, msg);
586   clib_memset (evt, 0, sizeof (*evt));
587   evt->event_type = SESSION_CTRL_EVT_APP_ADD_SEGMENT;
588   mp = (session_app_add_segment_msg_t *) evt->data;
589   clib_memset (mp, 0, sizeof (*mp));
590   mp->segment_size = sp->ssvm_size;
591   mp->fd_flags = fd_flags;
592   mp->segment_handle = segment_handle;
593   strncpy ((char *) mp->segment_name, (char *) sp->name,
594            sizeof (mp->segment_name) - 1);
595
596   svm_msg_q_add_and_unlock (app_mq, msg);
597
598   return 0;
599 }
600
601 static int
602 mq_send_del_segment_cb (u32 app_wrk_index, u64 segment_handle)
603 {
604   svm_msg_q_msg_t _msg, *msg = &_msg;
605   session_app_del_segment_msg_t *mp;
606   vl_api_registration_t *reg;
607   app_worker_t *app_wrk;
608   session_event_t *evt;
609   svm_msg_q_t *app_mq;
610
611   app_wrk = app_worker_get (app_wrk_index);
612   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
613   if (!reg)
614     {
615       clib_warning ("no registration: %u", app_wrk->api_client_index);
616       return -1;
617     }
618
619   app_mq = app_wrk->event_queue;
620   if (mq_try_lock_and_alloc_msg (app_mq, msg))
621     return -1;
622
623   evt = svm_msg_q_msg_data (app_mq, msg);
624   clib_memset (evt, 0, sizeof (*evt));
625   evt->event_type = SESSION_CTRL_EVT_APP_DEL_SEGMENT;
626   mp = (session_app_del_segment_msg_t *) evt->data;
627   clib_memset (mp, 0, sizeof (*mp));
628   mp->segment_handle = segment_handle;
629   svm_msg_q_add_and_unlock (app_mq, msg);
630
631   return 0;
632 }
633
634 static void
635 mq_send_session_cleanup_cb (session_t * s, session_cleanup_ntf_t ntf)
636 {
637   svm_msg_q_msg_t _msg, *msg = &_msg;
638   session_cleanup_msg_t *mp;
639   svm_msg_q_t *app_mq;
640   session_event_t *evt;
641   app_worker_t *app_wrk;
642
643   /* Only propagate session cleanup notification */
644   if (ntf == SESSION_CLEANUP_TRANSPORT)
645     return;
646
647   app_wrk = app_worker_get_if_valid (s->app_wrk_index);
648   if (!app_wrk)
649     return;
650
651   app_mq = app_wrk->event_queue;
652   if (mq_try_lock_and_alloc_msg (app_mq, msg))
653     return;
654
655   evt = svm_msg_q_msg_data (app_mq, msg);
656   clib_memset (evt, 0, sizeof (*evt));
657   evt->event_type = SESSION_CTRL_EVT_CLEANUP;
658   mp = (session_cleanup_msg_t *) evt->data;
659   mp->handle = session_handle (s);
660   svm_msg_q_add_and_unlock (app_mq, msg);
661 }
662
663 /* ### WILL BE DEPRECATED POST 20.01 ### */
664 static session_cb_vft_t session_mq_cb_vft_old = {
665   .session_accept_callback = mq_send_session_accepted_cb,
666   .session_disconnect_callback = mq_send_session_disconnected_cb,
667   .session_connected_callback = mq_send_session_connected_cb,
668   .session_reset_callback = mq_send_session_reset_cb,
669   .session_migrate_callback = mq_send_session_migrate_cb,
670   .add_segment_callback = send_add_segment_callback,
671   .del_segment_callback = send_del_segment_callback,
672 };
673
674 static session_cb_vft_t session_mq_cb_vft = {
675   .session_accept_callback = mq_send_session_accepted_cb,
676   .session_disconnect_callback = mq_send_session_disconnected_cb,
677   .session_connected_callback = mq_send_session_connected_cb,
678   .session_reset_callback = mq_send_session_reset_cb,
679   .session_migrate_callback = mq_send_session_migrate_cb,
680   .session_cleanup_callback = mq_send_session_cleanup_cb,
681   .add_segment_callback = mq_send_add_segment_cb,
682   .del_segment_callback = mq_send_del_segment_cb,
683 };
684
685 static void
686 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
687 {
688   vl_api_session_enable_disable_reply_t *rmp;
689   vlib_main_t *vm = vlib_get_main ();
690   int rv = 0;
691
692   vnet_session_enable_disable (vm, mp->is_enable);
693   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
694 }
695
696 /* ### WILL BE DEPRECATED POST 20.01 ### */
697 static void
698 vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
699 {
700   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
701   vl_api_application_attach_reply_t *rmp;
702   ssvm_private_t *segp, *evt_q_segment;
703   vnet_app_attach_args_t _a, *a = &_a;
704   vl_api_registration_t *reg;
705   u8 fd_flags = 0;
706
707   reg = vl_api_client_index_to_registration (mp->client_index);
708   if (!reg)
709     return;
710
711   if (session_main_is_enabled () == 0)
712     {
713       rv = VNET_API_ERROR_FEATURE_DISABLED;
714       goto done;
715     }
716
717   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
718                  sizeof (mp->options),
719                  "Out of options, fix api message definition");
720
721   clib_memset (a, 0, sizeof (*a));
722   a->api_client_index = mp->client_index;
723   a->options = mp->options;
724   a->session_cb_vft = &session_mq_cb_vft_old;
725   a->namespace_id =
726     (u8 *) vl_api_from_api_to_new_c_string (&mp->namespace_id);
727
728   if ((rv = vnet_application_attach (a)))
729     {
730       clib_warning ("attach returned: %d", rv);
731       vec_free (a->namespace_id);
732       goto done;
733     }
734   vec_free (a->namespace_id);
735
736   /* Send event queues segment */
737   if ((evt_q_segment = session_main_get_evt_q_segment ()))
738     {
739       fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
740       fds[n_fds] = evt_q_segment->fd;
741       n_fds += 1;
742     }
743   /* Send fifo segment fd if needed */
744   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
745     {
746       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
747       fds[n_fds] = a->segment->fd;
748       n_fds += 1;
749     }
750   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
751     {
752       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
753       fds[n_fds] = svm_msg_q_get_producer_eventfd (a->app_evt_q);
754       n_fds += 1;
755     }
756
757 done:
758
759   /* *INDENT-OFF* */
760   REPLY_MACRO2 (VL_API_APPLICATION_ATTACH_REPLY, ({
761     if (!rv)
762       {
763         segp = a->segment;
764         rmp->app_index = clib_host_to_net_u32 (a->app_index);
765         vl_api_vec_to_api_string (segp->name, &rmp->segment_name);
766         rmp->segment_size = segp->ssvm_size;
767         rmp->app_event_queue_address = pointer_to_uword (a->app_evt_q);
768         rmp->n_fds = n_fds;
769         rmp->fd_flags = fd_flags;
770         rmp->segment_handle = clib_host_to_net_u64 (a->segment_handle);
771       }
772   }));
773   /* *INDENT-ON* */
774
775   if (n_fds)
776     session_send_fds (reg, fds, n_fds);
777 }
778
779 static void
780 vl_api_app_attach_t_handler (vl_api_app_attach_t * mp)
781 {
782   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
783   vl_api_app_attach_reply_t *rmp;
784   ssvm_private_t *segp, *evt_q_segment;
785   vnet_app_attach_args_t _a, *a = &_a;
786   u8 fd_flags = 0, ctrl_thread;
787   vl_api_registration_t *reg;
788   svm_msg_q_t *ctrl_mq;
789
790   reg = vl_api_client_index_to_registration (mp->client_index);
791   if (!reg)
792     return;
793
794   if (session_main_is_enabled () == 0)
795     {
796       rv = VNET_API_ERROR_FEATURE_DISABLED;
797       goto done;
798     }
799
800   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
801                  sizeof (mp->options),
802                  "Out of options, fix api message definition");
803
804   clib_memset (a, 0, sizeof (*a));
805   a->api_client_index = mp->client_index;
806   a->options = mp->options;
807   a->session_cb_vft = &session_mq_cb_vft;
808
809   a->namespace_id = vl_api_from_api_to_new_vec (&mp->namespace_id);
810
811   if ((rv = vnet_application_attach (a)))
812     {
813       clib_warning ("attach returned: %d", rv);
814       vec_free (a->namespace_id);
815       goto done;
816     }
817   vec_free (a->namespace_id);
818
819   /* Send event queues segment */
820   if ((evt_q_segment = session_main_get_evt_q_segment ()))
821     {
822       fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
823       fds[n_fds] = evt_q_segment->fd;
824       n_fds += 1;
825     }
826   /* Send fifo segment fd if needed */
827   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
828     {
829       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
830       fds[n_fds] = a->segment->fd;
831       n_fds += 1;
832     }
833   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
834     {
835       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
836       fds[n_fds] = svm_msg_q_get_producer_eventfd (a->app_evt_q);
837       n_fds += 1;
838     }
839
840 done:
841   /* *INDENT-OFF* */
842   REPLY_MACRO2 (VL_API_APP_ATTACH_REPLY, ({
843     if (!rv)
844       {
845         ctrl_thread = vlib_num_workers () ? 1 : 0;
846         ctrl_mq = session_main_get_vpp_event_queue (ctrl_thread);
847         segp = a->segment;
848         rmp->app_index = clib_host_to_net_u32 (a->app_index);
849         rmp->app_mq = pointer_to_uword (a->app_evt_q);
850         rmp->vpp_ctrl_mq = pointer_to_uword (ctrl_mq);
851         rmp->vpp_ctrl_mq_thread = ctrl_thread;
852         rmp->n_fds = n_fds;
853         rmp->fd_flags = fd_flags;
854         if (vec_len (segp->name))
855           {
856             vl_api_vec_to_api_string (segp->name, &rmp->segment_name);
857           }
858         rmp->segment_size = segp->ssvm_size;
859         rmp->segment_handle = clib_host_to_net_u64 (a->segment_handle);
860       }
861   }));
862   /* *INDENT-ON* */
863
864   if (n_fds)
865     session_send_fds (reg, fds, n_fds);
866 }
867
868 /* ### WILL BE DEPRECATED POST 20.01 ### */
869 static void
870 vl_api_application_detach_t_handler (vl_api_application_detach_t * mp)
871 {
872   vl_api_application_detach_reply_t *rmp;
873   int rv = VNET_API_ERROR_INVALID_VALUE_2;
874   vnet_app_detach_args_t _a, *a = &_a;
875   application_t *app;
876
877   if (session_main_is_enabled () == 0)
878     {
879       rv = VNET_API_ERROR_FEATURE_DISABLED;
880       goto done;
881     }
882
883   app = application_lookup (mp->client_index);
884   if (app)
885     {
886       a->app_index = app->app_index;
887       a->api_client_index = mp->client_index;
888       rv = vnet_application_detach (a);
889     }
890
891 done:
892   REPLY_MACRO (VL_API_APPLICATION_DETACH_REPLY);
893 }
894
895 /* ### WILL BE DEPRECATED POST 20.01 ### */
896 static void
897 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
898 {
899   vl_api_bind_uri_reply_t *rmp;
900   vnet_listen_args_t _a, *a = &_a;
901   application_t *app = 0;
902   app_worker_t *app_wrk;
903   int rv;
904
905   if (session_main_is_enabled () == 0)
906     {
907       rv = VNET_API_ERROR_FEATURE_DISABLED;
908       goto done;
909     }
910
911   app = application_lookup (mp->client_index);
912   if (app)
913     {
914       clib_memset (a, 0, sizeof (*a));
915       a->uri = (char *) mp->uri;
916       a->app_index = app->app_index;
917       rv = vnet_bind_uri (a);
918     }
919   else
920     {
921       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
922     }
923
924 done:
925
926   REPLY_MACRO (VL_API_BIND_URI_REPLY);
927
928   if (app)
929     {
930       app_wrk = application_get_worker (app, 0);
931       mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle,
932                                 rv);
933     }
934 }
935
936 /* ### WILL BE DEPRECATED POST 20.01 ### */
937 static void
938 vl_api_unbind_uri_t_handler (vl_api_unbind_uri_t * mp)
939 {
940   vl_api_unbind_uri_reply_t *rmp;
941   application_t *app;
942   vnet_unlisten_args_t _a, *a = &_a;
943   int rv;
944
945   if (session_main_is_enabled () == 0)
946     {
947       rv = VNET_API_ERROR_FEATURE_DISABLED;
948       goto done;
949     }
950
951   app = application_lookup (mp->client_index);
952   if (app)
953     {
954       a->uri = (char *) mp->uri;
955       a->app_index = app->app_index;
956       a->wrk_map_index = 0;
957       rv = vnet_unbind_uri (a);
958     }
959   else
960     {
961       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
962     }
963
964 done:
965   REPLY_MACRO (VL_API_UNBIND_URI_REPLY);
966 }
967
968 /* ### WILL BE DEPRECATED POST 20.01 ### */
969 static void
970 vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
971 {
972   vl_api_connect_uri_reply_t *rmp;
973   vnet_connect_args_t _a, *a = &_a;
974   application_t *app;
975   int rv = 0;
976
977   if (session_main_is_enabled () == 0)
978     {
979       rv = VNET_API_ERROR_FEATURE_DISABLED;
980       goto done;
981     }
982
983   app = application_lookup (mp->client_index);
984   if (app)
985     {
986       clib_memset (a, 0, sizeof (*a));
987       a->uri = (char *) mp->uri;
988       a->api_context = mp->context;
989       a->app_index = app->app_index;
990       if ((rv = vnet_connect_uri (a)))
991         clib_warning ("connect_uri returned: %d", rv);
992     }
993   else
994     {
995       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
996     }
997
998   /*
999    * Don't reply to stream (tcp) connects. The reply will come once
1000    * the connection is established. In case of the redirects, the reply
1001    * will come from the server app.
1002    */
1003   if (rv == 0)
1004     return;
1005
1006 done:
1007   REPLY_MACRO (VL_API_CONNECT_URI_REPLY);
1008 }
1009
1010 /* ### WILL BE DEPRECATED POST 20.01 ### */
1011 static void
1012 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
1013 {
1014   vl_api_disconnect_session_reply_t *rmp;
1015   vnet_disconnect_args_t _a, *a = &_a;
1016   application_t *app;
1017   int rv = 0;
1018
1019   if (session_main_is_enabled () == 0)
1020     {
1021       rv = VNET_API_ERROR_FEATURE_DISABLED;
1022       goto done;
1023     }
1024
1025   app = application_lookup (mp->client_index);
1026   if (app)
1027     {
1028       a->handle = mp->handle;
1029       a->app_index = app->app_index;
1030       rv = vnet_disconnect_session (a);
1031     }
1032   else
1033     {
1034       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1035     }
1036
1037 done:
1038   REPLY_MACRO2 (VL_API_DISCONNECT_SESSION_REPLY, rmp->handle = mp->handle);
1039 }
1040
1041 /* ### WILL BE DEPRECATED POST 20.01 ### */
1042 static void
1043 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
1044                                            mp)
1045 {
1046   vnet_disconnect_args_t _a, *a = &_a;
1047   application_t *app;
1048
1049   /* Client objected to disconnecting the session, log and continue */
1050   if (mp->retval)
1051     {
1052       clib_warning ("client retval %d", mp->retval);
1053       return;
1054     }
1055
1056   /* Disconnect has been confirmed. Confirm close to transport */
1057   app = application_lookup (mp->context);
1058   if (app)
1059     {
1060       a->handle = mp->handle;
1061       a->app_index = app->app_index;
1062       vnet_disconnect_session (a);
1063     }
1064 }
1065
1066 /* ### WILL BE DEPRECATED POST 20.01 ### */
1067 static void
1068 vl_api_map_another_segment_reply_t_handler (vl_api_map_another_segment_reply_t
1069                                             * mp)
1070 {
1071   clib_warning ("not implemented");
1072 }
1073
1074 /* ### WILL BE DEPRECATED POST 20.01 ### */
1075 static void
1076 vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
1077 {
1078   vnet_listen_args_t _a, *a = &_a;
1079   vl_api_bind_sock_reply_t *rmp;
1080   application_t *app = 0;
1081   app_worker_t *app_wrk;
1082   int rv = 0;
1083
1084   if (session_main_is_enabled () == 0)
1085     {
1086       rv = VNET_API_ERROR_FEATURE_DISABLED;
1087       goto done;
1088     }
1089
1090   app = application_lookup (mp->client_index);
1091   if (!app)
1092     {
1093       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1094       goto done;
1095     }
1096
1097   clib_memset (a, 0, sizeof (*a));
1098   ip_address_decode (&mp->ip, &a->sep.ip);
1099   a->sep.is_ip4 = ip46_address_is_ip4 (&a->sep.ip);
1100   a->sep.port = mp->port;
1101   a->sep.fib_index = mp->vrf;
1102   a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
1103   a->sep.transport_proto = api_session_transport_proto_decode (&mp->proto);
1104   a->app_index = app->app_index;
1105   a->wrk_map_index = mp->wrk_index;
1106
1107   if ((rv = vnet_listen (a)))
1108     clib_warning ("listen returned: %d", rv);
1109
1110 done:
1111   /* Actual reply sent only over mq */
1112   REPLY_MACRO (VL_API_BIND_SOCK_REPLY);
1113
1114   if (app)
1115     {
1116       app_wrk = application_get_worker (app, mp->wrk_index);
1117       mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle,
1118                                 rv);
1119     }
1120 }
1121
1122 /* ### WILL BE DEPRECATED POST 20.01 ### */
1123 static void
1124 vl_api_unbind_sock_t_handler (vl_api_unbind_sock_t * mp)
1125 {
1126   vl_api_unbind_sock_reply_t *rmp;
1127   vnet_unlisten_args_t _a, *a = &_a;
1128   app_worker_t *app_wrk;
1129   application_t *app = 0;
1130   int rv = 0;
1131
1132   if (session_main_is_enabled () == 0)
1133     {
1134       rv = VNET_API_ERROR_FEATURE_DISABLED;
1135       goto done;
1136     }
1137
1138   app = application_lookup (mp->client_index);
1139   if (app)
1140     {
1141       a->app_index = app->app_index;
1142       a->handle = mp->handle;
1143       a->wrk_map_index = mp->wrk_index;
1144       if ((rv = vnet_unlisten (a)))
1145         clib_warning ("unlisten returned: %d", rv);
1146     }
1147   else
1148     {
1149       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1150     }
1151
1152 done:
1153   REPLY_MACRO (VL_API_UNBIND_SOCK_REPLY);
1154
1155   if (!app)
1156     return;
1157
1158   app_wrk = application_get_worker (app, a->wrk_map_index);
1159   if (!app_wrk)
1160     return;
1161
1162   mq_send_unlisten_reply (app_wrk, mp->handle, mp->context, rv);
1163 }
1164
1165 /* ### WILL BE DEPRECATED POST 20.01 ### */
1166 static void
1167 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
1168 {
1169   vl_api_connect_sock_reply_t *rmp;
1170   vnet_connect_args_t _a, *a = &_a;
1171   application_t *app = 0;
1172   int rv = 0;
1173
1174   if (session_main_is_enabled () == 0)
1175     {
1176       rv = VNET_API_ERROR_FEATURE_DISABLED;
1177       goto done;
1178     }
1179
1180   app = application_lookup (mp->client_index);
1181   if (app)
1182     {
1183       svm_queue_t *client_q;
1184
1185       clib_memset (a, 0, sizeof (*a));
1186       client_q = vl_api_client_index_to_input_queue (mp->client_index);
1187       mp->client_queue_address = pointer_to_uword (client_q);
1188       ip_address_decode (&mp->ip, &a->sep.ip);
1189       a->sep.is_ip4 = ip46_address_is_ip4 (&a->sep.ip);
1190       a->sep.port = mp->port;
1191       a->sep.transport_proto =
1192         api_session_transport_proto_decode (&mp->proto);
1193       a->sep.peer.fib_index = mp->vrf;
1194       a->sep.peer.sw_if_index = ENDPOINT_INVALID_INDEX;
1195       a->sep_ext.parent_handle = mp->parent_handle;
1196       a->sep_ext.hostname =
1197         (u8 *) vl_api_from_api_to_new_c_string (&mp->hostname);
1198       a->api_context = mp->context;
1199       a->app_index = app->app_index;
1200       a->wrk_map_index = mp->wrk_index;
1201       if ((rv = vnet_connect (a)))
1202         clib_warning ("connect returned: %U", format_vnet_api_errno, rv);
1203       vec_free (a->sep_ext.hostname);
1204     }
1205   else
1206     {
1207       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1208     }
1209
1210   if (rv == 0)
1211     return;
1212
1213   /* Got some error, relay it */
1214
1215 done:
1216   REPLY_MACRO (VL_API_CONNECT_SOCK_REPLY);
1217
1218   if (app)
1219     {
1220       app_worker_t *app_wrk = application_get_worker (app, mp->wrk_index);
1221       mq_send_session_connected_cb (app_wrk->wrk_index, mp->context, 0, 1);
1222     }
1223 }
1224
1225 static void
1226 vl_api_app_worker_add_del_t_handler (vl_api_app_worker_add_del_t * mp)
1227 {
1228   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
1229   vl_api_app_worker_add_del_reply_t *rmp;
1230   vl_api_registration_t *reg;
1231   application_t *app;
1232   u8 fd_flags = 0;
1233
1234   if (session_main_is_enabled () == 0)
1235     {
1236       rv = VNET_API_ERROR_FEATURE_DISABLED;
1237       goto done;
1238     }
1239
1240   reg = vl_api_client_index_to_registration (mp->client_index);
1241   if (!reg)
1242     return;
1243
1244   app = application_get_if_valid (clib_net_to_host_u32 (mp->app_index));
1245   if (!app)
1246     {
1247       rv = VNET_API_ERROR_INVALID_VALUE;
1248       goto done;
1249     }
1250
1251   vnet_app_worker_add_del_args_t args = {
1252     .app_index = app->app_index,
1253     .wrk_map_index = clib_net_to_host_u32 (mp->wrk_index),
1254     .api_client_index = mp->client_index,
1255     .is_add = mp->is_add
1256   };
1257   rv = vnet_app_worker_add_del (&args);
1258   if (rv)
1259     {
1260       clib_warning ("app worker add/del returned: %d", rv);
1261       goto done;
1262     }
1263
1264   if (!mp->is_add)
1265     goto done;
1266
1267   /* Send fifo segment fd if needed */
1268   if (ssvm_type (args.segment) == SSVM_SEGMENT_MEMFD)
1269     {
1270       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1271       fds[n_fds] = args.segment->fd;
1272       n_fds += 1;
1273     }
1274   if (application_segment_manager_properties (app)->use_mq_eventfd)
1275     {
1276       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1277       fds[n_fds] = svm_msg_q_get_producer_eventfd (args.evt_q);
1278       n_fds += 1;
1279     }
1280
1281   /* *INDENT-OFF* */
1282 done:
1283   REPLY_MACRO2 (VL_API_APP_WORKER_ADD_DEL_REPLY, ({
1284     rmp->is_add = mp->is_add;
1285     rmp->wrk_index = clib_host_to_net_u32 (args.wrk_map_index);
1286     rmp->segment_handle = clib_host_to_net_u64 (args.segment_handle);
1287     if (!rv && mp->is_add)
1288       {
1289         if (vec_len (args.segment->name))
1290           {
1291             vl_api_vec_to_api_string (args.segment->name, &rmp->segment_name);
1292           }
1293         rmp->app_event_queue_address = pointer_to_uword (args.evt_q);
1294         rmp->n_fds = n_fds;
1295         rmp->fd_flags = fd_flags;
1296       }
1297   }));
1298   /* *INDENT-ON* */
1299
1300   if (n_fds)
1301     session_send_fds (reg, fds, n_fds);
1302 }
1303
1304 static void
1305 vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp)
1306 {
1307   vl_api_app_namespace_add_del_reply_t *rmp;
1308   u32 appns_index = 0;
1309   u8 *ns_id = 0;
1310   int rv = 0;
1311   if (session_main_is_enabled () == 0)
1312     {
1313       rv = VNET_API_ERROR_FEATURE_DISABLED;
1314       goto done;
1315     }
1316
1317   ns_id = vl_api_from_api_to_new_vec (&mp->namespace_id);
1318
1319   vnet_app_namespace_add_del_args_t args = {
1320     .ns_id = ns_id,
1321     .secret = clib_net_to_host_u64 (mp->secret),
1322     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
1323     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
1324     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
1325     .is_add = 1
1326   };
1327   rv = vnet_app_namespace_add_del (&args);
1328   if (!rv)
1329     {
1330       appns_index = app_namespace_index_from_id (ns_id);
1331       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
1332         {
1333           clib_warning ("app ns lookup failed");
1334           rv = VNET_API_ERROR_UNSPECIFIED;
1335         }
1336     }
1337   vec_free (ns_id);
1338
1339   /* *INDENT-OFF* */
1340 done:
1341   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
1342     if (!rv)
1343       rmp->appns_index = clib_host_to_net_u32 (appns_index);
1344   }));
1345   /* *INDENT-ON* */
1346 }
1347
1348 static void
1349 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
1350 {
1351   vl_api_session_rule_add_del_reply_t *rmp;
1352   session_rule_add_del_args_t args;
1353   session_rule_table_add_del_args_t *table_args = &args.table_args;
1354   int rv = 0;
1355
1356   clib_memset (&args, 0, sizeof (args));
1357
1358   ip_prefix_decode (&mp->lcl, &table_args->lcl);
1359   ip_prefix_decode (&mp->rmt, &table_args->rmt);
1360
1361   table_args->lcl_port = mp->lcl_port;
1362   table_args->rmt_port = mp->rmt_port;
1363   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
1364   table_args->is_add = mp->is_add;
1365   mp->tag[sizeof (mp->tag) - 1] = 0;
1366   table_args->tag = format (0, "%s", mp->tag);
1367   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
1368   args.scope = mp->scope;
1369   args.transport_proto =
1370     api_session_transport_proto_decode (&mp->transport_proto) ==
1371     TRANSPORT_PROTO_UDP ? 1 : 0;
1372
1373   rv = vnet_session_rule_add_del (&args);
1374   if (rv)
1375     clib_warning ("rule add del returned: %d", rv);
1376   vec_free (table_args->tag);
1377   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
1378 }
1379
1380 static void
1381 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
1382                             u8 transport_proto, u32 appns_index, u8 * tag,
1383                             vl_api_registration_t * reg, u32 context)
1384 {
1385   vl_api_session_rules_details_t *rmp = 0;
1386   session_mask_or_match_4_t *match =
1387     (session_mask_or_match_4_t *) & rule->match;
1388   session_mask_or_match_4_t *mask =
1389     (session_mask_or_match_4_t *) & rule->mask;
1390   fib_prefix_t lcl, rmt;
1391
1392   rmp = vl_msg_api_alloc (sizeof (*rmp));
1393   clib_memset (rmp, 0, sizeof (*rmp));
1394   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1395   rmp->context = context;
1396
1397   clib_memset (&lcl, 0, sizeof (lcl));
1398   clib_memset (&rmt, 0, sizeof (rmt));
1399   ip_set (&lcl.fp_addr, &match->lcl_ip, 1);
1400   ip_set (&rmt.fp_addr, &match->rmt_ip, 1);
1401   lcl.fp_len = ip4_mask_to_preflen (&mask->lcl_ip);
1402   rmt.fp_len = ip4_mask_to_preflen (&mask->rmt_ip);
1403
1404   ip_prefix_encode (&lcl, &rmp->lcl);
1405   ip_prefix_encode (&rmt, &rmp->rmt);
1406   rmp->lcl_port = match->lcl_port;
1407   rmp->rmt_port = match->rmt_port;
1408   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1409   rmp->scope =
1410     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
1411   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
1412   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1413   if (tag)
1414     {
1415       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1416       rmp->tag[vec_len (tag)] = 0;
1417     }
1418
1419   vl_api_send_msg (reg, (u8 *) rmp);
1420 }
1421
1422 static void
1423 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
1424                             u8 transport_proto, u32 appns_index, u8 * tag,
1425                             vl_api_registration_t * reg, u32 context)
1426 {
1427   vl_api_session_rules_details_t *rmp = 0;
1428   session_mask_or_match_6_t *match =
1429     (session_mask_or_match_6_t *) & rule->match;
1430   session_mask_or_match_6_t *mask =
1431     (session_mask_or_match_6_t *) & rule->mask;
1432   fib_prefix_t lcl, rmt;
1433
1434   rmp = vl_msg_api_alloc (sizeof (*rmp));
1435   clib_memset (rmp, 0, sizeof (*rmp));
1436   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1437   rmp->context = context;
1438
1439   clib_memset (&lcl, 0, sizeof (lcl));
1440   clib_memset (&rmt, 0, sizeof (rmt));
1441   ip_set (&lcl.fp_addr, &match->lcl_ip, 0);
1442   ip_set (&rmt.fp_addr, &match->rmt_ip, 0);
1443   lcl.fp_len = ip6_mask_to_preflen (&mask->lcl_ip);
1444   rmt.fp_len = ip6_mask_to_preflen (&mask->rmt_ip);
1445
1446   ip_prefix_encode (&lcl, &rmp->lcl);
1447   ip_prefix_encode (&rmt, &rmp->rmt);
1448   rmp->lcl_port = match->lcl_port;
1449   rmp->rmt_port = match->rmt_port;
1450   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1451   rmp->scope =
1452     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
1453   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
1454   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1455   if (tag)
1456     {
1457       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1458       rmp->tag[vec_len (tag)] = 0;
1459     }
1460
1461   vl_api_send_msg (reg, (u8 *) rmp);
1462 }
1463
1464 static void
1465 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
1466                                   u8 tp, u8 is_local, u32 appns_index,
1467                                   vl_api_registration_t * reg, u32 context)
1468 {
1469   mma_rule_16_t *rule16;
1470   mma_rule_40_t *rule40;
1471   mma_rules_table_16_t *srt16;
1472   mma_rules_table_40_t *srt40;
1473   u32 ri;
1474
1475   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
1476     {
1477       u8 *tag = 0;
1478       /* *INDENT-OFF* */
1479       srt16 = &srt->session_rules_tables_16;
1480       pool_foreach (rule16, srt16->rules, ({
1481         ri = mma_rules_table_rule_index_16 (srt16, rule16);
1482         tag = session_rules_table_rule_tag (srt, ri, 1);
1483         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
1484                                     reg, context);
1485       }));
1486       /* *INDENT-ON* */
1487     }
1488   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
1489     {
1490       u8 *tag = 0;
1491       /* *INDENT-OFF* */
1492       srt40 = &srt->session_rules_tables_40;
1493       pool_foreach (rule40, srt40->rules, ({
1494         ri = mma_rules_table_rule_index_40 (srt40, rule40);
1495         tag = session_rules_table_rule_tag (srt, ri, 1);
1496         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
1497                                     reg, context);
1498       }));
1499       /* *INDENT-ON* */
1500     }
1501 }
1502
1503 static void
1504 vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
1505 {
1506   vl_api_registration_t *reg;
1507   session_table_t *st;
1508   u8 tp;
1509
1510   reg = vl_api_client_index_to_registration (mp->client_index);
1511   if (!reg)
1512     return;
1513
1514   /* *INDENT-OFF* */
1515   session_table_foreach (st, ({
1516     for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
1517       {
1518         send_session_rules_table_details (&st->session_rules[tp],
1519                                           st->active_fib_proto, tp,
1520                                           st->is_local, st->appns_index, reg,
1521                                           mp->context);
1522       }
1523   }));
1524   /* *INDENT-ON* */
1525 }
1526
1527 static void
1528 vl_api_app_add_cert_key_pair_t_handler (vl_api_app_add_cert_key_pair_t * mp)
1529 {
1530   vl_api_app_add_cert_key_pair_reply_t *rmp;
1531   vnet_app_add_cert_key_pair_args_t _a, *a = &_a;
1532   u32 certkey_len, key_len, cert_len;
1533   int rv = 0;
1534   if (session_main_is_enabled () == 0)
1535     {
1536       rv = VNET_API_ERROR_FEATURE_DISABLED;
1537       goto done;
1538     }
1539
1540   cert_len = clib_net_to_host_u16 (mp->cert_len);
1541   if (cert_len > 10000)
1542     {
1543       rv = VNET_API_ERROR_INVALID_VALUE;
1544       goto done;
1545     }
1546
1547   certkey_len = clib_net_to_host_u16 (mp->certkey_len);
1548   if (certkey_len < cert_len)
1549     {
1550       rv = VNET_API_ERROR_INVALID_VALUE;
1551       goto done;
1552     }
1553
1554   key_len = certkey_len - cert_len;
1555   if (key_len > 10000)
1556     {
1557       rv = VNET_API_ERROR_INVALID_VALUE;
1558       goto done;
1559     }
1560
1561   clib_memset (a, 0, sizeof (*a));
1562   vec_validate (a->cert, cert_len);
1563   vec_validate (a->key, key_len);
1564   clib_memcpy_fast (a->cert, mp->certkey, cert_len);
1565   clib_memcpy_fast (a->key, mp->certkey + cert_len, key_len);
1566   rv = vnet_app_add_cert_key_pair (a);
1567   vec_free (a->cert);
1568   vec_free (a->key);
1569
1570 done:
1571   /* *INDENT-OFF* */
1572   REPLY_MACRO2 (VL_API_APP_ADD_CERT_KEY_PAIR_REPLY, ({
1573     if (!rv)
1574       rmp->index = clib_host_to_net_u32 (a->index);
1575   }));
1576   /* *INDENT-ON* */
1577 }
1578
1579 static void
1580 vl_api_app_del_cert_key_pair_t_handler (vl_api_app_del_cert_key_pair_t * mp)
1581 {
1582   vl_api_app_del_cert_key_pair_reply_t *rmp;
1583   u32 ckpair_index;
1584   int rv = 0;
1585   if (session_main_is_enabled () == 0)
1586     {
1587       rv = VNET_API_ERROR_FEATURE_DISABLED;
1588       goto done;
1589     }
1590   ckpair_index = clib_net_to_host_u32 (mp->index);
1591   rv = vnet_app_del_cert_key_pair (ckpair_index);
1592
1593 done:
1594   REPLY_MACRO (VL_API_APP_DEL_CERT_KEY_PAIR_REPLY);
1595 }
1596
1597 /* ### WILL BE DEPRECATED POST 20.01 ### */
1598 static void
1599 vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t *
1600                                            mp)
1601 {
1602   vl_api_application_tls_cert_add_reply_t *rmp;
1603   app_cert_key_pair_t *ckpair;
1604   application_t *app;
1605   u32 cert_len;
1606   int rv = 0;
1607   if (session_main_is_enabled () == 0)
1608     {
1609       rv = VNET_API_ERROR_FEATURE_DISABLED;
1610       goto done;
1611     }
1612   if (!(app = application_lookup (mp->client_index)))
1613     {
1614       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1615       goto done;
1616     }
1617   cert_len = clib_net_to_host_u16 (mp->cert_len);
1618   if (cert_len > 10000)
1619     {
1620       rv = VNET_API_ERROR_INVALID_VALUE;
1621       goto done;
1622     }
1623   ckpair = app_cert_key_pair_get_default ();
1624   vec_validate (ckpair->cert, cert_len);
1625   clib_memcpy_fast (ckpair->cert, mp->cert, cert_len);
1626
1627 done:
1628   REPLY_MACRO (VL_API_APPLICATION_TLS_CERT_ADD_REPLY);
1629 }
1630
1631 /* ### WILL BE DEPRECATED POST 20.01 ### */
1632 static void
1633 vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t *
1634                                           mp)
1635 {
1636   vl_api_application_tls_key_add_reply_t *rmp;
1637   app_cert_key_pair_t *ckpair;
1638   application_t *app;
1639   u32 key_len;
1640   int rv = 0;
1641   if (session_main_is_enabled () == 0)
1642     {
1643       rv = VNET_API_ERROR_FEATURE_DISABLED;
1644       goto done;
1645     }
1646   if (!(app = application_lookup (mp->client_index)))
1647     {
1648       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1649       goto done;
1650     }
1651   key_len = clib_net_to_host_u16 (mp->key_len);
1652   if (key_len > 10000)
1653     {
1654       rv = VNET_API_ERROR_INVALID_VALUE;
1655       goto done;
1656     }
1657   ckpair = app_cert_key_pair_get_default ();
1658   vec_validate (ckpair->key, key_len);
1659   clib_memcpy_fast (ckpair->key, mp->key, key_len);
1660 done:
1661   REPLY_MACRO (VL_API_APPLICATION_TLS_KEY_ADD_REPLY);
1662 }
1663
1664 static clib_error_t *
1665 application_reaper_cb (u32 client_index)
1666 {
1667   application_t *app = application_lookup (client_index);
1668   vnet_app_detach_args_t _a, *a = &_a;
1669   if (app)
1670     {
1671       a->app_index = app->app_index;
1672       a->api_client_index = client_index;
1673       vnet_application_detach (a);
1674     }
1675   return 0;
1676 }
1677
1678 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1679
1680 #define vl_msg_name_crc_list
1681 #include <vnet/vnet_all_api_h.h>
1682 #undef vl_msg_name_crc_list
1683
1684 static void
1685 setup_message_id_table (api_main_t * am)
1686 {
1687 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1688   foreach_vl_msg_name_crc_session;
1689 #undef _
1690 }
1691
1692 /*
1693  * session_api_hookup
1694  * Add uri's API message handlers to the table.
1695  * vlib has already mapped shared memory and
1696  * added the client registration handlers.
1697  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
1698  */
1699 static clib_error_t *
1700 session_api_hookup (vlib_main_t * vm)
1701 {
1702   api_main_t *am = vlibapi_get_main ();
1703
1704 #define _(N,n)                                                  \
1705     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1706                            vl_api_##n##_t_handler,              \
1707                            vl_noop_handler,                     \
1708                            vl_api_##n##_t_endian,               \
1709                            vl_api_##n##_t_print,                \
1710                            sizeof(vl_api_##n##_t), 1);
1711   foreach_session_api_msg;
1712 #undef _
1713
1714   /*
1715    * Messages which bounce off the data-plane to
1716    * an API client. Simply tells the message handling infra not
1717    * to free the message.
1718    *
1719    * Bounced message handlers MUST NOT block the data plane
1720    */
1721   am->message_bounce[VL_API_CONNECT_URI] = 1;
1722   am->message_bounce[VL_API_CONNECT_SOCK] = 1;
1723
1724   /*
1725    * Set up the (msg_name, crc, message-id) table
1726    */
1727   setup_message_id_table (am);
1728
1729   return 0;
1730 }
1731
1732 VLIB_API_INIT_FUNCTION (session_api_hookup);
1733
1734 /*
1735  * fd.io coding-style-patch-verification: ON
1736  *
1737  * Local Variables:
1738  * eval: (c-set-style "gnu")
1739  * End:
1740  */