svm: allow mq attachments at random offsets
[vpp.git] / src / vcl / vcl_bapi.c
1 /*
2  * Copyright (c) 2018-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this
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 <vcl/vcl_private.h>
17 #include <vlibmemory/api.h>
18 #include <vpp/api/vpe_msg_enum.h>
19
20 #define vl_typedefs             /* define message structures */
21 #include <vpp/api/vpe_all_api_h.h>
22 #undef vl_typedefs
23
24 /* declare message handlers for each api */
25
26 #define vl_endianfun            /* define message structures */
27 #include <vpp/api/vpe_all_api_h.h>
28 #undef vl_endianfun
29
30 /* instantiate all the print functions we know about */
31 #define vl_print(handle, ...)
32 #define vl_printfun
33 #include <vpp/api/vpe_all_api_h.h>
34 #undef vl_printfun
35
36 static u8 *
37 format_api_error (u8 * s, va_list * args)
38 {
39   i32 error = va_arg (*args, u32);
40   uword *p;
41
42   p = hash_get (vcm->error_string_by_error_number, -error);
43
44   if (p)
45     s = format (s, "%s (%d)", p[0], error);
46   else
47     s = format (s, "%d", error);
48   return s;
49 }
50
51 static void
52   vl_api_session_enable_disable_reply_t_handler
53   (vl_api_session_enable_disable_reply_t * mp)
54 {
55   if (mp->retval)
56     {
57       clib_warning ("VCL<%d>: session_enable_disable failed: %U", getpid (),
58                     format_api_error, ntohl (mp->retval));
59     }
60   else
61     vcm->bapi_app_state = STATE_APP_ENABLED;
62 }
63
64 static void
65 vl_api_app_attach_reply_t_handler (vl_api_app_attach_reply_t * mp)
66 {
67   vcl_worker_t *wrk = vcl_worker_get (0);
68   u64 segment_handle;
69   int *fds = 0, i, rv;
70   u32 n_fds = 0;
71   char *segment_name = 0;
72
73   if (mp->retval)
74     {
75       VERR ("attach failed: %U", format_api_error, ntohl (mp->retval));
76       goto failed;
77     }
78
79   segment_handle = clib_net_to_host_u64 (mp->segment_handle);
80   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
81     {
82       VERR ("invalid segment handle");
83       goto failed;
84     }
85
86   if (mp->n_fds)
87     {
88       vec_validate (fds, mp->n_fds);
89       if (vl_socket_client_recv_fd_msg2 (&wrk->bapi_sock_ctx, fds, mp->n_fds,
90                                          5))
91         goto failed;
92
93       if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
94         if (vcl_segment_attach (vcl_vpp_worker_segment_handle (0),
95                                 "vpp-mq-seg", SSVM_SEGMENT_MEMFD,
96                                 fds[n_fds++]))
97           goto failed;
98
99       vcl_segment_attach_mq (vcl_vpp_worker_segment_handle (0),
100                              mp->vpp_ctrl_mq, mp->vpp_ctrl_mq_thread,
101                              &wrk->ctrl_mq);
102       vcm->ctrl_mq = wrk->ctrl_mq;
103
104       if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
105         {
106           segment_name = vl_api_from_api_to_new_c_string (&mp->segment_name);
107           rv =
108             vcl_segment_attach (segment_handle, segment_name,
109                                 SSVM_SEGMENT_MEMFD, fds[n_fds++]);
110           vec_free (segment_name);
111           if (rv != 0)
112             goto failed;
113         }
114
115       vcl_segment_attach_mq (segment_handle, mp->app_mq, 0,
116                              &wrk->app_event_queue);
117
118       if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
119         {
120           svm_msg_q_set_consumer_eventfd (wrk->app_event_queue, fds[n_fds]);
121           vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
122           n_fds++;
123         }
124
125       vec_free (fds);
126     }
127   else
128     {
129       segment_name = vl_api_from_api_to_new_c_string (&mp->segment_name);
130       rv =
131         vcl_segment_attach (segment_handle, segment_name, SSVM_SEGMENT_SHM,
132                             -1);
133       vec_free (segment_name);
134       if (rv != 0)
135         goto failed;
136     }
137
138   vcm->app_index = clib_net_to_host_u32 (mp->app_index);
139   vcm->bapi_app_state = STATE_APP_ATTACHED;
140   return;
141
142 failed:
143   vcm->bapi_app_state = STATE_APP_FAILED;
144   for (i = clib_max (n_fds - 1, 0); i < vec_len (fds); i++)
145     close (fds[i]);
146   vec_free (fds);
147 }
148
149 static void
150 vl_api_app_worker_add_del_reply_t_handler (vl_api_app_worker_add_del_reply_t *
151                                            mp)
152 {
153   int n_fds = 0, *fds = 0, i, rv;
154   u64 segment_handle;
155   vcl_worker_t *wrk;
156   u32 wrk_index;
157   char *segment_name = 0;
158
159   if (mp->retval)
160     {
161       clib_warning ("VCL<%d>: add/del worker failed: %U", getpid (),
162                     format_api_error, ntohl (mp->retval));
163       goto failed;
164     }
165
166   if (!mp->is_add)
167     return;
168
169   wrk_index = mp->context;
170   wrk = vcl_worker_get_if_valid (wrk_index);
171   if (!wrk)
172     return;
173
174   wrk->vpp_wrk_index = clib_net_to_host_u32 (mp->wrk_index);
175   wrk->ctrl_mq = vcm->ctrl_mq;
176
177   segment_handle = clib_net_to_host_u64 (mp->segment_handle);
178   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
179     {
180       clib_warning ("invalid segment handle");
181       goto failed;
182     }
183
184   if (mp->n_fds)
185     {
186       vec_validate (fds, mp->n_fds);
187       if (vl_socket_client_recv_fd_msg2 (&wrk->bapi_sock_ctx, fds, mp->n_fds,
188                                          5))
189         goto failed;
190
191       if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
192         if (vcl_segment_attach (vcl_vpp_worker_segment_handle (wrk_index),
193                                 "vpp-worker-seg", SSVM_SEGMENT_MEMFD,
194                                 fds[n_fds++]))
195           goto failed;
196
197       if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
198         {
199           segment_name = vl_api_from_api_to_new_c_string (&mp->segment_name);
200           rv =
201             vcl_segment_attach (segment_handle, segment_name,
202                                 SSVM_SEGMENT_MEMFD, fds[n_fds++]);
203           vec_free (segment_name);
204           if (rv != 0)
205             goto failed;
206         }
207
208       vcl_segment_attach_mq (segment_handle, mp->app_event_queue_address, 0,
209                              &wrk->app_event_queue);
210
211       if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
212         {
213           svm_msg_q_set_consumer_eventfd (wrk->app_event_queue, fds[n_fds]);
214           vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
215           n_fds++;
216         }
217
218       vec_free (fds);
219     }
220   else
221     {
222       segment_name = vl_api_from_api_to_new_c_string (&mp->segment_name);
223       rv =
224         vcl_segment_attach (segment_handle, segment_name, SSVM_SEGMENT_SHM,
225                             -1);
226       vec_free (segment_name);
227       if (rv != 0)
228         goto failed;
229     }
230   vcm->bapi_app_state = STATE_APP_READY;
231   VDBG (0, "worker %u vpp-worker %u added", wrk_index, wrk->vpp_wrk_index);
232   return;
233
234 failed:
235   vcm->bapi_app_state = STATE_APP_FAILED;
236   for (i = clib_max (n_fds - 1, 0); i < vec_len (fds); i++)
237     close (fds[i]);
238   vec_free (fds);
239 }
240
241 static void
242   vl_api_application_tls_cert_add_reply_t_handler
243   (vl_api_application_tls_cert_add_reply_t * mp)
244 {
245   if (mp->retval)
246     VDBG (0, "add cert failed: %U", format_api_error, ntohl (mp->retval));
247   vcm->bapi_app_state = STATE_APP_READY;
248 }
249
250 static void
251   vl_api_application_tls_key_add_reply_t_handler
252   (vl_api_application_tls_key_add_reply_t * mp)
253 {
254   if (mp->retval)
255     VDBG (0, "add key failed: %U", format_api_error, ntohl (mp->retval));
256   vcm->bapi_app_state = STATE_APP_READY;
257 }
258
259 #define foreach_sock_msg                                                \
260 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply)           \
261 _(APP_ATTACH_REPLY, app_attach_reply)                                   \
262 _(APPLICATION_TLS_CERT_ADD_REPLY, application_tls_cert_add_reply)       \
263 _(APPLICATION_TLS_KEY_ADD_REPLY, application_tls_key_add_reply)         \
264 _(APP_WORKER_ADD_DEL_REPLY, app_worker_add_del_reply)                   \
265
266 static void
267 vcl_bapi_hookup (void)
268 {
269 #define _(N, n)                                                 \
270     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
271                            vl_api_##n##_t_handler,              \
272                            vl_noop_handler,                     \
273                            vl_api_##n##_t_endian,               \
274                            vl_api_##n##_t_print,                \
275                            sizeof(vl_api_##n##_t), 1);
276   foreach_sock_msg;
277 #undef _
278 }
279
280 /*
281  * VPP-API message functions
282  */
283 static void
284 vcl_bapi_send_session_enable_disable (u8 is_enable)
285 {
286   vcl_worker_t *wrk = vcl_worker_get_current ();
287   vl_api_session_enable_disable_t *bmp;
288   bmp = vl_msg_api_alloc (sizeof (*bmp));
289   memset (bmp, 0, sizeof (*bmp));
290
291   bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
292   bmp->client_index = wrk->api_client_handle;
293   bmp->context = htonl (0xfeedface);
294   bmp->is_enable = is_enable;
295   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
296 }
297
298 void
299 vcl_bapi_send_attach (void)
300 {
301   vcl_worker_t *wrk = vcl_worker_get_current ();
302   u8 tls_engine = CRYPTO_ENGINE_OPENSSL;
303   vl_api_app_attach_t *bmp;
304   u8 nsid_len = vec_len (vcm->cfg.namespace_id);
305   u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
306                      vcm->cfg.app_proxy_transport_udp);
307
308   tls_engine = vcm->cfg.tls_engine ? vcm->cfg.tls_engine : tls_engine;
309
310   bmp = vl_msg_api_alloc (sizeof (*bmp));
311   memset (bmp, 0, sizeof (*bmp));
312
313   bmp->_vl_msg_id = ntohs (VL_API_APP_ATTACH);
314   bmp->client_index = wrk->api_client_handle;
315   bmp->context = htonl (0xfeedface);
316   bmp->options[APP_OPTIONS_FLAGS] =
317     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
318     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
319     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
320     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0) |
321     (vcm->cfg.use_mq_eventfd ? APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD : 0);
322   bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
323     (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
324            (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
325   bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
326   bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
327   bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
328   bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
329   bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
330     vcm->cfg.preallocated_fifo_pairs;
331   bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
332   bmp->options[APP_OPTIONS_TLS_ENGINE] = tls_engine;
333   if (nsid_len)
334     {
335       vl_api_vec_to_api_string (vcm->cfg.namespace_id, &bmp->namespace_id);
336       bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
337     }
338   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
339 }
340
341 void
342 vcl_bapi_send_detach (void)
343 {
344   vcl_worker_t *wrk = vcl_worker_get_current ();
345   vl_api_application_detach_t *bmp;
346   bmp = vl_msg_api_alloc (sizeof (*bmp));
347   memset (bmp, 0, sizeof (*bmp));
348
349   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
350   bmp->client_index = wrk->api_client_handle;
351   bmp->context = htonl (0xfeedface);
352   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
353 }
354
355 static void
356 vcl_bapi_send_app_worker_add_del (u8 is_add)
357 {
358   vcl_worker_t *wrk = vcl_worker_get_current ();
359   vl_api_app_worker_add_del_t *mp;
360
361   mp = vl_msg_api_alloc (sizeof (*mp));
362   memset (mp, 0, sizeof (*mp));
363
364   mp->_vl_msg_id = ntohs (VL_API_APP_WORKER_ADD_DEL);
365   mp->client_index = wrk->api_client_handle;
366   mp->app_index = clib_host_to_net_u32 (vcm->app_index);
367   mp->context = wrk->wrk_index;
368   mp->is_add = is_add;
369   if (!is_add)
370     mp->wrk_index = clib_host_to_net_u32 (wrk->vpp_wrk_index);
371
372   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & mp);
373 }
374
375 static void
376 vcl_bapi_send_child_worker_del (vcl_worker_t * child_wrk)
377 {
378   vcl_worker_t *wrk = vcl_worker_get_current ();
379   vl_api_app_worker_add_del_t *mp;
380
381   mp = vl_msg_api_alloc (sizeof (*mp));
382   memset (mp, 0, sizeof (*mp));
383
384   mp->_vl_msg_id = ntohs (VL_API_APP_WORKER_ADD_DEL);
385   mp->client_index = wrk->api_client_handle;
386   mp->app_index = clib_host_to_net_u32 (vcm->app_index);
387   mp->context = wrk->wrk_index;
388   mp->is_add = 0;
389   mp->wrk_index = clib_host_to_net_u32 (child_wrk->vpp_wrk_index);
390
391   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & mp);
392 }
393
394 void
395 vcl_bapi_send_application_tls_cert_add (vcl_session_t * session, char *cert,
396                                         u32 cert_len)
397 {
398   vcl_worker_t *wrk = vcl_worker_get_current ();
399   vl_api_application_tls_cert_add_t *cert_mp;
400
401   cert_mp = vl_msg_api_alloc (sizeof (*cert_mp) + cert_len);
402   clib_memset (cert_mp, 0, sizeof (*cert_mp));
403   cert_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_CERT_ADD);
404   cert_mp->client_index = wrk->api_client_handle;
405   cert_mp->context = session->session_index;
406   cert_mp->cert_len = clib_host_to_net_u16 (cert_len);
407   clib_memcpy_fast (cert_mp->cert, cert, cert_len);
408   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & cert_mp);
409 }
410
411 void
412 vcl_bapi_send_application_tls_key_add (vcl_session_t * session, char *key,
413                                        u32 key_len)
414 {
415   vcl_worker_t *wrk = vcl_worker_get_current ();
416   vl_api_application_tls_key_add_t *key_mp;
417
418   key_mp = vl_msg_api_alloc (sizeof (*key_mp) + key_len);
419   clib_memset (key_mp, 0, sizeof (*key_mp));
420   key_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_KEY_ADD);
421   key_mp->client_index = wrk->api_client_handle;
422   key_mp->context = session->session_index;
423   key_mp->key_len = clib_host_to_net_u16 (key_len);
424   clib_memcpy_fast (key_mp->key, key, key_len);
425   vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & key_mp);
426 }
427
428 u32
429 vcl_bapi_max_nsid_len (void)
430 {
431   vl_api_app_attach_t *mp;
432   return (sizeof (mp->namespace_id) - 1);
433 }
434
435 static void
436 vcl_bapi_init_error_string_table (void)
437 {
438   vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
439
440 #define _(n, v, s) hash_set (vcm->error_string_by_error_number, -v, s);
441   foreach_vnet_api_error;
442 #undef _
443
444   hash_set (vcm->error_string_by_error_number, 99, "Misc");
445 }
446
447 static void
448 vcl_bapi_cleanup (void)
449 {
450   socket_client_main_t *scm = &socket_client_main;
451   api_main_t *am = vlibapi_get_main ();
452
453   am->my_client_index = ~0;
454   am->my_registration = 0;
455   am->vl_input_queue = 0;
456   am->msg_index_by_name_and_crc = 0;
457   scm->socket_fd = 0;
458
459   vl_client_api_unmap ();
460 }
461
462 static int
463 vcl_bapi_connect_to_vpp (void)
464 {
465   vcl_worker_t *wrk = vcl_worker_get_current ();
466   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
467   int rv = VPPCOM_OK;
468   api_main_t *am;
469   u8 *wrk_name;
470
471   wrk_name = format (0, "%v-wrk-%u%c", vcm->app_name, wrk->wrk_index, 0);
472
473   /* Make sure api is cleaned up in case this is a connect from a
474    * forked worker */
475   vcl_bapi_cleanup ();
476
477   vlibapi_set_main (&wrk->bapi_api_ctx);
478   vcl_bapi_hookup ();
479
480   if (!vcl_cfg->vpp_bapi_socket_name)
481     {
482       rv = VPPCOM_EINVAL;
483       goto error;
484     }
485
486   if (vl_socket_client_connect2 (&wrk->bapi_sock_ctx,
487                                  (char *) vcl_cfg->vpp_bapi_socket_name,
488                                  (char *) wrk_name,
489                                  0 /* default rx/tx buffer */ ))
490     {
491       VERR ("app (%s) socket connect failed!", wrk_name);
492       rv = VPPCOM_ECONNREFUSED;
493       goto error;
494     }
495
496   if (vl_socket_client_init_shm2 (&wrk->bapi_sock_ctx, 0,
497                                   1 /* want_pthread */ ))
498     {
499       VERR ("app (%s) init shm failed!", wrk_name);
500       rv = VPPCOM_ECONNREFUSED;
501       goto error;
502     }
503
504   am = vlibapi_get_main ();
505   wrk->vl_input_queue = am->shmem_hdr->vl_input_queue;
506   wrk->api_client_handle = (u32) am->my_client_index;
507
508   VDBG (0, "app (%s) is connected to VPP!", wrk_name);
509   vcl_evt (VCL_EVT_INIT, vcm);
510
511 error:
512   vec_free (wrk_name);
513   return rv;
514 }
515
516 void
517 vcl_bapi_disconnect_from_vpp (void)
518 {
519   vcl_worker_t *wrk = vcl_worker_get_current ();
520   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
521
522   if (vcl_cfg->vpp_bapi_socket_name)
523     vl_socket_client_disconnect2 (&wrk->bapi_sock_ctx);
524   else
525     vl_client_disconnect_from_vlib ();
526 }
527
528 static const char *
529 vcl_bapi_app_state_str (vcl_bapi_app_state_t state)
530 {
531   char *st;
532
533   switch (state)
534     {
535     case STATE_APP_START:
536       st = "STATE_APP_START";
537       break;
538
539     case STATE_APP_CONN_VPP:
540       st = "STATE_APP_CONN_VPP";
541       break;
542
543     case STATE_APP_ENABLED:
544       st = "STATE_APP_ENABLED";
545       break;
546
547     case STATE_APP_ATTACHED:
548       st = "STATE_APP_ATTACHED";
549       break;
550
551     default:
552       st = "UNKNOWN_APP_STATE";
553       break;
554     }
555
556   return st;
557 }
558
559 static int
560 vcl_bapi_wait_for_app_state_change (vcl_bapi_app_state_t app_state)
561 {
562   vcl_worker_t *wrk = vcl_worker_get_current ();
563   f64 timeout = clib_time_now (&wrk->clib_time) + vcm->cfg.app_timeout;
564
565   while (clib_time_now (&wrk->clib_time) < timeout)
566     {
567       if (vcm->bapi_app_state == app_state)
568         return VPPCOM_OK;
569       if (vcm->bapi_app_state == STATE_APP_FAILED)
570         return VPPCOM_ECONNABORTED;
571     }
572   VDBG (0, "timeout waiting for state %s (%d)",
573         vcl_bapi_app_state_str (app_state), app_state);
574   vcl_evt (VCL_EVT_SESSION_TIMEOUT, vcm, bapi_app_state);
575
576   return VPPCOM_ETIMEDOUT;
577 }
578
579 static int
580 vcl_bapi_session_enable (void)
581 {
582   int rv;
583
584   if (vcm->bapi_app_state != STATE_APP_ENABLED)
585     {
586       vcl_bapi_send_session_enable_disable (1 /* is_enabled == TRUE */ );
587       rv = vcl_bapi_wait_for_app_state_change (STATE_APP_ENABLED);
588       if (PREDICT_FALSE (rv))
589         {
590           VDBG (0, "application session enable timed out! returning %d (%s)",
591                 rv, vppcom_retval_str (rv));
592           return rv;
593         }
594     }
595   return VPPCOM_OK;
596 }
597
598 static int
599 vcl_bapi_init (void)
600 {
601   int rv;
602
603   vcm->bapi_app_state = STATE_APP_START;
604   vcl_bapi_init_error_string_table ();
605   rv = vcl_bapi_connect_to_vpp ();
606   if (rv)
607     {
608       VERR ("couldn't connect to VPP!");
609       return rv;
610     }
611   VDBG (0, "sending session enable");
612   rv = vcl_bapi_session_enable ();
613   if (rv)
614     {
615       VERR ("vppcom_app_session_enable() failed!");
616       return rv;
617     }
618
619   return 0;
620 }
621
622 int
623 vcl_bapi_attach (void)
624 {
625   int rv;
626
627   /* API hookup and connect to VPP */
628   if ((rv = vcl_bapi_init ()))
629     return rv;
630
631   vcl_bapi_send_attach ();
632   rv = vcl_bapi_wait_for_app_state_change (STATE_APP_ATTACHED);
633   if (PREDICT_FALSE (rv))
634     {
635       VDBG (0, "application attach timed out! returning %d (%s)", rv,
636             vppcom_retval_str (rv));
637       return rv;
638     }
639
640   return 0;
641 }
642
643 int
644 vcl_bapi_app_worker_add (void)
645 {
646   if (vcl_bapi_connect_to_vpp ())
647     return -1;
648
649   vcm->bapi_app_state = STATE_APP_ADDING_WORKER;
650   vcl_bapi_send_app_worker_add_del (1 /* is_add */ );
651   if (vcl_bapi_wait_for_app_state_change (STATE_APP_READY))
652     return -1;
653   return 0;
654 }
655
656 void
657 vcl_bapi_app_worker_del (vcl_worker_t * wrk)
658 {
659   /* Notify vpp that the worker is going away */
660   if (wrk->wrk_index == vcl_get_worker_index ())
661     vcl_bapi_send_app_worker_add_del (0 /* is_add */ );
662   else
663     vcl_bapi_send_child_worker_del (wrk);
664
665   /* Disconnect the binary api */
666   if (vec_len (vcm->workers) == 1)
667     vcl_bapi_disconnect_from_vpp ();
668   else
669     vl_client_send_disconnect (1 /* vpp should cleanup */ );
670 }
671
672 int
673 vcl_bapi_recv_fds (vcl_worker_t * wrk, int *fds, int n_fds)
674 {
675   clib_error_t *err;
676
677   if ((err = vl_socket_client_recv_fd_msg2 (&wrk->bapi_sock_ctx, fds, n_fds,
678                                             5)))
679     {
680       clib_error_report (err);
681       return -1;
682     }
683
684   return 0;
685 }
686
687 int
688 vppcom_session_tls_add_cert (uint32_t session_handle, char *cert,
689                              uint32_t cert_len)
690 {
691
692   vcl_worker_t *wrk = vcl_worker_get_current ();
693   vcl_session_t *session = 0;
694
695   session = vcl_session_get_w_handle (wrk, session_handle);
696   if (!session)
697     return VPPCOM_EBADFD;
698
699   if (cert_len == 0 || cert_len == ~0)
700     return VPPCOM_EBADFD;
701
702   /*
703    * Send listen request to vpp and wait for reply
704    */
705   vcl_bapi_send_application_tls_cert_add (session, cert, cert_len);
706   vcm->bapi_app_state = STATE_APP_ADDING_TLS_DATA;
707   vcl_bapi_wait_for_app_state_change (STATE_APP_READY);
708   return VPPCOM_OK;
709 }
710
711 int
712 vppcom_session_tls_add_key (uint32_t session_handle, char *key,
713                             uint32_t key_len)
714 {
715
716   vcl_worker_t *wrk = vcl_worker_get_current ();
717   vcl_session_t *session = 0;
718
719   session = vcl_session_get_w_handle (wrk, session_handle);
720   if (!session)
721     return VPPCOM_EBADFD;
722
723   if (key_len == 0 || key_len == ~0)
724     return VPPCOM_EBADFD;
725
726   vcl_bapi_send_application_tls_key_add (session, key, key_len);
727   vcm->bapi_app_state = STATE_APP_ADDING_TLS_DATA;
728   vcl_bapi_wait_for_app_state_change (STATE_APP_READY);
729   return VPPCOM_OK;
730 }
731
732 int
733 vcl_bapi_worker_set (void)
734 {
735   vcl_worker_t *wrk = vcl_worker_get_current ();
736   int i;
737
738   /* Find the first worker with the same pid */
739   for (i = 0; i < vec_len (vcm->workers); i++)
740     {
741       if (i == wrk->wrk_index)
742         continue;
743       if (vcm->workers[i].current_pid == wrk->current_pid)
744         {
745           wrk->vl_input_queue = vcm->workers[i].vl_input_queue;
746           wrk->api_client_handle = vcm->workers[i].api_client_handle;
747           return 0;
748         }
749     }
750   return -1;
751 }
752
753 /*
754  * fd.io coding-style-patch-verification: ON
755  *
756  * Local Variables:
757  * eval: (c-set-style "gnu")
758  * End:
759  */