api: improve REPLY_MACRO safety
[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 #include <vnet/ip/ip_types_api.h>
25
26 #include <vnet/format_fns.h>
27 #include <vnet/session/session.api_enum.h>
28 #include <vnet/session/session.api_types.h>
29
30 #define REPLY_MSG_ID_BASE session_main.msg_id_base
31 #include <vlibapi/api_helper_macros.h>
32
33 static transport_proto_t
34 api_session_transport_proto_decode (const vl_api_transport_proto_t * api_tp)
35 {
36   switch (*api_tp)
37     {
38     case TRANSPORT_PROTO_API_TCP:
39       return TRANSPORT_PROTO_TCP;
40     case TRANSPORT_PROTO_API_UDP:
41       return TRANSPORT_PROTO_UDP;
42     case TRANSPORT_PROTO_API_TLS:
43       return TRANSPORT_PROTO_TLS;
44     case TRANSPORT_PROTO_API_QUIC:
45       return TRANSPORT_PROTO_QUIC;
46     default:
47       return TRANSPORT_PROTO_NONE;
48     }
49 }
50
51 static vl_api_transport_proto_t
52 api_session_transport_proto_encode (const transport_proto_t tp)
53 {
54   switch (tp)
55     {
56     case TRANSPORT_PROTO_TCP:
57       return TRANSPORT_PROTO_API_TCP;
58     case TRANSPORT_PROTO_UDP:
59       return TRANSPORT_PROTO_API_UDP;
60     case TRANSPORT_PROTO_TLS:
61       return TRANSPORT_PROTO_API_TLS;
62     case TRANSPORT_PROTO_QUIC:
63       return TRANSPORT_PROTO_API_QUIC;
64     default:
65       return TRANSPORT_PROTO_API_NONE;
66     }
67 }
68
69 static int
70 session_send_fds (vl_api_registration_t * reg, int fds[], int n_fds)
71 {
72   clib_error_t *error;
73   if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
74     return SESSION_E_BAPI_NO_FD;
75   error = vl_api_send_fd_msg (reg, fds, n_fds);
76   if (error)
77     {
78       clib_error_report (error);
79       return SESSION_E_BAPI_SEND_FD;
80     }
81   return 0;
82 }
83
84 static int
85 mq_try_lock_and_alloc_msg (svm_msg_q_t * app_mq, svm_msg_q_msg_t * msg)
86 {
87   int rv;
88   u8 try = 0;
89   while (try < 100)
90     {
91       rv = svm_msg_q_lock_and_alloc_msg_w_ring (app_mq,
92                                                 SESSION_MQ_CTRL_EVT_RING,
93                                                 SVM_Q_NOWAIT, msg);
94       if (!rv)
95         return 0;
96       /*
97        * Break the loop if mq is full, usually this is because the
98        * app has crashed or is hanging on somewhere.
99        */
100       if (rv != -1)
101         break;
102       try++;
103       usleep (1);
104     }
105   clib_warning ("failed to alloc msg");
106   return -1;
107 }
108
109 static int
110 mq_send_session_accepted_cb (session_t * s)
111 {
112   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
113   svm_msg_q_msg_t _msg, *msg = &_msg;
114   session_accepted_msg_t m = { 0 };
115   svm_msg_q_t *app_mq;
116   fifo_segment_t *eq_seg;
117   session_t *listener;
118   session_event_t *evt;
119   application_t *app;
120
121   app = application_get (app_wrk->app_index);
122
123   m.context = app->app_index;
124   m.server_rx_fifo = fifo_segment_fifo_offset (s->rx_fifo);
125   m.server_tx_fifo = fifo_segment_fifo_offset (s->tx_fifo);
126   m.segment_handle = session_segment_handle (s);
127   m.flags = s->flags;
128
129   eq_seg = application_get_rx_mqs_segment (app);
130
131   if (session_has_transport (s))
132     {
133       listener = listen_session_get_from_handle (s->listener_handle);
134       m.listener_handle = app_listen_session_handle (listener);
135       if (application_is_proxy (app))
136         {
137           listener =
138             app_worker_first_listener (app_wrk, session_get_fib_proto (s),
139                                        session_get_transport_proto (s));
140           if (listener)
141             m.listener_handle = listen_session_get_handle (listener);
142         }
143       m.vpp_event_queue_address =
144         fifo_segment_msg_q_offset (eq_seg, s->thread_index);
145       m.mq_index = s->thread_index;
146       m.handle = session_handle (s);
147
148       session_get_endpoint (s, &m.rmt, 0 /* is_lcl */);
149       session_get_endpoint (s, &m.lcl, 1 /* is_lcl */);
150     }
151   else
152     {
153       ct_connection_t *ct;
154
155       ct = (ct_connection_t *) session_get_transport (s);
156       listener = listen_session_get_from_handle (s->listener_handle);
157       m.listener_handle = app_listen_session_handle (listener);
158       m.rmt.is_ip4 = session_type_is_ip4 (listener->session_type);
159       m.rmt.port = ct->c_rmt_port;
160       m.lcl.port = ct->c_lcl_port;
161       m.handle = session_handle (s);
162       m.vpp_event_queue_address =
163         fifo_segment_msg_q_offset (eq_seg, s->thread_index);
164       m.mq_index = s->thread_index;
165     }
166
167   app_mq = app_wrk->event_queue;
168   if (mq_try_lock_and_alloc_msg (app_mq, msg))
169     return SESSION_E_MQ_MSG_ALLOC;
170
171   evt = svm_msg_q_msg_data (app_mq, msg);
172   clib_memset (evt, 0, sizeof (*evt));
173   evt->event_type = SESSION_CTRL_EVT_ACCEPTED;
174   clib_memcpy_fast (evt->data, &m, sizeof (m));
175   svm_msg_q_add_and_unlock (app_mq, msg);
176
177   return 0;
178 }
179
180 static inline void
181 mq_send_session_close_evt (app_worker_t * app_wrk, session_handle_t sh,
182                            session_evt_type_t evt_type)
183 {
184   svm_msg_q_msg_t _msg, *msg = &_msg;
185   session_disconnected_msg_t *mp;
186   svm_msg_q_t *app_mq;
187   session_event_t *evt;
188
189   app_mq = app_wrk->event_queue;
190   if (mq_try_lock_and_alloc_msg (app_mq, msg))
191     return;
192   evt = svm_msg_q_msg_data (app_mq, msg);
193   clib_memset (evt, 0, sizeof (*evt));
194   evt->event_type = evt_type;
195   mp = (session_disconnected_msg_t *) evt->data;
196   mp->handle = sh;
197   mp->context = app_wrk->api_client_index;
198   svm_msg_q_add_and_unlock (app_mq, msg);
199 }
200
201 static inline void
202 mq_notify_close_subscribers (u32 app_index, session_handle_t sh,
203                              svm_fifo_t * f, session_evt_type_t evt_type)
204 {
205   app_worker_t *app_wrk;
206   application_t *app;
207   int i;
208
209   app = application_get (app_index);
210   if (!app)
211     return;
212
213   for (i = 0; i < f->shr->n_subscribers; i++)
214     {
215       if (!(app_wrk = application_get_worker (app, f->shr->subscribers[i])))
216         continue;
217       mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_DISCONNECTED);
218     }
219 }
220
221 static void
222 mq_send_session_disconnected_cb (session_t * s)
223 {
224   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
225   session_handle_t sh = session_handle (s);
226
227   mq_send_session_close_evt (app_wrk, session_handle (s),
228                              SESSION_CTRL_EVT_DISCONNECTED);
229
230   if (svm_fifo_n_subscribers (s->rx_fifo))
231     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
232                                  SESSION_CTRL_EVT_DISCONNECTED);
233 }
234
235 static void
236 mq_send_session_reset_cb (session_t * s)
237 {
238   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
239   session_handle_t sh = session_handle (s);
240
241   mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_RESET);
242
243   if (svm_fifo_n_subscribers (s->rx_fifo))
244     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
245                                  SESSION_CTRL_EVT_RESET);
246 }
247
248 int
249 mq_send_session_connected_cb (u32 app_wrk_index, u32 api_context,
250                               session_t * s, session_error_t err)
251 {
252   svm_msg_q_msg_t _msg, *msg = &_msg;
253   session_connected_msg_t m = { 0 };
254   svm_msg_q_t *app_mq;
255   transport_connection_t *tc;
256   fifo_segment_t *eq_seg;
257   app_worker_t *app_wrk;
258   session_event_t *evt;
259   application_t *app;
260
261   app_wrk = app_worker_get (app_wrk_index);
262
263   m.context = api_context;
264   m.retval = err;
265
266   if (err)
267     goto snd_msg;
268
269   app = application_get (app_wrk->app_index);
270   eq_seg = application_get_rx_mqs_segment (app);
271
272   if (session_has_transport (s))
273     {
274       tc = session_get_transport (s);
275       if (!tc)
276         {
277           clib_warning ("failed to retrieve transport!");
278           m.retval = SESSION_E_REFUSED;
279           goto snd_msg;
280         }
281
282       m.handle = session_handle (s);
283       m.vpp_event_queue_address =
284         fifo_segment_msg_q_offset (eq_seg, s->thread_index);
285
286       session_get_endpoint (s, &m.lcl, 1 /* is_lcl */);
287
288       m.server_rx_fifo = fifo_segment_fifo_offset (s->rx_fifo);
289       m.server_tx_fifo = fifo_segment_fifo_offset (s->tx_fifo);
290       m.segment_handle = session_segment_handle (s);
291       m.mq_index = s->thread_index;
292     }
293   else
294     {
295       ct_connection_t *cct;
296       session_t *ss;
297
298       cct = (ct_connection_t *) session_get_transport (s);
299       m.handle = session_handle (s);
300       m.lcl.port = cct->c_lcl_port;
301       m.lcl.is_ip4 = cct->c_is_ip4;
302       m.vpp_event_queue_address =
303         fifo_segment_msg_q_offset (eq_seg, s->thread_index);
304       m.server_rx_fifo = fifo_segment_fifo_offset (s->rx_fifo);
305       m.server_tx_fifo = fifo_segment_fifo_offset (s->tx_fifo);
306       m.segment_handle = session_segment_handle (s);
307       ss = ct_session_get_peer (s);
308       m.ct_rx_fifo = fifo_segment_fifo_offset (ss->tx_fifo);
309       m.ct_tx_fifo = fifo_segment_fifo_offset (ss->rx_fifo);
310       m.ct_segment_handle = session_segment_handle (ss);
311       m.mq_index = s->thread_index;
312     }
313
314   /* Setup client session index in advance, in case data arrives
315    * before the app processes message and updates it */
316   s->rx_fifo->shr->client_session_index = api_context;
317   s->tx_fifo->shr->client_session_index = api_context;
318
319 snd_msg:
320
321   app_mq = app_wrk->event_queue;
322
323   if (mq_try_lock_and_alloc_msg (app_mq, msg))
324     return SESSION_E_MQ_MSG_ALLOC;
325
326   evt = svm_msg_q_msg_data (app_mq, msg);
327   clib_memset (evt, 0, sizeof (*evt));
328   evt->event_type = SESSION_CTRL_EVT_CONNECTED;
329   clib_memcpy_fast (evt->data, &m, sizeof (m));
330
331   svm_msg_q_add_and_unlock (app_mq, msg);
332   return 0;
333 }
334
335 int
336 mq_send_session_bound_cb (u32 app_wrk_index, u32 api_context,
337                           session_handle_t handle, int rv)
338 {
339   svm_msg_q_msg_t _msg, *msg = &_msg;
340   session_bound_msg_t m = { 0 };
341   svm_msg_q_t *app_mq;
342   transport_endpoint_t tep;
343   fifo_segment_t *eq_seg;
344   app_worker_t *app_wrk;
345   session_event_t *evt;
346   application_t *app;
347   app_listener_t *al;
348   session_t *ls = 0;
349
350   app_wrk = app_worker_get (app_wrk_index);
351
352   m.context = api_context;
353   m.retval = rv;
354
355   if (rv)
356     goto snd_msg;
357
358   m.handle = handle;
359   al = app_listener_get_w_handle (handle);
360   if (al->session_index != SESSION_INVALID_INDEX)
361     ls = app_listener_get_session (al);
362   else
363     ls = app_listener_get_local_session (al);
364
365   session_get_endpoint (ls, &tep, 1 /* is_lcl */);
366   m.lcl_port = tep.port;
367   m.lcl_is_ip4 = tep.is_ip4;
368   clib_memcpy_fast (m.lcl_ip, &tep.ip, sizeof (tep.ip));
369   app = application_get (app_wrk->app_index);
370   eq_seg = application_get_rx_mqs_segment (app);
371   m.vpp_evt_q = fifo_segment_msg_q_offset (eq_seg, ls->thread_index);
372   m.mq_index = ls->thread_index;
373
374   if (session_transport_service_type (ls) == TRANSPORT_SERVICE_CL &&
375       ls->rx_fifo)
376     {
377       m.rx_fifo = fifo_segment_fifo_offset (ls->rx_fifo);
378       m.tx_fifo = fifo_segment_fifo_offset (ls->tx_fifo);
379       m.segment_handle = session_segment_handle (ls);
380     }
381
382 snd_msg:
383
384   app_mq = app_wrk->event_queue;
385
386   if (mq_try_lock_and_alloc_msg (app_mq, msg))
387     return SESSION_E_MQ_MSG_ALLOC;
388
389   evt = svm_msg_q_msg_data (app_mq, msg);
390   clib_memset (evt, 0, sizeof (*evt));
391   evt->event_type = SESSION_CTRL_EVT_BOUND;
392   clib_memcpy_fast (evt->data, &m, sizeof (m));
393
394   svm_msg_q_add_and_unlock (app_mq, msg);
395   return 0;
396 }
397
398 void
399 mq_send_unlisten_reply (app_worker_t * app_wrk, session_handle_t sh,
400                         u32 context, int rv)
401 {
402   svm_msg_q_msg_t _msg, *msg = &_msg;
403   session_unlisten_reply_msg_t *ump;
404   svm_msg_q_t *app_mq;
405   session_event_t *evt;
406
407   app_mq = app_wrk->event_queue;
408   if (mq_try_lock_and_alloc_msg (app_mq, msg))
409     return;
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_UNLISTEN_REPLY;
414   ump = (session_unlisten_reply_msg_t *) evt->data;
415   ump->context = context;
416   ump->handle = sh;
417   ump->retval = rv;
418   svm_msg_q_add_and_unlock (app_mq, msg);
419 }
420
421 static void
422 mq_send_session_migrate_cb (session_t * s, session_handle_t new_sh)
423 {
424   svm_msg_q_msg_t _msg, *msg = &_msg;
425   session_migrated_msg_t m = { 0 };
426   fifo_segment_t *eq_seg;
427   app_worker_t *app_wrk;
428   session_event_t *evt;
429   svm_msg_q_t *app_mq;
430   application_t *app;
431   u32 thread_index;
432
433   thread_index = session_thread_from_handle (new_sh);
434   app_wrk = app_worker_get (s->app_wrk_index);
435   app_mq = app_wrk->event_queue;
436   app = application_get (app_wrk->app_index);
437   eq_seg = application_get_rx_mqs_segment (app);
438
439   m.handle = session_handle (s);
440   m.new_handle = new_sh;
441   m.vpp_thread_index = thread_index;
442   m.vpp_evt_q = fifo_segment_msg_q_offset (eq_seg, thread_index);
443   m.segment_handle = SESSION_INVALID_HANDLE;
444
445   if (mq_try_lock_and_alloc_msg (app_mq, msg))
446     return;
447
448   evt = svm_msg_q_msg_data (app_mq, msg);
449   clib_memset (evt, 0, sizeof (*evt));
450   evt->event_type = SESSION_CTRL_EVT_MIGRATED;
451   clib_memcpy_fast (evt->data, &m, sizeof (m));
452
453   svm_msg_q_add_and_unlock (app_mq, msg);
454 }
455
456 static int
457 mq_send_add_segment_cb (u32 app_wrk_index, u64 segment_handle)
458 {
459   int fds[SESSION_N_FD_TYPE], n_fds = 0;
460   svm_msg_q_msg_t _msg, *msg = &_msg;
461   session_app_add_segment_msg_t *mp;
462   vl_api_registration_t *reg;
463   app_worker_t *app_wrk;
464   session_event_t *evt;
465   svm_msg_q_t *app_mq;
466   fifo_segment_t *fs;
467   ssvm_private_t *sp;
468   u8 fd_flags = 0;
469
470   app_wrk = app_worker_get (app_wrk_index);
471
472   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
473   if (!reg)
474     {
475       clib_warning ("no api registration for client: %u",
476                     app_wrk->api_client_index);
477       return -1;
478     }
479
480   fs = segment_manager_get_segment_w_handle (segment_handle);
481   sp = &fs->ssvm;
482   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
483     {
484       if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
485         {
486           clib_warning ("can't send memfd fd");
487           return -1;
488         }
489
490       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
491       fds[n_fds] = sp->fd;
492       n_fds += 1;
493     }
494
495   app_mq = app_wrk->event_queue;
496   if (mq_try_lock_and_alloc_msg (app_mq, msg))
497     return -1;
498
499   if (n_fds)
500     session_send_fds (reg, fds, n_fds);
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_APP_ADD_SEGMENT;
505   mp = (session_app_add_segment_msg_t *) evt->data;
506   clib_memset (mp, 0, sizeof (*mp));
507   mp->segment_size = sp->ssvm_size;
508   mp->fd_flags = fd_flags;
509   mp->segment_handle = segment_handle;
510   strncpy ((char *) mp->segment_name, (char *) sp->name,
511            sizeof (mp->segment_name) - 1);
512
513   svm_msg_q_add_and_unlock (app_mq, msg);
514
515   return 0;
516 }
517
518 static int
519 mq_send_del_segment_cb (u32 app_wrk_index, u64 segment_handle)
520 {
521   svm_msg_q_msg_t _msg, *msg = &_msg;
522   session_app_del_segment_msg_t *mp;
523   vl_api_registration_t *reg;
524   app_worker_t *app_wrk;
525   session_event_t *evt;
526   svm_msg_q_t *app_mq;
527
528   app_wrk = app_worker_get (app_wrk_index);
529   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
530   if (!reg)
531     {
532       clib_warning ("no registration: %u", app_wrk->api_client_index);
533       return -1;
534     }
535
536   app_mq = app_wrk->event_queue;
537   if (mq_try_lock_and_alloc_msg (app_mq, msg))
538     return -1;
539
540   evt = svm_msg_q_msg_data (app_mq, msg);
541   clib_memset (evt, 0, sizeof (*evt));
542   evt->event_type = SESSION_CTRL_EVT_APP_DEL_SEGMENT;
543   mp = (session_app_del_segment_msg_t *) evt->data;
544   clib_memset (mp, 0, sizeof (*mp));
545   mp->segment_handle = segment_handle;
546   svm_msg_q_add_and_unlock (app_mq, msg);
547
548   return 0;
549 }
550
551 static void
552 mq_send_session_cleanup_cb (session_t * s, session_cleanup_ntf_t ntf)
553 {
554   svm_msg_q_msg_t _msg, *msg = &_msg;
555   session_cleanup_msg_t *mp;
556   svm_msg_q_t *app_mq;
557   session_event_t *evt;
558   app_worker_t *app_wrk;
559
560   /* Propagate transport cleanup notifications only if app didn't close */
561   if (ntf == SESSION_CLEANUP_TRANSPORT
562       && s->session_state != SESSION_STATE_TRANSPORT_DELETED)
563     return;
564
565   app_wrk = app_worker_get_if_valid (s->app_wrk_index);
566   if (!app_wrk)
567     return;
568
569   app_mq = app_wrk->event_queue;
570   if (mq_try_lock_and_alloc_msg (app_mq, msg))
571     return;
572
573   evt = svm_msg_q_msg_data (app_mq, msg);
574   clib_memset (evt, 0, sizeof (*evt));
575   evt->event_type = SESSION_CTRL_EVT_CLEANUP;
576   mp = (session_cleanup_msg_t *) evt->data;
577   mp->handle = session_handle (s);
578   mp->type = ntf;
579   svm_msg_q_add_and_unlock (app_mq, msg);
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   .session_cleanup_callback = mq_send_session_cleanup_cb,
589   .add_segment_callback = mq_send_add_segment_cb,
590   .del_segment_callback = mq_send_del_segment_cb,
591 };
592
593 static void
594 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
595 {
596   vl_api_session_enable_disable_reply_t *rmp;
597   vlib_main_t *vm = vlib_get_main ();
598   int rv = 0;
599
600   vnet_session_enable_disable (vm, mp->is_enable);
601   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
602 }
603
604 static void
605 vl_api_session_sapi_enable_disable_t_handler (
606   vl_api_session_sapi_enable_disable_t *mp)
607 {
608   vl_api_session_sapi_enable_disable_reply_t *rmp;
609   int rv = 0;
610
611   rv = appns_sapi_enable_disable (mp->is_enable);
612   REPLY_MACRO (VL_API_SESSION_SAPI_ENABLE_DISABLE_REPLY);
613 }
614
615 static void
616 vl_api_app_attach_t_handler (vl_api_app_attach_t * mp)
617 {
618   int rv = 0, *fds = 0, n_fds = 0, n_workers, i;
619   fifo_segment_t *segp, *rx_mqs_seg = 0;
620   vnet_app_attach_args_t _a, *a = &_a;
621   vl_api_app_attach_reply_t *rmp;
622   u8 fd_flags = 0, ctrl_thread;
623   vl_api_registration_t *reg;
624   svm_msg_q_t *rx_mq;
625   application_t *app;
626
627   reg = vl_api_client_index_to_registration (mp->client_index);
628   if (!reg)
629     return;
630
631   n_workers = vlib_num_workers ();
632   if (!session_main_is_enabled () || appns_sapi_enabled ())
633     {
634       rv = VNET_API_ERROR_FEATURE_DISABLED;
635       goto done;
636     }
637   /* Only support binary api with socket transport */
638   if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
639     {
640       rv = VNET_API_ERROR_APP_UNSUPPORTED_CFG;
641       goto done;
642     }
643
644   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
645                  sizeof (mp->options),
646                  "Out of options, fix api message definition");
647
648   clib_memset (a, 0, sizeof (*a));
649   a->api_client_index = mp->client_index;
650   a->options = mp->options;
651   a->session_cb_vft = &session_mq_cb_vft;
652   a->namespace_id = vl_api_from_api_to_new_vec (mp, &mp->namespace_id);
653
654   if ((rv = vnet_application_attach (a)))
655     {
656       clib_warning ("attach returned: %d", rv);
657       vec_free (a->namespace_id);
658       goto done;
659     }
660   vec_free (a->namespace_id);
661
662   vec_validate (fds, 3 /* segs + tx evtfd */ + n_workers);
663
664   /* Send rx mqs segment */
665   app = application_get (a->app_index);
666   rx_mqs_seg = application_get_rx_mqs_segment (app);
667
668   fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
669   fds[n_fds] = rx_mqs_seg->ssvm.fd;
670   n_fds += 1;
671
672   /* Send fifo segment fd if needed */
673   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
674     {
675       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
676       fds[n_fds] = a->segment->fd;
677       n_fds += 1;
678     }
679   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
680     {
681       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
682       fds[n_fds] = svm_msg_q_get_eventfd (a->app_evt_q);
683       n_fds += 1;
684     }
685
686   if (application_use_private_rx_mqs ())
687     {
688       fd_flags |= SESSION_FD_F_VPP_MQ_EVENTFD;
689       for (i = 0; i < n_workers + 1; i++)
690         {
691           rx_mq = application_rx_mq_get (app, i);
692           fds[n_fds] = svm_msg_q_get_eventfd (rx_mq);
693           n_fds += 1;
694         }
695     }
696
697 done:
698   /* *INDENT-OFF* */
699   REPLY_MACRO3 (
700     VL_API_APP_ATTACH_REPLY,
701     ((!rv) ? vec_len (((fifo_segment_t *) a->segment)->ssvm.name) : 0), ({
702       if (!rv)
703         {
704           ctrl_thread = n_workers ? 1 : 0;
705           segp = (fifo_segment_t *) a->segment;
706           rmp->app_index = clib_host_to_net_u32 (a->app_index);
707           rmp->app_mq = fifo_segment_msg_q_offset (segp, 0);
708           rmp->vpp_ctrl_mq =
709             fifo_segment_msg_q_offset (rx_mqs_seg, ctrl_thread);
710           rmp->vpp_ctrl_mq_thread = ctrl_thread;
711           rmp->n_fds = n_fds;
712           rmp->fd_flags = fd_flags;
713           if (vec_len (segp->ssvm.name))
714             {
715               vl_api_vec_to_api_string (segp->ssvm.name, &rmp->segment_name);
716             }
717           rmp->segment_size = segp->ssvm.ssvm_size;
718           rmp->segment_handle = clib_host_to_net_u64 (a->segment_handle);
719         }
720     }));
721   /* *INDENT-ON* */
722
723   if (n_fds)
724     session_send_fds (reg, fds, n_fds);
725   vec_free (fds);
726 }
727
728 static void
729 vl_api_app_worker_add_del_t_handler (vl_api_app_worker_add_del_t * mp)
730 {
731   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
732   vl_api_app_worker_add_del_reply_t *rmp;
733   vl_api_registration_t *reg;
734   application_t *app;
735   u8 fd_flags = 0;
736
737   if (!session_main_is_enabled () || appns_sapi_enabled ())
738     {
739       rv = VNET_API_ERROR_FEATURE_DISABLED;
740       goto done;
741     }
742
743   reg = vl_api_client_index_to_registration (mp->client_index);
744   if (!reg)
745     return;
746
747   app = application_get_if_valid (clib_net_to_host_u32 (mp->app_index));
748   if (!app)
749     {
750       rv = VNET_API_ERROR_INVALID_VALUE;
751       goto done;
752     }
753
754   vnet_app_worker_add_del_args_t args = {
755     .app_index = app->app_index,
756     .wrk_map_index = clib_net_to_host_u32 (mp->wrk_index),
757     .api_client_index = mp->client_index,
758     .is_add = mp->is_add
759   };
760   rv = vnet_app_worker_add_del (&args);
761   if (rv)
762     {
763       clib_warning ("app worker add/del returned: %d", rv);
764       goto done;
765     }
766
767   if (!mp->is_add)
768     goto done;
769
770   /* Send fifo segment fd if needed */
771   if (ssvm_type (args.segment) == SSVM_SEGMENT_MEMFD)
772     {
773       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
774       fds[n_fds] = args.segment->fd;
775       n_fds += 1;
776     }
777   if (application_segment_manager_properties (app)->use_mq_eventfd)
778     {
779       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
780       fds[n_fds] = svm_msg_q_get_eventfd (args.evt_q);
781       n_fds += 1;
782     }
783
784   /* *INDENT-OFF* */
785 done:
786   REPLY_MACRO3 (
787     VL_API_APP_WORKER_ADD_DEL_REPLY,
788     ((!rv && mp->is_add) ? vec_len (args.segment->name) : 0), ({
789       rmp->is_add = mp->is_add;
790       rmp->wrk_index = clib_host_to_net_u32 (args.wrk_map_index);
791       rmp->segment_handle = clib_host_to_net_u64 (args.segment_handle);
792       if (!rv && mp->is_add)
793         {
794           rmp->app_event_queue_address =
795             fifo_segment_msg_q_offset ((fifo_segment_t *) args.segment, 0);
796           rmp->n_fds = n_fds;
797           rmp->fd_flags = fd_flags;
798           if (vec_len (args.segment->name))
799             {
800               vl_api_vec_to_api_string (args.segment->name,
801                                         &rmp->segment_name);
802             }
803         }
804     }));
805   /* *INDENT-ON* */
806
807   if (n_fds)
808     session_send_fds (reg, fds, n_fds);
809 }
810
811 static void
812 vl_api_application_detach_t_handler (vl_api_application_detach_t * mp)
813 {
814   vl_api_application_detach_reply_t *rmp;
815   int rv = VNET_API_ERROR_INVALID_VALUE_2;
816   vnet_app_detach_args_t _a, *a = &_a;
817   application_t *app;
818
819   if (!session_main_is_enabled () || appns_sapi_enabled ())
820     {
821       rv = VNET_API_ERROR_FEATURE_DISABLED;
822       goto done;
823     }
824
825   app = application_lookup (mp->client_index);
826   if (app)
827     {
828       a->app_index = app->app_index;
829       a->api_client_index = mp->client_index;
830       rv = vnet_application_detach (a);
831     }
832
833 done:
834   REPLY_MACRO (VL_API_APPLICATION_DETACH_REPLY);
835 }
836
837 static void
838 vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp)
839 {
840   vl_api_app_namespace_add_del_reply_t *rmp;
841   u32 appns_index = 0;
842   u8 *ns_id = 0;
843   int rv = 0;
844   if (session_main_is_enabled () == 0)
845     {
846       rv = VNET_API_ERROR_FEATURE_DISABLED;
847       goto done;
848     }
849
850   ns_id = vl_api_from_api_to_new_vec (mp, &mp->namespace_id);
851
852   vnet_app_namespace_add_del_args_t args = {
853     .ns_id = ns_id,
854     .netns = 0,
855     .sock_name = 0,
856     .secret = clib_net_to_host_u64 (mp->secret),
857     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
858     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
859     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
860     .is_add = 1
861   };
862   rv = vnet_app_namespace_add_del (&args);
863   if (!rv)
864     {
865       appns_index = app_namespace_index_from_id (ns_id);
866       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
867         {
868           clib_warning ("app ns lookup failed");
869           rv = VNET_API_ERROR_UNSPECIFIED;
870         }
871     }
872   vec_free (ns_id);
873
874   /* *INDENT-OFF* */
875 done:
876   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
877     if (!rv)
878       rmp->appns_index = clib_host_to_net_u32 (appns_index);
879   }));
880   /* *INDENT-ON* */
881 }
882
883 static void
884 vl_api_app_namespace_add_del_v2_t_handler (
885   vl_api_app_namespace_add_del_v2_t *mp)
886 {
887   vl_api_app_namespace_add_del_v2_reply_t *rmp;
888   u8 *ns_id = 0, *netns = 0;
889   u32 appns_index = 0;
890   int rv = 0;
891
892   if (session_main_is_enabled () == 0)
893     {
894       rv = VNET_API_ERROR_FEATURE_DISABLED;
895       goto done;
896     }
897
898   mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0;
899   mp->netns[sizeof (mp->netns) - 1] = 0;
900   ns_id = format (0, "%s", &mp->namespace_id);
901   netns = format (0, "%s", &mp->netns);
902
903   vnet_app_namespace_add_del_args_t args = {
904     .ns_id = ns_id,
905     .netns = netns,
906     .sock_name = 0,
907     .secret = clib_net_to_host_u64 (mp->secret),
908     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
909     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
910     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
911     .is_add = 1
912   };
913   rv = vnet_app_namespace_add_del (&args);
914   if (!rv)
915     {
916       appns_index = app_namespace_index_from_id (ns_id);
917       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
918         {
919           clib_warning ("app ns lookup failed id:%s", ns_id);
920           rv = VNET_API_ERROR_UNSPECIFIED;
921         }
922     }
923   vec_free (ns_id);
924   vec_free (netns);
925
926 done:
927   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V2_REPLY, ({
928                   if (!rv)
929                     rmp->appns_index = clib_host_to_net_u32 (appns_index);
930                 }));
931 }
932
933 static void
934 vl_api_app_namespace_add_del_v3_t_handler (
935   vl_api_app_namespace_add_del_v3_t *mp)
936 {
937   vl_api_app_namespace_add_del_v3_reply_t *rmp;
938   u8 *ns_id = 0, *netns = 0, *sock_name = 0;
939   u32 appns_index = 0;
940   int rv = 0;
941   if (session_main_is_enabled () == 0)
942     {
943       rv = VNET_API_ERROR_FEATURE_DISABLED;
944       goto done;
945     }
946   mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0;
947   mp->netns[sizeof (mp->netns) - 1] = 0;
948   ns_id = format (0, "%s", &mp->namespace_id);
949   netns = format (0, "%s", &mp->netns);
950   sock_name = vl_api_from_api_to_new_vec (mp, &mp->sock_name);
951   vnet_app_namespace_add_del_args_t args = {
952     .ns_id = ns_id,
953     .netns = netns,
954     .sock_name = sock_name,
955     .secret = clib_net_to_host_u64 (mp->secret),
956     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
957     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
958     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
959     .is_add = mp->is_add,
960   };
961   rv = vnet_app_namespace_add_del (&args);
962   if (!rv && mp->is_add)
963     {
964       appns_index = app_namespace_index_from_id (ns_id);
965       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
966         {
967           clib_warning ("app ns lookup failed id:%s", ns_id);
968           rv = VNET_API_ERROR_UNSPECIFIED;
969         }
970     }
971   vec_free (ns_id);
972   vec_free (netns);
973   vec_free (sock_name);
974 done:
975   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V3_REPLY, ({
976                   if (!rv)
977                     rmp->appns_index = clib_host_to_net_u32 (appns_index);
978                 }));
979 }
980
981 static void
982 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
983 {
984   vl_api_session_rule_add_del_reply_t *rmp;
985   session_rule_add_del_args_t args;
986   session_rule_table_add_del_args_t *table_args = &args.table_args;
987   int rv = 0;
988
989   clib_memset (&args, 0, sizeof (args));
990
991   ip_prefix_decode (&mp->lcl, &table_args->lcl);
992   ip_prefix_decode (&mp->rmt, &table_args->rmt);
993
994   table_args->lcl_port = mp->lcl_port;
995   table_args->rmt_port = mp->rmt_port;
996   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
997   table_args->is_add = mp->is_add;
998   mp->tag[sizeof (mp->tag) - 1] = 0;
999   table_args->tag = format (0, "%s", mp->tag);
1000   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
1001   args.scope = mp->scope;
1002   args.transport_proto =
1003     api_session_transport_proto_decode (&mp->transport_proto) ==
1004     TRANSPORT_PROTO_UDP ? 1 : 0;
1005
1006   rv = vnet_session_rule_add_del (&args);
1007   if (rv)
1008     clib_warning ("rule add del returned: %d", rv);
1009   vec_free (table_args->tag);
1010   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
1011 }
1012
1013 static void
1014 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
1015                             u8 transport_proto, u32 appns_index, u8 * tag,
1016                             vl_api_registration_t * reg, u32 context)
1017 {
1018   vl_api_session_rules_details_t *rmp = 0;
1019   session_mask_or_match_4_t *match =
1020     (session_mask_or_match_4_t *) & rule->match;
1021   session_mask_or_match_4_t *mask =
1022     (session_mask_or_match_4_t *) & rule->mask;
1023   fib_prefix_t lcl, rmt;
1024
1025   rmp = vl_msg_api_alloc (sizeof (*rmp));
1026   clib_memset (rmp, 0, sizeof (*rmp));
1027   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_DETAILS);
1028   rmp->context = context;
1029
1030   clib_memset (&lcl, 0, sizeof (lcl));
1031   clib_memset (&rmt, 0, sizeof (rmt));
1032   ip_set (&lcl.fp_addr, &match->lcl_ip, 1);
1033   ip_set (&rmt.fp_addr, &match->rmt_ip, 1);
1034   lcl.fp_len = ip4_mask_to_preflen (&mask->lcl_ip);
1035   rmt.fp_len = ip4_mask_to_preflen (&mask->rmt_ip);
1036
1037   ip_prefix_encode (&lcl, &rmp->lcl);
1038   ip_prefix_encode (&rmt, &rmp->rmt);
1039   rmp->lcl_port = match->lcl_port;
1040   rmp->rmt_port = match->rmt_port;
1041   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1042   rmp->scope =
1043     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
1044   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
1045   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1046   if (tag)
1047     {
1048       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1049       rmp->tag[vec_len (tag)] = 0;
1050     }
1051
1052   vl_api_send_msg (reg, (u8 *) rmp);
1053 }
1054
1055 static void
1056 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
1057                             u8 transport_proto, u32 appns_index, u8 * tag,
1058                             vl_api_registration_t * reg, u32 context)
1059 {
1060   vl_api_session_rules_details_t *rmp = 0;
1061   session_mask_or_match_6_t *match =
1062     (session_mask_or_match_6_t *) & rule->match;
1063   session_mask_or_match_6_t *mask =
1064     (session_mask_or_match_6_t *) & rule->mask;
1065   fib_prefix_t lcl, rmt;
1066
1067   rmp = vl_msg_api_alloc (sizeof (*rmp));
1068   clib_memset (rmp, 0, sizeof (*rmp));
1069   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_DETAILS);
1070   rmp->context = context;
1071
1072   clib_memset (&lcl, 0, sizeof (lcl));
1073   clib_memset (&rmt, 0, sizeof (rmt));
1074   ip_set (&lcl.fp_addr, &match->lcl_ip, 0);
1075   ip_set (&rmt.fp_addr, &match->rmt_ip, 0);
1076   lcl.fp_len = ip6_mask_to_preflen (&mask->lcl_ip);
1077   rmt.fp_len = ip6_mask_to_preflen (&mask->rmt_ip);
1078
1079   ip_prefix_encode (&lcl, &rmp->lcl);
1080   ip_prefix_encode (&rmt, &rmp->rmt);
1081   rmp->lcl_port = match->lcl_port;
1082   rmp->rmt_port = match->rmt_port;
1083   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1084   rmp->scope =
1085     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
1086   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
1087   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1088   if (tag)
1089     {
1090       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1091       rmp->tag[vec_len (tag)] = 0;
1092     }
1093
1094   vl_api_send_msg (reg, (u8 *) rmp);
1095 }
1096
1097 static void
1098 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
1099                                   u8 tp, u8 is_local, u32 appns_index,
1100                                   vl_api_registration_t * reg, u32 context)
1101 {
1102   mma_rule_16_t *rule16;
1103   mma_rule_40_t *rule40;
1104   mma_rules_table_16_t *srt16;
1105   mma_rules_table_40_t *srt40;
1106   u32 ri;
1107
1108   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
1109     {
1110       u8 *tag = 0;
1111       /* *INDENT-OFF* */
1112       srt16 = &srt->session_rules_tables_16;
1113       pool_foreach (rule16, srt16->rules)  {
1114         ri = mma_rules_table_rule_index_16 (srt16, rule16);
1115         tag = session_rules_table_rule_tag (srt, ri, 1);
1116         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
1117                                     reg, context);
1118       }
1119       /* *INDENT-ON* */
1120     }
1121   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
1122     {
1123       u8 *tag = 0;
1124       /* *INDENT-OFF* */
1125       srt40 = &srt->session_rules_tables_40;
1126       pool_foreach (rule40, srt40->rules)  {
1127         ri = mma_rules_table_rule_index_40 (srt40, rule40);
1128         tag = session_rules_table_rule_tag (srt, ri, 1);
1129         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
1130                                     reg, context);
1131       }
1132       /* *INDENT-ON* */
1133     }
1134 }
1135
1136 static void
1137 vl_api_session_rules_dump_t_handler (vl_api_session_rules_dump_t * mp)
1138 {
1139   vl_api_registration_t *reg;
1140   session_table_t *st;
1141   u8 tp;
1142
1143   reg = vl_api_client_index_to_registration (mp->client_index);
1144   if (!reg)
1145     return;
1146
1147   /* *INDENT-OFF* */
1148   session_table_foreach (st, ({
1149     for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
1150       {
1151         send_session_rules_table_details (&st->session_rules[tp],
1152                                           st->active_fib_proto, tp,
1153                                           st->is_local, st->appns_index, reg,
1154                                           mp->context);
1155       }
1156   }));
1157   /* *INDENT-ON* */
1158 }
1159
1160 static void
1161 vl_api_app_add_cert_key_pair_t_handler (vl_api_app_add_cert_key_pair_t * mp)
1162 {
1163   vl_api_app_add_cert_key_pair_reply_t *rmp;
1164   vnet_app_add_cert_key_pair_args_t _a, *a = &_a;
1165   u32 certkey_len, key_len, cert_len;
1166   int rv = 0;
1167   if (session_main_is_enabled () == 0)
1168     {
1169       rv = VNET_API_ERROR_FEATURE_DISABLED;
1170       goto done;
1171     }
1172
1173   cert_len = clib_net_to_host_u16 (mp->cert_len);
1174   if (cert_len > 10000)
1175     {
1176       rv = VNET_API_ERROR_INVALID_VALUE;
1177       goto done;
1178     }
1179
1180   certkey_len = clib_net_to_host_u16 (mp->certkey_len);
1181   if (certkey_len < cert_len)
1182     {
1183       rv = VNET_API_ERROR_INVALID_VALUE;
1184       goto done;
1185     }
1186
1187   key_len = certkey_len - cert_len;
1188   if (key_len > 10000)
1189     {
1190       rv = VNET_API_ERROR_INVALID_VALUE;
1191       goto done;
1192     }
1193
1194   clib_memset (a, 0, sizeof (*a));
1195   a->cert = mp->certkey;
1196   a->key = mp->certkey + cert_len;
1197   a->cert_len = cert_len;
1198   a->key_len = key_len;
1199   rv = vnet_app_add_cert_key_pair (a);
1200
1201 done:
1202   /* *INDENT-OFF* */
1203   REPLY_MACRO2 (VL_API_APP_ADD_CERT_KEY_PAIR_REPLY, ({
1204     if (!rv)
1205       rmp->index = clib_host_to_net_u32 (a->index);
1206   }));
1207   /* *INDENT-ON* */
1208 }
1209
1210 static void
1211 vl_api_app_del_cert_key_pair_t_handler (vl_api_app_del_cert_key_pair_t * mp)
1212 {
1213   vl_api_app_del_cert_key_pair_reply_t *rmp;
1214   u32 ckpair_index;
1215   int rv = 0;
1216   if (session_main_is_enabled () == 0)
1217     {
1218       rv = VNET_API_ERROR_FEATURE_DISABLED;
1219       goto done;
1220     }
1221   ckpair_index = clib_net_to_host_u32 (mp->index);
1222   rv = vnet_app_del_cert_key_pair (ckpair_index);
1223
1224 done:
1225   REPLY_MACRO (VL_API_APP_DEL_CERT_KEY_PAIR_REPLY);
1226 }
1227
1228 static clib_error_t *
1229 application_reaper_cb (u32 client_index)
1230 {
1231   application_t *app = application_lookup (client_index);
1232   vnet_app_detach_args_t _a, *a = &_a;
1233   if (app)
1234     {
1235       a->app_index = app->app_index;
1236       a->api_client_index = client_index;
1237       vnet_application_detach (a);
1238     }
1239   return 0;
1240 }
1241
1242 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1243
1244 /*
1245  * Socket api functions
1246  */
1247
1248 static void
1249 sapi_send_fds (app_worker_t * app_wrk, int *fds, int n_fds)
1250 {
1251   app_sapi_msg_t smsg = { 0 };
1252   app_namespace_t *app_ns;
1253   application_t *app;
1254   clib_socket_t *cs;
1255   u32 cs_index;
1256
1257   app = application_get (app_wrk->app_index);
1258   app_ns = app_namespace_get (app->ns_index);
1259   cs_index = appns_sapi_handle_sock_index (app_wrk->api_client_index);
1260   cs = appns_sapi_get_socket (app_ns, cs_index);
1261   if (PREDICT_FALSE (!cs))
1262     return;
1263
1264   /* There's no payload for the message only the type */
1265   smsg.type = APP_SAPI_MSG_TYPE_SEND_FDS;
1266   clib_socket_sendmsg (cs, &smsg, sizeof (smsg), fds, n_fds);
1267 }
1268
1269 static int
1270 mq_send_add_segment_sapi_cb (u32 app_wrk_index, u64 segment_handle)
1271 {
1272   int fds[SESSION_N_FD_TYPE], n_fds = 0;
1273   svm_msg_q_msg_t _msg, *msg = &_msg;
1274   session_app_add_segment_msg_t *mp;
1275   app_worker_t *app_wrk;
1276   session_event_t *evt;
1277   svm_msg_q_t *app_mq;
1278   fifo_segment_t *fs;
1279   ssvm_private_t *sp;
1280   u8 fd_flags = 0;
1281
1282   app_wrk = app_worker_get (app_wrk_index);
1283
1284   fs = segment_manager_get_segment_w_handle (segment_handle);
1285   sp = &fs->ssvm;
1286   ASSERT (ssvm_type (sp) == SSVM_SEGMENT_MEMFD);
1287
1288   fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1289   fds[n_fds] = sp->fd;
1290   n_fds += 1;
1291
1292   app_mq = app_wrk->event_queue;
1293   if (mq_try_lock_and_alloc_msg (app_mq, msg))
1294     return -1;
1295
1296   /*
1297    * Send the fd over api socket
1298    */
1299   sapi_send_fds (app_wrk, fds, n_fds);
1300
1301   /*
1302    * Send the actual message over mq
1303    */
1304   evt = svm_msg_q_msg_data (app_mq, msg);
1305   clib_memset (evt, 0, sizeof (*evt));
1306   evt->event_type = SESSION_CTRL_EVT_APP_ADD_SEGMENT;
1307   mp = (session_app_add_segment_msg_t *) evt->data;
1308   clib_memset (mp, 0, sizeof (*mp));
1309   mp->segment_size = sp->ssvm_size;
1310   mp->fd_flags = fd_flags;
1311   mp->segment_handle = segment_handle;
1312   strncpy ((char *) mp->segment_name, (char *) sp->name,
1313            sizeof (mp->segment_name) - 1);
1314
1315   svm_msg_q_add_and_unlock (app_mq, msg);
1316
1317   return 0;
1318 }
1319
1320 static int
1321 mq_send_del_segment_sapi_cb (u32 app_wrk_index, u64 segment_handle)
1322 {
1323   svm_msg_q_msg_t _msg, *msg = &_msg;
1324   session_app_del_segment_msg_t *mp;
1325   app_worker_t *app_wrk;
1326   session_event_t *evt;
1327   svm_msg_q_t *app_mq;
1328
1329   app_wrk = app_worker_get (app_wrk_index);
1330
1331   app_mq = app_wrk->event_queue;
1332   if (mq_try_lock_and_alloc_msg (app_mq, msg))
1333     return -1;
1334
1335   evt = svm_msg_q_msg_data (app_mq, msg);
1336   clib_memset (evt, 0, sizeof (*evt));
1337   evt->event_type = SESSION_CTRL_EVT_APP_DEL_SEGMENT;
1338   mp = (session_app_del_segment_msg_t *) evt->data;
1339   clib_memset (mp, 0, sizeof (*mp));
1340   mp->segment_handle = segment_handle;
1341   svm_msg_q_add_and_unlock (app_mq, msg);
1342
1343   return 0;
1344 }
1345
1346 static session_cb_vft_t session_mq_sapi_cb_vft = {
1347   .session_accept_callback = mq_send_session_accepted_cb,
1348   .session_disconnect_callback = mq_send_session_disconnected_cb,
1349   .session_connected_callback = mq_send_session_connected_cb,
1350   .session_reset_callback = mq_send_session_reset_cb,
1351   .session_migrate_callback = mq_send_session_migrate_cb,
1352   .session_cleanup_callback = mq_send_session_cleanup_cb,
1353   .add_segment_callback = mq_send_add_segment_sapi_cb,
1354   .del_segment_callback = mq_send_del_segment_sapi_cb,
1355 };
1356
1357 static void
1358 session_api_attach_handler (app_namespace_t * app_ns, clib_socket_t * cs,
1359                             app_sapi_attach_msg_t * mp)
1360 {
1361   int rv = 0, *fds = 0, n_fds = 0, i, n_workers;
1362   vnet_app_attach_args_t _a, *a = &_a;
1363   app_sapi_attach_reply_msg_t *rmp;
1364   u8 fd_flags = 0, ctrl_thread;
1365   app_ns_api_handle_t *handle;
1366   fifo_segment_t *rx_mqs_seg;
1367   app_sapi_msg_t msg = { 0 };
1368   app_worker_t *app_wrk;
1369   application_t *app;
1370   svm_msg_q_t *rx_mq;
1371
1372   /* Make sure name is null terminated */
1373   mp->name[63] = 0;
1374
1375   clib_memset (a, 0, sizeof (*a));
1376   a->api_client_index = appns_sapi_socket_handle (app_ns, cs);
1377   a->name = format (0, "%s", (char *) mp->name);
1378   a->options = mp->options;
1379   a->session_cb_vft = &session_mq_sapi_cb_vft;
1380   a->use_sock_api = 1;
1381   a->options[APP_OPTIONS_NAMESPACE] = app_namespace_index (app_ns);
1382
1383   if ((rv = vnet_application_attach (a)))
1384     {
1385       clib_warning ("attach returned: %d", rv);
1386       goto done;
1387     }
1388
1389   n_workers = vlib_num_workers ();
1390   vec_validate (fds, 3 /* segs + tx evtfd */ + n_workers);
1391
1392   /* Send event queues segment */
1393   app = application_get (a->app_index);
1394   rx_mqs_seg = application_get_rx_mqs_segment (app);
1395
1396   fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
1397   fds[n_fds] = rx_mqs_seg->ssvm.fd;
1398   n_fds += 1;
1399
1400   /* Send fifo segment fd if needed */
1401   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
1402     {
1403       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1404       fds[n_fds] = a->segment->fd;
1405       n_fds += 1;
1406     }
1407   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
1408     {
1409       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1410       fds[n_fds] = svm_msg_q_get_eventfd (a->app_evt_q);
1411       n_fds += 1;
1412     }
1413
1414   if (application_use_private_rx_mqs ())
1415     {
1416       fd_flags |= SESSION_FD_F_VPP_MQ_EVENTFD;
1417       for (i = 0; i < n_workers + 1; i++)
1418         {
1419           rx_mq = application_rx_mq_get (app, i);
1420           fds[n_fds] = svm_msg_q_get_eventfd (rx_mq);
1421           n_fds += 1;
1422         }
1423     }
1424
1425 done:
1426
1427   msg.type = APP_SAPI_MSG_TYPE_ATTACH_REPLY;
1428   rmp = &msg.attach_reply;
1429   rmp->retval = rv;
1430   if (!rv)
1431     {
1432       ctrl_thread = n_workers ? 1 : 0;
1433       rmp->app_index = a->app_index;
1434       rmp->app_mq =
1435         fifo_segment_msg_q_offset ((fifo_segment_t *) a->segment, 0);
1436       rmp->vpp_ctrl_mq = fifo_segment_msg_q_offset (rx_mqs_seg, ctrl_thread);
1437       rmp->vpp_ctrl_mq_thread = ctrl_thread;
1438       rmp->n_fds = n_fds;
1439       rmp->fd_flags = fd_flags;
1440       /* No segment name and size since we only support memfds
1441        * in this configuration */
1442       rmp->segment_handle = a->segment_handle;
1443       rmp->api_client_handle = a->api_client_index;
1444
1445       /* Update app index for socket */
1446       handle = (app_ns_api_handle_t *) & cs->private_data;
1447       app_wrk = application_get_worker (app, 0);
1448       handle->aah_app_wrk_index = app_wrk->wrk_index;
1449     }
1450
1451   clib_socket_sendmsg (cs, &msg, sizeof (msg), fds, n_fds);
1452   vec_free (a->name);
1453   vec_free (fds);
1454 }
1455
1456 void
1457 sapi_socket_close_w_handle (u32 api_handle)
1458 {
1459   app_namespace_t *app_ns = app_namespace_get (api_handle >> 16);
1460   u16 sock_index = api_handle & 0xffff;
1461   app_ns_api_handle_t *handle;
1462   clib_socket_t *cs;
1463   clib_file_t *cf;
1464
1465   cs = appns_sapi_get_socket (app_ns, sock_index);
1466   if (!cs)
1467     return;
1468
1469   handle = (app_ns_api_handle_t *) & cs->private_data;
1470   cf = clib_file_get (&file_main, handle->aah_file_index);
1471   clib_file_del (&file_main, cf);
1472
1473   clib_socket_close (cs);
1474   appns_sapi_free_socket (app_ns, cs);
1475 }
1476
1477 static void
1478 sapi_add_del_worker_handler (app_namespace_t * app_ns,
1479                              clib_socket_t * cs,
1480                              app_sapi_worker_add_del_msg_t * mp)
1481 {
1482   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
1483   app_sapi_worker_add_del_reply_msg_t *rmp;
1484   app_ns_api_handle_t *handle;
1485   app_sapi_msg_t msg = { 0 };
1486   app_worker_t *app_wrk;
1487   u32 sapi_handle = -1;
1488   application_t *app;
1489   u8 fd_flags = 0;
1490
1491   app = application_get_if_valid (mp->app_index);
1492   if (!app)
1493     {
1494       rv = VNET_API_ERROR_INVALID_VALUE;
1495       goto done;
1496     }
1497
1498   sapi_handle = appns_sapi_socket_handle (app_ns, cs);
1499
1500   vnet_app_worker_add_del_args_t args = {
1501     .app_index = app->app_index,
1502     .wrk_map_index = mp->wrk_index,
1503     .api_client_index = sapi_handle,
1504     .is_add = mp->is_add
1505   };
1506   rv = vnet_app_worker_add_del (&args);
1507   if (rv)
1508     {
1509       clib_warning ("app worker add/del returned: %d", rv);
1510       goto done;
1511     }
1512
1513   if (!mp->is_add)
1514     goto done;
1515
1516   /* Send fifo segment fd if needed */
1517   if (ssvm_type (args.segment) == SSVM_SEGMENT_MEMFD)
1518     {
1519       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1520       fds[n_fds] = args.segment->fd;
1521       n_fds += 1;
1522     }
1523   if (application_segment_manager_properties (app)->use_mq_eventfd)
1524     {
1525       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1526       fds[n_fds] = svm_msg_q_get_eventfd (args.evt_q);
1527       n_fds += 1;
1528     }
1529
1530 done:
1531
1532   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER_REPLY;
1533   rmp = &msg.worker_add_del_reply;
1534   rmp->retval = rv;
1535   rmp->is_add = mp->is_add;
1536   rmp->api_client_handle = sapi_handle;
1537   rmp->wrk_index = args.wrk_map_index;
1538   rmp->segment_handle = args.segment_handle;
1539   if (!rv && mp->is_add)
1540     {
1541       /* No segment name and size. This supports only memfds */
1542       rmp->app_event_queue_address =
1543         fifo_segment_msg_q_offset ((fifo_segment_t *) args.segment, 0);
1544       rmp->n_fds = n_fds;
1545       rmp->fd_flags = fd_flags;
1546
1547       /* Update app index for socket */
1548       handle = (app_ns_api_handle_t *) & cs->private_data;
1549       app_wrk = application_get_worker (app, args.wrk_map_index);
1550       handle->aah_app_wrk_index = app_wrk->wrk_index;
1551     }
1552
1553   clib_socket_sendmsg (cs, &msg, sizeof (msg), fds, n_fds);
1554 }
1555
1556 static void
1557 sapi_add_del_cert_key_handler (app_namespace_t *app_ns, clib_socket_t *cs,
1558                                app_sapi_cert_key_add_del_msg_t *mp)
1559 {
1560   vnet_app_add_cert_key_pair_args_t _a, *a = &_a;
1561   app_sapi_cert_key_add_del_reply_msg_t *rmp;
1562   app_sapi_msg_t msg = { 0 };
1563   int rv = 0;
1564
1565   if (mp->is_add)
1566     {
1567       const u32 max_certkey_len = 2e4, max_cert_len = 1e4, max_key_len = 1e4;
1568       clib_error_t *err;
1569       u8 *certkey = 0;
1570       u32 key_len;
1571
1572       if (mp->certkey_len > max_certkey_len)
1573         {
1574           rv = SESSION_E_INVALID;
1575           goto send_reply;
1576         }
1577
1578       vec_validate (certkey, mp->certkey_len - 1);
1579       err = clib_socket_recvmsg (cs, certkey, mp->certkey_len, 0, 0);
1580       if (err)
1581         {
1582           clib_error_report (err);
1583           clib_error_free (err);
1584           rv = SESSION_E_INVALID;
1585           goto send_reply;
1586         }
1587
1588       if (mp->cert_len > max_cert_len)
1589         {
1590           rv = SESSION_E_INVALID;
1591           goto send_reply;
1592         }
1593
1594       if (mp->certkey_len < mp->cert_len)
1595         {
1596           rv = SESSION_E_INVALID;
1597           goto send_reply;
1598         }
1599
1600       key_len = mp->certkey_len - mp->cert_len;
1601       if (key_len > max_key_len)
1602         {
1603           rv = SESSION_E_INVALID;
1604           goto send_reply;
1605         }
1606
1607       clib_memset (a, 0, sizeof (*a));
1608       a->cert = certkey;
1609       a->key = certkey + mp->cert_len;
1610       a->cert_len = mp->cert_len;
1611       a->key_len = key_len;
1612       rv = vnet_app_add_cert_key_pair (a);
1613
1614       vec_free (certkey);
1615     }
1616   else
1617     {
1618       rv = vnet_app_del_cert_key_pair (mp->index);
1619     }
1620
1621 send_reply:
1622
1623   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY_REPLY;
1624   rmp = &msg.cert_key_add_del_reply;
1625   rmp->retval = rv;
1626   rmp->context = mp->context;
1627   if (!rv && mp->is_add)
1628     rmp->index = a->index;
1629
1630   clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
1631 }
1632
1633 static void
1634 sapi_socket_detach (app_namespace_t * app_ns, clib_socket_t * cs)
1635 {
1636   app_ns_api_handle_t *handle;
1637   app_worker_t *app_wrk;
1638   u32 api_client_handle;
1639
1640   api_client_handle = appns_sapi_socket_handle (app_ns, cs);
1641
1642   /* Cleanup everything because app worker closed socket or crashed */
1643   handle = (app_ns_api_handle_t *) & cs->private_data;
1644   app_wrk = app_worker_get (handle->aah_app_wrk_index);
1645
1646   vnet_app_worker_add_del_args_t args = {
1647     .app_index = app_wrk->app_index,
1648     .wrk_map_index = app_wrk->wrk_map_index,
1649     .api_client_index = api_client_handle,
1650     .is_add = 0
1651   };
1652   /* Send rpc to main thread for worker barrier */
1653   vlib_rpc_call_main_thread (vnet_app_worker_add_del, (u8 *) & args,
1654                              sizeof (args));
1655 }
1656
1657 static clib_error_t *
1658 sapi_sock_read_ready (clib_file_t * cf)
1659 {
1660   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1661   vlib_main_t *vm = vlib_get_main ();
1662   app_sapi_msg_t msg = { 0 };
1663   app_namespace_t *app_ns;
1664   clib_error_t *err = 0;
1665   clib_socket_t *cs;
1666
1667   app_ns = app_namespace_get (handle->aah_app_ns_index);
1668   cs = appns_sapi_get_socket (app_ns, handle->aah_sock_index);
1669   if (!cs)
1670     goto error;
1671
1672   err = clib_socket_recvmsg (cs, &msg, sizeof (msg), 0, 0);
1673   if (err)
1674     {
1675       clib_error_free (err);
1676       sapi_socket_detach (app_ns, cs);
1677       goto error;
1678     }
1679
1680   handle = (app_ns_api_handle_t *) & cs->private_data;
1681
1682   vlib_worker_thread_barrier_sync (vm);
1683
1684   switch (msg.type)
1685     {
1686     case APP_SAPI_MSG_TYPE_ATTACH:
1687       session_api_attach_handler (app_ns, cs, &msg.attach);
1688       break;
1689     case APP_SAPI_MSG_TYPE_ADD_DEL_WORKER:
1690       sapi_add_del_worker_handler (app_ns, cs, &msg.worker_add_del);
1691       break;
1692     case APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY:
1693       sapi_add_del_cert_key_handler (app_ns, cs, &msg.cert_key_add_del);
1694       break;
1695     default:
1696       clib_warning ("app wrk %u unknown message type: %u",
1697                     handle->aah_app_wrk_index, msg.type);
1698       break;
1699     }
1700
1701   vlib_worker_thread_barrier_release (vm);
1702
1703 error:
1704   return 0;
1705 }
1706
1707 static clib_error_t *
1708 sapi_sock_write_ready (clib_file_t * cf)
1709 {
1710   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1711   clib_warning ("called for app ns %u", handle->aah_app_ns_index);
1712   return 0;
1713 }
1714
1715 static clib_error_t *
1716 sapi_sock_error (clib_file_t * cf)
1717 {
1718   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1719   app_namespace_t *app_ns;
1720   clib_socket_t *cs;
1721
1722   app_ns = app_namespace_get (handle->aah_app_ns_index);
1723   cs = appns_sapi_get_socket (app_ns, handle->aah_sock_index);
1724   if (!cs)
1725     return 0;
1726
1727   sapi_socket_detach (app_ns, cs);
1728   return 0;
1729 }
1730
1731 static clib_error_t *
1732 sapi_sock_accept_ready (clib_file_t * scf)
1733 {
1734   app_ns_api_handle_t handle = *(app_ns_api_handle_t *) & scf->private_data;
1735   app_namespace_t *app_ns;
1736   clib_file_t cf = { 0 };
1737   clib_error_t *err = 0;
1738   clib_socket_t *ccs, *scs;
1739
1740   /* Listener files point to namespace */
1741   app_ns = app_namespace_get (handle.aah_app_ns_index);
1742
1743   /*
1744    * Initialize client socket
1745    */
1746   ccs = appns_sapi_alloc_socket (app_ns);
1747
1748   /* Grab server socket after client is initialized  */
1749   scs = appns_sapi_get_socket (app_ns, handle.aah_sock_index);
1750   if (!scs)
1751     goto error;
1752
1753   err = clib_socket_accept (scs, ccs);
1754   if (err)
1755     {
1756       clib_error_report (err);
1757       goto error;
1758     }
1759
1760   cf.read_function = sapi_sock_read_ready;
1761   cf.write_function = sapi_sock_write_ready;
1762   cf.error_function = sapi_sock_error;
1763   cf.file_descriptor = ccs->fd;
1764   /* File points to app namespace and socket */
1765   handle.aah_sock_index = appns_sapi_socket_index (app_ns, ccs);
1766   cf.private_data = handle.as_u64;
1767   cf.description = format (0, "app sock conn fd: %d", ccs->fd);
1768
1769   /* Poll until we get an attach message. Socket points to file and
1770    * application that owns the socket */
1771   handle.aah_app_wrk_index = APP_INVALID_INDEX;
1772   handle.aah_file_index = clib_file_add (&file_main, &cf);
1773   ccs->private_data = handle.as_u64;
1774
1775   return err;
1776
1777 error:
1778   appns_sapi_free_socket (app_ns, ccs);
1779   return err;
1780 }
1781
1782 void
1783 appns_sapi_del_ns_socket (app_namespace_t *app_ns)
1784 {
1785   app_ns_api_handle_t *handle;
1786   clib_socket_t *cs;
1787
1788   pool_foreach (cs, app_ns->app_sockets)
1789     {
1790       handle = (app_ns_api_handle_t *) &cs->private_data;
1791       clib_file_del_by_index (&file_main, handle->aah_file_index);
1792
1793       clib_socket_close (cs);
1794       clib_socket_free (cs);
1795     }
1796   pool_free (app_ns->app_sockets);
1797 }
1798
1799 int
1800 appns_sapi_add_ns_socket (app_namespace_t * app_ns)
1801 {
1802   char *subdir = "/app_ns_sockets/";
1803   app_ns_api_handle_t *handle;
1804   clib_file_t cf = { 0 };
1805   struct stat file_stat;
1806   clib_error_t *err;
1807   clib_socket_t *cs;
1808   char dir[4096];
1809
1810   if (app_ns->netns)
1811     {
1812       if (!app_ns->sock_name)
1813         app_ns->sock_name = format (0, "@vpp/session/%v%c", app_ns->ns_id, 0);
1814       if (app_ns->sock_name[0] != '@')
1815         return VNET_API_ERROR_INVALID_VALUE;
1816     }
1817   else
1818     {
1819       snprintf (dir, sizeof (dir), "%s%s", vlib_unix_get_runtime_dir (),
1820                 subdir);
1821       err = vlib_unix_recursive_mkdir ((char *) dir);
1822       if (err)
1823         {
1824           clib_error_report (err);
1825           return VNET_API_ERROR_SYSCALL_ERROR_1;
1826         }
1827
1828       if (!app_ns->sock_name)
1829         app_ns->sock_name = format (0, "%s%v%c", dir, app_ns->ns_id, 0);
1830     }
1831
1832   /*
1833    * Create and initialize socket to listen on
1834    */
1835   cs = appns_sapi_alloc_socket (app_ns);
1836   cs->config = (char *) vec_dup (app_ns->sock_name);
1837   cs->flags = CLIB_SOCKET_F_IS_SERVER |
1838     CLIB_SOCKET_F_ALLOW_GROUP_WRITE |
1839     CLIB_SOCKET_F_SEQPACKET | CLIB_SOCKET_F_PASSCRED;
1840
1841   if ((err = clib_socket_init_netns (cs, app_ns->netns)))
1842     {
1843       clib_error_report (err);
1844       return -1;
1845     }
1846
1847   if (!app_ns->netns && stat ((char *) app_ns->sock_name, &file_stat) == -1)
1848     return -1;
1849
1850   /*
1851    * Start polling it
1852    */
1853   cf.read_function = sapi_sock_accept_ready;
1854   cf.file_descriptor = cs->fd;
1855   /* File points to namespace */
1856   handle = (app_ns_api_handle_t *) & cf.private_data;
1857   handle->aah_app_ns_index = app_namespace_index (app_ns);
1858   handle->aah_sock_index = appns_sapi_socket_index (app_ns, cs);
1859   cf.description = format (0, "app sock listener: %s", app_ns->sock_name);
1860
1861   /* Socket points to clib file index */
1862   handle = (app_ns_api_handle_t *) & cs->private_data;
1863   handle->aah_file_index = clib_file_add (&file_main, &cf);
1864   handle->aah_app_wrk_index = APP_INVALID_INDEX;
1865
1866   return 0;
1867 }
1868
1869 static void
1870 vl_api_application_tls_cert_add_t_handler (
1871   vl_api_application_tls_cert_add_t *mp)
1872 {
1873   /* deprecated */
1874 }
1875
1876 static void
1877 vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t *mp)
1878 {
1879   /* deprecated */
1880 }
1881
1882 #include <vnet/session/session.api.c>
1883 static clib_error_t *
1884 session_api_hookup (vlib_main_t *vm)
1885 {
1886   /*
1887    * Set up the (msg_name, crc, message-id) table
1888    */
1889   REPLY_MSG_ID_BASE = setup_message_id_table ();
1890
1891   return 0;
1892 }
1893
1894 VLIB_API_INIT_FUNCTION (session_api_hookup);
1895
1896 /*
1897  * fd.io coding-style-patch-verification: ON
1898  *
1899  * Local Variables:
1900  * eval: (c-set-style "gnu")
1901  * End:
1902  */