3e99938dd6b86a774486f3ce45f586aad3a4a3a7
[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     .sock_name = 0,
729     .secret = clib_net_to_host_u64 (mp->secret),
730     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
731     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
732     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
733     .is_add = 1
734   };
735   rv = vnet_app_namespace_add_del (&args);
736   if (!rv)
737     {
738       appns_index = app_namespace_index_from_id (ns_id);
739       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
740         {
741           clib_warning ("app ns lookup failed");
742           rv = VNET_API_ERROR_UNSPECIFIED;
743         }
744     }
745   vec_free (ns_id);
746
747   /* *INDENT-OFF* */
748 done:
749   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
750     if (!rv)
751       rmp->appns_index = clib_host_to_net_u32 (appns_index);
752   }));
753   /* *INDENT-ON* */
754 }
755
756 static void
757 vl_api_app_namespace_add_del_v2_t_handler (
758   vl_api_app_namespace_add_del_v2_t *mp)
759 {
760   vl_api_app_namespace_add_del_v2_reply_t *rmp;
761   u8 *ns_id = 0;
762   u32 appns_index = 0;
763   int rv = 0;
764
765   if (session_main_is_enabled () == 0)
766     {
767       rv = VNET_API_ERROR_FEATURE_DISABLED;
768       goto done;
769     }
770
771   mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0;
772   ns_id = format (0, "%s", &mp->namespace_id);
773
774   vnet_app_namespace_add_del_args_t args = {
775     .ns_id = ns_id,
776     .sock_name = 0,
777     .secret = clib_net_to_host_u64 (mp->secret),
778     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
779     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
780     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
781     .is_add = 1
782   };
783   rv = vnet_app_namespace_add_del (&args);
784   if (!rv)
785     {
786       appns_index = app_namespace_index_from_id (ns_id);
787       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
788         {
789           clib_warning ("app ns lookup failed id:%s", ns_id);
790           rv = VNET_API_ERROR_UNSPECIFIED;
791         }
792     }
793   vec_free (ns_id);
794
795 done:
796   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V2_REPLY, ({
797                   if (!rv)
798                     rmp->appns_index = clib_host_to_net_u32 (appns_index);
799                 }));
800 }
801
802 static void
803 vl_api_app_namespace_add_del_v4_t_handler (
804   vl_api_app_namespace_add_del_v4_t *mp)
805 {
806   vl_api_app_namespace_add_del_v4_reply_t *rmp;
807   u8 *ns_id = 0, *sock_name = 0;
808   u32 appns_index = 0;
809   int rv = 0;
810   if (session_main_is_enabled () == 0)
811     {
812       rv = VNET_API_ERROR_FEATURE_DISABLED;
813       goto done;
814     }
815   mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0;
816   ns_id = format (0, "%s", &mp->namespace_id);
817   sock_name = vl_api_from_api_to_new_vec (mp, &mp->sock_name);
818   vnet_app_namespace_add_del_args_t args = {
819     .ns_id = ns_id,
820     .sock_name = sock_name,
821     .secret = clib_net_to_host_u64 (mp->secret),
822     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
823     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
824     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
825     .is_add = mp->is_add,
826   };
827   rv = vnet_app_namespace_add_del (&args);
828   if (!rv && mp->is_add)
829     {
830       appns_index = app_namespace_index_from_id (ns_id);
831       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
832         {
833           clib_warning ("app ns lookup failed id:%s", ns_id);
834           rv = VNET_API_ERROR_UNSPECIFIED;
835         }
836     }
837   vec_free (ns_id);
838   vec_free (sock_name);
839 done:
840   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V4_REPLY, ({
841                   if (!rv)
842                     rmp->appns_index = clib_host_to_net_u32 (appns_index);
843                 }));
844 }
845
846 static void
847 vl_api_app_namespace_add_del_v3_t_handler (
848   vl_api_app_namespace_add_del_v3_t *mp)
849 {
850   vl_api_app_namespace_add_del_v3_reply_t *rmp;
851   u8 *ns_id = 0, *sock_name = 0, *api_sock_name = 0;
852   u32 appns_index = 0;
853   int rv = 0;
854   if (session_main_is_enabled () == 0)
855     {
856       rv = VNET_API_ERROR_FEATURE_DISABLED;
857       goto done;
858     }
859   mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0;
860   ns_id = format (0, "%s", &mp->namespace_id);
861   api_sock_name = vl_api_from_api_to_new_vec (mp, &mp->sock_name);
862   mp->netns[sizeof (mp->netns) - 1] = 0;
863   if (strlen ((char *) mp->netns) != 0)
864     {
865       sock_name =
866         format (0, "abstract:%v,netns_name=%s", api_sock_name, &mp->netns);
867     }
868   else
869     {
870       sock_name = api_sock_name;
871       api_sock_name = 0; // for vec_free
872     }
873
874   vnet_app_namespace_add_del_args_t args = {
875     .ns_id = ns_id,
876     .sock_name = sock_name,
877     .secret = clib_net_to_host_u64 (mp->secret),
878     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
879     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
880     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
881     .is_add = mp->is_add,
882   };
883   rv = vnet_app_namespace_add_del (&args);
884   if (!rv && mp->is_add)
885     {
886       appns_index = app_namespace_index_from_id (ns_id);
887       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
888         {
889           clib_warning ("app ns lookup failed id:%s", ns_id);
890           rv = VNET_API_ERROR_UNSPECIFIED;
891         }
892     }
893   vec_free (ns_id);
894   vec_free (sock_name);
895   vec_free (api_sock_name);
896 done:
897   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V3_REPLY, ({
898                   if (!rv)
899                     rmp->appns_index = clib_host_to_net_u32 (appns_index);
900                 }));
901 }
902
903 static void
904 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
905 {
906   vl_api_session_rule_add_del_reply_t *rmp;
907   session_rule_add_del_args_t args;
908   session_rule_table_add_del_args_t *table_args = &args.table_args;
909   int rv = 0;
910
911   clib_memset (&args, 0, sizeof (args));
912
913   ip_prefix_decode (&mp->lcl, &table_args->lcl);
914   ip_prefix_decode (&mp->rmt, &table_args->rmt);
915
916   table_args->lcl_port = mp->lcl_port;
917   table_args->rmt_port = mp->rmt_port;
918   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
919   table_args->is_add = mp->is_add;
920   mp->tag[sizeof (mp->tag) - 1] = 0;
921   table_args->tag = format (0, "%s", mp->tag);
922   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
923   args.scope = mp->scope;
924   args.transport_proto =
925     api_session_transport_proto_decode (&mp->transport_proto) ==
926     TRANSPORT_PROTO_UDP ? 1 : 0;
927
928   rv = vnet_session_rule_add_del (&args);
929   if (rv)
930     clib_warning ("rule add del returned: %d", rv);
931   vec_free (table_args->tag);
932   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
933 }
934
935 static void
936 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
937                             u8 transport_proto, u32 appns_index, u8 * tag,
938                             vl_api_registration_t * reg, u32 context)
939 {
940   vl_api_session_rules_details_t *rmp = 0;
941   session_mask_or_match_4_t *match =
942     (session_mask_or_match_4_t *) & rule->match;
943   session_mask_or_match_4_t *mask =
944     (session_mask_or_match_4_t *) & rule->mask;
945   fib_prefix_t lcl, rmt;
946
947   rmp = vl_msg_api_alloc (sizeof (*rmp));
948   clib_memset (rmp, 0, sizeof (*rmp));
949   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_DETAILS);
950   rmp->context = context;
951
952   clib_memset (&lcl, 0, sizeof (lcl));
953   clib_memset (&rmt, 0, sizeof (rmt));
954   ip_set (&lcl.fp_addr, &match->lcl_ip, 1);
955   ip_set (&rmt.fp_addr, &match->rmt_ip, 1);
956   lcl.fp_len = ip4_mask_to_preflen (&mask->lcl_ip);
957   rmt.fp_len = ip4_mask_to_preflen (&mask->rmt_ip);
958
959   ip_prefix_encode (&lcl, &rmp->lcl);
960   ip_prefix_encode (&rmt, &rmp->rmt);
961   rmp->lcl_port = match->lcl_port;
962   rmp->rmt_port = match->rmt_port;
963   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
964   rmp->scope =
965     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
966   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
967   rmp->appns_index = clib_host_to_net_u32 (appns_index);
968   if (tag)
969     {
970       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
971       rmp->tag[vec_len (tag)] = 0;
972     }
973
974   vl_api_send_msg (reg, (u8 *) rmp);
975 }
976
977 static void
978 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
979                             u8 transport_proto, u32 appns_index, u8 * tag,
980                             vl_api_registration_t * reg, u32 context)
981 {
982   vl_api_session_rules_details_t *rmp = 0;
983   session_mask_or_match_6_t *match =
984     (session_mask_or_match_6_t *) & rule->match;
985   session_mask_or_match_6_t *mask =
986     (session_mask_or_match_6_t *) & rule->mask;
987   fib_prefix_t lcl, rmt;
988
989   rmp = vl_msg_api_alloc (sizeof (*rmp));
990   clib_memset (rmp, 0, sizeof (*rmp));
991   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_DETAILS);
992   rmp->context = context;
993
994   clib_memset (&lcl, 0, sizeof (lcl));
995   clib_memset (&rmt, 0, sizeof (rmt));
996   ip_set (&lcl.fp_addr, &match->lcl_ip, 0);
997   ip_set (&rmt.fp_addr, &match->rmt_ip, 0);
998   lcl.fp_len = ip6_mask_to_preflen (&mask->lcl_ip);
999   rmt.fp_len = ip6_mask_to_preflen (&mask->rmt_ip);
1000
1001   ip_prefix_encode (&lcl, &rmp->lcl);
1002   ip_prefix_encode (&rmt, &rmp->rmt);
1003   rmp->lcl_port = match->lcl_port;
1004   rmp->rmt_port = match->rmt_port;
1005   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1006   rmp->scope =
1007     is_local ? SESSION_RULE_SCOPE_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
1008   rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
1009   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1010   if (tag)
1011     {
1012       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1013       rmp->tag[vec_len (tag)] = 0;
1014     }
1015
1016   vl_api_send_msg (reg, (u8 *) rmp);
1017 }
1018
1019 static void
1020 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
1021                                   u8 tp, u8 is_local, u32 appns_index,
1022                                   vl_api_registration_t * reg, u32 context)
1023 {
1024   mma_rule_16_t *rule16;
1025   mma_rule_40_t *rule40;
1026   mma_rules_table_16_t *srt16;
1027   mma_rules_table_40_t *srt40;
1028   u32 ri;
1029
1030   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
1031     {
1032       u8 *tag = 0;
1033       /* *INDENT-OFF* */
1034       srt16 = &srt->session_rules_tables_16;
1035       pool_foreach (rule16, srt16->rules)  {
1036         ri = mma_rules_table_rule_index_16 (srt16, rule16);
1037         tag = session_rules_table_rule_tag (srt, ri, 1);
1038         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
1039                                     reg, context);
1040       }
1041       /* *INDENT-ON* */
1042     }
1043   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
1044     {
1045       u8 *tag = 0;
1046       /* *INDENT-OFF* */
1047       srt40 = &srt->session_rules_tables_40;
1048       pool_foreach (rule40, srt40->rules)  {
1049         ri = mma_rules_table_rule_index_40 (srt40, rule40);
1050         tag = session_rules_table_rule_tag (srt, ri, 1);
1051         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
1052                                     reg, context);
1053       }
1054       /* *INDENT-ON* */
1055     }
1056 }
1057
1058 static void
1059 vl_api_session_rules_dump_t_handler (vl_api_session_rules_dump_t * mp)
1060 {
1061   vl_api_registration_t *reg;
1062   session_table_t *st;
1063   u8 tp;
1064
1065   reg = vl_api_client_index_to_registration (mp->client_index);
1066   if (!reg)
1067     return;
1068
1069   /* *INDENT-OFF* */
1070   session_table_foreach (st, ({
1071     for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
1072       {
1073         send_session_rules_table_details (&st->session_rules[tp],
1074                                           st->active_fib_proto, tp,
1075                                           st->is_local, st->appns_index, reg,
1076                                           mp->context);
1077       }
1078   }));
1079   /* *INDENT-ON* */
1080 }
1081
1082 static void
1083 vl_api_app_add_cert_key_pair_t_handler (vl_api_app_add_cert_key_pair_t * mp)
1084 {
1085   vl_api_app_add_cert_key_pair_reply_t *rmp;
1086   vnet_app_add_cert_key_pair_args_t _a, *a = &_a;
1087   u32 certkey_len, key_len, cert_len;
1088   int rv = 0;
1089   if (session_main_is_enabled () == 0)
1090     {
1091       rv = VNET_API_ERROR_FEATURE_DISABLED;
1092       goto done;
1093     }
1094
1095   cert_len = clib_net_to_host_u16 (mp->cert_len);
1096   if (cert_len > 10000)
1097     {
1098       rv = VNET_API_ERROR_INVALID_VALUE;
1099       goto done;
1100     }
1101
1102   certkey_len = clib_net_to_host_u16 (mp->certkey_len);
1103   if (certkey_len < cert_len)
1104     {
1105       rv = VNET_API_ERROR_INVALID_VALUE;
1106       goto done;
1107     }
1108
1109   key_len = certkey_len - cert_len;
1110   if (key_len > 10000)
1111     {
1112       rv = VNET_API_ERROR_INVALID_VALUE;
1113       goto done;
1114     }
1115
1116   clib_memset (a, 0, sizeof (*a));
1117   a->cert = mp->certkey;
1118   a->key = mp->certkey + cert_len;
1119   a->cert_len = cert_len;
1120   a->key_len = key_len;
1121   rv = vnet_app_add_cert_key_pair (a);
1122
1123 done:
1124   /* *INDENT-OFF* */
1125   REPLY_MACRO2 (VL_API_APP_ADD_CERT_KEY_PAIR_REPLY, ({
1126     if (!rv)
1127       rmp->index = clib_host_to_net_u32 (a->index);
1128   }));
1129   /* *INDENT-ON* */
1130 }
1131
1132 static void
1133 vl_api_app_del_cert_key_pair_t_handler (vl_api_app_del_cert_key_pair_t * mp)
1134 {
1135   vl_api_app_del_cert_key_pair_reply_t *rmp;
1136   u32 ckpair_index;
1137   int rv = 0;
1138   if (session_main_is_enabled () == 0)
1139     {
1140       rv = VNET_API_ERROR_FEATURE_DISABLED;
1141       goto done;
1142     }
1143   ckpair_index = clib_net_to_host_u32 (mp->index);
1144   rv = vnet_app_del_cert_key_pair (ckpair_index);
1145
1146 done:
1147   REPLY_MACRO (VL_API_APP_DEL_CERT_KEY_PAIR_REPLY);
1148 }
1149
1150 static clib_error_t *
1151 application_reaper_cb (u32 client_index)
1152 {
1153   application_t *app = application_lookup (client_index);
1154   vnet_app_detach_args_t _a, *a = &_a;
1155   if (app)
1156     {
1157       a->app_index = app->app_index;
1158       a->api_client_index = client_index;
1159       vnet_application_detach (a);
1160     }
1161   return 0;
1162 }
1163
1164 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1165
1166 /*
1167  * Socket api functions
1168  */
1169
1170 static int
1171 mq_send_add_segment_sapi_cb (u32 app_wrk_index, u64 segment_handle)
1172 {
1173   session_app_add_segment_msg_t m = { 0 };
1174   app_worker_t *app_wrk;
1175   fifo_segment_t *fs;
1176   ssvm_private_t *sp;
1177   u8 fd_flags = 0;
1178
1179   app_wrk = app_worker_get (app_wrk_index);
1180
1181   fs = segment_manager_get_segment_w_handle (segment_handle);
1182   sp = &fs->ssvm;
1183   ASSERT (ssvm_type (sp) == SSVM_SEGMENT_MEMFD);
1184
1185   fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1186
1187   m.segment_size = sp->ssvm_size;
1188   m.fd_flags = fd_flags;
1189   m.segment_handle = segment_handle;
1190   strncpy ((char *) m.segment_name, (char *) sp->name,
1191            sizeof (m.segment_name) - 1);
1192
1193   app_wrk_send_ctrl_evt_fd (app_wrk, SESSION_CTRL_EVT_APP_ADD_SEGMENT, &m,
1194                             sizeof (m), sp->fd);
1195
1196   return 0;
1197 }
1198
1199 static int
1200 mq_send_del_segment_sapi_cb (u32 app_wrk_index, u64 segment_handle)
1201 {
1202   session_app_del_segment_msg_t m = { 0 };
1203   app_worker_t *app_wrk;
1204
1205   app_wrk = app_worker_get (app_wrk_index);
1206
1207   m.segment_handle = segment_handle;
1208
1209   app_wrk_send_ctrl_evt (app_wrk, SESSION_CTRL_EVT_APP_DEL_SEGMENT, &m,
1210                          sizeof (m));
1211
1212   return 0;
1213 }
1214
1215 static session_cb_vft_t session_mq_sapi_cb_vft = {
1216   .session_accept_callback = mq_send_session_accepted_cb,
1217   .session_disconnect_callback = mq_send_session_disconnected_cb,
1218   .session_connected_callback = mq_send_session_connected_cb,
1219   .session_reset_callback = mq_send_session_reset_cb,
1220   .session_migrate_callback = mq_send_session_migrate_cb,
1221   .session_cleanup_callback = mq_send_session_cleanup_cb,
1222   .add_segment_callback = mq_send_add_segment_sapi_cb,
1223   .del_segment_callback = mq_send_del_segment_sapi_cb,
1224 };
1225
1226 static void
1227 session_api_attach_handler (app_namespace_t * app_ns, clib_socket_t * cs,
1228                             app_sapi_attach_msg_t * mp)
1229 {
1230   int rv = 0, *fds = 0, n_fds = 0, i, n_workers;
1231   vnet_app_attach_args_t _a, *a = &_a;
1232   app_sapi_attach_reply_msg_t *rmp;
1233   u8 fd_flags = 0, ctrl_thread;
1234   app_ns_api_handle_t *handle;
1235   fifo_segment_t *rx_mqs_seg;
1236   app_sapi_msg_t msg = { 0 };
1237   app_worker_t *app_wrk;
1238   application_t *app;
1239   svm_msg_q_t *rx_mq;
1240
1241   /* Make sure name is null terminated */
1242   mp->name[63] = 0;
1243
1244   clib_memset (a, 0, sizeof (*a));
1245   a->api_client_index = appns_sapi_socket_handle (app_ns, cs);
1246   a->name = format (0, "%s", (char *) mp->name);
1247   a->options = mp->options;
1248   a->session_cb_vft = &session_mq_sapi_cb_vft;
1249   a->use_sock_api = 1;
1250   a->options[APP_OPTIONS_NAMESPACE] = app_namespace_index (app_ns);
1251
1252   if ((rv = vnet_application_attach (a)))
1253     {
1254       clib_warning ("attach returned: %d", rv);
1255       goto done;
1256     }
1257
1258   n_workers = vlib_num_workers ();
1259   vec_validate (fds, 3 /* segs + tx evtfd */ + n_workers);
1260
1261   /* Send event queues segment */
1262   app = application_get (a->app_index);
1263   rx_mqs_seg = application_get_rx_mqs_segment (app);
1264
1265   fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
1266   fds[n_fds] = rx_mqs_seg->ssvm.fd;
1267   n_fds += 1;
1268
1269   /* Send fifo segment fd if needed */
1270   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
1271     {
1272       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1273       fds[n_fds] = a->segment->fd;
1274       n_fds += 1;
1275     }
1276   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
1277     {
1278       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1279       fds[n_fds] = svm_msg_q_get_eventfd (a->app_evt_q);
1280       n_fds += 1;
1281     }
1282
1283   if (application_use_private_rx_mqs ())
1284     {
1285       fd_flags |= SESSION_FD_F_VPP_MQ_EVENTFD;
1286       for (i = 0; i < n_workers + 1; i++)
1287         {
1288           rx_mq = application_rx_mq_get (app, i);
1289           fds[n_fds] = svm_msg_q_get_eventfd (rx_mq);
1290           n_fds += 1;
1291         }
1292     }
1293
1294 done:
1295
1296   msg.type = APP_SAPI_MSG_TYPE_ATTACH_REPLY;
1297   rmp = &msg.attach_reply;
1298   rmp->retval = rv;
1299   if (!rv)
1300     {
1301       ctrl_thread = n_workers ? 1 : 0;
1302       rmp->app_index = a->app_index;
1303       rmp->app_mq =
1304         fifo_segment_msg_q_offset ((fifo_segment_t *) a->segment, 0);
1305       rmp->vpp_ctrl_mq = fifo_segment_msg_q_offset (rx_mqs_seg, ctrl_thread);
1306       rmp->vpp_ctrl_mq_thread = ctrl_thread;
1307       rmp->n_fds = n_fds;
1308       rmp->fd_flags = fd_flags;
1309       /* No segment name and size since we only support memfds
1310        * in this configuration */
1311       rmp->segment_handle = a->segment_handle;
1312       rmp->api_client_handle = a->api_client_index;
1313
1314       /* Update app index for socket */
1315       handle = (app_ns_api_handle_t *) & cs->private_data;
1316       app_wrk = application_get_worker (app, 0);
1317       handle->aah_app_wrk_index = app_wrk->wrk_index;
1318     }
1319
1320   clib_socket_sendmsg (cs, &msg, sizeof (msg), fds, n_fds);
1321   vec_free (a->name);
1322   vec_free (fds);
1323 }
1324
1325 void
1326 sapi_socket_close_w_handle (u32 api_handle)
1327 {
1328   app_namespace_t *app_ns = app_namespace_get (api_handle >> 16);
1329   u16 sock_index = api_handle & 0xffff;
1330   app_ns_api_handle_t *handle;
1331   clib_socket_t *cs;
1332   clib_file_t *cf;
1333
1334   cs = appns_sapi_get_socket (app_ns, sock_index);
1335   if (!cs)
1336     return;
1337
1338   handle = (app_ns_api_handle_t *) & cs->private_data;
1339   cf = clib_file_get (&file_main, handle->aah_file_index);
1340   clib_file_del (&file_main, cf);
1341
1342   clib_socket_close (cs);
1343   appns_sapi_free_socket (app_ns, cs);
1344 }
1345
1346 static void
1347 sapi_add_del_worker_handler (app_namespace_t * app_ns,
1348                              clib_socket_t * cs,
1349                              app_sapi_worker_add_del_msg_t * mp)
1350 {
1351   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
1352   app_sapi_worker_add_del_reply_msg_t *rmp;
1353   app_ns_api_handle_t *handle;
1354   app_sapi_msg_t msg = { 0 };
1355   app_worker_t *app_wrk;
1356   u32 sapi_handle = -1;
1357   application_t *app;
1358   u8 fd_flags = 0;
1359
1360   app = application_get_if_valid (mp->app_index);
1361   if (!app)
1362     {
1363       rv = VNET_API_ERROR_INVALID_VALUE;
1364       goto done;
1365     }
1366
1367   sapi_handle = appns_sapi_socket_handle (app_ns, cs);
1368
1369   vnet_app_worker_add_del_args_t args = {
1370     .app_index = app->app_index,
1371     .wrk_map_index = mp->wrk_index,
1372     .api_client_index = sapi_handle,
1373     .is_add = mp->is_add
1374   };
1375   rv = vnet_app_worker_add_del (&args);
1376   if (rv)
1377     {
1378       clib_warning ("app worker add/del returned: %d", rv);
1379       goto done;
1380     }
1381
1382   if (!mp->is_add)
1383     goto done;
1384
1385   /* Send fifo segment fd if needed */
1386   if (ssvm_type (args.segment) == SSVM_SEGMENT_MEMFD)
1387     {
1388       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1389       fds[n_fds] = args.segment->fd;
1390       n_fds += 1;
1391     }
1392   if (application_segment_manager_properties (app)->use_mq_eventfd)
1393     {
1394       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1395       fds[n_fds] = svm_msg_q_get_eventfd (args.evt_q);
1396       n_fds += 1;
1397     }
1398
1399 done:
1400
1401   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER_REPLY;
1402   rmp = &msg.worker_add_del_reply;
1403   rmp->retval = rv;
1404   rmp->is_add = mp->is_add;
1405   rmp->api_client_handle = sapi_handle;
1406   rmp->wrk_index = args.wrk_map_index;
1407   rmp->segment_handle = args.segment_handle;
1408   if (!rv && mp->is_add)
1409     {
1410       /* No segment name and size. This supports only memfds */
1411       rmp->app_event_queue_address =
1412         fifo_segment_msg_q_offset ((fifo_segment_t *) args.segment, 0);
1413       rmp->n_fds = n_fds;
1414       rmp->fd_flags = fd_flags;
1415
1416       /* Update app index for socket */
1417       handle = (app_ns_api_handle_t *) & cs->private_data;
1418       app_wrk = application_get_worker (app, args.wrk_map_index);
1419       handle->aah_app_wrk_index = app_wrk->wrk_index;
1420     }
1421
1422   clib_socket_sendmsg (cs, &msg, sizeof (msg), fds, n_fds);
1423 }
1424
1425 /* This is a workaround for the case when session layer starts reading
1426  * the socket before the client actualy sends the data
1427  */
1428 static clib_error_t *
1429 sapi_socket_receive_wait (clib_socket_t *cs, u8 *msg, u32 msg_len)
1430 {
1431   clib_error_t *err;
1432   int n_tries = 5;
1433
1434   while (1)
1435     {
1436       err = clib_socket_recvmsg (cs, msg, msg_len, 0, 0);
1437       if (!err)
1438         break;
1439
1440       if (!n_tries)
1441         return err;
1442
1443       n_tries--;
1444       usleep (1);
1445     }
1446
1447   return err;
1448 }
1449
1450 static void
1451 sapi_add_del_cert_key_handler (app_namespace_t *app_ns, clib_socket_t *cs,
1452                                app_sapi_cert_key_add_del_msg_t *mp)
1453 {
1454   vnet_app_add_cert_key_pair_args_t _a, *a = &_a;
1455   app_sapi_cert_key_add_del_reply_msg_t *rmp;
1456   app_sapi_msg_t msg = { 0 };
1457   int rv = 0;
1458
1459   if (mp->is_add)
1460     {
1461       const u32 max_certkey_len = 2e4, max_cert_len = 1e4, max_key_len = 1e4;
1462       clib_error_t *err;
1463       u8 *certkey = 0;
1464       u32 key_len;
1465
1466       if (mp->certkey_len > max_certkey_len)
1467         {
1468           rv = SESSION_E_INVALID;
1469           goto send_reply;
1470         }
1471
1472       vec_validate (certkey, mp->certkey_len - 1);
1473
1474       err = sapi_socket_receive_wait (cs, certkey, mp->certkey_len);
1475       if (err)
1476         {
1477           clib_error_report (err);
1478           rv = SESSION_E_INVALID;
1479           goto send_reply;
1480         }
1481
1482       if (mp->cert_len > max_cert_len)
1483         {
1484           rv = SESSION_E_INVALID;
1485           goto send_reply;
1486         }
1487
1488       if (mp->certkey_len < mp->cert_len)
1489         {
1490           rv = SESSION_E_INVALID;
1491           goto send_reply;
1492         }
1493
1494       key_len = mp->certkey_len - mp->cert_len;
1495       if (key_len > max_key_len)
1496         {
1497           rv = SESSION_E_INVALID;
1498           goto send_reply;
1499         }
1500
1501       clib_memset (a, 0, sizeof (*a));
1502       a->cert = certkey;
1503       a->key = certkey + mp->cert_len;
1504       a->cert_len = mp->cert_len;
1505       a->key_len = key_len;
1506       rv = vnet_app_add_cert_key_pair (a);
1507
1508       vec_free (certkey);
1509     }
1510   else
1511     {
1512       rv = vnet_app_del_cert_key_pair (mp->index);
1513     }
1514
1515 send_reply:
1516
1517   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY_REPLY;
1518   rmp = &msg.cert_key_add_del_reply;
1519   rmp->retval = rv;
1520   rmp->context = mp->context;
1521   if (!rv && mp->is_add)
1522     rmp->index = a->index;
1523
1524   clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
1525 }
1526
1527 static void
1528 sapi_socket_detach (app_namespace_t * app_ns, clib_socket_t * cs)
1529 {
1530   app_ns_api_handle_t *handle;
1531   app_worker_t *app_wrk;
1532   u32 api_client_handle;
1533
1534   api_client_handle = appns_sapi_socket_handle (app_ns, cs);
1535
1536   /* Cleanup everything because app worker closed socket or crashed */
1537   handle = (app_ns_api_handle_t *) & cs->private_data;
1538   app_wrk = app_worker_get_if_valid (handle->aah_app_wrk_index);
1539   if (!app_wrk)
1540     return;
1541
1542   vnet_app_worker_add_del_args_t args = {
1543     .app_index = app_wrk->app_index,
1544     .wrk_map_index = app_wrk->wrk_map_index,
1545     .api_client_index = api_client_handle,
1546     .is_add = 0
1547   };
1548   /* Send rpc to main thread for worker barrier */
1549   vlib_rpc_call_main_thread (vnet_app_worker_add_del, (u8 *) & args,
1550                              sizeof (args));
1551 }
1552
1553 static clib_error_t *
1554 sapi_sock_read_ready (clib_file_t * cf)
1555 {
1556   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1557   vlib_main_t *vm = vlib_get_main ();
1558   app_sapi_msg_t msg = { 0 };
1559   app_namespace_t *app_ns;
1560   clib_error_t *err = 0;
1561   clib_socket_t *cs;
1562
1563   app_ns = app_namespace_get (handle->aah_app_ns_index);
1564   cs = appns_sapi_get_socket (app_ns, handle->aah_sock_index);
1565   if (!cs)
1566     goto error;
1567
1568   err = clib_socket_recvmsg (cs, &msg, sizeof (msg), 0, 0);
1569   if (err)
1570     {
1571       clib_error_free (err);
1572       sapi_socket_detach (app_ns, cs);
1573       goto error;
1574     }
1575
1576   handle = (app_ns_api_handle_t *) & cs->private_data;
1577
1578   vlib_worker_thread_barrier_sync (vm);
1579
1580   switch (msg.type)
1581     {
1582     case APP_SAPI_MSG_TYPE_ATTACH:
1583       session_api_attach_handler (app_ns, cs, &msg.attach);
1584       break;
1585     case APP_SAPI_MSG_TYPE_ADD_DEL_WORKER:
1586       sapi_add_del_worker_handler (app_ns, cs, &msg.worker_add_del);
1587       break;
1588     case APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY:
1589       sapi_add_del_cert_key_handler (app_ns, cs, &msg.cert_key_add_del);
1590       break;
1591     default:
1592       clib_warning ("app wrk %u unknown message type: %u",
1593                     handle->aah_app_wrk_index, msg.type);
1594       break;
1595     }
1596
1597   vlib_worker_thread_barrier_release (vm);
1598
1599 error:
1600   return 0;
1601 }
1602
1603 static clib_error_t *
1604 sapi_sock_write_ready (clib_file_t * cf)
1605 {
1606   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1607   clib_warning ("called for app ns %u", handle->aah_app_ns_index);
1608   return 0;
1609 }
1610
1611 static clib_error_t *
1612 sapi_sock_error (clib_file_t * cf)
1613 {
1614   app_ns_api_handle_t *handle = (app_ns_api_handle_t *) & cf->private_data;
1615   app_namespace_t *app_ns;
1616   clib_socket_t *cs;
1617
1618   app_ns = app_namespace_get (handle->aah_app_ns_index);
1619   cs = appns_sapi_get_socket (app_ns, handle->aah_sock_index);
1620   if (!cs)
1621     return 0;
1622
1623   sapi_socket_detach (app_ns, cs);
1624   return 0;
1625 }
1626
1627 static clib_error_t *
1628 sapi_sock_accept_ready (clib_file_t * scf)
1629 {
1630   app_ns_api_handle_t handle = *(app_ns_api_handle_t *) & scf->private_data;
1631   app_namespace_t *app_ns;
1632   clib_file_t cf = { 0 };
1633   clib_error_t *err = 0;
1634   clib_socket_t *ccs, *scs;
1635
1636   /* Listener files point to namespace */
1637   app_ns = app_namespace_get (handle.aah_app_ns_index);
1638
1639   /*
1640    * Initialize client socket
1641    */
1642   ccs = appns_sapi_alloc_socket (app_ns);
1643
1644   /* Grab server socket after client is initialized  */
1645   scs = appns_sapi_get_socket (app_ns, handle.aah_sock_index);
1646   if (!scs)
1647     goto error;
1648
1649   err = clib_socket_accept (scs, ccs);
1650   if (err)
1651     {
1652       clib_error_report (err);
1653       goto error;
1654     }
1655
1656   cf.read_function = sapi_sock_read_ready;
1657   cf.write_function = sapi_sock_write_ready;
1658   cf.error_function = sapi_sock_error;
1659   cf.file_descriptor = ccs->fd;
1660   /* File points to app namespace and socket */
1661   handle.aah_sock_index = appns_sapi_socket_index (app_ns, ccs);
1662   cf.private_data = handle.as_u64;
1663   cf.description = format (0, "app sock conn fd: %d", ccs->fd);
1664
1665   /* Poll until we get an attach message. Socket points to file and
1666    * application that owns the socket */
1667   handle.aah_app_wrk_index = APP_INVALID_INDEX;
1668   handle.aah_file_index = clib_file_add (&file_main, &cf);
1669   ccs->private_data = handle.as_u64;
1670
1671   return err;
1672
1673 error:
1674   appns_sapi_free_socket (app_ns, ccs);
1675   return err;
1676 }
1677
1678 void
1679 appns_sapi_del_ns_socket (app_namespace_t *app_ns)
1680 {
1681   app_ns_api_handle_t *handle;
1682   clib_socket_t *cs;
1683
1684   pool_foreach (cs, app_ns->app_sockets)
1685     {
1686       handle = (app_ns_api_handle_t *) &cs->private_data;
1687       clib_file_del_by_index (&file_main, handle->aah_file_index);
1688
1689       clib_socket_close (cs);
1690       clib_socket_free (cs);
1691     }
1692   pool_free (app_ns->app_sockets);
1693 }
1694
1695 int
1696 appns_sapi_add_ns_socket (app_namespace_t * app_ns)
1697 {
1698   char *subdir = "/app_ns_sockets/";
1699   app_ns_api_handle_t *handle;
1700   clib_file_t cf = { 0 };
1701   struct stat file_stat;
1702   clib_error_t *err;
1703   clib_socket_t *cs;
1704   char dir[4096];
1705
1706   snprintf (dir, sizeof (dir), "%s%s", vlib_unix_get_runtime_dir (), subdir);
1707
1708   if (!app_ns->sock_name)
1709     app_ns->sock_name = format (0, "%s%v%c", dir, app_ns->ns_id, 0);
1710
1711   /*
1712    * Create and initialize socket to listen on
1713    */
1714   cs = appns_sapi_alloc_socket (app_ns);
1715   cs->config = (char *) vec_dup (app_ns->sock_name);
1716   cs->flags = CLIB_SOCKET_F_IS_SERVER |
1717     CLIB_SOCKET_F_ALLOW_GROUP_WRITE |
1718     CLIB_SOCKET_F_SEQPACKET | CLIB_SOCKET_F_PASSCRED;
1719
1720   if (clib_socket_prefix_get_type (cs->config) == CLIB_SOCKET_TYPE_UNIX)
1721     {
1722       err = vlib_unix_recursive_mkdir ((char *) dir);
1723       if (err)
1724         {
1725           clib_error_report (err);
1726           return VNET_API_ERROR_SYSCALL_ERROR_1;
1727         }
1728     }
1729
1730   if ((err = clib_socket_init (cs)))
1731     {
1732       clib_error_report (err);
1733       return -1;
1734     }
1735
1736   if (clib_socket_prefix_get_type (cs->config) == CLIB_SOCKET_TYPE_UNIX &&
1737       stat ((char *) app_ns->sock_name, &file_stat) == -1)
1738     return -1;
1739
1740   /*
1741    * Start polling it
1742    */
1743   cf.read_function = sapi_sock_accept_ready;
1744   cf.file_descriptor = cs->fd;
1745   /* File points to namespace */
1746   handle = (app_ns_api_handle_t *) & cf.private_data;
1747   handle->aah_app_ns_index = app_namespace_index (app_ns);
1748   handle->aah_sock_index = appns_sapi_socket_index (app_ns, cs);
1749   cf.description = format (0, "app sock listener: %s", app_ns->sock_name);
1750
1751   /* Socket points to clib file index */
1752   handle = (app_ns_api_handle_t *) & cs->private_data;
1753   handle->aah_file_index = clib_file_add (&file_main, &cf);
1754   handle->aah_app_wrk_index = APP_INVALID_INDEX;
1755
1756   return 0;
1757 }
1758
1759 #include <vnet/session/session.api.c>
1760 static clib_error_t *
1761 session_api_hookup (vlib_main_t *vm)
1762 {
1763   /*
1764    * Set up the (msg_name, crc, message-id) table
1765    */
1766   REPLY_MSG_ID_BASE = setup_message_id_table ();
1767
1768   return 0;
1769 }
1770
1771 VLIB_API_INIT_FUNCTION (session_api_hookup);
1772
1773 /*
1774  * fd.io coding-style-patch-verification: ON
1775  *
1776  * Local Variables:
1777  * eval: (c-set-style "gnu")
1778  * End:
1779  */