transport: cleanup
[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/session_rules_table.h>
21 #include <vnet/session/session_table.h>
22
23 #include <vnet/vnet_msg_enum.h>
24
25 #define vl_typedefs             /* define message structures */
26 #include <vnet/vnet_all_api_h.h>
27 #undef vl_typedefs
28
29 #define vl_endianfun            /* define message structures */
30 #include <vnet/vnet_all_api_h.h>
31 #undef vl_endianfun
32
33 /* instantiate all the print functions we know about */
34 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
35 #define vl_printfun
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_printfun
38
39 #include <vlibapi/api_helper_macros.h>
40
41 #define foreach_session_api_msg                                         \
42 _(MAP_ANOTHER_SEGMENT_REPLY, map_another_segment_reply)                 \
43 _(APPLICATION_ATTACH, application_attach)                               \
44 _(APPLICATION_DETACH, application_detach)                               \
45 _(BIND_URI, bind_uri)                                                   \
46 _(UNBIND_URI, unbind_uri)                                               \
47 _(CONNECT_URI, connect_uri)                                             \
48 _(DISCONNECT_SESSION, disconnect_session)                               \
49 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)                   \
50 _(ACCEPT_SESSION_REPLY, accept_session_reply)                           \
51 _(RESET_SESSION_REPLY, reset_session_reply)                             \
52 _(BIND_SOCK, bind_sock)                                                 \
53 _(UNBIND_SOCK, unbind_sock)                                             \
54 _(CONNECT_SOCK, connect_sock)                                           \
55 _(SESSION_ENABLE_DISABLE, session_enable_disable)                       \
56 _(APP_NAMESPACE_ADD_DEL, app_namespace_add_del)                         \
57 _(SESSION_RULE_ADD_DEL, session_rule_add_del)                           \
58 _(SESSION_RULES_DUMP, session_rules_dump)                               \
59 _(APPLICATION_TLS_CERT_ADD, application_tls_cert_add)                   \
60 _(APPLICATION_TLS_KEY_ADD, application_tls_key_add)                     \
61 _(APP_WORKER_ADD_DEL, app_worker_add_del)                               \
62
63 static int
64 session_send_fds (vl_api_registration_t * reg, int fds[], int n_fds)
65 {
66   clib_error_t *error;
67   if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
68     {
69       clib_warning ("can't send memfd fd");
70       return -1;
71     }
72   error = vl_api_send_fd_msg (reg, fds, n_fds);
73   if (error)
74     {
75       clib_error_report (error);
76       return -1;
77     }
78   return 0;
79 }
80
81 static int
82 send_add_segment_callback (u32 api_client_index, u64 segment_handle)
83 {
84   int fds[SESSION_N_FD_TYPE], n_fds = 0;
85   vl_api_map_another_segment_t *mp;
86   svm_fifo_segment_private_t *fs;
87   vl_api_registration_t *reg;
88   ssvm_private_t *sp;
89   u8 fd_flags = 0;
90
91   reg = vl_mem_api_client_index_to_registration (api_client_index);
92   if (!reg)
93     {
94       clib_warning ("no api registration for client: %u", api_client_index);
95       return -1;
96     }
97
98   fs = segment_manager_get_segment_w_handle (segment_handle);
99   sp = &fs->ssvm;
100   if (ssvm_type (sp) == SSVM_SEGMENT_MEMFD)
101     {
102       if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
103         {
104           clib_warning ("can't send memfd fd");
105           return -1;
106         }
107
108       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
109       fds[n_fds] = sp->fd;
110       n_fds += 1;
111     }
112
113   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
114   clib_memset (mp, 0, sizeof (*mp));
115   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MAP_ANOTHER_SEGMENT);
116   mp->segment_size = sp->ssvm_size;
117   mp->fd_flags = fd_flags;
118   mp->segment_handle = clib_host_to_net_u64 (segment_handle);
119   strncpy ((char *) mp->segment_name, (char *) sp->name,
120            sizeof (mp->segment_name) - 1);
121
122   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
123
124   if (n_fds)
125     return session_send_fds (reg, fds, n_fds);
126
127   return 0;
128 }
129
130 static int
131 send_del_segment_callback (u32 api_client_index, u64 segment_handle)
132 {
133   vl_api_unmap_segment_t *mp;
134   vl_api_registration_t *reg;
135
136   reg = vl_mem_api_client_index_to_registration (api_client_index);
137   if (!reg)
138     {
139       clib_warning ("no registration: %u", api_client_index);
140       return -1;
141     }
142
143   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
144   clib_memset (mp, 0, sizeof (*mp));
145   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_UNMAP_SEGMENT);
146   mp->segment_handle = clib_host_to_net_u64 (segment_handle);
147   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
148
149   return 0;
150 }
151
152 static int
153 send_app_cut_through_registration_add (u32 api_client_index,
154                                        u32 wrk_map_index, u64 mq_addr,
155                                        u64 peer_mq_addr)
156 {
157   vl_api_app_cut_through_registration_add_t *mp;
158   vl_api_registration_t *reg;
159   svm_msg_q_t *mq, *peer_mq;
160   int fds[2];
161
162   reg = vl_mem_api_client_index_to_registration (api_client_index);
163   if (!reg)
164     {
165       clib_warning ("no registration: %u", api_client_index);
166       return -1;
167     }
168
169   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
170   clib_memset (mp, 0, sizeof (*mp));
171   mp->_vl_msg_id =
172     clib_host_to_net_u16 (VL_API_APP_CUT_THROUGH_REGISTRATION_ADD);
173
174   mp->evt_q_address = mq_addr;
175   mp->peer_evt_q_address = peer_mq_addr;
176   mp->wrk_index = wrk_map_index;
177
178   mq = uword_to_pointer (mq_addr, svm_msg_q_t *);
179   peer_mq = uword_to_pointer (peer_mq_addr, svm_msg_q_t *);
180
181   if (svm_msg_q_get_producer_eventfd (mq) != -1)
182     {
183       mp->fd_flags |= SESSION_FD_F_MQ_EVENTFD;
184       mp->n_fds = 2;
185       /* app will overwrite exactly the fds we pass here. So
186        * when we swap mq with peer_mq (accept vs connect) the
187        * fds will still be valid */
188       fds[0] = svm_msg_q_get_consumer_eventfd (mq);
189       fds[1] = svm_msg_q_get_producer_eventfd (peer_mq);
190     }
191
192   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
193
194   if (mp->n_fds != 0)
195     session_send_fds (reg, fds, mp->n_fds);
196
197   return 0;
198 }
199
200 static int
201 send_session_accept_callback (session_t * s)
202 {
203   app_worker_t *server_wrk = app_worker_get (s->app_wrk_index);
204   vl_api_accept_session_t *mp;
205   vl_api_registration_t *reg;
206   transport_connection_t *tc;
207   session_t *listener;
208   svm_msg_q_t *vpp_queue;
209   application_t *server;
210
211   server = application_get (server_wrk->app_index);
212   reg =
213     vl_mem_api_client_index_to_registration (server_wrk->api_client_index);
214   if (!reg)
215     {
216       clib_warning ("no registration: %u", server_wrk->api_client_index);
217       return -1;
218     }
219
220   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
221   clib_memset (mp, 0, sizeof (*mp));
222
223   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION);
224   mp->context = server_wrk->wrk_index;
225   mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
226   mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
227
228   if (session_has_transport (s))
229     {
230       listener = listen_session_get (s->listener_index);
231       mp->listener_handle = listen_session_get_handle (listener);
232       if (application_is_proxy (server))
233         {
234           listener =
235             app_worker_first_listener (server_wrk, session_get_fib_proto (s),
236                                        session_get_transport_proto (s));
237           if (listener)
238             mp->listener_handle = listen_session_get_handle (listener);
239         }
240       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
241       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
242       mp->handle = session_handle (s);
243       tc = transport_get_connection (session_get_transport_proto (s),
244                                      s->connection_index, s->thread_index);
245       mp->port = tc->rmt_port;
246       mp->is_ip4 = tc->is_ip4;
247       clib_memcpy_fast (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
248     }
249   else
250     {
251       local_session_t *ls = (local_session_t *) s;
252       local_session_t *ll;
253       if (application_local_session_listener_has_transport (ls))
254         {
255           listener = listen_session_get (ls->listener_index);
256           mp->listener_handle = listen_session_get_handle (listener);
257           mp->is_ip4 = session_type_is_ip4 (listener->session_type);
258         }
259       else
260         {
261           ll = application_get_local_listen_session (server,
262                                                      ls->listener_index);
263           if (ll->transport_listener_index != ~0)
264             {
265               listener = listen_session_get (ll->transport_listener_index);
266               mp->listener_handle = listen_session_get_handle (listener);
267             }
268           else
269             {
270               mp->listener_handle = application_local_session_handle (ll);
271             }
272           mp->is_ip4 = session_type_is_ip4 (ll->listener_session_type);
273         }
274       mp->handle = application_local_session_handle (ls);
275       mp->port = ls->port;
276       mp->vpp_event_queue_address = ls->client_evt_q;
277       mp->server_event_queue_address = ls->server_evt_q;
278     }
279   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
280
281   return 0;
282 }
283
284 static void
285 send_session_disconnect_callback (session_t * s)
286 {
287   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
288   vl_api_disconnect_session_t *mp;
289   vl_api_registration_t *reg;
290
291   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
292   if (!reg)
293     {
294       clib_warning ("no registration: %u", app_wrk->api_client_index);
295       return;
296     }
297
298   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
299   clib_memset (mp, 0, sizeof (*mp));
300   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DISCONNECT_SESSION);
301   mp->handle = session_handle (s);
302   mp->context = app_wrk->api_client_index;
303   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
304 }
305
306 static void
307 send_session_reset_callback (session_t * s)
308 {
309   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
310   vl_api_registration_t *reg;
311   vl_api_reset_session_t *mp;
312
313   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
314   if (!reg)
315     {
316       clib_warning ("no registration: %u", app_wrk->api_client_index);
317       return;
318     }
319
320   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
321   clib_memset (mp, 0, sizeof (*mp));
322   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_RESET_SESSION);
323   mp->handle = session_handle (s);
324   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
325 }
326
327 int
328 send_session_connected_callback (u32 app_wrk_index, u32 api_context,
329                                  session_t * s, u8 is_fail)
330 {
331   vl_api_connect_session_reply_t *mp;
332   transport_connection_t *tc;
333   vl_api_registration_t *reg;
334   svm_msg_q_t *vpp_queue;
335   app_worker_t *app_wrk;
336
337   app_wrk = app_worker_get (app_wrk_index);
338   reg = vl_mem_api_client_index_to_registration (app_wrk->api_client_index);
339   if (!reg)
340     {
341       clib_warning ("no registration: %u", app_wrk->api_client_index);
342       return -1;
343     }
344
345   mp = vl_mem_api_alloc_as_if_client_w_reg (reg, sizeof (*mp));
346   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SESSION_REPLY);
347   mp->context = api_context;
348
349   if (is_fail)
350     goto done;
351
352   if (session_has_transport (s))
353     {
354       tc = session_get_transport (s);
355       if (!tc)
356         {
357           is_fail = 1;
358           goto done;
359         }
360
361       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
362       mp->handle = session_handle (s);
363       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
364       clib_memcpy_fast (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
365       mp->is_ip4 = tc->is_ip4;
366       mp->lcl_port = tc->lcl_port;
367       mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
368       mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
369     }
370   else
371     {
372       local_session_t *ls = (local_session_t *) s;
373       mp->handle = application_local_session_handle (ls);
374       mp->lcl_port = ls->port;
375       mp->vpp_event_queue_address = ls->server_evt_q;
376       mp->client_event_queue_address = ls->client_evt_q;
377       mp->server_rx_fifo = pointer_to_uword (s->tx_fifo);
378       mp->server_tx_fifo = pointer_to_uword (s->rx_fifo);
379     }
380
381 done:
382   mp->retval = is_fail ?
383     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
384   vl_msg_api_send_shmem (reg->vl_input_queue, (u8 *) & mp);
385   return 0;
386 }
387
388 static session_cb_vft_t session_cb_vft = {
389   .session_accept_callback = send_session_accept_callback,
390   .session_disconnect_callback = send_session_disconnect_callback,
391   .session_connected_callback = send_session_connected_callback,
392   .session_reset_callback = send_session_reset_callback,
393   .add_segment_callback = send_add_segment_callback,
394   .del_segment_callback = send_del_segment_callback,
395 };
396
397 static int
398 mq_try_lock_and_alloc_msg (svm_msg_q_t * app_mq, svm_msg_q_msg_t * msg)
399 {
400   int rv;
401   u8 try = 0;
402   while (try < 100)
403     {
404       rv = svm_msg_q_lock_and_alloc_msg_w_ring (app_mq,
405                                                 SESSION_MQ_CTRL_EVT_RING,
406                                                 SVM_Q_NOWAIT, msg);
407       if (!rv)
408         return 0;
409       try++;
410       usleep (1);
411     }
412   clib_warning ("failed to alloc msg");
413   return -1;
414 }
415
416 static int
417 mq_send_session_accepted_cb (session_t * s)
418 {
419   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
420   svm_msg_q_msg_t _msg, *msg = &_msg;
421   svm_msg_q_t *vpp_queue, *app_mq;
422   transport_connection_t *tc;
423   session_t *listener;
424   session_accepted_msg_t *mp;
425   session_event_t *evt;
426   application_t *app;
427
428   app = application_get (app_wrk->app_index);
429   app_mq = app_wrk->event_queue;
430   if (mq_try_lock_and_alloc_msg (app_mq, msg))
431     return -1;
432
433   evt = svm_msg_q_msg_data (app_mq, msg);
434   clib_memset (evt, 0, sizeof (*evt));
435   evt->event_type = SESSION_CTRL_EVT_ACCEPTED;
436   mp = (session_accepted_msg_t *) evt->data;
437   clib_memset (mp, 0, sizeof (*mp));
438   mp->context = app->app_index;
439   mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
440   mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
441   mp->segment_handle = session_segment_handle (s);
442
443   if (session_has_transport (s))
444     {
445       listener = listen_session_get (s->listener_index);
446       mp->listener_handle = listen_session_get_handle (listener);
447       if (application_is_proxy (app))
448         {
449           listener =
450             app_worker_first_listener (app_wrk, session_get_fib_proto (s),
451                                        session_get_transport_proto (s));
452           if (listener)
453             mp->listener_handle = listen_session_get_handle (listener);
454         }
455       vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
456       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
457       mp->handle = session_handle (s);
458       tc = transport_get_connection (session_get_transport_proto (s),
459                                      s->connection_index, s->thread_index);
460       mp->port = tc->rmt_port;
461       mp->is_ip4 = tc->is_ip4;
462       clib_memcpy_fast (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
463     }
464   else
465     {
466       local_session_t *ls = (local_session_t *) s;
467       local_session_t *ll;
468       u8 main_thread = vlib_num_workers ()? 1 : 0;
469
470       send_app_cut_through_registration_add (app_wrk->api_client_index,
471                                              app_wrk->wrk_map_index,
472                                              ls->server_evt_q,
473                                              ls->client_evt_q);
474
475       if (application_local_session_listener_has_transport (ls))
476         {
477           listener = listen_session_get (ls->listener_index);
478           mp->listener_handle = listen_session_get_handle (listener);
479           mp->is_ip4 = session_type_is_ip4 (listener->session_type);
480         }
481       else
482         {
483           ll = application_get_local_listen_session (app, ls->listener_index);
484           if (ll->transport_listener_index != ~0)
485             {
486               listener = listen_session_get (ll->transport_listener_index);
487               mp->listener_handle = listen_session_get_handle (listener);
488             }
489           else
490             {
491               mp->listener_handle = application_local_session_handle (ll);
492             }
493           mp->is_ip4 = session_type_is_ip4 (ll->listener_session_type);
494         }
495       mp->handle = application_local_session_handle (ls);
496       mp->port = ls->port;
497       vpp_queue = session_manager_get_vpp_event_queue (main_thread);
498       mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
499       mp->client_event_queue_address = ls->client_evt_q;
500       mp->server_event_queue_address = ls->server_evt_q;
501     }
502   svm_msg_q_add_and_unlock (app_mq, msg);
503
504   return 0;
505 }
506
507 static inline void
508 mq_send_session_close_evt (app_worker_t * app_wrk, session_handle_t sh,
509                            session_evt_type_t evt_type)
510 {
511   svm_msg_q_msg_t _msg, *msg = &_msg;
512   session_disconnected_msg_t *mp;
513   svm_msg_q_t *app_mq;
514   session_event_t *evt;
515
516   app_mq = app_wrk->event_queue;
517   if (mq_try_lock_and_alloc_msg (app_mq, msg))
518     return;
519   evt = svm_msg_q_msg_data (app_mq, msg);
520   clib_memset (evt, 0, sizeof (*evt));
521   evt->event_type = evt_type;
522   mp = (session_disconnected_msg_t *) evt->data;
523   mp->handle = sh;
524   mp->context = app_wrk->api_client_index;
525   svm_msg_q_add_and_unlock (app_mq, msg);
526 }
527
528 static inline void
529 mq_notify_close_subscribers (u32 app_index, session_handle_t sh,
530                              svm_fifo_t * f, session_evt_type_t evt_type)
531 {
532   app_worker_t *app_wrk;
533   application_t *app;
534   int i;
535
536   app = application_get (app_index);
537   if (!app)
538     return;
539
540   for (i = 0; i < f->n_subscribers; i++)
541     {
542       if (!(app_wrk = application_get_worker (app, f->subscribers[i])))
543         continue;
544       mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_DISCONNECTED);
545     }
546 }
547
548 static void
549 mq_send_session_disconnected_cb (session_t * s)
550 {
551   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
552   session_handle_t sh = session_handle (s);
553
554   mq_send_session_close_evt (app_wrk, session_handle (s),
555                              SESSION_CTRL_EVT_DISCONNECTED);
556
557   if (svm_fifo_n_subscribers (s->rx_fifo))
558     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
559                                  SESSION_CTRL_EVT_DISCONNECTED);
560 }
561
562 void
563 mq_send_local_session_disconnected_cb (u32 app_wrk_index,
564                                        local_session_t * ls)
565 {
566   app_worker_t *app_wrk = app_worker_get (app_wrk_index);
567   session_handle_t sh = application_local_session_handle (ls);
568
569   mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_DISCONNECTED);
570
571   if (svm_fifo_n_subscribers (ls->rx_fifo))
572     mq_notify_close_subscribers (app_wrk->app_index, sh, ls->rx_fifo,
573                                  SESSION_CTRL_EVT_DISCONNECTED);
574 }
575
576 static void
577 mq_send_session_reset_cb (session_t * s)
578 {
579   app_worker_t *app_wrk = app_worker_get (s->app_wrk_index);
580   session_handle_t sh = session_handle (s);
581
582   mq_send_session_close_evt (app_wrk, sh, SESSION_CTRL_EVT_RESET);
583
584   if (svm_fifo_n_subscribers (s->rx_fifo))
585     mq_notify_close_subscribers (app_wrk->app_index, sh, s->rx_fifo,
586                                  SESSION_CTRL_EVT_RESET);
587 }
588
589 static int
590 mq_send_session_connected_cb (u32 app_wrk_index, u32 api_context,
591                               session_t * s, u8 is_fail)
592 {
593   svm_msg_q_msg_t _msg, *msg = &_msg;
594   session_connected_msg_t *mp;
595   svm_msg_q_t *vpp_mq, *app_mq;
596   transport_connection_t *tc;
597   app_worker_t *app_wrk;
598   session_event_t *evt;
599
600   app_wrk = app_worker_get (app_wrk_index);
601   app_mq = app_wrk->event_queue;
602   if (!app_mq)
603     {
604       clib_warning ("app %u with api index: %u not attached",
605                     app_wrk->app_index, app_wrk->api_client_index);
606       return -1;
607     }
608
609   if (mq_try_lock_and_alloc_msg (app_mq, msg))
610     return -1;
611
612   evt = svm_msg_q_msg_data (app_mq, msg);
613   clib_memset (evt, 0, sizeof (*evt));
614   evt->event_type = SESSION_CTRL_EVT_CONNECTED;
615   mp = (session_connected_msg_t *) evt->data;
616   clib_memset (mp, 0, sizeof (*mp));
617   mp->context = api_context;
618
619   if (is_fail)
620     goto done;
621
622   mp->segment_handle = session_segment_handle (s);
623
624   if (session_has_transport (s))
625     {
626       tc = session_get_transport (s);
627       if (!tc)
628         {
629           is_fail = 1;
630           goto done;
631         }
632
633       vpp_mq = session_manager_get_vpp_event_queue (s->thread_index);
634       mp->handle = session_handle (s);
635       mp->vpp_event_queue_address = pointer_to_uword (vpp_mq);
636       clib_memcpy_fast (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
637       mp->is_ip4 = tc->is_ip4;
638       mp->lcl_port = tc->lcl_port;
639       mp->server_rx_fifo = pointer_to_uword (s->rx_fifo);
640       mp->server_tx_fifo = pointer_to_uword (s->tx_fifo);
641     }
642   else
643     {
644       local_session_t *ls = (local_session_t *) s;
645       u8 main_thread = vlib_num_workers ()? 1 : 0;
646
647       send_app_cut_through_registration_add (app_wrk->api_client_index,
648                                              app_wrk->wrk_map_index,
649                                              ls->client_evt_q,
650                                              ls->server_evt_q);
651
652       mp->handle = application_local_session_handle (ls);
653       mp->lcl_port = ls->port;
654       vpp_mq = session_manager_get_vpp_event_queue (main_thread);
655       mp->vpp_event_queue_address = pointer_to_uword (vpp_mq);
656       mp->client_event_queue_address = ls->client_evt_q;
657       mp->server_event_queue_address = ls->server_evt_q;
658       mp->server_rx_fifo = pointer_to_uword (s->tx_fifo);
659       mp->server_tx_fifo = pointer_to_uword (s->rx_fifo);
660     }
661
662 done:
663   mp->retval = is_fail ?
664     clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
665
666   svm_msg_q_add_and_unlock (app_mq, msg);
667   return 0;
668 }
669
670 static int
671 mq_send_session_bound_cb (u32 app_wrk_index, u32 api_context,
672                           session_handle_t handle, int rv)
673 {
674   svm_msg_q_msg_t _msg, *msg = &_msg;
675   svm_msg_q_t *app_mq, *vpp_evt_q;
676   transport_connection_t *tc;
677   session_t *ls = 0;
678   session_bound_msg_t *mp;
679   app_worker_t *app_wrk;
680   session_event_t *evt;
681   application_t *app;
682
683   app_wrk = app_worker_get (app_wrk_index);
684   app = application_get (app_wrk->app_index);
685   app_mq = app_wrk->event_queue;
686   if (!app_mq)
687     {
688       clib_warning ("app %u with api index: %u not attached",
689                     app_wrk->app_index, app_wrk->api_client_index);
690       return -1;
691     }
692
693   if (mq_try_lock_and_alloc_msg (app_mq, msg))
694     return -1;
695
696   evt = svm_msg_q_msg_data (app_mq, msg);
697   clib_memset (evt, 0, sizeof (*evt));
698   evt->event_type = SESSION_CTRL_EVT_BOUND;
699   mp = (session_bound_msg_t *) evt->data;
700   mp->context = api_context;
701
702   if (rv)
703     goto done;
704
705   mp->handle = handle;
706   if (application_has_global_scope (app))
707     {
708       ls = listen_session_get_from_handle (handle);
709       tc = listen_session_get_transport (ls);
710       mp->lcl_port = tc->lcl_port;
711       mp->lcl_is_ip4 = tc->is_ip4;
712       clib_memcpy_fast (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
713     }
714   else
715     {
716       local_session_t *local;
717       local = application_get_local_listener_w_handle (handle);
718       mp->lcl_port = local->port;
719       mp->lcl_is_ip4 = session_type_is_ip4 (local->session_type);
720     }
721
722   vpp_evt_q = session_manager_get_vpp_event_queue (0);
723   mp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
724
725   if (ls && session_transport_service_type (ls) == TRANSPORT_SERVICE_CL)
726     {
727       mp->rx_fifo = pointer_to_uword (ls->rx_fifo);
728       mp->tx_fifo = pointer_to_uword (ls->tx_fifo);
729     }
730
731 done:
732   mp->retval = rv;
733   svm_msg_q_add_and_unlock (app_mq, msg);
734   return 0;
735 }
736
737 static session_cb_vft_t session_mq_cb_vft = {
738   .session_accept_callback = mq_send_session_accepted_cb,
739   .session_disconnect_callback = mq_send_session_disconnected_cb,
740   .session_connected_callback = mq_send_session_connected_cb,
741   .session_reset_callback = mq_send_session_reset_cb,
742   .add_segment_callback = send_add_segment_callback,
743   .del_segment_callback = send_del_segment_callback,
744 };
745
746 static void
747 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
748 {
749   vl_api_session_enable_disable_reply_t *rmp;
750   vlib_main_t *vm = vlib_get_main ();
751   int rv = 0;
752
753   vnet_session_enable_disable (vm, mp->is_enable);
754   REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
755 }
756
757 static void
758 vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
759 {
760   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
761   vl_api_application_attach_reply_t *rmp;
762   ssvm_private_t *segp, *evt_q_segment;
763   vnet_app_attach_args_t _a, *a = &_a;
764   vl_api_registration_t *reg;
765   clib_error_t *error = 0;
766   u8 fd_flags = 0;
767
768   reg = vl_api_client_index_to_registration (mp->client_index);
769   if (!reg)
770     return;
771
772   if (session_manager_is_enabled () == 0)
773     {
774       rv = VNET_API_ERROR_FEATURE_DISABLED;
775       goto done;
776     }
777
778   STATIC_ASSERT (sizeof (u64) * APP_OPTIONS_N_OPTIONS <=
779                  sizeof (mp->options),
780                  "Out of options, fix api message definition");
781
782   clib_memset (a, 0, sizeof (*a));
783   a->api_client_index = mp->client_index;
784   a->options = mp->options;
785
786   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS)
787     a->session_cb_vft = &session_mq_cb_vft;
788   else
789     a->session_cb_vft = &session_cb_vft;
790
791   if (mp->namespace_id_len > 64)
792     {
793       rv = VNET_API_ERROR_INVALID_VALUE;
794       goto done;
795     }
796
797   if (mp->namespace_id_len)
798     {
799       vec_validate (a->namespace_id, mp->namespace_id_len - 1);
800       clib_memcpy_fast (a->namespace_id, mp->namespace_id,
801                         mp->namespace_id_len);
802     }
803
804   if ((error = vnet_application_attach (a)))
805     {
806       rv = clib_error_get_code (error);
807       clib_error_report (error);
808       vec_free (a->namespace_id);
809       goto done;
810     }
811   vec_free (a->namespace_id);
812
813   /* Send event queues segment */
814   if ((evt_q_segment = session_manager_get_evt_q_segment ()))
815     {
816       fd_flags |= SESSION_FD_F_VPP_MQ_SEGMENT;
817       fds[n_fds] = evt_q_segment->fd;
818       n_fds += 1;
819     }
820   /* Send fifo segment fd if needed */
821   if (ssvm_type (a->segment) == SSVM_SEGMENT_MEMFD)
822     {
823       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
824       fds[n_fds] = a->segment->fd;
825       n_fds += 1;
826     }
827   if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
828     {
829       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
830       fds[n_fds] = svm_msg_q_get_producer_eventfd (a->app_evt_q);
831       n_fds += 1;
832     }
833
834 done:
835
836   /* *INDENT-OFF* */
837   REPLY_MACRO2 (VL_API_APPLICATION_ATTACH_REPLY, ({
838     if (!rv)
839       {
840         segp = a->segment;
841         rmp->app_index = clib_host_to_net_u32 (a->app_index);
842         rmp->segment_name_length = 0;
843         rmp->segment_size = segp->ssvm_size;
844         if (vec_len (segp->name))
845           {
846             memcpy (rmp->segment_name, segp->name, vec_len (segp->name));
847             rmp->segment_name_length = vec_len (segp->name);
848           }
849         rmp->app_event_queue_address = pointer_to_uword (a->app_evt_q);
850         rmp->n_fds = n_fds;
851         rmp->fd_flags = fd_flags;
852         rmp->segment_handle = clib_host_to_net_u64 (a->segment_handle);
853       }
854   }));
855   /* *INDENT-ON* */
856
857   if (n_fds)
858     session_send_fds (reg, fds, n_fds);
859 }
860
861 static void
862 vl_api_application_detach_t_handler (vl_api_application_detach_t * mp)
863 {
864   vl_api_application_detach_reply_t *rmp;
865   int rv = VNET_API_ERROR_INVALID_VALUE_2;
866   vnet_app_detach_args_t _a, *a = &_a;
867   application_t *app;
868
869   if (session_manager_is_enabled () == 0)
870     {
871       rv = VNET_API_ERROR_FEATURE_DISABLED;
872       goto done;
873     }
874
875   app = application_lookup (mp->client_index);
876   if (app)
877     {
878       a->app_index = app->app_index;
879       a->api_client_index = mp->client_index;
880       rv = vnet_application_detach (a);
881     }
882
883 done:
884   REPLY_MACRO (VL_API_APPLICATION_DETACH_REPLY);
885 }
886
887 static void
888 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
889 {
890   transport_connection_t *tc = 0;
891   vnet_bind_args_t _a, *a = &_a;
892   vl_api_bind_uri_reply_t *rmp;
893   session_t *s;
894   application_t *app = 0;
895   svm_msg_q_t *vpp_evt_q;
896   app_worker_t *app_wrk;
897   int rv;
898
899   if (session_manager_is_enabled () == 0)
900     {
901       rv = VNET_API_ERROR_FEATURE_DISABLED;
902       goto done;
903     }
904
905   app = application_lookup (mp->client_index);
906   if (app)
907     {
908       clib_memset (a, 0, sizeof (*a));
909       a->uri = (char *) mp->uri;
910       a->app_index = app->app_index;
911       rv = vnet_bind_uri (a);
912     }
913   else
914     {
915       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
916     }
917
918 done:
919
920   /* *INDENT-OFF* */
921   REPLY_MACRO2 (VL_API_BIND_URI_REPLY, ({
922     if (!rv)
923       {
924         rmp->handle = a->handle;
925         if (app && application_has_global_scope (app))
926             {
927               s = listen_session_get_from_handle (a->handle);
928               tc = listen_session_get_transport (s);
929               rmp->lcl_is_ip4 = tc->is_ip4;
930               rmp->lcl_port = tc->lcl_port;
931               clib_memcpy_fast (rmp->lcl_ip, &tc->lcl_ip, sizeof(tc->lcl_ip));
932               if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
933                 {
934                   rmp->rx_fifo = pointer_to_uword (s->rx_fifo);
935                   rmp->tx_fifo = pointer_to_uword (s->tx_fifo);
936                   vpp_evt_q = session_manager_get_vpp_event_queue (0);
937                   rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
938                 }
939             }
940       }
941   }));
942   /* *INDENT-ON* */
943
944   /* If app uses mq for control messages, send an mq message as well */
945   if (app && application_use_mq_for_ctrl (app))
946     {
947       app_wrk = application_get_worker (app, 0);
948       mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle,
949                                 rv);
950     }
951 }
952
953 static void
954 vl_api_unbind_uri_t_handler (vl_api_unbind_uri_t * mp)
955 {
956   vl_api_unbind_uri_reply_t *rmp;
957   application_t *app;
958   vnet_unbind_args_t _a, *a = &_a;
959   int rv;
960
961   if (session_manager_is_enabled () == 0)
962     {
963       rv = VNET_API_ERROR_FEATURE_DISABLED;
964       goto done;
965     }
966
967   app = application_lookup (mp->client_index);
968   if (app)
969     {
970       a->uri = (char *) mp->uri;
971       a->app_index = app->app_index;
972       rv = vnet_unbind_uri (a);
973     }
974   else
975     {
976       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
977     }
978
979 done:
980   REPLY_MACRO (VL_API_UNBIND_URI_REPLY);
981 }
982
983 static void
984 vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
985 {
986   vl_api_connect_session_reply_t *rmp;
987   vnet_connect_args_t _a, *a = &_a;
988   application_t *app;
989   clib_error_t *error = 0;
990   int rv = 0;
991
992   if (session_manager_is_enabled () == 0)
993     {
994       rv = VNET_API_ERROR_FEATURE_DISABLED;
995       goto done;
996     }
997
998   app = application_lookup (mp->client_index);
999   if (app)
1000     {
1001       clib_memset (a, 0, sizeof (*a));
1002       a->uri = (char *) mp->uri;
1003       a->api_context = mp->context;
1004       a->app_index = app->app_index;
1005       if ((error = vnet_connect_uri (a)))
1006         {
1007           rv = clib_error_get_code (error);
1008           clib_error_report (error);
1009         }
1010     }
1011   else
1012     {
1013       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1014     }
1015
1016   /*
1017    * Don't reply to stream (tcp) connects. The reply will come once
1018    * the connection is established. In case of the redirects, the reply
1019    * will come from the server app.
1020    */
1021   if (rv == 0)
1022     return;
1023
1024 done:
1025   /* *INDENT-OFF* */
1026   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
1027   /* *INDENT-ON* */
1028 }
1029
1030 static void
1031 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
1032 {
1033   vl_api_disconnect_session_reply_t *rmp;
1034   vnet_disconnect_args_t _a, *a = &_a;
1035   application_t *app;
1036   int rv = 0;
1037
1038   if (session_manager_is_enabled () == 0)
1039     {
1040       rv = VNET_API_ERROR_FEATURE_DISABLED;
1041       goto done;
1042     }
1043
1044   app = application_lookup (mp->client_index);
1045   if (app)
1046     {
1047       a->handle = mp->handle;
1048       a->app_index = app->app_index;
1049       rv = vnet_disconnect_session (a);
1050     }
1051   else
1052     {
1053       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1054     }
1055
1056 done:
1057   REPLY_MACRO2 (VL_API_DISCONNECT_SESSION_REPLY, rmp->handle = mp->handle);
1058 }
1059
1060 static void
1061 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
1062                                            mp)
1063 {
1064   vnet_disconnect_args_t _a, *a = &_a;
1065   application_t *app;
1066
1067   /* Client objected to disconnecting the session, log and continue */
1068   if (mp->retval)
1069     {
1070       clib_warning ("client retval %d", mp->retval);
1071       return;
1072     }
1073
1074   /* Disconnect has been confirmed. Confirm close to transport */
1075   app = application_lookup (mp->context);
1076   if (app)
1077     {
1078       a->handle = mp->handle;
1079       a->app_index = app->app_index;
1080       vnet_disconnect_session (a);
1081     }
1082 }
1083
1084 static void
1085 vl_api_reset_session_reply_t_handler (vl_api_reset_session_reply_t * mp)
1086 {
1087   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
1088   app_worker_t *app_wrk;
1089   application_t *app;
1090   session_t *s;
1091   u32 index, thread_index;
1092
1093   app = application_lookup (mp->context);
1094   if (!app)
1095     return;
1096
1097   session_parse_handle (mp->handle, &index, &thread_index);
1098   s = session_get_if_valid (index, thread_index);
1099   if (!s)
1100     {
1101       clib_warning ("Invalid session!");
1102       return;
1103     }
1104
1105   app_wrk = app_worker_get (s->app_wrk_index);
1106   if (app_wrk->app_index != app->app_index)
1107     {
1108       clib_warning ("app %u does not own handle 0x%lx", app->app_index,
1109                     mp->handle);
1110       return;
1111     }
1112
1113   /* Client objected to resetting the session, log and continue */
1114   if (mp->retval)
1115     {
1116       clib_warning ("client retval %d", mp->retval);
1117       return;
1118     }
1119
1120   /* This comes as a response to a reset, transport only waiting for
1121    * confirmation to remove connection state, no need to disconnect */
1122   a->handle = mp->handle;
1123   a->app_index = app->app_index;
1124   vnet_disconnect_session (a);
1125 }
1126
1127 static void
1128 vl_api_accept_session_reply_t_handler (vl_api_accept_session_reply_t * mp)
1129 {
1130   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
1131   local_session_t *ls;
1132   session_t *s;
1133
1134   /* Server isn't interested, kill the session */
1135   if (mp->retval)
1136     {
1137       a->app_index = mp->context;
1138       a->handle = mp->handle;
1139       vnet_disconnect_session (a);
1140       return;
1141     }
1142
1143   if (session_handle_is_local (mp->handle))
1144     {
1145       ls = app_worker_get_local_session_from_handle (mp->handle);
1146       if (!ls || ls->app_wrk_index != mp->context)
1147         {
1148           clib_warning ("server %u doesn't own local handle %llu",
1149                         mp->context, mp->handle);
1150           return;
1151         }
1152       if (app_worker_local_session_connect_notify (ls))
1153         return;
1154       ls->session_state = SESSION_STATE_READY;
1155     }
1156   else
1157     {
1158       s = session_get_from_handle_if_valid (mp->handle);
1159       if (!s)
1160         {
1161           clib_warning ("session doesn't exist");
1162           return;
1163         }
1164       if (s->app_wrk_index != mp->context)
1165         {
1166           clib_warning ("app doesn't own session");
1167           return;
1168         }
1169       s->session_state = SESSION_STATE_READY;
1170     }
1171 }
1172
1173 static void
1174 vl_api_map_another_segment_reply_t_handler (vl_api_map_another_segment_reply_t
1175                                             * mp)
1176 {
1177   clib_warning ("not implemented");
1178 }
1179
1180 static void
1181 vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
1182 {
1183   vl_api_bind_sock_reply_t *rmp;
1184   vnet_bind_args_t _a, *a = &_a;
1185   int rv = 0;
1186   clib_error_t *error;
1187   application_t *app = 0;
1188   app_worker_t *app_wrk;
1189   session_t *s;
1190   transport_connection_t *tc = 0;
1191   ip46_address_t *ip46;
1192   svm_msg_q_t *vpp_evt_q;
1193
1194   if (session_manager_is_enabled () == 0)
1195     {
1196       rv = VNET_API_ERROR_FEATURE_DISABLED;
1197       goto done;
1198     }
1199
1200   app = application_lookup (mp->client_index);
1201   if (!app)
1202     {
1203       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1204       goto done;
1205     }
1206
1207   ip46 = (ip46_address_t *) mp->ip;
1208   clib_memset (a, 0, sizeof (*a));
1209   a->sep.is_ip4 = mp->is_ip4;
1210   a->sep.ip = *ip46;
1211   a->sep.port = mp->port;
1212   a->sep.fib_index = mp->vrf;
1213   a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
1214   a->sep.transport_proto = mp->proto;
1215   a->app_index = app->app_index;
1216   a->wrk_map_index = mp->wrk_index;
1217
1218   if ((error = vnet_bind (a)))
1219     {
1220       rv = clib_error_get_code (error);
1221       clib_error_report (error);
1222     }
1223
1224 done:
1225   /* *INDENT-OFF* */
1226   REPLY_MACRO2 (VL_API_BIND_SOCK_REPLY,({
1227     if (!rv)
1228       {
1229         rmp->handle = a->handle;
1230         rmp->lcl_port = mp->port;
1231         rmp->lcl_is_ip4 = mp->is_ip4;
1232         if (app && application_has_global_scope (app))
1233           {
1234             s = listen_session_get_from_handle (a->handle);
1235             tc = listen_session_get_transport (s);
1236             clib_memcpy_fast (rmp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
1237             if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
1238               {
1239                 rmp->rx_fifo = pointer_to_uword (s->rx_fifo);
1240                 rmp->tx_fifo = pointer_to_uword (s->tx_fifo);
1241                 vpp_evt_q = session_manager_get_vpp_event_queue (0);
1242                 rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
1243               }
1244           }
1245       }
1246   }));
1247   /* *INDENT-ON* */
1248
1249   /* If app uses mq for control messages, send an mq message as well */
1250   if (app && application_use_mq_for_ctrl (app))
1251     {
1252       app_wrk = application_get_worker (app, mp->wrk_index);
1253       mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle,
1254                                 rv);
1255     }
1256 }
1257
1258 static void
1259 vl_api_unbind_sock_t_handler (vl_api_unbind_sock_t * mp)
1260 {
1261   vl_api_unbind_sock_reply_t *rmp;
1262   vnet_unbind_args_t _a, *a = &_a;
1263   application_t *app;
1264   clib_error_t *error;
1265   int rv = 0;
1266
1267   if (session_manager_is_enabled () == 0)
1268     {
1269       rv = VNET_API_ERROR_FEATURE_DISABLED;
1270       goto done;
1271     }
1272
1273   app = application_lookup (mp->client_index);
1274   if (app)
1275     {
1276       a->app_index = app->app_index;
1277       a->handle = mp->handle;
1278       a->wrk_map_index = mp->wrk_index;
1279       if ((error = vnet_unbind (a)))
1280         {
1281           rv = clib_error_get_code (error);
1282           clib_error_report (error);
1283         }
1284     }
1285
1286 done:
1287   REPLY_MACRO (VL_API_UNBIND_SOCK_REPLY);
1288 }
1289
1290 static void
1291 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
1292 {
1293   vl_api_connect_session_reply_t *rmp;
1294   vnet_connect_args_t _a, *a = &_a;
1295   application_t *app = 0;
1296   clib_error_t *error = 0;
1297   int rv = 0;
1298
1299   if (session_manager_is_enabled () == 0)
1300     {
1301       rv = VNET_API_ERROR_FEATURE_DISABLED;
1302       goto done;
1303     }
1304
1305   app = application_lookup (mp->client_index);
1306   if (app)
1307     {
1308       svm_queue_t *client_q;
1309       ip46_address_t *ip46 = (ip46_address_t *) mp->ip;
1310
1311       clib_memset (a, 0, sizeof (*a));
1312       client_q = vl_api_client_index_to_input_queue (mp->client_index);
1313       mp->client_queue_address = pointer_to_uword (client_q);
1314       a->sep.is_ip4 = mp->is_ip4;
1315       a->sep.ip = *ip46;
1316       a->sep.port = mp->port;
1317       a->sep.transport_proto = mp->proto;
1318       a->sep.peer.fib_index = mp->vrf;
1319       a->sep.peer.sw_if_index = ENDPOINT_INVALID_INDEX;
1320       if (mp->hostname_len)
1321         {
1322           vec_validate (a->sep_ext.hostname, mp->hostname_len - 1);
1323           clib_memcpy_fast (a->sep_ext.hostname, mp->hostname,
1324                             mp->hostname_len);
1325         }
1326       a->api_context = mp->context;
1327       a->app_index = app->app_index;
1328       a->wrk_map_index = mp->wrk_index;
1329       if ((error = vnet_connect (a)))
1330         {
1331           rv = clib_error_get_code (error);
1332           clib_error_report (error);
1333         }
1334       vec_free (a->sep_ext.hostname);
1335     }
1336   else
1337     {
1338       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1339     }
1340
1341   if (rv == 0)
1342     return;
1343
1344   /* Got some error, relay it */
1345
1346 done:
1347   REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY);
1348
1349   if (app && application_use_mq_for_ctrl (app))
1350     {
1351       app_worker_t *app_wrk = application_get_worker (app, mp->wrk_index);
1352       mq_send_session_connected_cb (app_wrk->wrk_index, mp->context, 0, 1);
1353     }
1354 }
1355
1356 static void
1357 vl_api_app_worker_add_del_t_handler (vl_api_app_worker_add_del_t * mp)
1358 {
1359   int rv = 0, fds[SESSION_N_FD_TYPE], n_fds = 0;
1360   vl_api_app_worker_add_del_reply_t *rmp;
1361   vl_api_registration_t *reg;
1362   clib_error_t *error = 0;
1363   application_t *app;
1364   u8 fd_flags = 0;
1365
1366   if (!session_manager_is_enabled ())
1367     {
1368       rv = VNET_API_ERROR_FEATURE_DISABLED;
1369       goto done;
1370     }
1371
1372   reg = vl_api_client_index_to_registration (mp->client_index);
1373   if (!reg)
1374     return;
1375
1376   app = application_get_if_valid (clib_net_to_host_u32 (mp->app_index));
1377   if (!app)
1378     {
1379       rv = VNET_API_ERROR_INVALID_VALUE;
1380       goto done;
1381     }
1382
1383   vnet_app_worker_add_del_args_t args = {
1384     .app_index = app->app_index,
1385     .wrk_map_index = clib_net_to_host_u32 (mp->wrk_index),
1386     .api_client_index = mp->client_index,
1387     .is_add = mp->is_add
1388   };
1389   error = vnet_app_worker_add_del (&args);
1390   if (error)
1391     {
1392       rv = clib_error_get_code (error);
1393       clib_error_report (error);
1394       goto done;
1395     }
1396
1397   if (!mp->is_add)
1398     goto done;
1399
1400   /* Send fifo segment fd if needed */
1401   if (ssvm_type (args.segment) == SSVM_SEGMENT_MEMFD)
1402     {
1403       fd_flags |= SESSION_FD_F_MEMFD_SEGMENT;
1404       fds[n_fds] = args.segment->fd;
1405       n_fds += 1;
1406     }
1407   if (application_segment_manager_properties (app)->use_mq_eventfd)
1408     {
1409       fd_flags |= SESSION_FD_F_MQ_EVENTFD;
1410       fds[n_fds] = svm_msg_q_get_producer_eventfd (args.evt_q);
1411       n_fds += 1;
1412     }
1413
1414   /* *INDENT-OFF* */
1415 done:
1416   REPLY_MACRO2 (VL_API_APP_WORKER_ADD_DEL_REPLY, ({
1417     rmp->is_add = mp->is_add;
1418     rmp->wrk_index = clib_host_to_net_u32 (args.wrk_map_index);
1419     rmp->segment_handle = clib_host_to_net_u64 (args.segment_handle);
1420     if (!rv && mp->is_add)
1421       {
1422         if (vec_len (args.segment->name))
1423           {
1424             memcpy (rmp->segment_name, args.segment->name,
1425                     vec_len (args.segment->name));
1426             rmp->segment_name_length = vec_len (args.segment->name);
1427           }
1428         rmp->app_event_queue_address = pointer_to_uword (args.evt_q);
1429         rmp->n_fds = n_fds;
1430         rmp->fd_flags = fd_flags;
1431       }
1432   }));
1433   /* *INDENT-ON* */
1434
1435   if (n_fds)
1436     session_send_fds (reg, fds, n_fds);
1437 }
1438
1439 static void
1440 vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp)
1441 {
1442   vl_api_app_namespace_add_del_reply_t *rmp;
1443   clib_error_t *error = 0;
1444   u32 appns_index = 0;
1445   u8 *ns_id = 0;
1446   int rv = 0;
1447   if (!session_manager_is_enabled ())
1448     {
1449       rv = VNET_API_ERROR_FEATURE_DISABLED;
1450       goto done;
1451     }
1452
1453   if (mp->namespace_id_len > ARRAY_LEN (mp->namespace_id))
1454     {
1455       rv = VNET_API_ERROR_INVALID_VALUE;
1456       goto done;
1457     }
1458
1459   vec_validate (ns_id, mp->namespace_id_len - 1);
1460   clib_memcpy_fast (ns_id, mp->namespace_id, mp->namespace_id_len);
1461   vnet_app_namespace_add_del_args_t args = {
1462     .ns_id = ns_id,
1463     .secret = clib_net_to_host_u64 (mp->secret),
1464     .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index),
1465     .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id),
1466     .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id),
1467     .is_add = 1
1468   };
1469   error = vnet_app_namespace_add_del (&args);
1470   if (error)
1471     {
1472       rv = clib_error_get_code (error);
1473       clib_error_report (error);
1474     }
1475   else
1476     {
1477       appns_index = app_namespace_index_from_id (ns_id);
1478       if (appns_index == APP_NAMESPACE_INVALID_INDEX)
1479         {
1480           clib_warning ("app ns lookup failed");
1481           rv = VNET_API_ERROR_UNSPECIFIED;
1482         }
1483     }
1484   vec_free (ns_id);
1485
1486   /* *INDENT-OFF* */
1487 done:
1488   REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_REPLY, ({
1489     if (!rv)
1490       rmp->appns_index = clib_host_to_net_u32 (appns_index);
1491   }));
1492   /* *INDENT-ON* */
1493 }
1494
1495 static void
1496 vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp)
1497 {
1498   vl_api_session_rule_add_del_reply_t *rmp;
1499   session_rule_add_del_args_t args;
1500   session_rule_table_add_del_args_t *table_args = &args.table_args;
1501   clib_error_t *error;
1502   u8 fib_proto;
1503   int rv = 0;
1504
1505   clib_memset (&args, 0, sizeof (args));
1506   fib_proto = mp->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
1507
1508   table_args->lcl.fp_len = mp->lcl_plen;
1509   table_args->lcl.fp_proto = fib_proto;
1510   table_args->rmt.fp_len = mp->rmt_plen;
1511   table_args->rmt.fp_proto = fib_proto;
1512   table_args->lcl_port = mp->lcl_port;
1513   table_args->rmt_port = mp->rmt_port;
1514   table_args->action_index = clib_net_to_host_u32 (mp->action_index);
1515   table_args->is_add = mp->is_add;
1516   mp->tag[sizeof (mp->tag) - 1] = 0;
1517   table_args->tag = format (0, "%s", mp->tag);
1518   args.appns_index = clib_net_to_host_u32 (mp->appns_index);
1519   args.scope = mp->scope;
1520   args.transport_proto = mp->transport_proto;
1521
1522   clib_memset (&table_args->lcl.fp_addr, 0, sizeof (table_args->lcl.fp_addr));
1523   clib_memset (&table_args->rmt.fp_addr, 0, sizeof (table_args->rmt.fp_addr));
1524   ip_set (&table_args->lcl.fp_addr, mp->lcl_ip, mp->is_ip4);
1525   ip_set (&table_args->rmt.fp_addr, mp->rmt_ip, mp->is_ip4);
1526   error = vnet_session_rule_add_del (&args);
1527   if (error)
1528     {
1529       rv = clib_error_get_code (error);
1530       clib_error_report (error);
1531     }
1532   vec_free (table_args->tag);
1533   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
1534 }
1535
1536 static void
1537 send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
1538                             u8 transport_proto, u32 appns_index, u8 * tag,
1539                             vl_api_registration_t * reg, u32 context)
1540 {
1541   vl_api_session_rules_details_t *rmp = 0;
1542   session_mask_or_match_4_t *match =
1543     (session_mask_or_match_4_t *) & rule->match;
1544   session_mask_or_match_4_t *mask =
1545     (session_mask_or_match_4_t *) & rule->mask;
1546
1547   rmp = vl_msg_api_alloc (sizeof (*rmp));
1548   clib_memset (rmp, 0, sizeof (*rmp));
1549   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1550   rmp->context = context;
1551
1552   rmp->is_ip4 = 1;
1553   clib_memcpy_fast (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
1554   clib_memcpy_fast (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
1555   rmp->lcl_plen = ip4_mask_to_preflen (&mask->lcl_ip);
1556   rmp->rmt_plen = ip4_mask_to_preflen (&mask->rmt_ip);
1557   rmp->lcl_port = match->lcl_port;
1558   rmp->rmt_port = match->rmt_port;
1559   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1560   rmp->scope =
1561     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
1562   rmp->transport_proto = transport_proto;
1563   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1564   if (tag)
1565     {
1566       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1567       rmp->tag[vec_len (tag)] = 0;
1568     }
1569
1570   vl_api_send_msg (reg, (u8 *) rmp);
1571 }
1572
1573 static void
1574 send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
1575                             u8 transport_proto, u32 appns_index, u8 * tag,
1576                             vl_api_registration_t * reg, u32 context)
1577 {
1578   vl_api_session_rules_details_t *rmp = 0;
1579   session_mask_or_match_6_t *match =
1580     (session_mask_or_match_6_t *) & rule->match;
1581   session_mask_or_match_6_t *mask =
1582     (session_mask_or_match_6_t *) & rule->mask;
1583
1584   rmp = vl_msg_api_alloc (sizeof (*rmp));
1585   clib_memset (rmp, 0, sizeof (*rmp));
1586   rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
1587   rmp->context = context;
1588
1589   rmp->is_ip4 = 0;
1590   clib_memcpy_fast (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
1591   clib_memcpy_fast (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
1592   rmp->lcl_plen = ip6_mask_to_preflen (&mask->lcl_ip);
1593   rmp->rmt_plen = ip6_mask_to_preflen (&mask->rmt_ip);
1594   rmp->lcl_port = match->lcl_port;
1595   rmp->rmt_port = match->rmt_port;
1596   rmp->action_index = clib_host_to_net_u32 (rule->action_index);
1597   rmp->scope =
1598     is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
1599   rmp->transport_proto = transport_proto;
1600   rmp->appns_index = clib_host_to_net_u32 (appns_index);
1601   if (tag)
1602     {
1603       clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
1604       rmp->tag[vec_len (tag)] = 0;
1605     }
1606
1607   vl_api_send_msg (reg, (u8 *) rmp);
1608 }
1609
1610 static void
1611 send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
1612                                   u8 tp, u8 is_local, u32 appns_index,
1613                                   vl_api_registration_t * reg, u32 context)
1614 {
1615   mma_rule_16_t *rule16;
1616   mma_rule_40_t *rule40;
1617   mma_rules_table_16_t *srt16;
1618   mma_rules_table_40_t *srt40;
1619   u32 ri;
1620
1621   if (is_local || fib_proto == FIB_PROTOCOL_IP4)
1622     {
1623       u8 *tag = 0;
1624       /* *INDENT-OFF* */
1625       srt16 = &srt->session_rules_tables_16;
1626       pool_foreach (rule16, srt16->rules, ({
1627         ri = mma_rules_table_rule_index_16 (srt16, rule16);
1628         tag = session_rules_table_rule_tag (srt, ri, 1);
1629         send_session_rule_details4 (rule16, is_local, tp, appns_index, tag,
1630                                     reg, context);
1631       }));
1632       /* *INDENT-ON* */
1633     }
1634   if (is_local || fib_proto == FIB_PROTOCOL_IP6)
1635     {
1636       u8 *tag = 0;
1637       /* *INDENT-OFF* */
1638       srt40 = &srt->session_rules_tables_40;
1639       pool_foreach (rule40, srt40->rules, ({
1640         ri = mma_rules_table_rule_index_40 (srt40, rule40);
1641         tag = session_rules_table_rule_tag (srt, ri, 1);
1642         send_session_rule_details6 (rule40, is_local, tp, appns_index, tag,
1643                                     reg, context);
1644       }));
1645       /* *INDENT-ON* */
1646     }
1647 }
1648
1649 static void
1650 vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
1651 {
1652   vl_api_registration_t *reg;
1653   session_table_t *st;
1654   u8 tp;
1655
1656   reg = vl_api_client_index_to_registration (mp->client_index);
1657   if (!reg)
1658     return;
1659
1660   /* *INDENT-OFF* */
1661   session_table_foreach (st, ({
1662     for (tp = 0; tp < TRANSPORT_N_PROTO; tp++)
1663       {
1664         send_session_rules_table_details (&st->session_rules[tp],
1665                                           st->active_fib_proto, tp,
1666                                           st->is_local, st->appns_index, reg,
1667                                           mp->context);
1668       }
1669   }));
1670   /* *INDENT-ON* */
1671 }
1672
1673 static void
1674 vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t *
1675                                            mp)
1676 {
1677   vl_api_app_namespace_add_del_reply_t *rmp;
1678   vnet_app_add_tls_cert_args_t _a, *a = &_a;
1679   clib_error_t *error;
1680   application_t *app;
1681   u32 cert_len;
1682   int rv = 0;
1683   if (!session_manager_is_enabled ())
1684     {
1685       rv = VNET_API_ERROR_FEATURE_DISABLED;
1686       goto done;
1687     }
1688   if (!(app = application_lookup (mp->client_index)))
1689     {
1690       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1691       goto done;
1692     }
1693   clib_memset (a, 0, sizeof (*a));
1694   a->app_index = app->app_index;
1695   cert_len = clib_net_to_host_u16 (mp->cert_len);
1696   if (cert_len > 10000)
1697     {
1698       rv = VNET_API_ERROR_INVALID_VALUE;
1699       goto done;
1700     }
1701   vec_validate (a->cert, cert_len);
1702   clib_memcpy_fast (a->cert, mp->cert, cert_len);
1703   if ((error = vnet_app_add_tls_cert (a)))
1704     {
1705       rv = clib_error_get_code (error);
1706       clib_error_report (error);
1707     }
1708   vec_free (a->cert);
1709 done:
1710   REPLY_MACRO (VL_API_APPLICATION_TLS_CERT_ADD_REPLY);
1711 }
1712
1713 static void
1714 vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t *
1715                                           mp)
1716 {
1717   vl_api_app_namespace_add_del_reply_t *rmp;
1718   vnet_app_add_tls_key_args_t _a, *a = &_a;
1719   clib_error_t *error;
1720   application_t *app;
1721   u32 key_len;
1722   int rv = 0;
1723   if (!session_manager_is_enabled ())
1724     {
1725       rv = VNET_API_ERROR_FEATURE_DISABLED;
1726       goto done;
1727     }
1728   if (!(app = application_lookup (mp->client_index)))
1729     {
1730       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1731       goto done;
1732     }
1733   clib_memset (a, 0, sizeof (*a));
1734   a->app_index = app->app_index;
1735   key_len = clib_net_to_host_u16 (mp->key_len);
1736   if (key_len > 10000)
1737     {
1738       rv = VNET_API_ERROR_INVALID_VALUE;
1739       goto done;
1740     }
1741   vec_validate (a->key, key_len);
1742   clib_memcpy_fast (a->key, mp->key, key_len);
1743   if ((error = vnet_app_add_tls_key (a)))
1744     {
1745       rv = clib_error_get_code (error);
1746       clib_error_report (error);
1747     }
1748   vec_free (a->key);
1749 done:
1750   REPLY_MACRO (VL_API_APPLICATION_TLS_KEY_ADD_REPLY);
1751 }
1752
1753 static clib_error_t *
1754 application_reaper_cb (u32 client_index)
1755 {
1756   application_t *app = application_lookup (client_index);
1757   vnet_app_detach_args_t _a, *a = &_a;
1758   if (app)
1759     {
1760       a->app_index = app->app_index;
1761       a->api_client_index = client_index;
1762       vnet_application_detach (a);
1763     }
1764   return 0;
1765 }
1766
1767 VL_MSG_API_REAPER_FUNCTION (application_reaper_cb);
1768
1769 #define vl_msg_name_crc_list
1770 #include <vnet/vnet_all_api_h.h>
1771 #undef vl_msg_name_crc_list
1772
1773 static void
1774 setup_message_id_table (api_main_t * am)
1775 {
1776 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1777   foreach_vl_msg_name_crc_session;
1778 #undef _
1779 }
1780
1781 /*
1782  * session_api_hookup
1783  * Add uri's API message handlers to the table.
1784  * vlib has alread mapped shared memory and
1785  * added the client registration handlers.
1786  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
1787  */
1788 static clib_error_t *
1789 session_api_hookup (vlib_main_t * vm)
1790 {
1791   api_main_t *am = &api_main;
1792
1793 #define _(N,n)                                                  \
1794     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1795                            vl_api_##n##_t_handler,              \
1796                            vl_noop_handler,                     \
1797                            vl_api_##n##_t_endian,               \
1798                            vl_api_##n##_t_print,                \
1799                            sizeof(vl_api_##n##_t), 1);
1800   foreach_session_api_msg;
1801 #undef _
1802
1803   /*
1804    * Messages which bounce off the data-plane to
1805    * an API client. Simply tells the message handling infra not
1806    * to free the message.
1807    *
1808    * Bounced message handlers MUST NOT block the data plane
1809    */
1810   am->message_bounce[VL_API_CONNECT_URI] = 1;
1811   am->message_bounce[VL_API_CONNECT_SOCK] = 1;
1812
1813   /*
1814    * Set up the (msg_name, crc, message-id) table
1815    */
1816   setup_message_id_table (am);
1817
1818   return 0;
1819 }
1820
1821 VLIB_API_INIT_FUNCTION (session_api_hookup);
1822
1823 /*
1824  * fd.io coding-style-patch-verification: ON
1825  *
1826  * Local Variables:
1827  * eval: (c-set-style "gnu")
1828  * End:
1829  */