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