blob: 26c5708342fa4d18f7c052547a988a5d7508d9ea [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;
Stanislav Zaikin56777b92022-07-21 19:07:50 +020066 vapi_msg_id_t response_id;
67 enum vapi_request_type type;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +020068} vapi_req_t;
69
70static const u32 context_counter_mask = (1 << 31);
71
72typedef struct
73{
74 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id,
75 void *payload);
76 void *ctx;
77} vapi_generic_cb_with_ctx;
78
79typedef struct
80{
81 vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, void *payload);
82 void *ctx;
83} vapi_event_cb_with_ctx;
84
85struct vapi_ctx_s
86{
87 vapi_mode_e mode;
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 */
91 vapi_req_t *requests;
92 u32 context_counter;
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;
96 u16 vl_msg_id_max;
97 vapi_msg_id_t *vl_msg_id_to_vapi_msg_t;
98 bool connected;
Klement Sekeradab732a2018-07-04 13:43:46 +020099 bool handle_keepalives;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200100 pthread_mutex_t requests_mutex;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100101 bool use_uds;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100102
103 svm_queue_t *vl_input_queue;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100104 clib_socket_t client_socket;
105 clib_time_t time;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100106 u32 my_client_index;
107 /** client message index hash table */
108 uword *msg_index_by_name_and_crc;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200109};
110
111u32
112vapi_gen_req_context (vapi_ctx_t ctx)
113{
114 ++ctx->context_counter;
115 ctx->context_counter %= context_counter_mask;
116 return ctx->context_counter | context_counter_mask;
117}
118
119size_t
120vapi_get_request_count (vapi_ctx_t ctx)
121{
122 return ctx->requests_count;
123}
124
125bool
126vapi_requests_full (vapi_ctx_t ctx)
127{
128 return (ctx->requests_count == ctx->requests_size);
129}
130
Klement Sekeradc15be22017-06-12 06:49:33 +0200131bool
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200132vapi_requests_empty (vapi_ctx_t ctx)
133{
134 return (0 == ctx->requests_count);
135}
136
137static int
138vapi_requests_end (vapi_ctx_t ctx)
139{
140 return (ctx->requests_start + ctx->requests_count) % ctx->requests_size;
141}
142
143void
Stanislav Zaikin56777b92022-07-21 19:07:50 +0200144vapi_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,
146 void *callback_ctx)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200147{
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];
Stanislav Zaikin56777b92022-07-21 19:07:50 +0200153 slot->type = request_type;
154 slot->response_id = response_id;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200155 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));
162}
163
164#if VAPI_DEBUG_ALLOC
165struct to_be_freed_s;
166struct to_be_freed_s
167{
168 void *v;
169 struct to_be_freed_s *next;
170};
171
172static struct to_be_freed_s *to_be_freed = NULL;
173
174void
175vapi_add_to_be_freed (void *v)
176{
177 struct to_be_freed_s *prev = NULL;
178 struct to_be_freed_s *tmp;
179 tmp = to_be_freed;
180 while (tmp && tmp->v)
181 {
182 prev = tmp;
183 tmp = tmp->next;
184 }
185 if (!tmp)
186 {
187 if (!prev)
188 {
189 tmp = to_be_freed = calloc (1, sizeof (*to_be_freed));
190 }
191 else
192 {
193 tmp = prev->next = calloc (1, sizeof (*to_be_freed));
194 }
195 }
196 VAPI_DBG ("To be freed %p", v);
197 tmp->v = v;
198}
199
200void
201vapi_trace_free (void *v)
202{
203 struct to_be_freed_s *tmp = to_be_freed;
204 while (tmp && tmp->v != v)
205 {
206 tmp = tmp->next;
207 }
208 if (tmp && tmp->v == v)
209 {
210 VAPI_DBG ("Freed %p", v);
211 tmp->v = NULL;
212 }
213 else
214 {
215 VAPI_ERR ("Trying to free untracked pointer %p", v);
216 abort ();
217 }
218}
219
220void
221vapi_to_be_freed_validate ()
222{
223 struct to_be_freed_s *tmp = to_be_freed;
224 while (tmp)
225 {
226 if (tmp->v)
227 {
228 VAPI_ERR ("Unfreed msg %p!", tmp->v);
229 }
230 tmp = tmp->next;
231 }
232}
233
234#endif
235
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100236static void *
237vapi_shm_msg_alloc (vapi_ctx_t ctx, size_t size)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200238{
239 if (!ctx->connected)
240 {
241 return NULL;
242 }
Ole Troan2ca88ff2022-01-27 16:25:43 +0100243 void *rv = vl_msg_api_alloc_as_if_client_or_null (size);
Klement Sekera35418ba2020-06-09 14:17:45 +0000244 if (rv)
245 {
246 clib_memset (rv, 0, size);
247 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200248 return rv;
249}
250
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100251static void *
252vapi_sock_msg_alloc (size_t size)
253{
254 u8 *rv = 0;
255 vec_validate_init_empty (rv, size - 1, 0);
256 return rv;
257}
258
259void *
260vapi_msg_alloc (vapi_ctx_t ctx, size_t size)
261{
262 if (ctx->use_uds)
263 return vapi_sock_msg_alloc (size);
264
265 return vapi_shm_msg_alloc (ctx, size);
266}
267
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200268void
269vapi_msg_free (vapi_ctx_t ctx, void *msg)
270{
271 if (!ctx->connected)
272 {
273 return;
274 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100275
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200276#if VAPI_DEBUG_ALLOC
277 vapi_trace_free (msg);
278#endif
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100279
280 if (ctx->use_uds)
281 {
282 vec_free (msg);
283 }
284 else
285 {
286 vl_msg_api_free (msg);
287 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200288}
289
Klement Sekeradc15be22017-06-12 06:49:33 +0200290vapi_msg_id_t
291vapi_lookup_vapi_msg_id_t (vapi_ctx_t ctx, u16 vl_msg_id)
292{
293 if (vl_msg_id <= ctx->vl_msg_id_max)
294 {
295 return ctx->vl_msg_id_to_vapi_msg_t[vl_msg_id];
296 }
Klement Sekeradab732a2018-07-04 13:43:46 +0200297 return VAPI_INVALID_MSG_ID;
Klement Sekeradc15be22017-06-12 06:49:33 +0200298}
299
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200300vapi_error_e
301vapi_ctx_alloc (vapi_ctx_t * result)
302{
303 vapi_ctx_t ctx = calloc (1, sizeof (struct vapi_ctx_s));
304 if (!ctx)
305 {
306 return VAPI_ENOMEM;
307 }
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)
313 {
314 goto fail;
315 }
Dave Barachb7b92992018-10-17 10:38:51 -0400316 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));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200319 ctx->event_cbs = calloc (__vapi_metadata.count, sizeof (*ctx->event_cbs));
320 if (!ctx->event_cbs)
321 {
322 goto fail;
323 }
324 pthread_mutex_init (&ctx->requests_mutex, NULL);
325 *result = ctx;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100326 clib_time_init (&ctx->time);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200327 return VAPI_OK;
328fail:
329 vapi_ctx_free (ctx);
330 return VAPI_ENOMEM;
331}
332
333void
334vapi_ctx_free (vapi_ctx_t ctx)
335{
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);
342 free (ctx);
343}
344
345bool
346vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t id)
347{
348 return vapi_lookup_vl_msg_id (ctx, id) != UINT16_MAX;
349}
350
Ole Troan2ca88ff2022-01-27 16:25:43 +0100351/* Cut and paste to avoid adding dependency to client library */
352__clib_nosanitize_addr static void
353VL_API_VEC_UNPOISON (const void *v)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200354{
Ole Troan2ca88ff2022-01-27 16:25:43 +0100355 const vec_header_t *vh = &((vec_header_t *) v)[-1];
356 clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
357}
358
359static void
360vapi_api_name_and_crc_free (vapi_ctx_t ctx)
361{
362 int i;
363 u8 **keys = 0;
364 hash_pair_t *hp;
365
366 if (!ctx->msg_index_by_name_and_crc)
367 return;
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++)
371 vec_free (keys[i]);
372 vec_free (keys);
373 hash_free (ctx->msg_index_by_name_and_crc);
374}
375
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100376static vapi_error_e
377vapi_sock_get_errno (int err)
378{
379 switch (err)
380 {
381 case ENOTSOCK:
382 return VAPI_ENOTSOCK;
383 case EACCES:
384 return VAPI_EACCES;
385 case ECONNRESET:
386 return VAPI_ECONNRESET;
387 default:
388 break;
389 }
390 return VAPI_ESOCK_FAILURE;
391}
392
393static vapi_error_e
394vapi_sock_send (vapi_ctx_t ctx, u8 *msg)
395{
396 size_t n;
397 struct msghdr hdr;
398
399 const size_t len = vec_len (msg);
400 const size_t total_len = len + sizeof (msgbuf_t);
401
402 msgbuf_t msgbuf1 = {
403 .q = 0,
404 .gc_mark_timestamp = 0,
405 .data_len = htonl (len),
406 };
407
408 struct iovec bufs[2] = {
409 [0] = { .iov_base = &msgbuf1, .iov_len = sizeof (msgbuf1) },
410 [1] = { .iov_base = msg, .iov_len = len },
411 };
412
413 clib_memset (&hdr, 0, sizeof (hdr));
414 hdr.msg_iov = bufs;
415 hdr.msg_iovlen = 2;
416
417 n = sendmsg (ctx->client_socket.fd, &hdr, 0);
418 if (n < 0)
419 {
420 return vapi_sock_get_errno (errno);
421 }
422
423 if (n < total_len)
424 {
425 return VAPI_EAGAIN;
426 }
427
428 vec_free (msg);
429
430 return VAPI_OK;
431}
432
433static vapi_error_e
434vapi_sock_send2 (vapi_ctx_t ctx, u8 *msg1, u8 *msg2)
435{
436 size_t n;
437 struct msghdr hdr;
438
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);
442
443 msgbuf_t msgbuf1 = {
444 .q = 0,
445 .gc_mark_timestamp = 0,
446 .data_len = htonl (len1),
447 };
448
449 msgbuf_t msgbuf2 = {
450 .q = 0,
451 .gc_mark_timestamp = 0,
452 .data_len = htonl (len2),
453 };
454
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 },
460 };
461
462 clib_memset (&hdr, 0, sizeof (hdr));
463 hdr.msg_iov = bufs;
464 hdr.msg_iovlen = 4;
465
466 n = sendmsg (ctx->client_socket.fd, &hdr, 0);
467 if (n < 0)
468 {
469 return vapi_sock_get_errno (errno);
470 }
471
472 if (n < total_len)
473 {
474 return VAPI_EAGAIN;
475 }
476
477 vec_free (msg1);
478 vec_free (msg2);
479
480 return VAPI_OK;
481}
482
483static vapi_error_e
484vapi_sock_recv_internal (vapi_ctx_t ctx, u8 **vec_msg, u32 timeout)
485{
486 clib_socket_t *sock = &ctx->client_socket;
487 u32 data_len = 0, msg_size;
488 msgbuf_t *mbp = 0;
489 ssize_t n, current_rx_index;
490 f64 deadline;
491 vapi_error_e rv = VAPI_EAGAIN;
492
493 if (ctx->client_socket.fd == 0)
494 return VAPI_ENOTSOCK;
495
496 deadline = clib_time_now (&ctx->time) + timeout;
497
498 while (1)
499 {
500 current_rx_index = vec_len (sock->rx_buffer);
501 while (current_rx_index < sizeof (*mbp))
502 {
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);
506 if (n < 0)
507 {
508 if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
509 return VAPI_EAGAIN;
510
511 if (errno == EAGAIN)
512 continue;
513
514 clib_unix_warning ("socket_read");
515 vec_set_len (sock->rx_buffer, current_rx_index);
516 return vapi_sock_get_errno (errno);
517 }
518 current_rx_index += n;
519 }
520 vec_set_len (sock->rx_buffer, current_rx_index);
521
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);
528
529 while (current_rx_index < msg_size)
530 {
531 n = recv (sock->fd, sock->rx_buffer + current_rx_index,
532 msg_size - current_rx_index, MSG_DONTWAIT);
533 if (n < 0)
534 {
535 if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
536 return VAPI_EAGAIN;
537
538 if (errno == EAGAIN)
539 continue;
540
541 clib_unix_warning ("socket_read");
542 vec_set_len (sock->rx_buffer, current_rx_index);
543 return vapi_sock_get_errno (errno);
544 }
545 current_rx_index += n;
546 }
547 vec_set_len (sock->rx_buffer, current_rx_index);
548
549 if (vec_len (sock->rx_buffer) >= data_len + sizeof (*mbp))
550 {
551 if (data_len)
552 {
553 vec_add (*vec_msg, mbp->data, data_len);
554 rv = VAPI_OK;
555 }
556 else
557 {
558 *vec_msg = 0;
559 }
560
561 if (vec_len (sock->rx_buffer) == data_len + sizeof (*mbp))
562 vec_set_len (sock->rx_buffer, 0);
563 else
564 vec_delete (sock->rx_buffer, data_len + sizeof (*mbp), 0);
565 mbp = 0;
566
567 /* Quit if we're out of data, and not expecting a ping reply */
568 if (vec_len (sock->rx_buffer) == 0)
569 break;
570 }
571 }
572 return rv;
573}
574
Ole Troan2ca88ff2022-01-27 16:25:43 +0100575static void
576vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
577 vl_api_memclnt_create_v2_reply_t *mp)
578{
579 serialize_main_t _sm, *sm = &_sm;
580 u8 *tblv;
581 u32 nmsgs;
582 int i;
583 u8 *name_and_crc;
584 u32 msg_index;
585
586 ctx->my_client_index = mp->index;
587
588 /* Clean out any previous hash table (unlikely) */
589 vapi_api_name_and_crc_free (ctx);
590
591 ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
592
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));
597
598 VL_API_VEC_UNPOISON (tblv);
599
600 for (i = 0; i < nmsgs; i++)
601 {
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);
605 }
606}
607
608static void
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100609vapi_sockclnt_create_reply_t_handler (vapi_ctx_t ctx,
610 vl_api_sockclnt_create_reply_t *mp)
611{
612 int i;
613 u8 *name_and_crc;
614
615 ctx->my_client_index = mp->index;
616
617 /* Clean out any previous hash table (unlikely) */
618 vapi_api_name_and_crc_free (ctx);
619
620 ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
621
622 for (i = 0; i < be16toh (mp->count); i++)
623 {
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));
627 }
628}
629
630static void
Ole Troan2ca88ff2022-01-27 16:25:43 +0100631vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
632 vl_api_memclnt_delete_reply_t *mp)
633{
634 void *oldheap;
635 oldheap = vl_msg_push_heap ();
636 svm_queue_free (ctx->vl_input_queue);
637 vl_msg_pop_heap (oldheap);
638
639 ctx->my_client_index = ~0;
640 ctx->vl_input_queue = 0;
641}
642
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100643static void
644vapi_sockclnt_delete_reply_t_handler (vapi_ctx_t ctx,
645 vl_api_sockclnt_delete_reply_t *mp)
646{
647 ctx->my_client_index = ~0;
648 ctx->vl_input_queue = 0;
649}
650
Mauro Sardara8c626b42022-12-12 14:04:09 +0000651static int
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100652vapi_shm_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
653 int input_queue_size, bool keepalive)
Ole Troan2ca88ff2022-01-27 16:25:43 +0100654{
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;
659 int rv = 0;
660 void *oldheap;
661 api_main_t *am = vlibapi_get_main ();
662
663 shmem_hdr = am->shmem_hdr;
664
665 if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
666 {
667 clib_warning ("shmem_hdr / input queue NULL");
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100668 return VAPI_ECON_FAIL;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100669 }
670
671 clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
672 VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
673
674 oldheap = vl_msg_push_heap ();
675 vl_input_queue =
676 svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
677 vl_msg_pop_heap (oldheap);
678
679 ctx->my_client_index = ~0;
680 ctx->vl_input_queue = vl_input_queue;
681
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;
689
690 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
691
692 while (1)
693 {
694 int qstatus;
695 struct timespec ts, tsrem;
696 int i;
697
698 /* Wait up to 10 seconds */
699 for (i = 0; i < 1000; i++)
700 {
701 qstatus =
702 svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
703 if (qstatus == 0)
704 goto read_one_msg;
705 ts.tv_sec = 0;
706 ts.tv_nsec = 10000 * 1000; /* 10 ms */
707 while (nanosleep (&ts, &tsrem) < 0)
708 ts = tsrem;
709 }
710 /* Timeout... */
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100711 return VAPI_ECON_FAIL;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100712
713 read_one_msg:
714 VL_MSG_API_UNPOISON (rp);
715 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
716 {
717 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
718 continue;
719 }
720 rv = clib_net_to_host_u32 (rp->response);
721 vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
722 break;
723 }
724 return (rv);
725}
726
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100727static int
728vapi_sock_client_connect (vapi_ctx_t ctx, char *path, const char *name)
729{
730 clib_error_t *error;
731 clib_socket_t *sock;
732 vl_api_sockclnt_create_t *mp;
733 vl_api_sockclnt_create_reply_t *rp;
734 int rv = 0;
735 u8 *msg = 0;
736
737 ctx->my_client_index = ~0;
738
739 if (ctx->client_socket.fd)
740 return VAPI_EINVAL;
741
742 if (name == 0)
743 return VAPI_EINVAL;
744
745 sock = &ctx->client_socket;
746 sock->config = path ? path : API_SOCKET_FILE;
747 sock->flags = CLIB_SOCKET_F_IS_CLIENT;
748
749 if ((error = clib_socket_init (sock)))
750 {
751 clib_error_report (error);
752 return VAPI_ECON_FAIL;
753 }
754
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);
758
759 if (vapi_sock_send (ctx, (void *) mp) != VAPI_OK)
760 {
761 return VAPI_ECON_FAIL;
762 }
763
764 while (1)
765 {
766 int qstatus;
767 struct timespec ts, tsrem;
768 int i;
769
770 /* Wait up to 10 seconds */
771 for (i = 0; i < 1000; i++)
772 {
773 qstatus = vapi_sock_recv_internal (ctx, &msg, 0);
774
775 if (qstatus == 0)
776 goto read_one_msg;
777 ts.tv_sec = 0;
778 ts.tv_nsec = 10000 * 1000; /* 10 ms */
779 while (nanosleep (&ts, &tsrem) < 0)
780 ts = tsrem;
781 }
782 /* Timeout... */
783 return -1;
784
785 read_one_msg:
786 if (vec_len (msg) == 0)
787 continue;
788
789 rp = (void *) msg;
790 if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY)
791 {
792 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
793 continue;
794 }
795 rv = clib_net_to_host_u32 (rp->response);
796 vapi_sockclnt_create_reply_t_handler (ctx, rp);
797 break;
798 }
799 return (rv);
800}
801
Mauro Sardara8c626b42022-12-12 14:04:09 +0000802static void
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100803vapi_shm_client_send_disconnect (vapi_ctx_t ctx, u8 do_cleanup)
Mauro Sardara8c626b42022-12-12 14:04:09 +0000804{
805 vl_api_memclnt_delete_t *mp;
806 vl_shmem_hdr_t *shmem_hdr;
807 api_main_t *am = vlibapi_get_main ();
808
809 ASSERT (am->vlib_rp);
810 shmem_hdr = am->shmem_hdr;
811 ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
812
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;
818
819 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
820}
821
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100822static vapi_error_e
823vapi_sock_client_send_disconnect (vapi_ctx_t ctx)
824{
825 vl_api_sockclnt_delete_t *mp;
826
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;
831
832 return vapi_sock_send (ctx, (void *) mp);
833}
834
Mauro Sardara8c626b42022-12-12 14:04:09 +0000835static int
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100836vapi_shm_client_disconnect (vapi_ctx_t ctx)
Mauro Sardara8c626b42022-12-12 14:04:09 +0000837{
838 vl_api_memclnt_delete_reply_t *rp;
839 svm_queue_t *vl_input_queue;
840 time_t begin;
841 msgbuf_t *msgbuf;
842
843 vl_input_queue = ctx->vl_input_queue;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100844 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
Mauro Sardara8c626b42022-12-12 14:04:09 +0000845
846 /*
847 * Have to be careful here, in case the client is disconnecting
848 * because e.g. the vlib process died, or is unresponsive.
849 */
850 begin = time (0);
851 while (1)
852 {
853 time_t now;
854
855 now = time (0);
856
857 if (now >= (begin + 2))
858 {
859 clib_warning ("peer unresponsive, give up");
860 ctx->my_client_index = ~0;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100861 return VAPI_ENORESP;
Mauro Sardara8c626b42022-12-12 14:04:09 +0000862 }
863 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
864 continue;
865
866 VL_MSG_API_UNPOISON (rp);
867
868 /* drain the queue */
869 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
870 {
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));
874 continue;
875 }
876 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
877 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
878 break;
879 }
880
881 vapi_api_name_and_crc_free (ctx);
882 return 0;
883}
884
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100885static vapi_error_e
886vapi_sock_client_disconnect (vapi_ctx_t ctx)
887{
888 vl_api_sockclnt_delete_reply_t *rp;
889 u8 *msg = 0;
890 msgbuf_t *msgbuf;
891 int rv;
892 f64 deadline;
893
894 deadline = clib_time_now (&ctx->time) + 2;
895
896 do
897 {
898 rv = vapi_sock_client_send_disconnect (ctx);
899 }
900 while (clib_time_now (&ctx->time) < deadline && rv != VAPI_OK);
901
902 while (1)
903 {
904 if (clib_time_now (&ctx->time) >= deadline)
905 {
906 clib_warning ("peer unresponsive, give up");
907 ctx->my_client_index = ~0;
908 return VAPI_ENORESP;
909 }
910
911 if (vapi_sock_recv_internal (ctx, &msg, 0) != VAPI_OK)
912 continue;
913
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)
918 {
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));
922 continue;
923 }
924 msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
925 vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
926 break;
927 }
928
929 clib_socket_close (&ctx->client_socket);
930 vapi_api_name_and_crc_free (ctx);
931 return VAPI_OK;
932}
933
934int
935vapi_client_disconnect (vapi_ctx_t ctx)
936{
937 if (ctx->use_uds)
938 {
939 return vapi_sock_client_disconnect (ctx);
940 }
941 return vapi_shm_client_disconnect (ctx);
942}
943
Ole Troan2ca88ff2022-01-27 16:25:43 +0100944u32
945vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
946{
947 uword *p;
948
949 if (ctx->msg_index_by_name_and_crc)
950 {
951 p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
952 if (p)
953 return p[0];
954 }
955 return ~0;
956}
957
958vapi_error_e
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100959vapi_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)
Ole Troan2ca88ff2022-01-27 16:25:43 +0100962{
963 int rv;
964
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200965 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
966 {
967 return VAPI_EINVAL;
968 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100969
970 if (!clib_mem_get_per_cpu_heap () && !clib_mem_init (0, 1024L * 1024 * 32))
Klement Sekera7ff0a262018-09-03 12:35:27 +0200971 {
972 return VAPI_ENOMEM;
973 }
Ole Troan2ca88ff2022-01-27 16:25:43 +0100974
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200975 ctx->requests_size = max_outstanding_requests;
976 const size_t size = ctx->requests_size * sizeof (*ctx->requests);
977 void *tmp = realloc (ctx->requests, size);
978 if (!tmp)
979 {
980 return VAPI_ENOMEM;
981 }
982 ctx->requests = tmp;
Dave Barachb7b92992018-10-17 10:38:51 -0400983 clib_memset (ctx->requests, 0, size);
Chris Luke879ace32017-09-26 13:15:16 -0400984 /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200985 ctx->requests_start = ctx->requests_count = 0;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100986 ctx->use_uds = use_uds;
Ole Troan2ca88ff2022-01-27 16:25:43 +0100987
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100988 if (use_uds)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200989 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100990 if (vapi_sock_client_connect (ctx, (char *) path, name) < 0)
991 {
992 return VAPI_ECON_FAIL;
993 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200994 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100995 else
Klement Sekera8f2a4ea2017-05-04 06:15:18 +0200996 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +0100997 if (path)
998 {
999 VAPI_DBG ("set memory root path `%s'", path);
1000 vl_set_memory_root_path ((char *) path);
1001 }
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)
1005 {
1006 return VAPI_EMAP_FAIL;
1007 }
1008 VAPI_DBG ("connect client `%s'", name);
1009 if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1010 true) < 0)
1011 {
1012 vl_client_api_unmap ();
1013 return VAPI_ECON_FAIL;
1014 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001015#if VAPI_DEBUG_CONNECT
1016 VAPI_DBG ("start probing messages");
1017#endif
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001018 }
Ole Troan2ca88ff2022-01-27 16:25:43 +01001019
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001020 int i;
1021 for (i = 0; i < __vapi_metadata.count; ++i)
1022 {
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);
Ole Troan2ca88ff2022-01-27 16:25:43 +01001026 u32 id = vapi_api_get_msg_index (ctx, scratch);
1027
Klement Sekeradab732a2018-07-04 13:43:46 +02001028 if (VAPI_INVALID_MSG_ID != id)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001029 {
1030 if (id > UINT16_MAX)
1031 {
1032 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1033 UINT16_MAX);
1034 rv = VAPI_EINVAL;
1035 goto fail;
1036 }
1037 if (id > ctx->vl_msg_id_max)
1038 {
Ole Troan2ca88ff2022-01-27 16:25:43 +01001039 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));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001042 if (!tmp)
1043 {
1044 rv = VAPI_ENOMEM;
1045 goto fail;
1046 }
1047 ctx->vl_msg_id_to_vapi_msg_t = tmp;
1048 ctx->vl_msg_id_max = id;
1049 }
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,
1054 (unsigned) id);
1055#endif
1056 }
1057 else
1058 {
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);
1061 }
1062 }
1063#if VAPI_DEBUG_CONNECT
1064 VAPI_DBG ("finished probing messages");
1065#endif
1066 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1067 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1068 {
Ole Troan2ca88ff2022-01-27 16:25:43 +01001069 VAPI_ERR (
1070 "control ping or control ping reply not available, cannot connect");
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001071 rv = VAPI_EINCOMPATIBLE;
1072 goto fail;
1073 }
1074 ctx->mode = mode;
1075 ctx->connected = true;
Klement Sekeradab732a2018-07-04 13:43:46 +02001076 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1077 {
1078 ctx->handle_keepalives = handle_keepalives;
1079 }
1080 else
1081 {
1082 ctx->handle_keepalives = false;
1083 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001084 return VAPI_OK;
1085fail:
Mauro Sardara8c626b42022-12-12 14:04:09 +00001086 vapi_client_disconnect (ctx);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001087 vl_client_api_unmap ();
1088 return rv;
1089}
1090
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001091vapi_error_e
1092vapi_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)
1095{
1096 return vapi_connect_ex (ctx, name, chroot_prefix, max_outstanding_requests,
1097 response_queue_size, mode, handle_keepalives, false);
1098}
1099
Ole Troan2ca88ff2022-01-27 16:25:43 +01001100/*
1101 * API client running in the same process as VPP
1102 */
1103vapi_error_e
1104vapi_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)
1107{
1108 int rv;
1109
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001110 if (ctx->use_uds)
1111 {
1112 return VAPI_ENOTSUP;
1113 }
1114
Ole Troan2ca88ff2022-01-27 16:25:43 +01001115 if (response_queue_size <= 0 || max_outstanding_requests <= 0)
1116 {
1117 return VAPI_EINVAL;
1118 }
1119
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);
1123 if (!tmp)
1124 {
1125 return VAPI_ENOMEM;
1126 }
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;
1131
1132 VAPI_DBG ("connect client `%s'", name);
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001133 if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1134 handle_keepalives) < 0)
Ole Troan2ca88ff2022-01-27 16:25:43 +01001135 {
1136 return VAPI_ECON_FAIL;
1137 }
1138
1139 int i;
1140 for (i = 0; i < __vapi_metadata.count; ++i)
1141 {
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)
1147 {
1148 if (id > UINT16_MAX)
1149 {
1150 VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1151 UINT16_MAX);
1152 rv = VAPI_EINVAL;
1153 goto fail;
1154 }
1155 if (id > ctx->vl_msg_id_max)
1156 {
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));
1160 if (!tmp)
1161 {
1162 rv = VAPI_ENOMEM;
1163 goto fail;
1164 }
1165 ctx->vl_msg_id_to_vapi_msg_t = tmp;
1166 ctx->vl_msg_id_max = id;
1167 }
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;
1170 }
1171 else
1172 {
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);
1175 }
1176 }
1177 if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1178 !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1179 {
1180 VAPI_ERR (
1181 "control ping or control ping reply not available, cannot connect");
1182 rv = VAPI_EINCOMPATIBLE;
1183 goto fail;
1184 }
1185 ctx->mode = mode;
1186 ctx->connected = true;
1187 if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1188 {
1189 ctx->handle_keepalives = handle_keepalives;
1190 }
1191 else
1192 {
1193 ctx->handle_keepalives = false;
1194 }
1195 return VAPI_OK;
1196fail:
Mauro Sardara8c626b42022-12-12 14:04:09 +00001197 vapi_client_disconnect (ctx);
Ole Troan2ca88ff2022-01-27 16:25:43 +01001198 return rv;
1199}
1200
1201vapi_error_e
1202vapi_disconnect_from_vpp (vapi_ctx_t ctx)
1203{
1204 if (!ctx->connected)
1205 {
1206 return VAPI_EINVAL;
1207 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001208
1209 if (ctx->use_uds)
1210 {
1211 return VAPI_ENOTSUP;
1212 }
1213
Ole Troan2ca88ff2022-01-27 16:25:43 +01001214 vl_api_memclnt_delete_reply_t *rp;
1215 svm_queue_t *vl_input_queue;
1216 time_t begin;
1217 vl_input_queue = ctx->vl_input_queue;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001218 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
Ole Troan2ca88ff2022-01-27 16:25:43 +01001219
1220 /*
1221 * Have to be careful here, in case the client is disconnecting
1222 * because e.g. the vlib process died, or is unresponsive.
1223 */
1224 begin = time (0);
1225 vapi_error_e rv = VAPI_OK;
1226 while (1)
1227 {
1228 time_t now;
1229
1230 now = time (0);
1231
1232 if (now >= (begin + 2))
1233 {
1234 clib_warning ("peer unresponsive, give up");
1235 ctx->my_client_index = ~0;
1236 rv = VAPI_ENORESP;
1237 goto fail;
1238 }
1239 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1240 continue;
1241
1242 VL_MSG_API_UNPOISON (rp);
1243
1244 /* drain the queue */
1245 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1246 {
1247 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1248 vl_msg_api_free (rp);
1249 continue;
1250 }
1251 vapi_memclnt_delete_reply_t_handler (
1252 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1253 break;
1254 }
1255fail:
1256 vapi_api_name_and_crc_free (ctx);
1257
1258 ctx->connected = false;
1259 return rv;
1260}
1261
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001262static vapi_error_e
1263vapi_shm_disconnect (vapi_ctx_t ctx)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001264{
Ole Troan2ca88ff2022-01-27 16:25:43 +01001265 vl_api_memclnt_delete_reply_t *rp;
1266 svm_queue_t *vl_input_queue;
1267 time_t begin;
1268 vl_input_queue = ctx->vl_input_queue;
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001269 vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
Ole Troan2ca88ff2022-01-27 16:25:43 +01001270
1271 /*
1272 * Have to be careful here, in case the client is disconnecting
1273 * because e.g. the vlib process died, or is unresponsive.
1274 */
1275 begin = time (0);
1276 vapi_error_e rv = VAPI_OK;
1277 while (1)
1278 {
1279 time_t now;
1280
1281 now = time (0);
1282
1283 if (now >= (begin + 2))
1284 {
1285 clib_warning ("peer unresponsive, give up");
1286 ctx->my_client_index = ~0;
1287 rv = VAPI_ENORESP;
1288 goto fail;
1289 }
1290 if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1291 continue;
1292
1293 VL_MSG_API_UNPOISON (rp);
1294
1295 /* drain the queue */
1296 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1297 {
1298 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1299 vl_msg_api_free (rp);
1300 continue;
1301 }
1302 vapi_memclnt_delete_reply_t_handler (
1303 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1304 break;
1305 }
1306fail:
1307 vapi_api_name_and_crc_free (ctx);
1308
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001309 vl_client_api_unmap ();
1310#if VAPI_DEBUG_ALLOC
1311 vapi_to_be_freed_validate ();
1312#endif
1313 ctx->connected = false;
Ole Troan2ca88ff2022-01-27 16:25:43 +01001314 return rv;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001315}
1316
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001317static vapi_error_e
1318vapi_sock_disconnect (vapi_ctx_t ctx)
1319{
1320 vl_api_sockclnt_delete_reply_t *rp;
1321 time_t begin;
1322 u8 *msg = 0;
1323
1324 vapi_sock_client_send_disconnect (ctx);
1325
1326 begin = time (0);
1327 vapi_error_e rv = VAPI_OK;
1328 while (1)
1329 {
1330 time_t now;
1331
1332 now = time (0);
1333
1334 if (now >= (begin + 2))
1335 {
1336 clib_warning ("peer unresponsive, give up");
1337 ctx->my_client_index = ~0;
1338 rv = VAPI_ENORESP;
1339 goto fail;
1340 }
1341 if (vapi_sock_recv_internal (ctx, &msg, 0) < 0)
1342 continue;
1343
1344 if (vec_len (msg) == 0)
1345 continue;
1346
1347 rp = (void *) msg;
1348
1349 /* drain the queue */
1350 if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_DELETE_REPLY)
1351 {
1352 clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1353 continue;
1354 }
1355 vapi_sockclnt_delete_reply_t_handler (
1356 ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1357 break;
1358 }
1359fail:
1360 clib_socket_close (&ctx->client_socket);
1361 vapi_api_name_and_crc_free (ctx);
1362
1363 ctx->connected = false;
1364 return rv;
1365}
1366
1367vapi_error_e
1368vapi_disconnect (vapi_ctx_t ctx)
1369{
1370 if (!ctx->connected)
1371 {
1372 return VAPI_EINVAL;
1373 }
1374
1375 if (ctx->use_uds)
1376 {
1377 return vapi_sock_disconnect (ctx);
1378 }
1379 return vapi_shm_disconnect (ctx);
1380}
1381
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001382vapi_error_e
1383vapi_get_fd (vapi_ctx_t ctx, int *fd)
1384{
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001385 if (ctx->use_uds && fd)
1386 {
1387 *fd = ctx->client_socket.fd;
1388 return VAPI_OK;
1389 }
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001390 return VAPI_ENOTSUP;
1391}
1392
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001393#if VAPI_DEBUG
1394static void
1395vapi_debug_log (vapi_ctx_t ctx, void *msg, const char *fun)
1396{
1397 unsigned msgid = be16toh (*(u16 *) msg);
1398 if (msgid <= ctx->vl_msg_id_max)
1399 {
1400 vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
1401 if (id < __vapi_metadata.count)
1402 {
1403 VAPI_DBG ("%s msg@%p:%u[%s]", fun, msg, msgid,
1404 __vapi_metadata.msgs[id]->name);
1405 }
1406 else
1407 {
1408 VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1409 }
1410 }
1411 else
1412 {
1413 VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1414 }
1415}
1416#endif
1417
1418static vapi_error_e
1419vapi_shm_send (vapi_ctx_t ctx, void *msg)
1420{
1421 int rv = VAPI_OK;
1422 int tmp;
1423 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1424#if VAPI_DEBUG
1425 vapi_debug_log (ctx, msg, "send");
1426#endif
1427 tmp =
1428 svm_queue_add (q, (u8 *) &msg, VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
1429 if (tmp < 0)
1430 {
1431 rv = VAPI_EAGAIN;
1432 }
1433 else
1434 VL_MSG_API_POISON (msg);
1435
1436 return rv;
1437}
1438
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001439vapi_error_e
1440vapi_send (vapi_ctx_t ctx, void *msg)
1441{
1442 vapi_error_e rv = VAPI_OK;
1443 if (!ctx || !msg || !ctx->connected)
1444 {
1445 rv = VAPI_EINVAL;
1446 goto out;
1447 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001448
1449 if (ctx->use_uds)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001450 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001451 rv = vapi_sock_send (ctx, msg);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001452 }
1453 else
1454 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001455 rv = vapi_shm_send (ctx, msg);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001456 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001457
1458out:
1459 VAPI_DBG ("vapi_send() rv = %d", rv);
1460 return rv;
1461}
1462
1463static vapi_error_e
1464vapi_shm_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1465{
1466 vapi_error_e rv = VAPI_OK;
1467 svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1468#if VAPI_DEBUG
1469 vapi_debug_log (ctx, msg1, "send2");
1470 vapi_debug_log (ctx, msg2, "send2");
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001471#endif
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001472 int tmp = svm_queue_add2 (q, (u8 *) &msg1, (u8 *) &msg2,
1473 VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001474 if (tmp < 0)
1475 {
1476 rv = VAPI_EAGAIN;
1477 }
Benoît Ganne9fb6d402019-04-15 15:28:21 +02001478 else
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001479 VL_MSG_API_POISON (msg1);
1480
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001481 return rv;
1482}
1483
1484vapi_error_e
1485vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1486{
1487 vapi_error_e rv = VAPI_OK;
1488 if (!ctx || !msg1 || !msg2 || !ctx->connected)
1489 {
1490 rv = VAPI_EINVAL;
1491 goto out;
1492 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001493
1494 if (ctx->use_uds)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001495 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001496 rv = vapi_sock_send2 (ctx, msg1, msg2);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001497 }
Benoît Ganne9fb6d402019-04-15 15:28:21 +02001498 else
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001499 {
1500 rv = vapi_shm_send2 (ctx, msg1, msg2);
1501 }
1502
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001503out:
1504 VAPI_DBG ("vapi_send() rv = %d", rv);
1505 return rv;
1506}
1507
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001508static vapi_error_e
1509vapi_shm_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1510 svm_q_conditional_wait_t cond, u32 time)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001511{
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001512 vapi_error_e rv = VAPI_OK;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001513 uword data;
1514
Ole Troan2ca88ff2022-01-27 16:25:43 +01001515 svm_queue_t *q = ctx->vl_input_queue;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001516
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001517 VAPI_DBG ("doing shm queue sub");
Mohsin Kazmi3fca5672018-01-04 18:57:26 +01001518
1519 int tmp = svm_queue_sub (q, (u8 *) & data, cond, time);
1520
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001521 if (tmp != 0)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001522 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001523 return VAPI_EAGAIN;
1524 }
1525
Benoît Ganne9fb6d402019-04-15 15:28:21 +02001526 VL_MSG_API_UNPOISON ((void *) data);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001527#if VAPI_DEBUG_ALLOC
1528 vapi_add_to_be_freed ((void *) data);
1529#endif
1530 msgbuf_t *msgbuf =
1531 (msgbuf_t *) ((u8 *) data - offsetof (msgbuf_t, data));
1532 if (!msgbuf->data_len)
1533 {
1534 vapi_msg_free (ctx, (u8 *) data);
1535 return VAPI_EAGAIN;
1536 }
1537 *msg = (u8 *) data;
1538 *msg_size = ntohl (msgbuf->data_len);
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001539
Klement Sekeradc15be22017-06-12 06:49:33 +02001540#if VAPI_DEBUG
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001541 vapi_debug_log (ctx, msg, "recv");
Klement Sekeradc15be22017-06-12 06:49:33 +02001542#endif
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001543
1544 return rv;
1545}
1546
1547static vapi_error_e
1548vapi_sock_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size, u32 time)
1549{
1550 vapi_error_e rv = VAPI_OK;
1551 u8 *data = 0;
1552 if (time == 0 && ctx->mode == VAPI_MODE_BLOCKING)
1553 time = 1;
1554
1555 rv = vapi_sock_recv_internal (ctx, &data, time);
1556
1557 if (rv != VAPI_OK)
1558 {
1559 return rv;
1560 }
1561
1562 *msg = data;
1563 *msg_size = vec_len (data);
1564
1565#if VAPI_DEBUG
1566 vapi_debug_log (ctx, msg, "recv");
1567#endif
1568
1569 return rv;
1570}
1571
1572vapi_error_e
1573vapi_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1574 svm_q_conditional_wait_t cond, u32 time)
1575{
1576 if (!ctx || !ctx->connected || !msg || !msg_size)
1577 {
1578 return VAPI_EINVAL;
1579 }
1580 vapi_error_e rv = VAPI_OK;
1581
1582again:
1583 if (ctx->use_uds)
1584 {
1585 rv = vapi_sock_recv (ctx, msg, msg_size, time);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001586 }
1587 else
1588 {
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001589 rv = vapi_shm_recv (ctx, msg, msg_size, cond, time);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001590 }
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001591
1592 if (rv != VAPI_OK)
1593 return rv;
1594
1595 if (ctx->handle_keepalives)
1596 {
1597 unsigned msgid = be16toh (*(u16 *) *msg);
1598 if (msgid == vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive))
1599 {
1600 vapi_msg_memclnt_keepalive_reply *reply = NULL;
1601 do
1602 {
1603 reply = vapi_msg_alloc (ctx, sizeof (*reply));
1604 }
1605 while (!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))
1612 ;
1613 vapi_msg_free (ctx, *msg);
1614 goto again;
1615 }
1616 }
1617
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001618 return rv;
1619}
1620
1621vapi_error_e
Matthew Smith4b9935c2022-12-02 20:46:16 +00001622vapi_wait (vapi_ctx_t ctx)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001623{
Stanislav Zaikindc4d21e2024-03-06 19:48:30 +01001624 if (ctx->use_uds)
1625 return VAPI_ENOTSUP;
1626
Matthew Smith4b9935c2022-12-02 20:46:16 +00001627 svm_queue_lock (ctx->vl_input_queue);
1628 svm_queue_wait (ctx->vl_input_queue);
1629 svm_queue_unlock (ctx->vl_input_queue);
1630
1631 return VAPI_OK;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001632}
1633
1634static vapi_error_e
1635vapi_dispatch_response (vapi_ctx_t ctx, vapi_msg_id_t id,
1636 u32 context, void *msg)
1637{
1638 int mrv;
1639 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1640 {
1641 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1642 return VAPI_MUTEX_FAILURE;
1643 }
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)
1647 {
1648 ++tmp;
1649 if (tmp == ctx->requests_size)
1650 {
1651 tmp = 0;
1652 }
1653 }
1654 VAPI_DBG ("dispatch, search from %d, %s at %d", ctx->requests_start,
1655 ctx->requests[tmp].context == context ? "matched" : "stopped",
1656 tmp);
1657 vapi_error_e rv = VAPI_OK;
1658 if (ctx->requests[tmp].context == context)
1659 {
1660 while (ctx->requests_start != tmp)
1661 {
1662 VAPI_ERR ("No response to req with context=%u",
1663 (unsigned) ctx->requests[tmp].context);
Klement Sekeradab732a2018-07-04 13:43:46 +02001664 ctx->requests[ctx->requests_start].callback (ctx, ctx->requests
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001665 [ctx->
1666 requests_start].callback_ctx,
1667 VAPI_ENORESP, true,
1668 NULL);
Dave Barachb7b92992018-10-17 10:38:51 -04001669 clib_memset (&ctx->requests[ctx->requests_start], 0,
1670 sizeof (ctx->requests[ctx->requests_start]));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001671 ++ctx->requests_start;
1672 --ctx->requests_count;
1673 if (ctx->requests_start == ctx->requests_size)
1674 {
1675 ctx->requests_start = 0;
1676 }
1677 }
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;
Stanislav Zaikin56777b92022-07-21 19:07:50 +02001682 switch (ctx->requests[tmp].type)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001683 {
Stanislav Zaikin56777b92022-07-21 19:07:50 +02001684 case VAPI_REQUEST_STREAM:
1685 if (ctx->requests[tmp].response_id == id)
1686 {
1687 is_last = false;
1688 }
1689 else
1690 {
1691 VAPI_DBG ("Stream response ID doesn't match current ID, move to "
1692 "next ID");
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)
1698 {
1699 ctx->requests_start = 0;
1700 }
1701 tmp = ctx->requests_start;
1702 if (ctx->requests[tmp].context != context)
1703 {
1704 VAPI_ERR ("Unexpected context %u, expected context %u!",
1705 ctx->requests[tmp].context, context);
1706 }
1707 }
1708 break;
1709 case VAPI_REQUEST_DUMP:
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001710 if (vapi_msg_id_control_ping_reply == id)
1711 {
1712 payload = NULL;
1713 }
1714 else
1715 {
1716 is_last = false;
1717 }
Stanislav Zaikin56777b92022-07-21 19:07:50 +02001718 break;
1719 case VAPI_REQUEST_REG:
1720 break;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001721 }
1722 if (payload_offset != -1)
1723 {
Ole Troan2ca88ff2022-01-27 16:25:43 +01001724 rv = ctx->requests[tmp].callback (
1725 ctx, ctx->requests[tmp].callback_ctx, VAPI_OK, is_last, payload);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001726 }
1727 else
1728 {
1729 /* this is a message without payload, so bend the callback a little
1730 */
1731 rv =
1732 ((vapi_error_e (*)(vapi_ctx_t, void *, vapi_error_e, bool))
1733 ctx->requests[tmp].callback) (ctx,
1734 ctx->requests[tmp].callback_ctx,
1735 VAPI_OK, is_last);
1736 }
1737 if (is_last)
1738 {
Dave Barachb7b92992018-10-17 10:38:51 -04001739 clib_memset (&ctx->requests[ctx->requests_start], 0,
1740 sizeof (ctx->requests[ctx->requests_start]));
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001741 ++ctx->requests_start;
1742 --ctx->requests_count;
1743 if (ctx->requests_start == ctx->requests_size)
1744 {
1745 ctx->requests_start = 0;
1746 }
1747 }
1748 VAPI_DBG ("after dispatch, req start = %d, end = %d, count = %d",
1749 ctx->requests_start, requests_end, ctx->requests_count);
1750 }
1751 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1752 {
1753 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1754 strerror (mrv));
1755 abort (); /* this really shouldn't happen */
1756 }
1757 return rv;
1758}
1759
1760static vapi_error_e
1761vapi_dispatch_event (vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
1762{
1763 if (ctx->event_cbs[id].cb)
1764 {
1765 return ctx->event_cbs[id].cb (ctx, ctx->event_cbs[id].ctx, msg);
1766 }
1767 else if (ctx->generic_cb.cb)
1768 {
1769 return ctx->generic_cb.cb (ctx, ctx->generic_cb.ctx, id, msg);
1770 }
1771 else
1772 {
1773 VAPI_DBG
1774 ("No handler/generic handler for msg id %u[%s], message ignored",
1775 (unsigned) id, __vapi_metadata.msgs[id]->name);
1776 }
1777 return VAPI_OK;
1778}
1779
Klement Sekeradc15be22017-06-12 06:49:33 +02001780bool
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001781vapi_msg_is_with_context (vapi_msg_id_t id)
1782{
1783 assert (id <= __vapi_metadata.count);
1784 return __vapi_metadata.msgs[id]->has_context;
1785}
1786
Klement Sekeraa25ce962021-11-15 15:52:37 +01001787static int
1788vapi_verify_msg_size (vapi_msg_id_t id, void *buf, uword buf_size)
1789{
1790 assert (id < __vapi_metadata.count);
1791 return __vapi_metadata.msgs[id]->verify_msg_size (buf, buf_size);
1792}
1793
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001794vapi_error_e
Dau Do10dbb372024-06-10 19:55:19 -07001795vapi_dispatch_one_timedwait (vapi_ctx_t ctx, u32 wait_time)
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001796{
1797 VAPI_DBG ("vapi_dispatch_one()");
1798 void *msg;
Klement Sekeraa25ce962021-11-15 15:52:37 +01001799 uword size;
Klement Sekera5f0106a2022-01-24 21:37:09 +00001800 svm_q_conditional_wait_t cond =
Dau Do10dbb372024-06-10 19:55:19 -07001801 vapi_is_nonblocking (ctx) ? (wait_time ? SVM_Q_TIMEDWAIT : SVM_Q_NOWAIT) :
1802 SVM_Q_WAIT;
1803 vapi_error_e rv = vapi_recv (ctx, &msg, &size, cond, wait_time);
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001804 if (VAPI_OK != rv)
1805 {
1806 VAPI_DBG ("vapi_recv failed with rv=%d", rv);
1807 return rv;
1808 }
1809 u16 vpp_id = be16toh (*(u16 *) msg);
1810 if (vpp_id > ctx->vl_msg_id_max)
1811 {
1812 VAPI_ERR ("Unknown msg ID received, id `%u', out of range <0,%u>",
1813 (unsigned) vpp_id, (unsigned) ctx->vl_msg_id_max);
1814 vapi_msg_free (ctx, msg);
1815 return VAPI_EINVAL;
1816 }
Klement Sekeradab732a2018-07-04 13:43:46 +02001817 if (VAPI_INVALID_MSG_ID == (unsigned) ctx->vl_msg_id_to_vapi_msg_t[vpp_id])
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001818 {
1819 VAPI_ERR ("Unknown msg ID received, id `%u' marked as not supported",
1820 (unsigned) vpp_id);
1821 vapi_msg_free (ctx, msg);
1822 return VAPI_EINVAL;
1823 }
1824 const vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[vpp_id];
Sylvain Cadilhacdb8c2852023-07-26 16:16:47 +02001825 vapi_get_swap_to_host_func (id) (msg);
Klement Sekeraa25ce962021-11-15 15:52:37 +01001826 if (vapi_verify_msg_size (id, msg, size))
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001827 {
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001828 vapi_msg_free (ctx, msg);
1829 return VAPI_EINVAL;
1830 }
1831 u32 context;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001832 if (vapi_msg_is_with_context (id))
1833 {
1834 context = *(u32 *) (((u8 *) msg) + vapi_get_context_offset (id));
1835 /* is this a message originating from VAPI? */
1836 VAPI_DBG ("dispatch, context is %x", context);
1837 if (context & context_counter_mask)
1838 {
1839 rv = vapi_dispatch_response (ctx, id, context, msg);
1840 goto done;
1841 }
1842 }
1843 rv = vapi_dispatch_event (ctx, id, msg);
1844
1845done:
1846 vapi_msg_free (ctx, msg);
1847 return rv;
1848}
1849
1850vapi_error_e
Dau Do10dbb372024-06-10 19:55:19 -07001851vapi_dispatch_one (vapi_ctx_t ctx)
1852{
1853 return vapi_dispatch_one_timedwait (ctx, 0);
1854}
1855
1856vapi_error_e
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001857vapi_dispatch (vapi_ctx_t ctx)
1858{
1859 vapi_error_e rv = VAPI_OK;
1860 while (!vapi_requests_empty (ctx))
1861 {
1862 rv = vapi_dispatch_one (ctx);
1863 if (VAPI_OK != rv)
1864 {
1865 return rv;
1866 }
1867 }
1868 return rv;
1869}
1870
1871void
1872vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
1873 vapi_event_cb callback, void *callback_ctx)
1874{
1875 vapi_event_cb_with_ctx *c = &ctx->event_cbs[id];
1876 c->cb = callback;
1877 c->ctx = callback_ctx;
1878}
1879
1880void
1881vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id)
1882{
1883 vapi_set_event_cb (ctx, id, NULL, NULL);
1884}
1885
1886void
1887vapi_set_generic_event_cb (vapi_ctx_t ctx, vapi_generic_event_cb callback,
1888 void *callback_ctx)
1889{
1890 ctx->generic_cb.cb = callback;
1891 ctx->generic_cb.ctx = callback_ctx;
1892}
1893
1894void
1895vapi_clear_generic_event_cb (vapi_ctx_t ctx)
1896{
1897 ctx->generic_cb.cb = NULL;
1898 ctx->generic_cb.ctx = NULL;
1899}
1900
1901u16
1902vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id)
1903{
1904 assert (id < __vapi_metadata.count);
1905 return ctx->vapi_msg_id_t_to_vl_msg_id[id];
1906}
1907
1908int
1909vapi_get_client_index (vapi_ctx_t ctx)
1910{
Ole Troan2ca88ff2022-01-27 16:25:43 +01001911 return ctx->my_client_index;
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001912}
1913
1914bool
1915vapi_is_nonblocking (vapi_ctx_t ctx)
1916{
1917 return (VAPI_MODE_NONBLOCKING == ctx->mode);
1918}
1919
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001920size_t
1921vapi_get_max_request_count (vapi_ctx_t ctx)
1922{
1923 return ctx->requests_size - 1;
1924}
1925
1926int
1927vapi_get_payload_offset (vapi_msg_id_t id)
1928{
1929 assert (id < __vapi_metadata.count);
1930 return __vapi_metadata.msgs[id]->payload_offset;
1931}
1932
1933void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *msg)
1934{
1935 assert (id < __vapi_metadata.count);
1936 return __vapi_metadata.msgs[id]->swap_to_host;
1937}
1938
1939void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *msg)
1940{
1941 assert (id < __vapi_metadata.count);
1942 return __vapi_metadata.msgs[id]->swap_to_be;
1943}
1944
1945size_t
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02001946vapi_get_context_offset (vapi_msg_id_t id)
1947{
1948 assert (id < __vapi_metadata.count);
1949 return __vapi_metadata.msgs[id]->context_offset;
1950}
1951
1952vapi_msg_id_t
1953vapi_register_msg (vapi_message_desc_t * msg)
1954{
1955 int i = 0;
1956 for (i = 0; i < __vapi_metadata.count; ++i)
1957 {
1958 if (!strcmp
1959 (msg->name_with_crc, __vapi_metadata.msgs[i]->name_with_crc))
1960 {
1961 /* this happens if somebody is linking together several objects while
1962 * using the static inline headers, just fill in the already
1963 * assigned id here so that all the objects are in sync */
1964 msg->id = __vapi_metadata.msgs[i]->id;
1965 return msg->id;
1966 }
1967 }
1968 vapi_msg_id_t id = __vapi_metadata.count;
1969 ++__vapi_metadata.count;
1970 __vapi_metadata.msgs =
1971 realloc (__vapi_metadata.msgs,
1972 sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
1973 __vapi_metadata.msgs[id] = msg;
1974 size_t s = strlen (msg->name_with_crc);
1975 if (s > __vapi_metadata.max_len_name_with_crc)
1976 {
1977 __vapi_metadata.max_len_name_with_crc = s;
1978 }
1979 msg->id = id;
1980 return id;
1981}
1982
1983vapi_error_e
1984vapi_producer_lock (vapi_ctx_t ctx)
1985{
1986 int mrv;
1987 if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1988 {
1989 VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1990 (void) mrv; /* avoid warning if the above debug is not enabled */
1991 return VAPI_MUTEX_FAILURE;
1992 }
1993 return VAPI_OK;
1994}
1995
1996vapi_error_e
1997vapi_producer_unlock (vapi_ctx_t ctx)
1998{
1999 int mrv;
2000 if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
2001 {
2002 VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
2003 strerror (mrv));
2004 (void) mrv; /* avoid warning if the above debug is not enabled */
2005 return VAPI_MUTEX_FAILURE;
2006 }
2007 return VAPI_OK;
2008}
2009
Klement Sekeradc15be22017-06-12 06:49:33 +02002010size_t
2011vapi_get_message_count ()
2012{
2013 return __vapi_metadata.count;
2014}
2015
2016const char *
2017vapi_get_msg_name (vapi_msg_id_t id)
2018{
2019 return __vapi_metadata.msgs[id]->name;
2020}
2021
Matthew Smith57f177d2022-12-15 22:18:08 +00002022void
2023vapi_stop_rx_thread (vapi_ctx_t ctx)
2024{
2025 if (!ctx || !ctx->connected || !ctx->vl_input_queue)
2026 {
2027 return;
2028 }
2029
2030 vl_client_stop_rx_thread (ctx->vl_input_queue);
2031}
Klement Sekera8f2a4ea2017-05-04 06:15:18 +02002032/*
2033 * fd.io coding-style-patch-verification: ON
2034 *
2035 * Local Variables:
2036 * eval: (c-set-style "gnu")
2037 * End:
2038 */