2 *------------------------------------------------------------------
3 * Copyright (c) 2017 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
21 #include <arpa/inet.h>
25 #include <vpp-api/vapi/vapi_dbg.h>
26 #include <vpp-api/vapi/vapi.h>
27 #include <vpp-api/vapi/vapi_internal.h>
28 #include <vppinfra/types.h>
29 #include <vppinfra/pool.h>
30 #include <vlib/vlib.h>
31 #include <vlibapi/api_common.h>
32 #include <vlibmemory/memory_client.h>
33 #include <vlibmemory/memory_api.h>
34 #include <vlibmemory/api.h>
36 #include <vapi/memclnt.api.vapi.h>
37 #include <vapi/vlib.api.vapi.h>
39 #include <vlibmemory/vl_memory_msg_enum.h>
41 #define vl_typedefs /* define message structures */
42 #include <vlibmemory/vl_memory_api_h.h>
45 /* we need to use control pings for some stuff and because we're forced to put
46 * the code in headers, we need a way to be able to grab the ids of these
47 * messages - so declare them here as extern */
48 vapi_msg_id_t vapi_msg_id_control_ping = 0;
49 vapi_msg_id_t vapi_msg_id_control_ping_reply = 0;
51 DEFINE_VAPI_MSG_IDS_MEMCLNT_API_JSON;
52 DEFINE_VAPI_MSG_IDS_VLIB_API_JSON;
57 vapi_message_desc_t **msgs;
58 size_t max_len_name_with_crc;
66 vapi_msg_id_t response_id;
67 enum vapi_request_type type;
70 static const u32 context_counter_mask = (1 << 31);
74 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id,
77 } vapi_generic_cb_with_ctx;
81 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, void *payload);
83 } vapi_event_cb_with_ctx;
88 int requests_size; /* size of the requests array (circular queue) */
89 int requests_start; /* index of first request */
90 int requests_count; /* number of used slots */
93 vapi_generic_cb_with_ctx generic_cb;
94 vapi_event_cb_with_ctx *event_cbs;
95 u16 *vapi_msg_id_t_to_vl_msg_id;
97 vapi_msg_id_t *vl_msg_id_to_vapi_msg_t;
99 bool handle_keepalives;
100 pthread_mutex_t requests_mutex;
103 svm_queue_t *vl_input_queue;
104 clib_socket_t client_socket;
107 /** client message index hash table */
108 uword *msg_index_by_name_and_crc;
112 vapi_gen_req_context (vapi_ctx_t ctx)
114 ++ctx->context_counter;
115 ctx->context_counter %= context_counter_mask;
116 return ctx->context_counter | context_counter_mask;
120 vapi_get_request_count (vapi_ctx_t ctx)
122 return ctx->requests_count;
126 vapi_requests_full (vapi_ctx_t ctx)
128 return (ctx->requests_count == ctx->requests_size);
132 vapi_requests_empty (vapi_ctx_t ctx)
134 return (0 == ctx->requests_count);
138 vapi_requests_end (vapi_ctx_t ctx)
140 return (ctx->requests_start + ctx->requests_count) % ctx->requests_size;
144 vapi_store_request (vapi_ctx_t ctx, u32 context, vapi_msg_id_t response_id,
145 enum vapi_request_type request_type, vapi_cb_t callback,
148 assert (!vapi_requests_full (ctx));
149 /* if the mutex is not held, bad things will happen */
150 assert (0 != pthread_mutex_trylock (&ctx->requests_mutex));
151 const int requests_end = vapi_requests_end (ctx);
152 vapi_req_t *slot = &ctx->requests[requests_end];
153 slot->type = request_type;
154 slot->response_id = response_id;
155 slot->context = context;
156 slot->callback = callback;
157 slot->callback_ctx = callback_ctx;
158 VAPI_DBG ("stored@%d: context:%x (start is @%d)", requests_end, context,
159 ctx->requests_start);
160 ++ctx->requests_count;
161 assert (!vapi_requests_empty (ctx));
165 struct to_be_freed_s;
169 struct to_be_freed_s *next;
172 static struct to_be_freed_s *to_be_freed = NULL;
175 vapi_add_to_be_freed (void *v)
177 struct to_be_freed_s *prev = NULL;
178 struct to_be_freed_s *tmp;
180 while (tmp && tmp->v)
189 tmp = to_be_freed = calloc (1, sizeof (*to_be_freed));
193 tmp = prev->next = calloc (1, sizeof (*to_be_freed));
196 VAPI_DBG ("To be freed %p", v);
201 vapi_trace_free (void *v)
203 struct to_be_freed_s *tmp = to_be_freed;
204 while (tmp && tmp->v != v)
208 if (tmp && tmp->v == v)
210 VAPI_DBG ("Freed %p", v);
215 VAPI_ERR ("Trying to free untracked pointer %p", v);
221 vapi_to_be_freed_validate ()
223 struct to_be_freed_s *tmp = to_be_freed;
228 VAPI_ERR ("Unfreed msg %p!", tmp->v);
237 vapi_shm_msg_alloc (vapi_ctx_t ctx, size_t size)
243 void *rv = vl_msg_api_alloc_as_if_client_or_null (size);
246 clib_memset (rv, 0, size);
252 vapi_sock_msg_alloc (size_t size)
255 vec_validate_init_empty (rv, size - 1, 0);
260 vapi_msg_alloc (vapi_ctx_t ctx, size_t size)
263 return vapi_sock_msg_alloc (size);
265 return vapi_shm_msg_alloc (ctx, size);
269 vapi_msg_free (vapi_ctx_t ctx, void *msg)
277 vapi_trace_free (msg);
286 vl_msg_api_free (msg);
291 vapi_lookup_vapi_msg_id_t (vapi_ctx_t ctx, u16 vl_msg_id)
293 if (vl_msg_id <= ctx->vl_msg_id_max)
295 return ctx->vl_msg_id_to_vapi_msg_t[vl_msg_id];
297 return VAPI_INVALID_MSG_ID;
301 vapi_ctx_alloc (vapi_ctx_t * result)
303 vapi_ctx_t ctx = calloc (1, sizeof (struct vapi_ctx_s));
308 ctx->context_counter = 0;
309 ctx->vapi_msg_id_t_to_vl_msg_id =
310 malloc (__vapi_metadata.count *
311 sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
312 if (!ctx->vapi_msg_id_t_to_vl_msg_id)
316 clib_memset (ctx->vapi_msg_id_t_to_vl_msg_id, ~0,
317 __vapi_metadata.count *
318 sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
319 ctx->event_cbs = calloc (__vapi_metadata.count, sizeof (*ctx->event_cbs));
324 pthread_mutex_init (&ctx->requests_mutex, NULL);
326 clib_time_init (&ctx->time);
334 vapi_ctx_free (vapi_ctx_t ctx)
336 assert (!ctx->connected);
337 free (ctx->requests);
338 free (ctx->vapi_msg_id_t_to_vl_msg_id);
339 free (ctx->event_cbs);
340 free (ctx->vl_msg_id_to_vapi_msg_t);
341 pthread_mutex_destroy (&ctx->requests_mutex);
346 vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t id)
348 return vapi_lookup_vl_msg_id (ctx, id) != UINT16_MAX;
351 /* Cut and paste to avoid adding dependency to client library */
352 __clib_nosanitize_addr static void
353 VL_API_VEC_UNPOISON (const void *v)
355 const vec_header_t *vh = &((vec_header_t *) v)[-1];
356 clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
360 vapi_api_name_and_crc_free (vapi_ctx_t ctx)
366 if (!ctx->msg_index_by_name_and_crc)
368 hash_foreach_pair (hp, ctx->msg_index_by_name_and_crc,
369 ({ vec_add1 (keys, (u8 *) hp->key); }));
370 for (i = 0; i < vec_len (keys); i++)
373 hash_free (ctx->msg_index_by_name_and_crc);
377 vapi_sock_get_errno (int err)
382 return VAPI_ENOTSOCK;
386 return VAPI_ECONNRESET;
390 return VAPI_ESOCK_FAILURE;
394 vapi_sock_send (vapi_ctx_t ctx, u8 *msg)
399 const size_t len = vec_len (msg);
400 const size_t total_len = len + sizeof (msgbuf_t);
404 .gc_mark_timestamp = 0,
405 .data_len = htonl (len),
408 struct iovec bufs[2] = {
409 [0] = { .iov_base = &msgbuf1, .iov_len = sizeof (msgbuf1) },
410 [1] = { .iov_base = msg, .iov_len = len },
413 clib_memset (&hdr, 0, sizeof (hdr));
417 n = sendmsg (ctx->client_socket.fd, &hdr, 0);
420 return vapi_sock_get_errno (errno);
434 vapi_sock_send2 (vapi_ctx_t ctx, u8 *msg1, u8 *msg2)
439 const size_t len1 = vec_len (msg1);
440 const size_t len2 = vec_len (msg2);
441 const size_t total_len = len1 + len2 + 2 * sizeof (msgbuf_t);
445 .gc_mark_timestamp = 0,
446 .data_len = htonl (len1),
451 .gc_mark_timestamp = 0,
452 .data_len = htonl (len2),
455 struct iovec bufs[4] = {
456 [0] = { .iov_base = &msgbuf1, .iov_len = sizeof (msgbuf1) },
457 [1] = { .iov_base = msg1, .iov_len = len1 },
458 [2] = { .iov_base = &msgbuf2, .iov_len = sizeof (msgbuf2) },
459 [3] = { .iov_base = msg2, .iov_len = len2 },
462 clib_memset (&hdr, 0, sizeof (hdr));
466 n = sendmsg (ctx->client_socket.fd, &hdr, 0);
469 return vapi_sock_get_errno (errno);
484 vapi_sock_recv_internal (vapi_ctx_t ctx, u8 **vec_msg, u32 timeout)
486 clib_socket_t *sock = &ctx->client_socket;
487 u32 data_len = 0, msg_size;
489 ssize_t n, current_rx_index;
491 vapi_error_e rv = VAPI_EAGAIN;
493 if (ctx->client_socket.fd == 0)
494 return VAPI_ENOTSOCK;
496 deadline = clib_time_now (&ctx->time) + timeout;
500 current_rx_index = vec_len (sock->rx_buffer);
501 while (current_rx_index < sizeof (*mbp))
503 vec_validate (sock->rx_buffer, sizeof (*mbp) - 1);
504 n = recv (sock->fd, sock->rx_buffer + current_rx_index,
505 sizeof (*mbp) - current_rx_index, MSG_DONTWAIT);
508 if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
514 clib_unix_warning ("socket_read");
515 vec_set_len (sock->rx_buffer, current_rx_index);
516 return vapi_sock_get_errno (errno);
518 current_rx_index += n;
520 vec_set_len (sock->rx_buffer, current_rx_index);
522 mbp = (msgbuf_t *) (sock->rx_buffer);
523 data_len = ntohl (mbp->data_len);
524 current_rx_index = vec_len (sock->rx_buffer);
525 vec_validate (sock->rx_buffer, current_rx_index + data_len);
526 mbp = (msgbuf_t *) (sock->rx_buffer);
527 msg_size = data_len + sizeof (*mbp);
529 while (current_rx_index < msg_size)
531 n = recv (sock->fd, sock->rx_buffer + current_rx_index,
532 msg_size - current_rx_index, MSG_DONTWAIT);
535 if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
541 clib_unix_warning ("socket_read");
542 vec_set_len (sock->rx_buffer, current_rx_index);
543 return vapi_sock_get_errno (errno);
545 current_rx_index += n;
547 vec_set_len (sock->rx_buffer, current_rx_index);
549 if (vec_len (sock->rx_buffer) >= data_len + sizeof (*mbp))
553 vec_add (*vec_msg, mbp->data, data_len);
561 if (vec_len (sock->rx_buffer) == data_len + sizeof (*mbp))
562 vec_set_len (sock->rx_buffer, 0);
564 vec_delete (sock->rx_buffer, data_len + sizeof (*mbp), 0);
567 /* Quit if we're out of data, and not expecting a ping reply */
568 if (vec_len (sock->rx_buffer) == 0)
576 vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
577 vl_api_memclnt_create_v2_reply_t *mp)
579 serialize_main_t _sm, *sm = &_sm;
586 ctx->my_client_index = mp->index;
588 /* Clean out any previous hash table (unlikely) */
589 vapi_api_name_and_crc_free (ctx);
591 ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
593 /* Recreate the vnet-side API message handler table */
594 tblv = uword_to_pointer (mp->message_table, u8 *);
595 unserialize_open_data (sm, tblv, vec_len (tblv));
596 unserialize_integer (sm, &nmsgs, sizeof (u32));
598 VL_API_VEC_UNPOISON (tblv);
600 for (i = 0; i < nmsgs; i++)
602 msg_index = unserialize_likely_small_unsigned_integer (sm);
603 unserialize_cstring (sm, (char **) &name_and_crc);
604 hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc, msg_index);
609 vapi_sockclnt_create_reply_t_handler (vapi_ctx_t ctx,
610 vl_api_sockclnt_create_reply_t *mp)
615 ctx->my_client_index = mp->index;
617 /* Clean out any previous hash table (unlikely) */
618 vapi_api_name_and_crc_free (ctx);
620 ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
622 for (i = 0; i < be16toh (mp->count); i++)
624 name_and_crc = format (0, "%s%c", mp->message_table[i].name, 0);
625 hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc,
626 be16toh (mp->message_table[i].index));
631 vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
632 vl_api_memclnt_delete_reply_t *mp)
635 oldheap = vl_msg_push_heap ();
636 svm_queue_free (ctx->vl_input_queue);
637 vl_msg_pop_heap (oldheap);
639 ctx->my_client_index = ~0;
640 ctx->vl_input_queue = 0;
644 vapi_sockclnt_delete_reply_t_handler (vapi_ctx_t ctx,
645 vl_api_sockclnt_delete_reply_t *mp)
647 ctx->my_client_index = ~0;
648 ctx->vl_input_queue = 0;
652 vapi_shm_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
653 int input_queue_size, bool keepalive)
655 vl_api_memclnt_create_v2_t *mp;
656 vl_api_memclnt_create_v2_reply_t *rp;
657 svm_queue_t *vl_input_queue;
658 vl_shmem_hdr_t *shmem_hdr;
661 api_main_t *am = vlibapi_get_main ();
663 shmem_hdr = am->shmem_hdr;
665 if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
667 clib_warning ("shmem_hdr / input queue NULL");
668 return VAPI_ECON_FAIL;
671 clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
672 VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
674 oldheap = vl_msg_push_heap ();
676 svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
677 vl_msg_pop_heap (oldheap);
679 ctx->my_client_index = ~0;
680 ctx->vl_input_queue = vl_input_queue;
682 mp = vl_msg_api_alloc_as_if_client (sizeof (vl_api_memclnt_create_v2_t));
683 clib_memset (mp, 0, sizeof (*mp));
684 mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2);
685 mp->ctx_quota = ctx_quota;
686 mp->input_queue = (uword) vl_input_queue;
687 strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
688 mp->keepalive = keepalive;
690 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
695 struct timespec ts, tsrem;
698 /* Wait up to 10 seconds */
699 for (i = 0; i < 1000; i++)
702 svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
706 ts.tv_nsec = 10000 * 1000; /* 10 ms */
707 while (nanosleep (&ts, &tsrem) < 0)
711 return VAPI_ECON_FAIL;
714 VL_MSG_API_UNPOISON (rp);
715 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
717 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
720 rv = clib_net_to_host_u32 (rp->response);
721 vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
728 vapi_sock_client_connect (vapi_ctx_t ctx, char *path, const char *name)
732 vl_api_sockclnt_create_t *mp;
733 vl_api_sockclnt_create_reply_t *rp;
737 ctx->my_client_index = ~0;
739 if (ctx->client_socket.fd)
745 sock = &ctx->client_socket;
746 sock->config = path ? path : API_SOCKET_FILE;
747 sock->flags = CLIB_SOCKET_F_IS_CLIENT;
749 if ((error = clib_socket_init (sock)))
751 clib_error_report (error);
752 return VAPI_ECON_FAIL;
755 mp = vapi_sock_msg_alloc (sizeof (vl_api_sockclnt_create_t));
756 mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_CREATE);
757 strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
759 if (vapi_sock_send (ctx, (void *) mp) != VAPI_OK)
761 return VAPI_ECON_FAIL;
767 struct timespec ts, tsrem;
770 /* Wait up to 10 seconds */
771 for (i = 0; i < 1000; i++)
773 qstatus = vapi_sock_recv_internal (ctx, &msg, 0);
778 ts.tv_nsec = 10000 * 1000; /* 10 ms */
779 while (nanosleep (&ts, &tsrem) < 0)
786 if (vec_len (msg) == 0)
790 if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY)
792 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
795 rv = clib_net_to_host_u32 (rp->response);
796 vapi_sockclnt_create_reply_t_handler (ctx, rp);
803 vapi_shm_client_send_disconnect (vapi_ctx_t ctx, u8 do_cleanup)
805 vl_api_memclnt_delete_t *mp;
806 vl_shmem_hdr_t *shmem_hdr;
807 api_main_t *am = vlibapi_get_main ();
809 ASSERT (am->vlib_rp);
810 shmem_hdr = am->shmem_hdr;
811 ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
813 mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
814 clib_memset (mp, 0, sizeof (*mp));
815 mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
816 mp->index = ctx->my_client_index;
817 mp->do_cleanup = do_cleanup;
819 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
823 vapi_sock_client_send_disconnect (vapi_ctx_t ctx)
825 vl_api_sockclnt_delete_t *mp;
827 mp = vapi_msg_alloc (ctx, sizeof (vl_api_sockclnt_delete_t));
828 clib_memset (mp, 0, sizeof (*mp));
829 mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_DELETE);
830 mp->client_index = ctx->my_client_index;
832 return vapi_sock_send (ctx, (void *) mp);
836 vapi_shm_client_disconnect (vapi_ctx_t ctx)
838 vl_api_memclnt_delete_reply_t *rp;
839 svm_queue_t *vl_input_queue;
843 vl_input_queue = ctx->vl_input_queue;
844 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
847 * Have to be careful here, in case the client is disconnecting
848 * because e.g. the vlib process died, or is unresponsive.
857 if (now >= (begin + 2))
859 clib_warning ("peer unresponsive, give up");
860 ctx->my_client_index = ~0;
863 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
866 VL_MSG_API_UNPOISON (rp);
868 /* drain the queue */
869 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
871 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
872 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
873 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
876 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
877 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
881 vapi_api_name_and_crc_free (ctx);
886 vapi_sock_client_disconnect (vapi_ctx_t ctx)
888 vl_api_sockclnt_delete_reply_t *rp;
894 deadline = clib_time_now (&ctx->time) + 2;
898 rv = vapi_sock_client_send_disconnect (ctx);
900 while (clib_time_now (&ctx->time) < deadline && rv != VAPI_OK);
904 if (clib_time_now (&ctx->time) >= deadline)
906 clib_warning ("peer unresponsive, give up");
907 ctx->my_client_index = ~0;
911 if (vapi_sock_recv_internal (ctx, &msg, 0) != VAPI_OK)
914 msgbuf = (void *) msg;
915 rp = (void *) msgbuf->data;
916 /* drain the queue */
917 if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_DELETE_REPLY)
919 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
920 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
921 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
924 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
925 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
929 clib_socket_close (&ctx->client_socket);
930 vapi_api_name_and_crc_free (ctx);
935 vapi_client_disconnect (vapi_ctx_t ctx)
939 return vapi_sock_client_disconnect (ctx);
941 return vapi_shm_client_disconnect (ctx);
945 vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
949 if (ctx->msg_index_by_name_and_crc)
951 p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
959 vapi_connect_ex (vapi_ctx_t ctx, const char *name, const char *path,
960 int max_outstanding_requests, int response_queue_size,
961 vapi_mode_e mode, bool handle_keepalives, bool use_uds)
965 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
970 if (!clib_mem_get_per_cpu_heap () && !clib_mem_init (0, 1024L * 1024 * 32))
975 ctx->requests_size = max_outstanding_requests;
976 const size_t size = ctx->requests_size * sizeof (*ctx->requests);
977 void *tmp = realloc (ctx->requests, size);
983 clib_memset (ctx->requests, 0, size);
984 /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
985 ctx->requests_start = ctx->requests_count = 0;
986 ctx->use_uds = use_uds;
990 if (vapi_sock_client_connect (ctx, (char *) path, name) < 0)
992 return VAPI_ECON_FAIL;
999 VAPI_DBG ("set memory root path `%s'", path);
1000 vl_set_memory_root_path ((char *) path);
1002 static char api_map[] = "/vpe-api";
1003 VAPI_DBG ("client api map `%s'", api_map);
1004 if ((rv = vl_map_shmem (api_map, 0 /* is_vlib */)) < 0)
1006 return VAPI_EMAP_FAIL;
1008 VAPI_DBG ("connect client `%s'", name);
1009 if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1012 vl_client_api_unmap ();
1013 return VAPI_ECON_FAIL;
1015 #if VAPI_DEBUG_CONNECT
1016 VAPI_DBG ("start probing messages");
1021 for (i = 0; i < __vapi_metadata.count; ++i)
1023 vapi_message_desc_t *m = __vapi_metadata.msgs[i];
1024 u8 scratch[m->name_with_crc_len + 1];
1025 memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
1026 u32 id = vapi_api_get_msg_index (ctx, scratch);
1028 if (VAPI_INVALID_MSG_ID != id)
1030 if (id > UINT16_MAX)
1032 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1037 if (id > ctx->vl_msg_id_max)
1039 vapi_msg_id_t *tmp =
1040 realloc (ctx->vl_msg_id_to_vapi_msg_t,
1041 sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
1047 ctx->vl_msg_id_to_vapi_msg_t = tmp;
1048 ctx->vl_msg_id_max = id;
1050 ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
1051 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
1052 #if VAPI_DEBUG_CONNECT
1053 VAPI_DBG ("Message `%s' has vl_msg_id `%u'", m->name_with_crc,
1059 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
1060 VAPI_DBG ("Message `%s' not available", m->name_with_crc);
1063 #if VAPI_DEBUG_CONNECT
1064 VAPI_DBG ("finished probing messages");
1066 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1067 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1070 "control ping or control ping reply not available, cannot connect");
1071 rv = VAPI_EINCOMPATIBLE;
1075 ctx->connected = true;
1076 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1078 ctx->handle_keepalives = handle_keepalives;
1082 ctx->handle_keepalives = false;
1086 vapi_client_disconnect (ctx);
1087 vl_client_api_unmap ();
1092 vapi_connect (vapi_ctx_t ctx, const char *name, const char *chroot_prefix,
1093 int max_outstanding_requests, int response_queue_size,
1094 vapi_mode_e mode, bool handle_keepalives)
1096 return vapi_connect_ex (ctx, name, chroot_prefix, max_outstanding_requests,
1097 response_queue_size, mode, handle_keepalives, false);
1101 * API client running in the same process as VPP
1104 vapi_connect_from_vpp (vapi_ctx_t ctx, const char *name,
1105 int max_outstanding_requests, int response_queue_size,
1106 vapi_mode_e mode, bool handle_keepalives)
1112 return VAPI_ENOTSUP;
1115 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
1120 ctx->requests_size = max_outstanding_requests;
1121 const size_t size = ctx->requests_size * sizeof (*ctx->requests);
1122 void *tmp = realloc (ctx->requests, size);
1127 ctx->requests = tmp;
1128 clib_memset (ctx->requests, 0, size);
1129 /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
1130 ctx->requests_start = ctx->requests_count = 0;
1132 VAPI_DBG ("connect client `%s'", name);
1133 if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1134 handle_keepalives) < 0)
1136 return VAPI_ECON_FAIL;
1140 for (i = 0; i < __vapi_metadata.count; ++i)
1142 vapi_message_desc_t *m = __vapi_metadata.msgs[i];
1143 u8 scratch[m->name_with_crc_len + 1];
1144 memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
1145 u32 id = vapi_api_get_msg_index (ctx, scratch);
1146 if (VAPI_INVALID_MSG_ID != id)
1148 if (id > UINT16_MAX)
1150 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1155 if (id > ctx->vl_msg_id_max)
1157 vapi_msg_id_t *tmp =
1158 realloc (ctx->vl_msg_id_to_vapi_msg_t,
1159 sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
1165 ctx->vl_msg_id_to_vapi_msg_t = tmp;
1166 ctx->vl_msg_id_max = id;
1168 ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
1169 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
1173 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
1174 VAPI_DBG ("Message `%s' not available", m->name_with_crc);
1177 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1178 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1181 "control ping or control ping reply not available, cannot connect");
1182 rv = VAPI_EINCOMPATIBLE;
1186 ctx->connected = true;
1187 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1189 ctx->handle_keepalives = handle_keepalives;
1193 ctx->handle_keepalives = false;
1197 vapi_client_disconnect (ctx);
1202 vapi_disconnect_from_vpp (vapi_ctx_t ctx)
1204 if (!ctx->connected)
1211 return VAPI_ENOTSUP;
1214 vl_api_memclnt_delete_reply_t *rp;
1215 svm_queue_t *vl_input_queue;
1217 vl_input_queue = ctx->vl_input_queue;
1218 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
1221 * Have to be careful here, in case the client is disconnecting
1222 * because e.g. the vlib process died, or is unresponsive.
1225 vapi_error_e rv = VAPI_OK;
1232 if (now >= (begin + 2))
1234 clib_warning ("peer unresponsive, give up");
1235 ctx->my_client_index = ~0;
1239 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1242 VL_MSG_API_UNPOISON (rp);
1244 /* drain the queue */
1245 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1247 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1248 vl_msg_api_free (rp);
1251 vapi_memclnt_delete_reply_t_handler (
1252 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1256 vapi_api_name_and_crc_free (ctx);
1258 ctx->connected = false;
1263 vapi_shm_disconnect (vapi_ctx_t ctx)
1265 vl_api_memclnt_delete_reply_t *rp;
1266 svm_queue_t *vl_input_queue;
1268 vl_input_queue = ctx->vl_input_queue;
1269 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
1272 * Have to be careful here, in case the client is disconnecting
1273 * because e.g. the vlib process died, or is unresponsive.
1276 vapi_error_e rv = VAPI_OK;
1283 if (now >= (begin + 2))
1285 clib_warning ("peer unresponsive, give up");
1286 ctx->my_client_index = ~0;
1290 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1293 VL_MSG_API_UNPOISON (rp);
1295 /* drain the queue */
1296 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1298 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1299 vl_msg_api_free (rp);
1302 vapi_memclnt_delete_reply_t_handler (
1303 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1307 vapi_api_name_and_crc_free (ctx);
1309 vl_client_api_unmap ();
1310 #if VAPI_DEBUG_ALLOC
1311 vapi_to_be_freed_validate ();
1313 ctx->connected = false;
1318 vapi_sock_disconnect (vapi_ctx_t ctx)
1320 vl_api_sockclnt_delete_reply_t *rp;
1324 vapi_sock_client_send_disconnect (ctx);
1327 vapi_error_e rv = VAPI_OK;
1334 if (now >= (begin + 2))
1336 clib_warning ("peer unresponsive, give up");
1337 ctx->my_client_index = ~0;
1341 if (vapi_sock_recv_internal (ctx, &msg, 0) < 0)
1344 if (vec_len (msg) == 0)
1349 /* drain the queue */
1350 if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_DELETE_REPLY)
1352 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1355 vapi_sockclnt_delete_reply_t_handler (
1356 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1360 clib_socket_close (&ctx->client_socket);
1361 vapi_api_name_and_crc_free (ctx);
1363 ctx->connected = false;
1368 vapi_disconnect (vapi_ctx_t ctx)
1370 if (!ctx->connected)
1377 return vapi_sock_disconnect (ctx);
1379 return vapi_shm_disconnect (ctx);
1383 vapi_get_fd (vapi_ctx_t ctx, int *fd)
1385 if (ctx->use_uds && fd)
1387 *fd = ctx->client_socket.fd;
1390 return VAPI_ENOTSUP;
1395 vapi_debug_log (vapi_ctx_t ctx, void *msg, const char *fun)
1397 unsigned msgid = be16toh (*(u16 *) msg);
1398 if (msgid <= ctx->vl_msg_id_max)
1400 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
1401 if (id < __vapi_metadata.count)
1403 VAPI_DBG ("%s msg@%p:%u[%s]", fun, msg, msgid,
1404 __vapi_metadata.msgs[id]->name);
1408 VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1413 VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1419 vapi_shm_send (vapi_ctx_t ctx, void *msg)
1423 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1425 vapi_debug_log (ctx, msg, "send");
1428 svm_queue_add (q, (u8 *) &msg, VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
1434 VL_MSG_API_POISON (msg);
1440 vapi_send (vapi_ctx_t ctx, void *msg)
1442 vapi_error_e rv = VAPI_OK;
1443 if (!ctx || !msg || !ctx->connected)
1451 rv = vapi_sock_send (ctx, msg);
1455 rv = vapi_shm_send (ctx, msg);
1459 VAPI_DBG ("vapi_send() rv = %d", rv);
1464 vapi_shm_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1466 vapi_error_e rv = VAPI_OK;
1467 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1469 vapi_debug_log (ctx, msg1, "send2");
1470 vapi_debug_log (ctx, msg2, "send2");
1472 int tmp = svm_queue_add2 (q, (u8 *) &msg1, (u8 *) &msg2,
1473 VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
1479 VL_MSG_API_POISON (msg1);
1485 vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1487 vapi_error_e rv = VAPI_OK;
1488 if (!ctx || !msg1 || !msg2 || !ctx->connected)
1496 rv = vapi_sock_send2 (ctx, msg1, msg2);
1500 rv = vapi_shm_send2 (ctx, msg1, msg2);
1504 VAPI_DBG ("vapi_send() rv = %d", rv);
1509 vapi_shm_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1510 svm_q_conditional_wait_t cond, u32 time)
1512 vapi_error_e rv = VAPI_OK;
1515 svm_queue_t *q = ctx->vl_input_queue;
1517 VAPI_DBG ("doing shm queue sub");
1519 int tmp = svm_queue_sub (q, (u8 *) & data, cond, time);
1526 VL_MSG_API_UNPOISON ((void *) data);
1527 #if VAPI_DEBUG_ALLOC
1528 vapi_add_to_be_freed ((void *) data);
1531 (msgbuf_t *) ((u8 *) data - offsetof (msgbuf_t, data));
1532 if (!msgbuf->data_len)
1534 vapi_msg_free (ctx, (u8 *) data);
1538 *msg_size = ntohl (msgbuf->data_len);
1541 vapi_debug_log (ctx, msg, "recv");
1548 vapi_sock_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size, u32 time)
1550 vapi_error_e rv = VAPI_OK;
1552 if (time == 0 && ctx->mode == VAPI_MODE_BLOCKING)
1555 rv = vapi_sock_recv_internal (ctx, &data, time);
1563 *msg_size = vec_len (data);
1566 vapi_debug_log (ctx, msg, "recv");
1573 vapi_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1574 svm_q_conditional_wait_t cond, u32 time)
1576 if (!ctx || !ctx->connected || !msg || !msg_size)
1580 vapi_error_e rv = VAPI_OK;
1585 rv = vapi_sock_recv (ctx, msg, msg_size, time);
1589 rv = vapi_shm_recv (ctx, msg, msg_size, cond, time);
1595 if (ctx->handle_keepalives)
1597 unsigned msgid = be16toh (*(u16 *) *msg);
1598 if (msgid == vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive))
1600 vapi_msg_memclnt_keepalive_reply *reply = NULL;
1603 reply = vapi_msg_alloc (ctx, sizeof (*reply));
1606 reply->header.context = vapi_get_client_index (ctx);
1607 reply->header._vl_msg_id =
1608 vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive_reply);
1609 reply->payload.retval = 0;
1610 vapi_msg_memclnt_keepalive_reply_hton (reply);
1611 while (VAPI_EAGAIN == vapi_send (ctx, reply))
1613 vapi_msg_free (ctx, *msg);
1622 vapi_wait (vapi_ctx_t ctx)
1625 return VAPI_ENOTSUP;
1627 svm_queue_lock (ctx->vl_input_queue);
1628 svm_queue_wait (ctx->vl_input_queue);
1629 svm_queue_unlock (ctx->vl_input_queue);
1635 vapi_dispatch_response (vapi_ctx_t ctx, vapi_msg_id_t id,
1636 u32 context, void *msg)
1639 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1641 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1642 return VAPI_MUTEX_FAILURE;
1644 int tmp = ctx->requests_start;
1645 const int requests_end = vapi_requests_end (ctx);
1646 while (ctx->requests[tmp].context != context && tmp != requests_end)
1649 if (tmp == ctx->requests_size)
1654 VAPI_DBG ("dispatch, search from %d, %s at %d", ctx->requests_start,
1655 ctx->requests[tmp].context == context ? "matched" : "stopped",
1657 vapi_error_e rv = VAPI_OK;
1658 if (ctx->requests[tmp].context == context)
1660 while (ctx->requests_start != tmp)
1662 VAPI_ERR ("No response to req with context=%u",
1663 (unsigned) ctx->requests[tmp].context);
1664 ctx->requests[ctx->requests_start].callback (ctx, ctx->requests
1666 requests_start].callback_ctx,
1669 clib_memset (&ctx->requests[ctx->requests_start], 0,
1670 sizeof (ctx->requests[ctx->requests_start]));
1671 ++ctx->requests_start;
1672 --ctx->requests_count;
1673 if (ctx->requests_start == ctx->requests_size)
1675 ctx->requests_start = 0;
1678 // now ctx->requests_start == tmp
1679 int payload_offset = vapi_get_payload_offset (id);
1680 void *payload = ((u8 *) msg) + payload_offset;
1681 bool is_last = true;
1682 switch (ctx->requests[tmp].type)
1684 case VAPI_REQUEST_STREAM:
1685 if (ctx->requests[tmp].response_id == id)
1691 VAPI_DBG ("Stream response ID doesn't match current ID, move to "
1693 clib_memset (&ctx->requests[tmp], 0,
1694 sizeof (ctx->requests[tmp]));
1695 ++ctx->requests_start;
1696 --ctx->requests_count;
1697 if (ctx->requests_start == ctx->requests_size)
1699 ctx->requests_start = 0;
1701 tmp = ctx->requests_start;
1702 if (ctx->requests[tmp].context != context)
1704 VAPI_ERR ("Unexpected context %u, expected context %u!",
1705 ctx->requests[tmp].context, context);
1709 case VAPI_REQUEST_DUMP:
1710 if (vapi_msg_id_control_ping_reply == id)
1719 case VAPI_REQUEST_REG:
1722 if (payload_offset != -1)
1724 rv = ctx->requests[tmp].callback (
1725 ctx, ctx->requests[tmp].callback_ctx, VAPI_OK, is_last, payload);
1729 /* this is a message without payload, so bend the callback a little
1732 ((vapi_error_e (*)(vapi_ctx_t, void *, vapi_error_e, bool))
1733 ctx->requests[tmp].callback) (ctx,
1734 ctx->requests[tmp].callback_ctx,
1739 clib_memset (&ctx->requests[ctx->requests_start], 0,
1740 sizeof (ctx->requests[ctx->requests_start]));
1741 ++ctx->requests_start;
1742 --ctx->requests_count;
1743 if (ctx->requests_start == ctx->requests_size)
1745 ctx->requests_start = 0;
1748 VAPI_DBG ("after dispatch, req start = %d, end = %d, count = %d",
1749 ctx->requests_start, requests_end, ctx->requests_count);
1751 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1753 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1755 abort (); /* this really shouldn't happen */
1761 vapi_dispatch_event (vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
1763 if (ctx->event_cbs[id].cb)
1765 return ctx->event_cbs[id].cb (ctx, ctx->event_cbs[id].ctx, msg);
1767 else if (ctx->generic_cb.cb)
1769 return ctx->generic_cb.cb (ctx, ctx->generic_cb.ctx, id, msg);
1774 ("No handler/generic handler for msg id %u[%s], message ignored",
1775 (unsigned) id, __vapi_metadata.msgs[id]->name);
1781 vapi_msg_is_with_context (vapi_msg_id_t id)
1783 assert (id <= __vapi_metadata.count);
1784 return __vapi_metadata.msgs[id]->has_context;
1788 vapi_verify_msg_size (vapi_msg_id_t id, void *buf, uword buf_size)
1790 assert (id < __vapi_metadata.count);
1791 return __vapi_metadata.msgs[id]->verify_msg_size (buf, buf_size);
1795 vapi_dispatch_one (vapi_ctx_t ctx)
1797 VAPI_DBG ("vapi_dispatch_one()");
1800 svm_q_conditional_wait_t cond =
1801 vapi_is_nonblocking (ctx) ? SVM_Q_NOWAIT : SVM_Q_WAIT;
1802 vapi_error_e rv = vapi_recv (ctx, &msg, &size, cond, 0);
1805 VAPI_DBG ("vapi_recv failed with rv=%d", rv);
1808 u16 vpp_id = be16toh (*(u16 *) msg);
1809 if (vpp_id > ctx->vl_msg_id_max)
1811 VAPI_ERR ("Unknown msg ID received, id `%u', out of range <0,%u>",
1812 (unsigned) vpp_id, (unsigned) ctx->vl_msg_id_max);
1813 vapi_msg_free (ctx, msg);
1816 if (VAPI_INVALID_MSG_ID == (unsigned) ctx->vl_msg_id_to_vapi_msg_t[vpp_id])
1818 VAPI_ERR ("Unknown msg ID received, id `%u' marked as not supported",
1820 vapi_msg_free (ctx, msg);
1823 const vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[vpp_id];
1824 vapi_get_swap_to_host_func (id) (msg);
1825 if (vapi_verify_msg_size (id, msg, size))
1827 vapi_msg_free (ctx, msg);
1831 if (vapi_msg_is_with_context (id))
1833 context = *(u32 *) (((u8 *) msg) + vapi_get_context_offset (id));
1834 /* is this a message originating from VAPI? */
1835 VAPI_DBG ("dispatch, context is %x", context);
1836 if (context & context_counter_mask)
1838 rv = vapi_dispatch_response (ctx, id, context, msg);
1842 rv = vapi_dispatch_event (ctx, id, msg);
1845 vapi_msg_free (ctx, msg);
1850 vapi_dispatch (vapi_ctx_t ctx)
1852 vapi_error_e rv = VAPI_OK;
1853 while (!vapi_requests_empty (ctx))
1855 rv = vapi_dispatch_one (ctx);
1865 vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
1866 vapi_event_cb callback, void *callback_ctx)
1868 vapi_event_cb_with_ctx *c = &ctx->event_cbs[id];
1870 c->ctx = callback_ctx;
1874 vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id)
1876 vapi_set_event_cb (ctx, id, NULL, NULL);
1880 vapi_set_generic_event_cb (vapi_ctx_t ctx, vapi_generic_event_cb callback,
1883 ctx->generic_cb.cb = callback;
1884 ctx->generic_cb.ctx = callback_ctx;
1888 vapi_clear_generic_event_cb (vapi_ctx_t ctx)
1890 ctx->generic_cb.cb = NULL;
1891 ctx->generic_cb.ctx = NULL;
1895 vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id)
1897 assert (id < __vapi_metadata.count);
1898 return ctx->vapi_msg_id_t_to_vl_msg_id[id];
1902 vapi_get_client_index (vapi_ctx_t ctx)
1904 return ctx->my_client_index;
1908 vapi_is_nonblocking (vapi_ctx_t ctx)
1910 return (VAPI_MODE_NONBLOCKING == ctx->mode);
1914 vapi_get_max_request_count (vapi_ctx_t ctx)
1916 return ctx->requests_size - 1;
1920 vapi_get_payload_offset (vapi_msg_id_t id)
1922 assert (id < __vapi_metadata.count);
1923 return __vapi_metadata.msgs[id]->payload_offset;
1926 void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *msg)
1928 assert (id < __vapi_metadata.count);
1929 return __vapi_metadata.msgs[id]->swap_to_host;
1932 void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *msg)
1934 assert (id < __vapi_metadata.count);
1935 return __vapi_metadata.msgs[id]->swap_to_be;
1939 vapi_get_context_offset (vapi_msg_id_t id)
1941 assert (id < __vapi_metadata.count);
1942 return __vapi_metadata.msgs[id]->context_offset;
1946 vapi_register_msg (vapi_message_desc_t * msg)
1949 for (i = 0; i < __vapi_metadata.count; ++i)
1952 (msg->name_with_crc, __vapi_metadata.msgs[i]->name_with_crc))
1954 /* this happens if somebody is linking together several objects while
1955 * using the static inline headers, just fill in the already
1956 * assigned id here so that all the objects are in sync */
1957 msg->id = __vapi_metadata.msgs[i]->id;
1961 vapi_msg_id_t id = __vapi_metadata.count;
1962 ++__vapi_metadata.count;
1963 __vapi_metadata.msgs =
1964 realloc (__vapi_metadata.msgs,
1965 sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
1966 __vapi_metadata.msgs[id] = msg;
1967 size_t s = strlen (msg->name_with_crc);
1968 if (s > __vapi_metadata.max_len_name_with_crc)
1970 __vapi_metadata.max_len_name_with_crc = s;
1977 vapi_producer_lock (vapi_ctx_t ctx)
1980 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1982 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1983 (void) mrv; /* avoid warning if the above debug is not enabled */
1984 return VAPI_MUTEX_FAILURE;
1990 vapi_producer_unlock (vapi_ctx_t ctx)
1993 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1995 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1997 (void) mrv; /* avoid warning if the above debug is not enabled */
1998 return VAPI_MUTEX_FAILURE;
2004 vapi_get_message_count ()
2006 return __vapi_metadata.count;
2010 vapi_get_msg_name (vapi_msg_id_t id)
2012 return __vapi_metadata.msgs[id]->name;
2016 vapi_stop_rx_thread (vapi_ctx_t ctx)
2018 if (!ctx || !ctx->connected || !ctx->vl_input_queue)
2023 vl_client_stop_rx_thread (ctx->vl_input_queue);
2026 * fd.io coding-style-patch-verification: ON
2029 * eval: (c-set-style "gnu")