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