blob: 25571dcb54a698b0b83a492d280e6058c653c4da [file] [log] [blame]
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001/*
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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 *------------------------------------------------------------------
16 */
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <stdint.h>
21#include <arpa/inet.h>
22#include <stddef.h>
23#include <assert.h>
24
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>
Dave Barach59b25652017-09-10 15:04:27 -040029#include <vppinfra/pool.h>
30#include <vlib/vlib.h>
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020031#include <vlibapi/api_common.h>
Florin Corase86a8ed2018-01-05 03:20:25 -080032#include <vlibmemory/memory_client.h>
Ole Troan2ca88ff2022-01-27 16:25:43 +010033#include <vlibmemory/memory_api.h>
34#include <vlibmemory/api.h>
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020035
Klement Sekeradab732a2018-07-04 13:43:46 +020036#include <vapi/memclnt.api.vapi.h>
Filip Tehlarf0e67d72021-07-23 22:03:05 +000037#include <vapi/vlib.api.vapi.h>
Klement Sekeradab732a2018-07-04 13:43:46 +020038
Ole Troan2ca88ff2022-01-27 16:25:43 +010039#include <vlibmemory/vl_memory_msg_enum.h>
40
41#define vl_typedefs /* define message structures */
42#include <vlibmemory/vl_memory_api_h.h>
43#undef vl_typedefs
44
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020045/* 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 */
48vapi_msg_id_t vapi_msg_id_control_ping = 0;
49vapi_msg_id_t vapi_msg_id_control_ping_reply = 0;
50
Klement Sekeradab732a2018-07-04 13:43:46 +020051DEFINE_VAPI_MSG_IDS_MEMCLNT_API_JSON;
Florin Corasa1400ce2021-09-15 09:02:08 -070052DEFINE_VAPI_MSG_IDS_VLIB_API_JSON;
Klement Sekeradab732a2018-07-04 13:43:46 +020053
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020054struct
55{
56 size_t count;
57 vapi_message_desc_t **msgs;
58 size_t max_len_name_with_crc;
59} __vapi_metadata;
60
61typedef struct
62{
63 u32 context;
64 vapi_cb_t callback;
65 void *callback_ctx;
66 bool is_dump;
67} vapi_req_t;
68
69static const u32 context_counter_mask = (1 << 31);
70
71typedef struct
72{
73 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id,
74 void *payload);
75 void *ctx;
76} vapi_generic_cb_with_ctx;
77
78typedef struct
79{
80 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, void *payload);
81 void *ctx;
82} vapi_event_cb_with_ctx;
83
84struct vapi_ctx_s
85{
86 vapi_mode_e mode;
87 int requests_size; /* size of the requests array (circular queue) */
88 int requests_start; /* index of first request */
89 int requests_count; /* number of used slots */
90 vapi_req_t *requests;
91 u32 context_counter;
92 vapi_generic_cb_with_ctx generic_cb;
93 vapi_event_cb_with_ctx *event_cbs;
94 u16 *vapi_msg_id_t_to_vl_msg_id;
95 u16 vl_msg_id_max;
96 vapi_msg_id_t *vl_msg_id_to_vapi_msg_t;
97 bool connected;
Klement Sekeradab732a2018-07-04 13:43:46 +020098 bool handle_keepalives;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020099 pthread_mutex_t requests_mutex;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100100
101 svm_queue_t *vl_input_queue;
102 u32 my_client_index;
103 /** client message index hash table */
104 uword *msg_index_by_name_and_crc;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200105};
106
107u32
108vapi_gen_req_context (vapi_ctx_t ctx)
109{
110 ++ctx->context_counter;
111 ctx->context_counter %= context_counter_mask;
112 return ctx->context_counter | context_counter_mask;
113}
114
115size_t
116vapi_get_request_count (vapi_ctx_t ctx)
117{
118 return ctx->requests_count;
119}
120
121bool
122vapi_requests_full (vapi_ctx_t ctx)
123{
124 return (ctx->requests_count == ctx->requests_size);
125}
126
Klement Sekeradc15be22017-06-12 06:49:33 +0200127bool
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200128vapi_requests_empty (vapi_ctx_t ctx)
129{
130 return (0 == ctx->requests_count);
131}
132
133static int
134vapi_requests_end (vapi_ctx_t ctx)
135{
136 return (ctx->requests_start + ctx->requests_count) % ctx->requests_size;
137}
138
139void
140vapi_store_request (vapi_ctx_t ctx, u32 context, bool is_dump,
141 vapi_cb_t callback, void *callback_ctx)
142{
143 assert (!vapi_requests_full (ctx));
144 /* if the mutex is not held, bad things will happen */
145 assert (0 != pthread_mutex_trylock (&ctx->requests_mutex));
146 const int requests_end = vapi_requests_end (ctx);
147 vapi_req_t *slot = &ctx->requests[requests_end];
148 slot->is_dump = is_dump;
149 slot->context = context;
150 slot->callback = callback;
151 slot->callback_ctx = callback_ctx;
152 VAPI_DBG ("stored@%d: context:%x (start is @%d)", requests_end, context,
153 ctx->requests_start);
154 ++ctx->requests_count;
155 assert (!vapi_requests_empty (ctx));
156}
157
158#if VAPI_DEBUG_ALLOC
159struct to_be_freed_s;
160struct to_be_freed_s
161{
162 void *v;
163 struct to_be_freed_s *next;
164};
165
166static struct to_be_freed_s *to_be_freed = NULL;
167
168void
169vapi_add_to_be_freed (void *v)
170{
171 struct to_be_freed_s *prev = NULL;
172 struct to_be_freed_s *tmp;
173 tmp = to_be_freed;
174 while (tmp && tmp->v)
175 {
176 prev = tmp;
177 tmp = tmp->next;
178 }
179 if (!tmp)
180 {
181 if (!prev)
182 {
183 tmp = to_be_freed = calloc (1, sizeof (*to_be_freed));
184 }
185 else
186 {
187 tmp = prev->next = calloc (1, sizeof (*to_be_freed));
188 }
189 }
190 VAPI_DBG ("To be freed %p", v);
191 tmp->v = v;
192}
193
194void
195vapi_trace_free (void *v)
196{
197 struct to_be_freed_s *tmp = to_be_freed;
198 while (tmp && tmp->v != v)
199 {
200 tmp = tmp->next;
201 }
202 if (tmp && tmp->v == v)
203 {
204 VAPI_DBG ("Freed %p", v);
205 tmp->v = NULL;
206 }
207 else
208 {
209 VAPI_ERR ("Trying to free untracked pointer %p", v);
210 abort ();
211 }
212}
213
214void
215vapi_to_be_freed_validate ()
216{
217 struct to_be_freed_s *tmp = to_be_freed;
218 while (tmp)
219 {
220 if (tmp->v)
221 {
222 VAPI_ERR ("Unfreed msg %p!", tmp->v);
223 }
224 tmp = tmp->next;
225 }
226}
227
228#endif
229
230void *
231vapi_msg_alloc (vapi_ctx_t ctx, size_t size)
232{
233 if (!ctx->connected)
234 {
235 return NULL;
236 }
Ole Troan2ca88ff2022-01-27 16:25:43 +0100237 void *rv = vl_msg_api_alloc_as_if_client_or_null (size);
Klement Sekera35418ba2020-06-09 14:17:45 +0000238 if (rv)
239 {
240 clib_memset (rv, 0, size);
241 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200242 return rv;
243}
244
245void
246vapi_msg_free (vapi_ctx_t ctx, void *msg)
247{
248 if (!ctx->connected)
249 {
250 return;
251 }
252#if VAPI_DEBUG_ALLOC
253 vapi_trace_free (msg);
254#endif
255 vl_msg_api_free (msg);
256}
257
Klement Sekeradc15be22017-06-12 06:49:33 +0200258vapi_msg_id_t
259vapi_lookup_vapi_msg_id_t (vapi_ctx_t ctx, u16 vl_msg_id)
260{
261 if (vl_msg_id <= ctx->vl_msg_id_max)
262 {
263 return ctx->vl_msg_id_to_vapi_msg_t[vl_msg_id];
264 }
Klement Sekeradab732a2018-07-04 13:43:46 +0200265 return VAPI_INVALID_MSG_ID;
Klement Sekeradc15be22017-06-12 06:49:33 +0200266}
267
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200268vapi_error_e
269vapi_ctx_alloc (vapi_ctx_t * result)
270{
271 vapi_ctx_t ctx = calloc (1, sizeof (struct vapi_ctx_s));
272 if (!ctx)
273 {
274 return VAPI_ENOMEM;
275 }
276 ctx->context_counter = 0;
277 ctx->vapi_msg_id_t_to_vl_msg_id =
278 malloc (__vapi_metadata.count *
279 sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
280 if (!ctx->vapi_msg_id_t_to_vl_msg_id)
281 {
282 goto fail;
283 }
Dave Barachb7b92992018-10-17 10:38:51 -0400284 clib_memset (ctx->vapi_msg_id_t_to_vl_msg_id, ~0,
285 __vapi_metadata.count *
286 sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200287 ctx->event_cbs = calloc (__vapi_metadata.count, sizeof (*ctx->event_cbs));
288 if (!ctx->event_cbs)
289 {
290 goto fail;
291 }
292 pthread_mutex_init (&ctx->requests_mutex, NULL);
293 *result = ctx;
294 return VAPI_OK;
295fail:
296 vapi_ctx_free (ctx);
297 return VAPI_ENOMEM;
298}
299
300void
301vapi_ctx_free (vapi_ctx_t ctx)
302{
303 assert (!ctx->connected);
304 free (ctx->requests);
305 free (ctx->vapi_msg_id_t_to_vl_msg_id);
306 free (ctx->event_cbs);
307 free (ctx->vl_msg_id_to_vapi_msg_t);
308 pthread_mutex_destroy (&ctx->requests_mutex);
309 free (ctx);
310}
311
312bool
313vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t id)
314{
315 return vapi_lookup_vl_msg_id (ctx, id) != UINT16_MAX;
316}
317
Ole Troan2ca88ff2022-01-27 16:25:43 +0100318/* Cut and paste to avoid adding dependency to client library */
319__clib_nosanitize_addr static void
320VL_API_VEC_UNPOISON (const void *v)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200321{
Ole Troan2ca88ff2022-01-27 16:25:43 +0100322 const vec_header_t *vh = &((vec_header_t *) v)[-1];
323 clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
324}
325
326static void
327vapi_api_name_and_crc_free (vapi_ctx_t ctx)
328{
329 int i;
330 u8 **keys = 0;
331 hash_pair_t *hp;
332
333 if (!ctx->msg_index_by_name_and_crc)
334 return;
335 hash_foreach_pair (hp, ctx->msg_index_by_name_and_crc,
336 ({ vec_add1 (keys, (u8 *) hp->key); }));
337 for (i = 0; i < vec_len (keys); i++)
338 vec_free (keys[i]);
339 vec_free (keys);
340 hash_free (ctx->msg_index_by_name_and_crc);
341}
342
343static void
344vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
345 vl_api_memclnt_create_v2_reply_t *mp)
346{
347 serialize_main_t _sm, *sm = &_sm;
348 u8 *tblv;
349 u32 nmsgs;
350 int i;
351 u8 *name_and_crc;
352 u32 msg_index;
353
354 ctx->my_client_index = mp->index;
355
356 /* Clean out any previous hash table (unlikely) */
357 vapi_api_name_and_crc_free (ctx);
358
359 ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
360
361 /* Recreate the vnet-side API message handler table */
362 tblv = uword_to_pointer (mp->message_table, u8 *);
363 unserialize_open_data (sm, tblv, vec_len (tblv));
364 unserialize_integer (sm, &nmsgs, sizeof (u32));
365
366 VL_API_VEC_UNPOISON (tblv);
367
368 for (i = 0; i < nmsgs; i++)
369 {
370 msg_index = unserialize_likely_small_unsigned_integer (sm);
371 unserialize_cstring (sm, (char **) &name_and_crc);
372 hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc, msg_index);
373 }
374}
375
376static void
377vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
378 vl_api_memclnt_delete_reply_t *mp)
379{
380 void *oldheap;
381 oldheap = vl_msg_push_heap ();
382 svm_queue_free (ctx->vl_input_queue);
383 vl_msg_pop_heap (oldheap);
384
385 ctx->my_client_index = ~0;
386 ctx->vl_input_queue = 0;
387}
388
389int
390vapi_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
391 int input_queue_size, bool keepalive)
392{
393 vl_api_memclnt_create_v2_t *mp;
394 vl_api_memclnt_create_v2_reply_t *rp;
395 svm_queue_t *vl_input_queue;
396 vl_shmem_hdr_t *shmem_hdr;
397 int rv = 0;
398 void *oldheap;
399 api_main_t *am = vlibapi_get_main ();
400
401 shmem_hdr = am->shmem_hdr;
402
403 if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
404 {
405 clib_warning ("shmem_hdr / input queue NULL");
406 return -1;
407 }
408
409 clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
410 VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
411
412 oldheap = vl_msg_push_heap ();
413 vl_input_queue =
414 svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
415 vl_msg_pop_heap (oldheap);
416
417 ctx->my_client_index = ~0;
418 ctx->vl_input_queue = vl_input_queue;
419
420 mp = vl_msg_api_alloc_as_if_client (sizeof (vl_api_memclnt_create_v2_t));
421 clib_memset (mp, 0, sizeof (*mp));
422 mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2);
423 mp->ctx_quota = ctx_quota;
424 mp->input_queue = (uword) vl_input_queue;
425 strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
426 mp->keepalive = keepalive;
427
428 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
429
430 while (1)
431 {
432 int qstatus;
433 struct timespec ts, tsrem;
434 int i;
435
436 /* Wait up to 10 seconds */
437 for (i = 0; i < 1000; i++)
438 {
439 qstatus =
440 svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
441 if (qstatus == 0)
442 goto read_one_msg;
443 ts.tv_sec = 0;
444 ts.tv_nsec = 10000 * 1000; /* 10 ms */
445 while (nanosleep (&ts, &tsrem) < 0)
446 ts = tsrem;
447 }
448 /* Timeout... */
449 return -1;
450
451 read_one_msg:
452 VL_MSG_API_UNPOISON (rp);
453 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
454 {
455 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
456 continue;
457 }
458 rv = clib_net_to_host_u32 (rp->response);
459 vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
460 break;
461 }
462 return (rv);
463}
464
465u32
466vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
467{
468 uword *p;
469
470 if (ctx->msg_index_by_name_and_crc)
471 {
472 p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
473 if (p)
474 return p[0];
475 }
476 return ~0;
477}
478
479vapi_error_e
480vapi_connect (vapi_ctx_t ctx, const char *name, const char *chroot_prefix,
481 int max_outstanding_requests, int response_queue_size,
482 vapi_mode_e mode, bool handle_keepalives)
483{
484 int rv;
485
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200486 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
487 {
488 return VAPI_EINVAL;
489 }
Klement Sekera7ff0a262018-09-03 12:35:27 +0200490 if (!clib_mem_get_per_cpu_heap () && !clib_mem_init (0, 1024 * 1024 * 32))
491 {
492 return VAPI_ENOMEM;
493 }
Ole Troan2ca88ff2022-01-27 16:25:43 +0100494
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200495 ctx->requests_size = max_outstanding_requests;
496 const size_t size = ctx->requests_size * sizeof (*ctx->requests);
497 void *tmp = realloc (ctx->requests, size);
498 if (!tmp)
499 {
500 return VAPI_ENOMEM;
501 }
502 ctx->requests = tmp;
Dave Barachb7b92992018-10-17 10:38:51 -0400503 clib_memset (ctx->requests, 0, size);
Chris Luke879ace32017-09-26 13:15:16 -0400504 /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200505 ctx->requests_start = ctx->requests_count = 0;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100506
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200507 if (chroot_prefix)
508 {
509 VAPI_DBG ("set memory root path `%s'", chroot_prefix);
510 vl_set_memory_root_path ((char *) chroot_prefix);
511 }
512 static char api_map[] = "/vpe-api";
513 VAPI_DBG ("client api map `%s'", api_map);
Ole Troan2ca88ff2022-01-27 16:25:43 +0100514 if ((rv = vl_map_shmem (api_map, 0 /* is_vlib */)) < 0)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200515 {
516 return VAPI_EMAP_FAIL;
517 }
518 VAPI_DBG ("connect client `%s'", name);
Ole Troan2ca88ff2022-01-27 16:25:43 +0100519 if (vapi_client_connect (ctx, (char *) name, 0, response_queue_size, true) <
520 0)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200521 {
522 vl_client_api_unmap ();
523 return VAPI_ECON_FAIL;
524 }
525#if VAPI_DEBUG_CONNECT
526 VAPI_DBG ("start probing messages");
527#endif
Ole Troan2ca88ff2022-01-27 16:25:43 +0100528
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200529 int i;
530 for (i = 0; i < __vapi_metadata.count; ++i)
531 {
532 vapi_message_desc_t *m = __vapi_metadata.msgs[i];
533 u8 scratch[m->name_with_crc_len + 1];
534 memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
Ole Troan2ca88ff2022-01-27 16:25:43 +0100535 u32 id = vapi_api_get_msg_index (ctx, scratch);
536
Klement Sekeradab732a2018-07-04 13:43:46 +0200537 if (VAPI_INVALID_MSG_ID != id)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200538 {
539 if (id > UINT16_MAX)
540 {
541 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
542 UINT16_MAX);
543 rv = VAPI_EINVAL;
544 goto fail;
545 }
546 if (id > ctx->vl_msg_id_max)
547 {
Ole Troan2ca88ff2022-01-27 16:25:43 +0100548 vapi_msg_id_t *tmp =
549 realloc (ctx->vl_msg_id_to_vapi_msg_t,
550 sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200551 if (!tmp)
552 {
553 rv = VAPI_ENOMEM;
554 goto fail;
555 }
556 ctx->vl_msg_id_to_vapi_msg_t = tmp;
557 ctx->vl_msg_id_max = id;
558 }
559 ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
560 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
561#if VAPI_DEBUG_CONNECT
562 VAPI_DBG ("Message `%s' has vl_msg_id `%u'", m->name_with_crc,
563 (unsigned) id);
564#endif
565 }
566 else
567 {
568 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
569 VAPI_DBG ("Message `%s' not available", m->name_with_crc);
570 }
571 }
572#if VAPI_DEBUG_CONNECT
573 VAPI_DBG ("finished probing messages");
574#endif
575 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
576 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
577 {
Ole Troan2ca88ff2022-01-27 16:25:43 +0100578 VAPI_ERR (
579 "control ping or control ping reply not available, cannot connect");
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200580 rv = VAPI_EINCOMPATIBLE;
581 goto fail;
582 }
583 ctx->mode = mode;
584 ctx->connected = true;
Klement Sekeradab732a2018-07-04 13:43:46 +0200585 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
586 {
587 ctx->handle_keepalives = handle_keepalives;
588 }
589 else
590 {
591 ctx->handle_keepalives = false;
592 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200593 return VAPI_OK;
594fail:
595 vl_client_disconnect ();
596 vl_client_api_unmap ();
597 return rv;
598}
599
Ole Troan2ca88ff2022-01-27 16:25:43 +0100600/*
601 * API client running in the same process as VPP
602 */
603vapi_error_e
604vapi_connect_from_vpp (vapi_ctx_t ctx, const char *name,
605 int max_outstanding_requests, int response_queue_size,
606 vapi_mode_e mode, bool handle_keepalives)
607{
608 int rv;
609
610 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
611 {
612 return VAPI_EINVAL;
613 }
614
615 ctx->requests_size = max_outstanding_requests;
616 const size_t size = ctx->requests_size * sizeof (*ctx->requests);
617 void *tmp = realloc (ctx->requests, size);
618 if (!tmp)
619 {
620 return VAPI_ENOMEM;
621 }
622 ctx->requests = tmp;
623 clib_memset (ctx->requests, 0, size);
624 /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
625 ctx->requests_start = ctx->requests_count = 0;
626
627 VAPI_DBG ("connect client `%s'", name);
628 if (vapi_client_connect (ctx, (char *) name, 0, response_queue_size,
629 handle_keepalives) < 0)
630 {
631 return VAPI_ECON_FAIL;
632 }
633
634 int i;
635 for (i = 0; i < __vapi_metadata.count; ++i)
636 {
637 vapi_message_desc_t *m = __vapi_metadata.msgs[i];
638 u8 scratch[m->name_with_crc_len + 1];
639 memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
640 u32 id = vapi_api_get_msg_index (ctx, scratch);
641 if (VAPI_INVALID_MSG_ID != id)
642 {
643 if (id > UINT16_MAX)
644 {
645 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
646 UINT16_MAX);
647 rv = VAPI_EINVAL;
648 goto fail;
649 }
650 if (id > ctx->vl_msg_id_max)
651 {
652 vapi_msg_id_t *tmp =
653 realloc (ctx->vl_msg_id_to_vapi_msg_t,
654 sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
655 if (!tmp)
656 {
657 rv = VAPI_ENOMEM;
658 goto fail;
659 }
660 ctx->vl_msg_id_to_vapi_msg_t = tmp;
661 ctx->vl_msg_id_max = id;
662 }
663 ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
664 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
665 }
666 else
667 {
668 ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
669 VAPI_DBG ("Message `%s' not available", m->name_with_crc);
670 }
671 }
672 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
673 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
674 {
675 VAPI_ERR (
676 "control ping or control ping reply not available, cannot connect");
677 rv = VAPI_EINCOMPATIBLE;
678 goto fail;
679 }
680 ctx->mode = mode;
681 ctx->connected = true;
682 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
683 {
684 ctx->handle_keepalives = handle_keepalives;
685 }
686 else
687 {
688 ctx->handle_keepalives = false;
689 }
690 return VAPI_OK;
691fail:
692 vl_client_disconnect ();
693 return rv;
694}
695
696vapi_error_e
697vapi_disconnect_from_vpp (vapi_ctx_t ctx)
698{
699 if (!ctx->connected)
700 {
701 return VAPI_EINVAL;
702 }
703 vl_api_memclnt_delete_reply_t *rp;
704 svm_queue_t *vl_input_queue;
705 time_t begin;
706 vl_input_queue = ctx->vl_input_queue;
707 vl_client_send_disconnect (0 /* wait for reply */);
708
709 /*
710 * Have to be careful here, in case the client is disconnecting
711 * because e.g. the vlib process died, or is unresponsive.
712 */
713 begin = time (0);
714 vapi_error_e rv = VAPI_OK;
715 while (1)
716 {
717 time_t now;
718
719 now = time (0);
720
721 if (now >= (begin + 2))
722 {
723 clib_warning ("peer unresponsive, give up");
724 ctx->my_client_index = ~0;
725 rv = VAPI_ENORESP;
726 goto fail;
727 }
728 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
729 continue;
730
731 VL_MSG_API_UNPOISON (rp);
732
733 /* drain the queue */
734 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
735 {
736 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
737 vl_msg_api_free (rp);
738 continue;
739 }
740 vapi_memclnt_delete_reply_t_handler (
741 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
742 break;
743 }
744fail:
745 vapi_api_name_and_crc_free (ctx);
746
747 ctx->connected = false;
748 return rv;
749}
750
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200751vapi_error_e
752vapi_disconnect (vapi_ctx_t ctx)
753{
754 if (!ctx->connected)
755 {
756 return VAPI_EINVAL;
757 }
Ole Troan2ca88ff2022-01-27 16:25:43 +0100758
759 vl_api_memclnt_delete_reply_t *rp;
760 svm_queue_t *vl_input_queue;
761 time_t begin;
762 vl_input_queue = ctx->vl_input_queue;
763 vl_client_send_disconnect (0 /* wait for reply */);
764
765 /*
766 * Have to be careful here, in case the client is disconnecting
767 * because e.g. the vlib process died, or is unresponsive.
768 */
769 begin = time (0);
770 vapi_error_e rv = VAPI_OK;
771 while (1)
772 {
773 time_t now;
774
775 now = time (0);
776
777 if (now >= (begin + 2))
778 {
779 clib_warning ("peer unresponsive, give up");
780 ctx->my_client_index = ~0;
781 rv = VAPI_ENORESP;
782 goto fail;
783 }
784 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
785 continue;
786
787 VL_MSG_API_UNPOISON (rp);
788
789 /* drain the queue */
790 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
791 {
792 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
793 vl_msg_api_free (rp);
794 continue;
795 }
796 vapi_memclnt_delete_reply_t_handler (
797 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
798 break;
799 }
800fail:
801 vapi_api_name_and_crc_free (ctx);
802
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200803 vl_client_api_unmap ();
804#if VAPI_DEBUG_ALLOC
805 vapi_to_be_freed_validate ();
806#endif
807 ctx->connected = false;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100808 return rv;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200809}
810
811vapi_error_e
812vapi_get_fd (vapi_ctx_t ctx, int *fd)
813{
814 return VAPI_ENOTSUP;
815}
816
817vapi_error_e
818vapi_send (vapi_ctx_t ctx, void *msg)
819{
820 vapi_error_e rv = VAPI_OK;
821 if (!ctx || !msg || !ctx->connected)
822 {
823 rv = VAPI_EINVAL;
824 goto out;
825 }
826 int tmp;
Dave Barach39d69112019-11-27 11:42:13 -0500827 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200828#if VAPI_DEBUG
829 unsigned msgid = be16toh (*(u16 *) msg);
830 if (msgid <= ctx->vl_msg_id_max)
831 {
832 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
833 if (id < __vapi_metadata.count)
834 {
Klement Sekeradc15be22017-06-12 06:49:33 +0200835 VAPI_DBG ("send msg@%p:%u[%s]", msg, msgid,
836 __vapi_metadata.msgs[id]->name);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200837 }
838 else
839 {
Klement Sekeradc15be22017-06-12 06:49:33 +0200840 VAPI_DBG ("send msg@%p:%u[UNKNOWN]", msg, msgid);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200841 }
842 }
843 else
844 {
Klement Sekeradc15be22017-06-12 06:49:33 +0200845 VAPI_DBG ("send msg@%p:%u[UNKNOWN]", msg, msgid);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200846 }
847#endif
Florin Corase86a8ed2018-01-05 03:20:25 -0800848 tmp = svm_queue_add (q, (u8 *) & msg,
849 VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200850 if (tmp < 0)
851 {
852 rv = VAPI_EAGAIN;
853 }
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200854 else
855 VL_MSG_API_POISON (msg);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200856out:
857 VAPI_DBG ("vapi_send() rv = %d", rv);
858 return rv;
859}
860
861vapi_error_e
862vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
863{
864 vapi_error_e rv = VAPI_OK;
865 if (!ctx || !msg1 || !msg2 || !ctx->connected)
866 {
867 rv = VAPI_EINVAL;
868 goto out;
869 }
Dave Barach39d69112019-11-27 11:42:13 -0500870 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200871#if VAPI_DEBUG
872 unsigned msgid1 = be16toh (*(u16 *) msg1);
873 unsigned msgid2 = be16toh (*(u16 *) msg2);
874 const char *name1 = "UNKNOWN";
875 const char *name2 = "UNKNOWN";
876 if (msgid1 <= ctx->vl_msg_id_max)
877 {
878 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid1];
879 if (id < __vapi_metadata.count)
880 {
881 name1 = __vapi_metadata.msgs[id]->name;
882 }
883 }
884 if (msgid2 <= ctx->vl_msg_id_max)
885 {
886 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid2];
887 if (id < __vapi_metadata.count)
888 {
889 name2 = __vapi_metadata.msgs[id]->name;
890 }
891 }
892 VAPI_DBG ("send two: %u[%s], %u[%s]", msgid1, name1, msgid2, name2);
893#endif
Florin Corase86a8ed2018-01-05 03:20:25 -0800894 int tmp = svm_queue_add2 (q, (u8 *) & msg1, (u8 *) & msg2,
895 VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200896 if (tmp < 0)
897 {
898 rv = VAPI_EAGAIN;
899 }
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200900 else
901 VL_MSG_API_POISON (msg1);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200902out:
903 VAPI_DBG ("vapi_send() rv = %d", rv);
904 return rv;
905}
906
907vapi_error_e
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100908vapi_recv (vapi_ctx_t ctx, void **msg, size_t * msg_size,
909 svm_q_conditional_wait_t cond, u32 time)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200910{
911 if (!ctx || !ctx->connected || !msg || !msg_size)
912 {
913 return VAPI_EINVAL;
914 }
915 vapi_error_e rv = VAPI_OK;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200916 uword data;
917
Ole Troan2ca88ff2022-01-27 16:25:43 +0100918 svm_queue_t *q = ctx->vl_input_queue;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200919
Klement Sekeradab732a2018-07-04 13:43:46 +0200920again:
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200921 VAPI_DBG ("doing shm queue sub");
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100922
923 int tmp = svm_queue_sub (q, (u8 *) & data, cond, time);
924
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200925 if (tmp == 0)
926 {
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200927 VL_MSG_API_UNPOISON ((void *) data);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200928#if VAPI_DEBUG_ALLOC
929 vapi_add_to_be_freed ((void *) data);
930#endif
931 msgbuf_t *msgbuf =
932 (msgbuf_t *) ((u8 *) data - offsetof (msgbuf_t, data));
933 if (!msgbuf->data_len)
934 {
935 vapi_msg_free (ctx, (u8 *) data);
936 return VAPI_EAGAIN;
937 }
938 *msg = (u8 *) data;
939 *msg_size = ntohl (msgbuf->data_len);
Klement Sekeradc15be22017-06-12 06:49:33 +0200940#if VAPI_DEBUG
941 unsigned msgid = be16toh (*(u16 *) * msg);
942 if (msgid <= ctx->vl_msg_id_max)
943 {
944 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
945 if (id < __vapi_metadata.count)
946 {
947 VAPI_DBG ("recv msg@%p:%u[%s]", *msg, msgid,
948 __vapi_metadata.msgs[id]->name);
949 }
950 else
951 {
952 VAPI_DBG ("recv msg@%p:%u[UNKNOWN]", *msg, msgid);
953 }
954 }
955 else
956 {
957 VAPI_DBG ("recv msg@%p:%u[UNKNOWN]", *msg, msgid);
958 }
959#endif
Klement Sekeradab732a2018-07-04 13:43:46 +0200960 if (ctx->handle_keepalives)
961 {
962 unsigned msgid = be16toh (*(u16 *) * msg);
963 if (msgid ==
964 vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive))
965 {
966 vapi_msg_memclnt_keepalive_reply *reply = NULL;
967 do
968 {
969 reply = vapi_msg_alloc (ctx, sizeof (*reply));
970 }
971 while (!reply);
972 reply->header.context = vapi_get_client_index (ctx);
973 reply->header._vl_msg_id =
974 vapi_lookup_vl_msg_id (ctx,
975 vapi_msg_id_memclnt_keepalive_reply);
976 reply->payload.retval = 0;
977 vapi_msg_memclnt_keepalive_reply_hton (reply);
978 while (VAPI_EAGAIN == vapi_send (ctx, reply));
979 vapi_msg_free (ctx, *msg);
Klement Sekeradab732a2018-07-04 13:43:46 +0200980 goto again;
981 }
982 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200983 }
984 else
985 {
986 rv = VAPI_EAGAIN;
987 }
988 return rv;
989}
990
991vapi_error_e
Matthew Smith4b9935c2022-12-02 20:46:16 +0000992vapi_wait (vapi_ctx_t ctx)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200993{
Matthew Smith4b9935c2022-12-02 20:46:16 +0000994 svm_queue_lock (ctx->vl_input_queue);
995 svm_queue_wait (ctx->vl_input_queue);
996 svm_queue_unlock (ctx->vl_input_queue);
997
998 return VAPI_OK;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200999}
1000
1001static vapi_error_e
1002vapi_dispatch_response (vapi_ctx_t ctx, vapi_msg_id_t id,
1003 u32 context, void *msg)
1004{
1005 int mrv;
1006 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1007 {
1008 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1009 return VAPI_MUTEX_FAILURE;
1010 }
1011 int tmp = ctx->requests_start;
1012 const int requests_end = vapi_requests_end (ctx);
1013 while (ctx->requests[tmp].context != context && tmp != requests_end)
1014 {
1015 ++tmp;
1016 if (tmp == ctx->requests_size)
1017 {
1018 tmp = 0;
1019 }
1020 }
1021 VAPI_DBG ("dispatch, search from %d, %s at %d", ctx->requests_start,
1022 ctx->requests[tmp].context == context ? "matched" : "stopped",
1023 tmp);
1024 vapi_error_e rv = VAPI_OK;
1025 if (ctx->requests[tmp].context == context)
1026 {
1027 while (ctx->requests_start != tmp)
1028 {
1029 VAPI_ERR ("No response to req with context=%u",
1030 (unsigned) ctx->requests[tmp].context);
Klement Sekeradab732a2018-07-04 13:43:46 +02001031 ctx->requests[ctx->requests_start].callback (ctx, ctx->requests
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001032 [ctx->
1033 requests_start].callback_ctx,
1034 VAPI_ENORESP, true,
1035 NULL);
Dave Barachb7b92992018-10-17 10:38:51 -04001036 clib_memset (&ctx->requests[ctx->requests_start], 0,
1037 sizeof (ctx->requests[ctx->requests_start]));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001038 ++ctx->requests_start;
1039 --ctx->requests_count;
1040 if (ctx->requests_start == ctx->requests_size)
1041 {
1042 ctx->requests_start = 0;
1043 }
1044 }
1045 // now ctx->requests_start == tmp
1046 int payload_offset = vapi_get_payload_offset (id);
1047 void *payload = ((u8 *) msg) + payload_offset;
1048 bool is_last = true;
1049 if (ctx->requests[tmp].is_dump)
1050 {
1051 if (vapi_msg_id_control_ping_reply == id)
1052 {
1053 payload = NULL;
1054 }
1055 else
1056 {
1057 is_last = false;
1058 }
1059 }
1060 if (payload_offset != -1)
1061 {
Ole Troan2ca88ff2022-01-27 16:25:43 +01001062 rv = ctx->requests[tmp].callback (
1063 ctx, ctx->requests[tmp].callback_ctx, VAPI_OK, is_last, payload);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001064 }
1065 else
1066 {
1067 /* this is a message without payload, so bend the callback a little
1068 */
1069 rv =
1070 ((vapi_error_e (*)(vapi_ctx_t, void *, vapi_error_e, bool))
1071 ctx->requests[tmp].callback) (ctx,
1072 ctx->requests[tmp].callback_ctx,
1073 VAPI_OK, is_last);
1074 }
1075 if (is_last)
1076 {
Dave Barachb7b92992018-10-17 10:38:51 -04001077 clib_memset (&ctx->requests[ctx->requests_start], 0,
1078 sizeof (ctx->requests[ctx->requests_start]));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001079 ++ctx->requests_start;
1080 --ctx->requests_count;
1081 if (ctx->requests_start == ctx->requests_size)
1082 {
1083 ctx->requests_start = 0;
1084 }
1085 }
1086 VAPI_DBG ("after dispatch, req start = %d, end = %d, count = %d",
1087 ctx->requests_start, requests_end, ctx->requests_count);
1088 }
1089 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1090 {
1091 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1092 strerror (mrv));
1093 abort (); /* this really shouldn't happen */
1094 }
1095 return rv;
1096}
1097
1098static vapi_error_e
1099vapi_dispatch_event (vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
1100{
1101 if (ctx->event_cbs[id].cb)
1102 {
1103 return ctx->event_cbs[id].cb (ctx, ctx->event_cbs[id].ctx, msg);
1104 }
1105 else if (ctx->generic_cb.cb)
1106 {
1107 return ctx->generic_cb.cb (ctx, ctx->generic_cb.ctx, id, msg);
1108 }
1109 else
1110 {
1111 VAPI_DBG
1112 ("No handler/generic handler for msg id %u[%s], message ignored",
1113 (unsigned) id, __vapi_metadata.msgs[id]->name);
1114 }
1115 return VAPI_OK;
1116}
1117
Klement Sekeradc15be22017-06-12 06:49:33 +02001118bool
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001119vapi_msg_is_with_context (vapi_msg_id_t id)
1120{
1121 assert (id <= __vapi_metadata.count);
1122 return __vapi_metadata.msgs[id]->has_context;
1123}
1124
Klement Sekeraa25ce962021-11-15 15:52:37 +01001125static int
1126vapi_verify_msg_size (vapi_msg_id_t id, void *buf, uword buf_size)
1127{
1128 assert (id < __vapi_metadata.count);
1129 return __vapi_metadata.msgs[id]->verify_msg_size (buf, buf_size);
1130}
1131
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001132vapi_error_e
1133vapi_dispatch_one (vapi_ctx_t ctx)
1134{
1135 VAPI_DBG ("vapi_dispatch_one()");
1136 void *msg;
Klement Sekeraa25ce962021-11-15 15:52:37 +01001137 uword size;
Klement Sekera5f0106a2022-01-24 21:37:09 +00001138 svm_q_conditional_wait_t cond =
1139 vapi_is_nonblocking (ctx) ? SVM_Q_NOWAIT : SVM_Q_WAIT;
1140 vapi_error_e rv = vapi_recv (ctx, &msg, &size, cond, 0);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001141 if (VAPI_OK != rv)
1142 {
1143 VAPI_DBG ("vapi_recv failed with rv=%d", rv);
1144 return rv;
1145 }
1146 u16 vpp_id = be16toh (*(u16 *) msg);
1147 if (vpp_id > ctx->vl_msg_id_max)
1148 {
1149 VAPI_ERR ("Unknown msg ID received, id `%u', out of range <0,%u>",
1150 (unsigned) vpp_id, (unsigned) ctx->vl_msg_id_max);
1151 vapi_msg_free (ctx, msg);
1152 return VAPI_EINVAL;
1153 }
Klement Sekeradab732a2018-07-04 13:43:46 +02001154 if (VAPI_INVALID_MSG_ID == (unsigned) ctx->vl_msg_id_to_vapi_msg_t[vpp_id])
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001155 {
1156 VAPI_ERR ("Unknown msg ID received, id `%u' marked as not supported",
1157 (unsigned) vpp_id);
1158 vapi_msg_free (ctx, msg);
1159 return VAPI_EINVAL;
1160 }
1161 const vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[vpp_id];
Klement Sekeraa25ce962021-11-15 15:52:37 +01001162 if (vapi_verify_msg_size (id, msg, size))
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001163 {
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001164 vapi_msg_free (ctx, msg);
1165 return VAPI_EINVAL;
1166 }
1167 u32 context;
1168 vapi_get_swap_to_host_func (id) (msg);
1169 if (vapi_msg_is_with_context (id))
1170 {
1171 context = *(u32 *) (((u8 *) msg) + vapi_get_context_offset (id));
1172 /* is this a message originating from VAPI? */
1173 VAPI_DBG ("dispatch, context is %x", context);
1174 if (context & context_counter_mask)
1175 {
1176 rv = vapi_dispatch_response (ctx, id, context, msg);
1177 goto done;
1178 }
1179 }
1180 rv = vapi_dispatch_event (ctx, id, msg);
1181
1182done:
1183 vapi_msg_free (ctx, msg);
1184 return rv;
1185}
1186
1187vapi_error_e
1188vapi_dispatch (vapi_ctx_t ctx)
1189{
1190 vapi_error_e rv = VAPI_OK;
1191 while (!vapi_requests_empty (ctx))
1192 {
1193 rv = vapi_dispatch_one (ctx);
1194 if (VAPI_OK != rv)
1195 {
1196 return rv;
1197 }
1198 }
1199 return rv;
1200}
1201
1202void
1203vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
1204 vapi_event_cb callback, void *callback_ctx)
1205{
1206 vapi_event_cb_with_ctx *c = &ctx->event_cbs[id];
1207 c->cb = callback;
1208 c->ctx = callback_ctx;
1209}
1210
1211void
1212vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id)
1213{
1214 vapi_set_event_cb (ctx, id, NULL, NULL);
1215}
1216
1217void
1218vapi_set_generic_event_cb (vapi_ctx_t ctx, vapi_generic_event_cb callback,
1219 void *callback_ctx)
1220{
1221 ctx->generic_cb.cb = callback;
1222 ctx->generic_cb.ctx = callback_ctx;
1223}
1224
1225void
1226vapi_clear_generic_event_cb (vapi_ctx_t ctx)
1227{
1228 ctx->generic_cb.cb = NULL;
1229 ctx->generic_cb.ctx = NULL;
1230}
1231
1232u16
1233vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id)
1234{
1235 assert (id < __vapi_metadata.count);
1236 return ctx->vapi_msg_id_t_to_vl_msg_id[id];
1237}
1238
1239int
1240vapi_get_client_index (vapi_ctx_t ctx)
1241{
Ole Troan2ca88ff2022-01-27 16:25:43 +01001242 return ctx->my_client_index;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001243}
1244
1245bool
1246vapi_is_nonblocking (vapi_ctx_t ctx)
1247{
1248 return (VAPI_MODE_NONBLOCKING == ctx->mode);
1249}
1250
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001251size_t
1252vapi_get_max_request_count (vapi_ctx_t ctx)
1253{
1254 return ctx->requests_size - 1;
1255}
1256
1257int
1258vapi_get_payload_offset (vapi_msg_id_t id)
1259{
1260 assert (id < __vapi_metadata.count);
1261 return __vapi_metadata.msgs[id]->payload_offset;
1262}
1263
1264void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *msg)
1265{
1266 assert (id < __vapi_metadata.count);
1267 return __vapi_metadata.msgs[id]->swap_to_host;
1268}
1269
1270void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *msg)
1271{
1272 assert (id < __vapi_metadata.count);
1273 return __vapi_metadata.msgs[id]->swap_to_be;
1274}
1275
1276size_t
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001277vapi_get_context_offset (vapi_msg_id_t id)
1278{
1279 assert (id < __vapi_metadata.count);
1280 return __vapi_metadata.msgs[id]->context_offset;
1281}
1282
1283vapi_msg_id_t
1284vapi_register_msg (vapi_message_desc_t * msg)
1285{
1286 int i = 0;
1287 for (i = 0; i < __vapi_metadata.count; ++i)
1288 {
1289 if (!strcmp
1290 (msg->name_with_crc, __vapi_metadata.msgs[i]->name_with_crc))
1291 {
1292 /* this happens if somebody is linking together several objects while
1293 * using the static inline headers, just fill in the already
1294 * assigned id here so that all the objects are in sync */
1295 msg->id = __vapi_metadata.msgs[i]->id;
1296 return msg->id;
1297 }
1298 }
1299 vapi_msg_id_t id = __vapi_metadata.count;
1300 ++__vapi_metadata.count;
1301 __vapi_metadata.msgs =
1302 realloc (__vapi_metadata.msgs,
1303 sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
1304 __vapi_metadata.msgs[id] = msg;
1305 size_t s = strlen (msg->name_with_crc);
1306 if (s > __vapi_metadata.max_len_name_with_crc)
1307 {
1308 __vapi_metadata.max_len_name_with_crc = s;
1309 }
1310 msg->id = id;
1311 return id;
1312}
1313
1314vapi_error_e
1315vapi_producer_lock (vapi_ctx_t ctx)
1316{
1317 int mrv;
1318 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1319 {
1320 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1321 (void) mrv; /* avoid warning if the above debug is not enabled */
1322 return VAPI_MUTEX_FAILURE;
1323 }
1324 return VAPI_OK;
1325}
1326
1327vapi_error_e
1328vapi_producer_unlock (vapi_ctx_t ctx)
1329{
1330 int mrv;
1331 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1332 {
1333 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1334 strerror (mrv));
1335 (void) mrv; /* avoid warning if the above debug is not enabled */
1336 return VAPI_MUTEX_FAILURE;
1337 }
1338 return VAPI_OK;
1339}
1340
Klement Sekeradc15be22017-06-12 06:49:33 +02001341size_t
1342vapi_get_message_count ()
1343{
1344 return __vapi_metadata.count;
1345}
1346
1347const char *
1348vapi_get_msg_name (vapi_msg_id_t id)
1349{
1350 return __vapi_metadata.msgs[id]->name;
1351}
1352
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001353/*
1354 * fd.io coding-style-patch-verification: ON
1355 *
1356 * Local Variables:
1357 * eval: (c-set-style "gnu")
1358 * End:
1359 */