vcl_bapi.c revision 458089bb
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
36u8 *
37format_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
51static 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->app_state = STATE_APP_ENABLED;
62}
63
64static int
65vcl_segment_attach (u64 segment_handle, char *name, ssvm_segment_type_t type,
66		    int fd)
67{
68  fifo_segment_create_args_t _a, *a = &_a;
69  int rv;
70
71  memset (a, 0, sizeof (*a));
72  a->segment_name = (char *) name;
73  a->segment_type = type;
74
75  if (type == SSVM_SEGMENT_MEMFD)
76    a->memfd_fd = fd;
77
78  if ((rv = fifo_segment_attach (&vcm->segment_main, a)))
79    {
80      clib_warning ("svm_fifo_segment_attach ('%s') failed", name);
81      return rv;
82    }
83  vcl_segment_table_add (segment_handle, a->new_segment_indices[0]);
84  vec_reset_length (a->new_segment_indices);
85  return 0;
86}
87
88static void
89vcl_segment_detach (u64 segment_handle)
90{
91  fifo_segment_main_t *sm = &vcm->segment_main;
92  fifo_segment_t *segment;
93  u32 segment_index;
94
95  segment_index = vcl_segment_table_lookup (segment_handle);
96  if (segment_index == (u32) ~ 0)
97    return;
98  segment = fifo_segment_get_segment (sm, segment_index);
99  fifo_segment_delete (sm, segment);
100  vcl_segment_table_del (segment_handle);
101  VDBG (0, "detached segment %u handle %u", segment_index, segment_handle);
102}
103
104static u64
105vcl_vpp_worker_segment_handle (u32 wrk_index)
106{
107  return (VCL_INVALID_SEGMENT_HANDLE - wrk_index - 1);
108}
109
110static void
111vl_api_app_attach_reply_t_handler (vl_api_app_attach_reply_t * mp)
112{
113  vcl_worker_t *wrk = vcl_worker_get (0);
114  svm_msg_q_t *ctrl_mq;
115  u64 segment_handle;
116  int *fds = 0, i;
117  u32 n_fds = 0;
118
119  if (mp->retval)
120    {
121      VERR ("attach failed: %U", format_api_error, ntohl (mp->retval));
122      goto failed;
123    }
124
125  wrk->app_event_queue = uword_to_pointer (mp->app_mq, svm_msg_q_t *);
126  ctrl_mq = uword_to_pointer (mp->vpp_ctrl_mq, svm_msg_q_t *);
127  vec_validate (wrk->vpp_event_queues, mp->vpp_ctrl_mq_thread);
128  wrk->vpp_event_queues[mp->vpp_ctrl_mq_thread] = ctrl_mq;
129  wrk->ctrl_mq = ctrl_mq;
130  segment_handle = clib_net_to_host_u64 (mp->segment_handle);
131  if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
132    {
133      VERR ("invalid segment handle");
134      goto failed;
135    }
136
137  if (mp->n_fds)
138    {
139      vec_validate (fds, mp->n_fds);
140      if (vl_socket_client_recv_fd_msg (fds, mp->n_fds, 5))
141	goto failed;
142
143      if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
144	if (vcl_segment_attach (vcl_vpp_worker_segment_handle (0),
145				"vpp-mq-seg", SSVM_SEGMENT_MEMFD,
146				fds[n_fds++]))
147	  goto failed;
148
149      if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
150	if (vcl_segment_attach (segment_handle, (char *) mp->segment_name,
151				SSVM_SEGMENT_MEMFD, fds[n_fds++]))
152	  goto failed;
153
154      if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
155	{
156	  svm_msg_q_set_consumer_eventfd (wrk->app_event_queue, fds[n_fds]);
157	  vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
158	  n_fds++;
159	}
160
161      vec_free (fds);
162    }
163  else
164    {
165      if (vcl_segment_attach (segment_handle, (char *) mp->segment_name,
166			      SSVM_SEGMENT_SHM, -1))
167	goto failed;
168    }
169
170  vcm->app_index = clib_net_to_host_u32 (mp->app_index);
171  vcm->app_state = STATE_APP_ATTACHED;
172  return;
173
174failed:
175  vcm->app_state = STATE_APP_FAILED;
176  for (i = clib_max (n_fds - 1, 0); i < vec_len (fds); i++)
177    close (fds[i]);
178  vec_free (fds);
179}
180
181static void
182vl_api_app_worker_add_del_reply_t_handler (vl_api_app_worker_add_del_reply_t *
183					   mp)
184{
185  int n_fds = 0, *fds = 0, i;
186  u64 segment_handle;
187  vcl_worker_t *wrk;
188  u32 wrk_index;
189
190  if (mp->retval)
191    {
192      clib_warning ("VCL<%d>: add/del worker failed: %U", getpid (),
193		    format_api_error, ntohl (mp->retval));
194      goto failed;
195    }
196
197  if (!mp->is_add)
198    return;
199
200  wrk_index = mp->context;
201  wrk = vcl_worker_get_if_valid (wrk_index);
202  if (!wrk)
203    return;
204
205  wrk->vpp_wrk_index = clib_net_to_host_u32 (mp->wrk_index);
206  wrk->app_event_queue = uword_to_pointer (mp->app_event_queue_address,
207					   svm_msg_q_t *);
208
209  segment_handle = clib_net_to_host_u64 (mp->segment_handle);
210  if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
211    {
212      clib_warning ("invalid segment handle");
213      goto failed;
214    }
215
216  if (mp->n_fds)
217    {
218      vec_validate (fds, mp->n_fds);
219      if (vl_socket_client_recv_fd_msg (fds, mp->n_fds, 5))
220	goto failed;
221
222      if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
223	if (vcl_segment_attach (vcl_vpp_worker_segment_handle (wrk_index),
224				"vpp-worker-seg", SSVM_SEGMENT_MEMFD,
225				fds[n_fds++]))
226	  goto failed;
227
228      if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
229	if (vcl_segment_attach (segment_handle, (char *) mp->segment_name,
230				SSVM_SEGMENT_MEMFD, fds[n_fds++]))
231	  goto failed;
232
233      if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
234	{
235	  svm_msg_q_set_consumer_eventfd (wrk->app_event_queue, fds[n_fds]);
236	  vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
237	  n_fds++;
238	}
239
240      vec_free (fds);
241    }
242  else
243    {
244      if (vcl_segment_attach (segment_handle, (char *) mp->segment_name,
245			      SSVM_SEGMENT_SHM, -1))
246	goto failed;
247    }
248  vcm->app_state = STATE_APP_READY;
249  VDBG (0, "worker %u vpp-worker %u added", wrk_index, wrk->vpp_wrk_index);
250  return;
251
252failed:
253  vcm->app_state = STATE_APP_FAILED;
254  for (i = clib_max (n_fds - 1, 0); i < vec_len (fds); i++)
255    close (fds[i]);
256  vec_free (fds);
257}
258
259static void
260vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
261{
262  ssvm_segment_type_t seg_type = SSVM_SEGMENT_SHM;
263  u64 segment_handle;
264  int fd = -1;
265
266  if (mp->fd_flags)
267    {
268      vl_socket_client_recv_fd_msg (&fd, 1, 5);
269      seg_type = SSVM_SEGMENT_MEMFD;
270    }
271
272  segment_handle = clib_net_to_host_u64 (mp->segment_handle);
273  if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
274    {
275      clib_warning ("invalid segment handle");
276      return;
277    }
278
279  if (vcl_segment_attach (segment_handle, (char *) mp->segment_name,
280			  seg_type, fd))
281    {
282      clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
283		    getpid (), mp->segment_name);
284      return;
285    }
286
287  VDBG (1, "VCL<%d>: mapped new segment '%s' size %d", getpid (),
288	mp->segment_name, mp->segment_size);
289}
290
291static void
292vl_api_unmap_segment_t_handler (vl_api_unmap_segment_t * mp)
293{
294  u64 segment_handle = clib_net_to_host_u64 (mp->segment_handle);
295  vcl_segment_detach (segment_handle);
296  VDBG (1, "Unmapped segment: %d", segment_handle);
297}
298
299static void
300  vl_api_application_tls_cert_add_reply_t_handler
301  (vl_api_application_tls_cert_add_reply_t * mp)
302{
303  if (mp->retval)
304    VDBG (0, "add cert failed: %U", format_api_error, ntohl (mp->retval));
305  vcm->app_state = STATE_APP_READY;
306}
307
308static void
309  vl_api_application_tls_key_add_reply_t_handler
310  (vl_api_application_tls_key_add_reply_t * mp)
311{
312  if (mp->retval)
313    VDBG (0, "add key failed: %U", format_api_error, ntohl (mp->retval));
314  vcm->app_state = STATE_APP_READY;
315}
316
317#define foreach_sock_msg                                        	\
318_(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply)   	\
319_(APP_ATTACH_REPLY, app_attach_reply)           			\
320_(APPLICATION_TLS_CERT_ADD_REPLY, application_tls_cert_add_reply)  	\
321_(APPLICATION_TLS_KEY_ADD_REPLY, application_tls_key_add_reply)  	\
322_(MAP_ANOTHER_SEGMENT, map_another_segment)                     	\
323_(UNMAP_SEGMENT, unmap_segment)						\
324_(APP_WORKER_ADD_DEL_REPLY, app_worker_add_del_reply)			\
325
326void
327vppcom_api_hookup (void)
328{
329#define _(N, n)                                                	\
330    vl_msg_api_set_handlers(VL_API_##N, #n,                    	\
331                           vl_api_##n##_t_handler,              \
332                           vl_noop_handler,                     \
333                           vl_api_##n##_t_endian,               \
334                           vl_api_##n##_t_print,                \
335                           sizeof(vl_api_##n##_t), 1);
336  foreach_sock_msg;
337#undef _
338}
339
340/*
341 * VPP-API message functions
342 */
343void
344vppcom_send_session_enable_disable (u8 is_enable)
345{
346  vcl_worker_t *wrk = vcl_worker_get_current ();
347  vl_api_session_enable_disable_t *bmp;
348  bmp = vl_msg_api_alloc (sizeof (*bmp));
349  memset (bmp, 0, sizeof (*bmp));
350
351  bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
352  bmp->client_index = wrk->my_client_index;
353  bmp->context = htonl (0xfeedface);
354  bmp->is_enable = is_enable;
355  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
356}
357
358void
359vppcom_app_send_attach (void)
360{
361  vcl_worker_t *wrk = vcl_worker_get_current ();
362  vl_api_app_attach_t *bmp;
363  u8 nsid_len = vec_len (vcm->cfg.namespace_id);
364  u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
365		     vcm->cfg.app_proxy_transport_udp);
366
367  bmp = vl_msg_api_alloc (sizeof (*bmp));
368  memset (bmp, 0, sizeof (*bmp));
369
370  bmp->_vl_msg_id = ntohs (VL_API_APP_ATTACH);
371  bmp->client_index = wrk->my_client_index;
372  bmp->context = htonl (0xfeedface);
373  bmp->options[APP_OPTIONS_FLAGS] =
374    APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
375    (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
376    (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
377    (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0) |
378    (vcm->cfg.use_mq_eventfd ? APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD : 0);
379  bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
380    (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
381	   (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
382  bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
383  bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
384  bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
385  bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
386  bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
387    vcm->cfg.preallocated_fifo_pairs;
388  bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
389  bmp->options[APP_OPTIONS_TLS_ENGINE] = TLS_ENGINE_OPENSSL;
390  if (nsid_len)
391    {
392      bmp->namespace_id_len = nsid_len;
393      clib_memcpy_fast (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
394      bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
395    }
396  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
397}
398
399void
400vppcom_app_send_detach (void)
401{
402  vcl_worker_t *wrk = vcl_worker_get_current ();
403  vl_api_application_detach_t *bmp;
404  bmp = vl_msg_api_alloc (sizeof (*bmp));
405  memset (bmp, 0, sizeof (*bmp));
406
407  bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
408  bmp->client_index = wrk->my_client_index;
409  bmp->context = htonl (0xfeedface);
410  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp);
411}
412
413void
414vcl_send_app_worker_add_del (u8 is_add)
415{
416  vcl_worker_t *wrk = vcl_worker_get_current ();
417  vl_api_app_worker_add_del_t *mp;
418
419  mp = vl_msg_api_alloc (sizeof (*mp));
420  memset (mp, 0, sizeof (*mp));
421
422  mp->_vl_msg_id = ntohs (VL_API_APP_WORKER_ADD_DEL);
423  mp->client_index = wrk->my_client_index;
424  mp->app_index = clib_host_to_net_u32 (vcm->app_index);
425  mp->context = wrk->wrk_index;
426  mp->is_add = is_add;
427  if (!is_add)
428    mp->wrk_index = clib_host_to_net_u32 (wrk->vpp_wrk_index);
429
430  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & mp);
431}
432
433void
434vcl_send_child_worker_del (vcl_worker_t * child_wrk)
435{
436  vcl_worker_t *wrk = vcl_worker_get_current ();
437  vl_api_app_worker_add_del_t *mp;
438
439  mp = vl_msg_api_alloc (sizeof (*mp));
440  memset (mp, 0, sizeof (*mp));
441
442  mp->_vl_msg_id = ntohs (VL_API_APP_WORKER_ADD_DEL);
443  mp->client_index = wrk->my_client_index;
444  mp->app_index = clib_host_to_net_u32 (vcm->app_index);
445  mp->context = wrk->wrk_index;
446  mp->is_add = 0;
447  mp->wrk_index = clib_host_to_net_u32 (child_wrk->vpp_wrk_index);
448
449  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & mp);
450}
451
452void
453vppcom_send_application_tls_cert_add (vcl_session_t * session, char *cert,
454				      u32 cert_len)
455{
456  vcl_worker_t *wrk = vcl_worker_get_current ();
457  vl_api_application_tls_cert_add_t *cert_mp;
458
459  cert_mp = vl_msg_api_alloc (sizeof (*cert_mp) + cert_len);
460  clib_memset (cert_mp, 0, sizeof (*cert_mp));
461  cert_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_CERT_ADD);
462  cert_mp->client_index = wrk->my_client_index;
463  cert_mp->context = session->session_index;
464  cert_mp->cert_len = clib_host_to_net_u16 (cert_len);
465  clib_memcpy_fast (cert_mp->cert, cert, cert_len);
466  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & cert_mp);
467}
468
469void
470vppcom_send_application_tls_key_add (vcl_session_t * session, char *key,
471				     u32 key_len)
472{
473  vcl_worker_t *wrk = vcl_worker_get_current ();
474  vl_api_application_tls_key_add_t *key_mp;
475
476  key_mp = vl_msg_api_alloc (sizeof (*key_mp) + key_len);
477  clib_memset (key_mp, 0, sizeof (*key_mp));
478  key_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_KEY_ADD);
479  key_mp->client_index = wrk->my_client_index;
480  key_mp->context = session->session_index;
481  key_mp->key_len = clib_host_to_net_u16 (key_len);
482  clib_memcpy_fast (key_mp->key, key, key_len);
483  vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & key_mp);
484}
485
486u32
487vcl_max_nsid_len (void)
488{
489  vl_api_application_attach_t *mp;
490  return (sizeof (mp->namespace_id) - 1);
491}
492
493void
494vppcom_init_error_string_table (void)
495{
496  vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
497
498#define _(n, v, s) hash_set (vcm->error_string_by_error_number, -v, s);
499  foreach_vnet_api_error;
500#undef _
501
502  hash_set (vcm->error_string_by_error_number, 99, "Misc");
503}
504
505int
506vppcom_connect_to_vpp (char *app_name)
507{
508  vcl_worker_t *wrk = vcl_worker_get_current ();
509  api_main_t *am = &api_main;
510  vppcom_cfg_t *vcl_cfg = &vcm->cfg;
511
512  if (vcl_cfg->vpp_api_socket_name)
513    {
514      if (vl_socket_client_connect ((char *) vcl_cfg->vpp_api_socket_name,
515				    app_name, 0 /* default rx/tx buffer */ ))
516	{
517	  VERR ("app (%s) socket connect failed!", app_name);
518	  return VPPCOM_ECONNREFUSED;
519	}
520
521      if (vl_socket_client_init_shm (0, 1 /* want_pthread */ ))
522	{
523	  VERR ("app (%s) init shm failed!", app_name);
524	  return VPPCOM_ECONNREFUSED;
525	}
526    }
527  else
528    {
529      if (!vcl_cfg->vpp_api_filename)
530	vcl_cfg->vpp_api_filename = format (0, "/vpe-api%c", 0);
531
532      VDBG (0, "app (%s) connecting to VPP api (%s)...",
533	    app_name, vcl_cfg->vpp_api_filename);
534
535      if (vl_client_connect_to_vlib ((char *) vcl_cfg->vpp_api_filename,
536				     app_name, vcm->cfg.vpp_api_q_length) < 0)
537	{
538	  VERR ("app (%s) connect failed!", app_name);
539	  return VPPCOM_ECONNREFUSED;
540	}
541
542    }
543
544  wrk->vl_input_queue = am->shmem_hdr->vl_input_queue;
545  wrk->my_client_index = (u32) am->my_client_index;
546  wrk->wrk_state = STATE_APP_CONN_VPP;
547
548  VDBG (0, "app (%s) is connected to VPP!", app_name);
549  vcl_evt (VCL_EVT_INIT, vcm);
550  return VPPCOM_OK;
551}
552
553void
554vppcom_disconnect_from_vpp (void)
555{
556  vppcom_cfg_t *vcl_cfg = &vcm->cfg;
557
558  if (vcl_cfg->vpp_api_socket_name)
559    vl_socket_client_disconnect ();
560  else
561    vl_client_disconnect_from_vlib ();
562}
563
564/*
565 * fd.io coding-style-patch-verification: ON
566 *
567 * Local Variables:
568 * eval: (c-set-style "gnu")
569 * End:
570 */
571