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