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