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