|
FD.io VPP
v21.10.1-2-g0a485f517
Vector Packet Processing
|
Go to the documentation of this file.
21 #include <arpa/inet.h>
34 #include <vapi/memclnt.api.vapi.h>
96 ++
ctx->context_counter;
104 return ctx->requests_count;
110 return (
ctx->requests_count ==
ctx->requests_size);
116 return (0 ==
ctx->requests_count);
122 return (
ctx->requests_start +
ctx->requests_count) %
ctx->requests_size;
131 assert (0 != pthread_mutex_trylock (&
ctx->requests_mutex));
134 slot->is_dump = is_dump;
136 slot->callback = callback;
137 slot->callback_ctx = callback_ctx;
138 VAPI_DBG (
"stored@%d: context:%x (start is @%d)", requests_end,
context,
139 ctx->requests_start);
140 ++
ctx->requests_count;
145 struct to_be_freed_s;
149 struct to_be_freed_s *
next;
152 static struct to_be_freed_s *to_be_freed = NULL;
155 vapi_add_to_be_freed (
void *v)
157 struct to_be_freed_s *prev = NULL;
158 struct to_be_freed_s *
tmp;
169 tmp = to_be_freed =
calloc (1,
sizeof (*to_be_freed));
173 tmp = prev->next =
calloc (1,
sizeof (*to_be_freed));
181 vapi_trace_free (
void *v)
183 struct to_be_freed_s *
tmp = to_be_freed;
184 while (
tmp &&
tmp->v != v)
195 VAPI_ERR (
"Trying to free untracked pointer %p", v);
201 vapi_to_be_freed_validate ()
203 struct to_be_freed_s *
tmp = to_be_freed;
239 vapi_trace_free (msg);
247 if (vl_msg_id <= ctx->vl_msg_id_max)
262 ctx->context_counter = 0;
263 ctx->vapi_msg_id_t_to_vl_msg_id =
264 malloc (__vapi_metadata.count *
265 sizeof (*
ctx->vapi_msg_id_t_to_vl_msg_id));
266 if (!
ctx->vapi_msg_id_t_to_vl_msg_id)
271 __vapi_metadata.count *
272 sizeof (*
ctx->vapi_msg_id_t_to_vl_msg_id));
273 ctx->event_cbs =
calloc (__vapi_metadata.count, sizeof (*
ctx->event_cbs));
278 pthread_mutex_init (&
ctx->requests_mutex, NULL);
291 free (
ctx->vapi_msg_id_t_to_vl_msg_id);
293 free (
ctx->vl_msg_id_to_vapi_msg_t);
294 pthread_mutex_destroy (&
ctx->requests_mutex);
306 const char *chroot_prefix,
309 bool handle_keepalives)
320 const size_t size =
ctx->requests_size *
sizeof (*
ctx->requests);
329 ctx->requests_start =
ctx->requests_count = 0;
332 VAPI_DBG (
"set memory root path `%s'", chroot_prefix);
335 static char api_map[] =
"/vpe-api";
336 VAPI_DBG (
"client api map `%s'", api_map);
347 #if VAPI_DEBUG_CONNECT
348 VAPI_DBG (
"start probing messages");
352 for (
i = 0;
i < __vapi_metadata.count; ++
i)
362 VAPI_ERR (
"Returned vl_msg_id `%u' > UINT16MAX `%u'!",
id,
367 if (
id >
ctx->vl_msg_id_max)
371 (*
ctx->vl_msg_id_to_vapi_msg_t) *
378 ctx->vl_msg_id_to_vapi_msg_t =
tmp;
379 ctx->vl_msg_id_max =
id;
381 ctx->vl_msg_id_to_vapi_msg_t[
id] = m->
id;
382 ctx->vapi_msg_id_t_to_vl_msg_id[m->
id] =
id;
383 #if VAPI_DEBUG_CONNECT
390 ctx->vapi_msg_id_t_to_vl_msg_id[m->
id] = UINT16_MAX;
394 #if VAPI_DEBUG_CONNECT
395 VAPI_DBG (
"finished probing messages");
401 (
"control ping or control ping reply not available, cannot connect");
406 ctx->connected =
true;
409 ctx->handle_keepalives = handle_keepalives;
413 ctx->handle_keepalives =
false;
432 vapi_to_be_freed_validate ();
434 ctx->connected =
false;
448 if (!
ctx || !msg || !
ctx->connected)
456 unsigned msgid = be16toh (*(
u16 *) msg);
457 if (msgid <= ctx->vl_msg_id_max)
460 if (
id < __vapi_metadata.count)
462 VAPI_DBG (
"send msg@%p:%u[%s]", msg, msgid,
463 __vapi_metadata.msgs[
id]->name);
467 VAPI_DBG (
"send msg@%p:%u[UNKNOWN]", msg, msgid);
472 VAPI_DBG (
"send msg@%p:%u[UNKNOWN]", msg, msgid);
492 if (!
ctx || !msg1 || !msg2 || !
ctx->connected)
499 unsigned msgid1 = be16toh (*(
u16 *) msg1);
500 unsigned msgid2 = be16toh (*(
u16 *) msg2);
501 const char *name1 =
"UNKNOWN";
502 const char *name2 =
"UNKNOWN";
503 if (msgid1 <= ctx->vl_msg_id_max)
506 if (
id < __vapi_metadata.count)
508 name1 = __vapi_metadata.msgs[
id]->name;
511 if (msgid2 <= ctx->vl_msg_id_max)
514 if (
id < __vapi_metadata.count)
516 name2 = __vapi_metadata.msgs[
id]->name;
519 VAPI_DBG (
"send two: %u[%s], %u[%s]", msgid1, name1, msgid2, name2);
538 if (!
ctx || !
ctx->connected || !msg || !msg_size)
546 if (
am->our_pid == 0)
561 vapi_add_to_be_freed ((
void *)
data);
571 *msg_size = ntohl (msgbuf->
data_len);
573 unsigned msgid = be16toh (*(
u16 *) * msg);
574 if (msgid <= ctx->vl_msg_id_max)
577 if (
id < __vapi_metadata.count)
579 VAPI_DBG (
"recv msg@%p:%u[%s]", *msg, msgid,
580 __vapi_metadata.msgs[
id]->name);
584 VAPI_DBG (
"recv msg@%p:%u[UNKNOWN]", *msg, msgid);
589 VAPI_DBG (
"recv msg@%p:%u[UNKNOWN]", *msg, msgid);
592 if (
ctx->handle_keepalives)
594 unsigned msgid = be16toh (*(
u16 *) * msg);
598 vapi_msg_memclnt_keepalive_reply *reply = NULL;
605 reply->header._vl_msg_id =
607 vapi_msg_id_memclnt_keepalive_reply);
608 reply->payload.retval = 0;
609 vapi_msg_memclnt_keepalive_reply_hton (reply);
612 VAPI_DBG (
"autohandled memclnt_keepalive");
635 if (0 != (mrv = pthread_mutex_lock (&
ctx->requests_mutex)))
637 VAPI_DBG (
"pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
640 int tmp =
ctx->requests_start;
645 if (
tmp ==
ctx->requests_size)
650 VAPI_DBG (
"dispatch, search from %d, %s at %d",
ctx->requests_start,
651 ctx->requests[
tmp].context ==
context ?
"matched" :
"stopped",
656 while (
ctx->requests_start !=
tmp)
658 VAPI_ERR (
"No response to req with context=%u",
659 (
unsigned)
ctx->requests[
tmp].context);
660 ctx->requests[
ctx->requests_start].callback (
ctx,
ctx->requests
662 requests_start].callback_ctx,
666 sizeof (
ctx->requests[
ctx->requests_start]));
667 ++
ctx->requests_start;
668 --
ctx->requests_count;
669 if (
ctx->requests_start ==
ctx->requests_size)
671 ctx->requests_start = 0;
676 void *payload = ((
u8 *) msg) + payload_offset;
678 if (
ctx->requests[
tmp].is_dump)
689 if (payload_offset != -1)
702 ctx->requests[
tmp].callback_ctx,
708 sizeof (
ctx->requests[
ctx->requests_start]));
709 ++
ctx->requests_start;
710 --
ctx->requests_count;
711 if (
ctx->requests_start ==
ctx->requests_size)
713 ctx->requests_start = 0;
716 VAPI_DBG (
"after dispatch, req start = %d, end = %d, count = %d",
717 ctx->requests_start, requests_end,
ctx->requests_count);
719 if (0 != (mrv = pthread_mutex_unlock (&
ctx->requests_mutex)))
721 VAPI_DBG (
"pthread_mutex_unlock() failed, rv=%d:%s", mrv,
731 if (
ctx->event_cbs[
id].cb)
733 return ctx->event_cbs[
id].cb (
ctx,
ctx->event_cbs[
id].ctx, msg);
735 else if (
ctx->generic_cb.cb)
737 return ctx->generic_cb.cb (
ctx,
ctx->generic_cb.ctx,
id, msg);
742 (
"No handler/generic handler for msg id %u[%s], message ignored",
743 (
unsigned)
id, __vapi_metadata.msgs[
id]->name);
751 assert (
id <= __vapi_metadata.count);
752 return __vapi_metadata.msgs[
id]->has_context;
767 u16 vpp_id = be16toh (*(
u16 *) msg);
768 if (vpp_id >
ctx->vl_msg_id_max)
770 VAPI_ERR (
"Unknown msg ID received, id `%u', out of range <0,%u>",
771 (
unsigned) vpp_id, (
unsigned)
ctx->vl_msg_id_max);
777 VAPI_ERR (
"Unknown msg ID received, id `%u' marked as not supported",
784 if (
size < expect_size)
787 (
"Invalid msg received, unexpected size `%zu' < expected min `%zu'",
833 c->ctx = callback_ctx;
846 ctx->generic_cb.cb = callback;
847 ctx->generic_cb.ctx = callback_ctx;
853 ctx->generic_cb.cb = NULL;
854 ctx->generic_cb.ctx = NULL;
860 assert (
id < __vapi_metadata.count);
861 return ctx->vapi_msg_id_t_to_vl_msg_id[
id];
879 return ctx->requests_size - 1;
885 assert (
id < __vapi_metadata.count);
886 return __vapi_metadata.msgs[
id]->payload_offset;
891 assert (
id < __vapi_metadata.count);
892 return __vapi_metadata.msgs[
id]->swap_to_host;
897 assert (
id < __vapi_metadata.count);
898 return __vapi_metadata.msgs[
id]->swap_to_be;
904 assert (
id < __vapi_metadata.count);
905 return __vapi_metadata.msgs[
id]->size;
911 assert (
id < __vapi_metadata.count);
912 return __vapi_metadata.msgs[
id]->context_offset;
919 for (
i = 0;
i < __vapi_metadata.count; ++
i)
927 msg->
id = __vapi_metadata.msgs[
i]->id;
932 ++__vapi_metadata.count;
933 __vapi_metadata.msgs =
935 sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
936 __vapi_metadata.msgs[
id] = msg;
938 if (s > __vapi_metadata.max_len_name_with_crc)
940 __vapi_metadata.max_len_name_with_crc = s;
950 if (0 != (mrv = pthread_mutex_lock (&
ctx->requests_mutex)))
952 VAPI_DBG (
"pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
963 if (0 != (mrv = pthread_mutex_unlock (&
ctx->requests_mutex)))
965 VAPI_DBG (
"pthread_mutex_unlock() failed, rv=%d:%s", mrv,
976 return __vapi_metadata.count;
982 return __vapi_metadata.msgs[
id]->name;
DEFINE_VAPI_MSG_IDS_MEMCLNT_API_JSON
vapi_error_e vapi_recv(vapi_ctx_t ctx, void **msg, size_t *msg_size, svm_q_conditional_wait_t cond, u32 time)
low-level api for reading messages from vpp
void * vl_msg_api_alloc_or_null(int nbytes)
vapi_error_e vapi_connect(vapi_ctx_t ctx, const char *name, const char *chroot_prefix, int max_outstanding_requests, int response_queue_size, vapi_mode_e mode, bool handle_keepalives)
connect to vpp
void vapi_ctx_free(vapi_ctx_t ctx)
free vapi context
void * realloc(void *p, size_t size)
void vl_client_api_unmap(void)
int vapi_get_payload_offset(vapi_msg_id_t id)
struct _svm_queue svm_queue_t
void vapi_set_generic_event_cb(vapi_ctx_t ctx, vapi_generic_event_cb callback, void *callback_ctx)
set generic event callback
void vapi_set_event_cb(vapi_ctx_t ctx, vapi_msg_id_t id, vapi_event_cb callback, void *callback_ctx)
set event callback to call when message with given id is dispatched
vapi_error_e vapi_producer_unlock(vapi_ctx_t ctx)
vl_api_tunnel_mode_t mode
struct vapi_ctx_s * vapi_ctx_t
size_t max_len_name_with_crc
u32 data_len
message length not including header
bool vapi_requests_full(vapi_ctx_t ctx)
void vapi_clear_event_cb(vapi_ctx_t ctx, vapi_msg_id_t id)
clear event callback for given message id
bool vapi_msg_is_with_context(vapi_msg_id_t id)
int vl_client_disconnect(void)
static vapi_error_e vapi_dispatch_response(vapi_ctx_t ctx, vapi_msg_id_t id, u32 context, void *msg)
@ VAPI_MODE_NONBLOCKING
operations never block
DEFINE_VAPI_MSG_IDS_VPE_API_JSON
static const u32 context_counter_mask
static CLIB_NOSANITIZE_ADDR void VL_MSG_API_UNPOISON(const void *a)
int vl_client_api_map(const char *region_name)
vapi_event_cb_with_ctx * event_cbs
vapi_generic_cb_with_ctx generic_cb
static clib_mem_heap_t * clib_mem_get_per_cpu_heap(void)
static int vapi_requests_end(vapi_ctx_t ctx)
vapi_msg_id_t vapi_msg_id_control_ping
u16 vapi_lookup_vl_msg_id(vapi_ctx_t ctx, vapi_msg_id_t id)
@ VAPI_MODE_BLOCKING
operations block until response received
@ VAPI_EAGAIN
operation would block
vapi_msg_id_t vapi_lookup_vapi_msg_id_t(vapi_ctx_t ctx, u16 vl_msg_id)
@ VAPI_EINCOMPATIBLE
fundamental incompatibility while connecting to vpp (control ping/control ping reply mismatch)
pthread_mutex_t requests_mutex
int my_client_index
All VLIB-side message handlers use my_client_index to identify the queue / client.
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
unsigned int vapi_msg_id_t
svm_queue_t * vl_input_queue
@ VAPI_ENORESP
no response to request
void vl_set_memory_root_path(const char *name)
Fixed length block allocator. Pools are built from clib vectors and bitmaps. Use pools when repeatedl...
int vapi_get_client_index(vapi_ctx_t ctx)
static api_main_t * vlibapi_get_main(void)
size_t vapi_get_message_count()
vapi_error_e(* vapi_event_cb)(vapi_ctx_t ctx, void *callback_ctx, void *payload)
generic vapi event callback
bool vapi_is_msg_available(vapi_ctx_t ctx, vapi_msg_id_t id)
check if message identified by it's message id is known by the vpp to which the connection is open
u32 vl_msg_api_get_msg_index(u8 *name_and_crc)
static void VL_MSG_API_POISON(const void *a)
static vapi_error_e vapi_dispatch_event(vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
static const int response_queue_size
size_t vapi_get_context_offset(vapi_msg_id_t id)
vapi_error_e vapi_get_fd(vapi_ctx_t ctx, int *fd)
get event file descriptor
vapi_error_e vapi_dispatch_one(vapi_ctx_t ctx)
pick next message sent by vpp and call the appropriate callback
size_t vapi_get_request_count(vapi_ctx_t ctx)
vapi_msg_id_t vapi_register_msg(vapi_message_desc_t *msg)
void vapi_msg_free(vapi_ctx_t ctx, void *msg)
free a vapi message
const char * name_with_crc
vapi_error_e vapi_send(vapi_ctx_t ctx, void *msg)
low-level api for sending messages to vpp
size_t vapi_get_message_size(vapi_msg_id_t id)
bool vapi_requests_empty(vapi_ctx_t ctx)
API main structure, used by both vpp and binary API clients.
vapi_error_e vapi_ctx_alloc(vapi_ctx_t *result)
allocate vapi context
vapi_error_e(* vapi_cb_t)(struct vapi_ctx_s *, void *, vapi_error_e, bool, void *)
int svm_queue_add(svm_queue_t *q, u8 *elem, int nowait)
void vl_msg_api_free(void *)
vapi_msg_id_t vapi_msg_id_control_ping_reply
const char * vapi_get_msg_name(vapi_msg_id_t id)
vapi_error_e vapi_send2(vapi_ctx_t ctx, void *msg1, void *msg2)
low-level api for atomically sending two messages to vpp - either both messages are sent or neither o...
size_t vapi_get_max_request_count(vapi_ctx_t ctx)
void(*)(void *msg) vapi_get_swap_to_be_func(vapi_msg_id_t id)
vapi_error_e vapi_disconnect(vapi_ctx_t ctx)
disconnect from vpp
int svm_queue_add2(svm_queue_t *q, u8 *elem, u8 *elem2, int nowait)
u32 vapi_gen_req_context(vapi_ctx_t ctx)
vapi_error_e vapi_producer_lock(vapi_ctx_t ctx)
vapi_error_e vapi_wait(vapi_ctx_t ctx, vapi_wait_mode_e mode)
wait for connection to become readable or writable
vapi_message_desc_t ** msgs
Message header structure.
void * clib_mem_init(void *base, uword size)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void * calloc(size_t nmemb, size_t size)
vapi_error_e vapi_dispatch(vapi_ctx_t ctx)
loop vapi_dispatch_one until responses to all currently outstanding requests have been received and t...
vapi_msg_id_t * vl_msg_id_to_vapi_msg_t
#define VAPI_INVALID_MSG_ID
u16 * vapi_msg_id_t_to_vl_msg_id
void(*)(void *msg) vapi_get_swap_to_host_func(vapi_msg_id_t id)
void * malloc(size_t size)
int svm_queue_sub(svm_queue_t *q, u8 *elem, svm_q_conditional_wait_t cond, u32 time)
@ VAPI_ECON_FAIL
failure while connecting to vpp
@ SVM_Q_WAIT
blocking call - best used in combination with condvars, for eventfds we don't yield the cpu
vapi_error_e(* vapi_generic_event_cb)(vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id, void *msg)
generic vapi event callback
@ VAPI_ENOMEM
out of memory
@ VAPI_EMAP_FAIL
failure while mapping api
@ VAPI_ENOTSUP
operation not supported
static const int max_outstanding_requests
void vapi_clear_generic_event_cb(vapi_ctx_t ctx)
clear generic event callback
int vl_client_connect(const char *name, int ctx_quota, int input_queue_size)
bool vapi_is_nonblocking(vapi_ctx_t ctx)
void * vapi_msg_alloc(vapi_ctx_t ctx, size_t size)
allocate vapi message of given size
void vapi_store_request(vapi_ctx_t ctx, u32 context, bool is_dump, vapi_cb_t callback, void *callback_ctx)
@ VAPI_EINVAL
invalid value encountered
@ VAPI_MUTEX_FAILURE
failure manipulating internal mutex(es)