blob: 7a30792402c70370dbb966aad64db0217aa909b3 [file] [log] [blame]
Damjan Marion7cd468a2016-12-19 23:05:39 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
Ole Troanf68fccf2020-09-28 16:15:18 +020015#include <assert.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010016#include <stdio.h>
17#include <stdlib.h>
18#include <stddef.h>
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/mman.h>
22#include <sys/stat.h>
23#include <netinet/in.h>
24#include <netdb.h>
25#include <signal.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010026#include <stdbool.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010027#include <vnet/vnet.h>
28#include <vlib/vlib.h>
29#include <vlib/unix/unix.h>
30#include <vlibapi/api.h>
31#include <vlibmemory/api.h>
32
Ole Troan3459ece2021-09-27 17:11:34 +020033#include <vlibmemory/memclnt.api_enum.h>
34#include <vlibmemory/memclnt.api_types.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010035
Damjan Marion5fec1e82017-04-13 19:13:47 +020036#include "vppapiclient.h"
Damjan Marion7cd468a2016-12-19 23:05:39 +010037
Ole Troande728ac2018-10-08 11:24:22 +020038bool timeout_cancelled;
39bool timeout_in_progress;
Ole Troanc5607892019-04-10 19:32:02 +020040bool rx_thread_done;
Ole Troande728ac2018-10-08 11:24:22 +020041
Ole Troandfc9b7c2017-03-06 23:51:57 +010042/*
43 * Asynchronous mode:
44 * Client registers a callback. All messages are sent to the callback.
45 * Synchronous mode:
46 * Client calls blocking read().
47 * Clients are expected to collate events on a queue.
Damjan Marion5fec1e82017-04-13 19:13:47 +020048 * vac_write() -> suspends RX thread
49 * vac_read() -> resumes RX thread
Ole Troandfc9b7c2017-03-06 23:51:57 +010050 */
51
Damjan Marion7cd468a2016-12-19 23:05:39 +010052typedef struct {
Damjan Marion7cd468a2016-12-19 23:05:39 +010053 u8 connected_to_vlib;
Damjan Marion7cd468a2016-12-19 23:05:39 +010054 pthread_t rx_thread_handle;
Ole Troandfc9b7c2017-03-06 23:51:57 +010055 pthread_t timeout_thread_handle;
56 pthread_mutex_t queue_lock;
57 pthread_cond_t suspend_cv;
58 pthread_cond_t resume_cv;
59 pthread_mutex_t timeout_lock;
Neale Ranns1d652792018-07-26 08:05:53 -070060 u8 timeout_loop;
Ole Troandfc9b7c2017-03-06 23:51:57 +010061 pthread_cond_t timeout_cv;
62 pthread_cond_t timeout_cancel_cv;
63 pthread_cond_t terminate_cv;
Damjan Marion5fec1e82017-04-13 19:13:47 +020064} vac_main_t;
Damjan Marion7cd468a2016-12-19 23:05:39 +010065
Damjan Marion5fec1e82017-04-13 19:13:47 +020066vac_main_t vac_main;
67vac_callback_t vac_callback;
Ole Troandfc9b7c2017-03-06 23:51:57 +010068u16 read_timeout = 0;
69bool rx_is_running = false;
Ole Troan4e588aa2018-09-07 11:01:47 +020070bool timeout_thread_cancelled = false;
Ole Troandfc9b7c2017-03-06 23:51:57 +010071
Ole Troan65fa0362020-09-30 10:43:00 +020072/* Only ever allocate one heap */
73bool mem_initialized = false;
74
Ole Troandfc9b7c2017-03-06 23:51:57 +010075static void
76init (void)
77{
Damjan Marion5fec1e82017-04-13 19:13:47 +020078 vac_main_t *pm = &vac_main;
Dave Barachb7b92992018-10-17 10:38:51 -040079 clib_memset(pm, 0, sizeof(*pm));
Ole Troandfc9b7c2017-03-06 23:51:57 +010080 pthread_mutex_init(&pm->queue_lock, NULL);
81 pthread_cond_init(&pm->suspend_cv, NULL);
82 pthread_cond_init(&pm->resume_cv, NULL);
83 pthread_mutex_init(&pm->timeout_lock, NULL);
Neale Ranns1d652792018-07-26 08:05:53 -070084 pm->timeout_loop = 1;
Ole Troandfc9b7c2017-03-06 23:51:57 +010085 pthread_cond_init(&pm->timeout_cv, NULL);
86 pthread_cond_init(&pm->timeout_cancel_cv, NULL);
87 pthread_cond_init(&pm->terminate_cv, NULL);
88}
89
90static void
91cleanup (void)
92{
Damjan Marion5fec1e82017-04-13 19:13:47 +020093 vac_main_t *pm = &vac_main;
Ole Troan73710c72018-06-04 22:27:49 +020094 pthread_mutex_destroy(&pm->queue_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +010095 pthread_cond_destroy(&pm->suspend_cv);
96 pthread_cond_destroy(&pm->resume_cv);
Ole Troan73710c72018-06-04 22:27:49 +020097 pthread_mutex_destroy(&pm->timeout_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +010098 pthread_cond_destroy(&pm->timeout_cv);
99 pthread_cond_destroy(&pm->timeout_cancel_cv);
100 pthread_cond_destroy(&pm->terminate_cv);
Dave Barachb7b92992018-10-17 10:38:51 -0400101 clib_memset(pm, 0, sizeof(*pm));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100102}
Damjan Marion7cd468a2016-12-19 23:05:39 +0100103
Damjan Marion7cd468a2016-12-19 23:05:39 +0100104void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200105vac_free (void * msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100106{
107 vl_msg_api_free (msg);
108}
109
110static void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200111vac_api_handler (void *msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100112{
113 u16 id = ntohs(*((u16 *)msg));
Damjan Marion7cd468a2016-12-19 23:05:39 +0100114 msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
115 int l = ntohl(msgbuf->data_len);
116 if (l == 0)
117 clib_warning("Message ID %d has wrong length: %d\n", id, l);
118
119 /* Call Python callback */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200120 ASSERT(vac_callback);
121 (vac_callback)(msg, l);
122 vac_free(msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100123}
124
125static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200126vac_rx_thread_fn (void *arg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100127{
Florin Corase86a8ed2018-01-05 03:20:25 -0800128 svm_queue_t *q;
Dave Barach59b25652017-09-10 15:04:27 -0400129 vl_api_memclnt_keepalive_t *mp;
130 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200131 vac_main_t *pm = &vac_main;
Dave Barach39d69112019-11-27 11:42:13 -0500132 api_main_t *am = vlibapi_get_main();
Dave Barach59b25652017-09-10 15:04:27 -0400133 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100134 uword msg;
135
136 q = am->vl_input_queue;
137
Ole Troandfc9b7c2017-03-06 23:51:57 +0100138 while (1)
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100139 while (!svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0))
Ole Troandfc9b7c2017-03-06 23:51:57 +0100140 {
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200141 VL_MSG_API_UNPOISON((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100142 u16 id = ntohs(*((u16 *)msg));
143 switch (id) {
144 case VL_API_RX_THREAD_EXIT:
145 vl_msg_api_free((void *) msg);
146 /* signal waiting threads that this thread is about to terminate */
147 pthread_mutex_lock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200148 rx_thread_done = true;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100149 pthread_cond_signal(&pm->terminate_cv);
150 pthread_mutex_unlock(&pm->queue_lock);
151 pthread_exit(0);
152 return 0;
153 break;
154
155 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
156 vl_msg_api_free((void * )msg);
157 /* Suspend thread and signal reader */
158 pthread_mutex_lock(&pm->queue_lock);
159 pthread_cond_signal(&pm->suspend_cv);
160 /* Wait for the resume signal */
161 pthread_cond_wait (&pm->resume_cv, &pm->queue_lock);
162 pthread_mutex_unlock(&pm->queue_lock);
163 break;
164
165 case VL_API_MEMCLNT_READ_TIMEOUT:
166 clib_warning("Received read timeout in async thread\n");
167 vl_msg_api_free((void *) msg);
168 break;
169
Dave Barach59b25652017-09-10 15:04:27 -0400170 case VL_API_MEMCLNT_KEEPALIVE:
171 mp = (void *)msg;
172 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400173 clib_memset (rmp, 0, sizeof (*rmp));
Dave Barach59b25652017-09-10 15:04:27 -0400174 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
175 rmp->context = mp->context;
176 shmem_hdr = am->shmem_hdr;
177 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
178 vl_msg_api_free((void *) msg);
179 break;
180
Ole Troandfc9b7c2017-03-06 23:51:57 +0100181 default:
Damjan Marion5fec1e82017-04-13 19:13:47 +0200182 vac_api_handler((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100183 }
184 }
185}
186
187static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200188vac_timeout_thread_fn (void *arg)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100189{
190 vl_api_memclnt_read_timeout_t *ep;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200191 vac_main_t *pm = &vac_main;
Dave Barach39d69112019-11-27 11:42:13 -0500192 api_main_t *am = vlibapi_get_main();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100193 struct timespec ts;
194 struct timeval tv;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100195 int rv;
196
Neale Ranns1d652792018-07-26 08:05:53 -0700197 while (pm->timeout_loop)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100198 {
199 /* Wait for poke */
200 pthread_mutex_lock(&pm->timeout_lock);
Ole Troande728ac2018-10-08 11:24:22 +0200201 while (!timeout_in_progress)
202 pthread_cond_wait (&pm->timeout_cv, &pm->timeout_lock);
203
204 /* Starting timer */
Ole Troandfc9b7c2017-03-06 23:51:57 +0100205 gettimeofday(&tv, NULL);
Ole Troande728ac2018-10-08 11:24:22 +0200206 ts.tv_sec = tv.tv_sec + read_timeout;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100207 ts.tv_nsec = 0;
Ole Troande728ac2018-10-08 11:24:22 +0200208
209 if (!timeout_cancelled) {
210 rv = pthread_cond_timedwait (&pm->timeout_cancel_cv,
211 &pm->timeout_lock, &ts);
212 if (rv == ETIMEDOUT && !timeout_thread_cancelled) {
Ole Troandfc9b7c2017-03-06 23:51:57 +0100213 ep = vl_msg_api_alloc (sizeof (*ep));
214 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_READ_TIMEOUT);
215 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
216 }
Ole Troande728ac2018-10-08 11:24:22 +0200217 }
218
219 pthread_mutex_unlock(&pm->timeout_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100220 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100221 pthread_exit(0);
222}
223
Ole Troandfc9b7c2017-03-06 23:51:57 +0100224void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200225vac_rx_suspend (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100226{
Dave Barach39d69112019-11-27 11:42:13 -0500227 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200228 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100229 vl_api_memclnt_rx_thread_suspend_t *ep;
230
231 if (!pm->rx_thread_handle) return;
232 pthread_mutex_lock(&pm->queue_lock);
233 if (rx_is_running)
234 {
235 ep = vl_msg_api_alloc (sizeof (*ep));
236 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_RX_THREAD_SUSPEND);
237 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700238 /* Wait for RX thread to tell us it has suspended */
Ole Troandfc9b7c2017-03-06 23:51:57 +0100239 pthread_cond_wait(&pm->suspend_cv, &pm->queue_lock);
240 rx_is_running = false;
241 }
242 pthread_mutex_unlock(&pm->queue_lock);
243}
244
245void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200246vac_rx_resume (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100247{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200248 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100249 if (!pm->rx_thread_handle) return;
250 pthread_mutex_lock(&pm->queue_lock);
Ole Troanad0697a2017-03-09 21:10:45 +0100251 if (rx_is_running) goto unlock;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100252 pthread_cond_signal(&pm->resume_cv);
253 rx_is_running = true;
Ole Troanad0697a2017-03-09 21:10:45 +0100254 unlock:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100255 pthread_mutex_unlock(&pm->queue_lock);
256}
257
Ole Troan3cc49712017-03-08 12:02:24 +0100258static uword *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200259vac_msg_table_get_hash (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100260{
Dave Barach39d69112019-11-27 11:42:13 -0500261 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100262 return (am->msg_index_by_name_and_crc);
263}
264
265int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200266vac_msg_table_size(void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100267{
Dave Barach39d69112019-11-27 11:42:13 -0500268 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100269 return hash_elts(am->msg_index_by_name_and_crc);
270}
271
272int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200273vac_connect (char * name, char * chroot_prefix, vac_callback_t cb,
Ole Troanf68fccf2020-09-28 16:15:18 +0200274 int rx_qlen)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100275{
Ole Troanc5607892019-04-10 19:32:02 +0200276 rx_thread_done = false;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100277 int rv = 0;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200278 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100279
Ole Troanf68fccf2020-09-28 16:15:18 +0200280 assert (clib_mem_get_heap ());
Ole Troandfc9b7c2017-03-06 23:51:57 +0100281 init();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100282 if (chroot_prefix != NULL)
283 vl_set_memory_root_path (chroot_prefix);
284
285 if ((rv = vl_client_api_map("/vpe-api"))) {
Ondrej Fabrye29cb672018-08-16 08:36:19 +0200286 clib_warning ("vl_client_api_map returned %d", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100287 return rv;
288 }
289
Dave Barachf9526922017-01-06 16:33:06 -0500290 if (vl_client_connect(name, 0, rx_qlen) < 0) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100291 vl_client_api_unmap();
292 return (-1);
293 }
294
295 if (cb) {
296 /* Start the rx queue thread */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200297 rv = pthread_create(&pm->rx_thread_handle, NULL, vac_rx_thread_fn, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100298 if (rv) {
299 clib_warning("pthread_create returned %d", rv);
300 vl_client_api_unmap();
301 return (-1);
302 }
Damjan Marion5fec1e82017-04-13 19:13:47 +0200303 vac_callback = cb;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100304 rx_is_running = true;
305 }
306
307 /* Start read timeout thread */
308 rv = pthread_create(&pm->timeout_thread_handle, NULL,
Damjan Marion5fec1e82017-04-13 19:13:47 +0200309 vac_timeout_thread_fn, 0);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100310 if (rv) {
311 clib_warning("pthread_create returned %d", rv);
312 vl_client_api_unmap();
313 return (-1);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100314 }
315
316 pm->connected_to_vlib = 1;
317
318 return (0);
319}
Neale Rannsc16f6b32018-06-03 21:21:19 -0700320static void
321set_timeout (unsigned short timeout)
322{
323 vac_main_t *pm = &vac_main;
324 pthread_mutex_lock(&pm->timeout_lock);
325 read_timeout = timeout;
Ole Troande728ac2018-10-08 11:24:22 +0200326 timeout_in_progress = true;
327 timeout_cancelled = false;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700328 pthread_cond_signal(&pm->timeout_cv);
329 pthread_mutex_unlock(&pm->timeout_lock);
330}
331
332static void
333unset_timeout (void)
334{
335 vac_main_t *pm = &vac_main;
336 pthread_mutex_lock(&pm->timeout_lock);
Ole Troande728ac2018-10-08 11:24:22 +0200337 timeout_in_progress = false;
338 timeout_cancelled = true;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700339 pthread_cond_signal(&pm->timeout_cancel_cv);
340 pthread_mutex_unlock(&pm->timeout_lock);
341}
342
Damjan Marion7cd468a2016-12-19 23:05:39 +0100343int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200344vac_disconnect (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100345{
Dave Barach39d69112019-11-27 11:42:13 -0500346 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200347 vac_main_t *pm = &vac_main;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700348 uword junk;
Ole Troanc5607892019-04-10 19:32:02 +0200349 int rv = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100350
Ole Troandfc9b7c2017-03-06 23:51:57 +0100351 if (!pm->connected_to_vlib) return 0;
352
353 if (pm->rx_thread_handle) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100354 vl_api_rx_thread_exit_t *ep;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100355 ep = vl_msg_api_alloc (sizeof (*ep));
356 ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT);
357 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100358
359 /* wait (with timeout) until RX thread has finished */
360 struct timespec ts;
361 struct timeval tv;
362 gettimeofday(&tv, NULL);
363 ts.tv_sec = tv.tv_sec + 5;
364 ts.tv_nsec = 0;
Ole Troanc5607892019-04-10 19:32:02 +0200365
Ole Troandfc9b7c2017-03-06 23:51:57 +0100366 pthread_mutex_lock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200367 if (rx_thread_done == false)
368 rv = pthread_cond_timedwait(&pm->terminate_cv, &pm->queue_lock, &ts);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100369 pthread_mutex_unlock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200370
Ole Troandfc9b7c2017-03-06 23:51:57 +0100371 /* now join so we wait until thread has -really- finished */
372 if (rv == ETIMEDOUT)
373 pthread_cancel(pm->rx_thread_handle);
374 else
375 pthread_join(pm->rx_thread_handle, (void **) &junk);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100376 }
Neale Rannsc16f6b32018-06-03 21:21:19 -0700377 if (pm->timeout_thread_handle) {
378 /* cancel, wake then join the timeout thread */
Neale Ranns1d652792018-07-26 08:05:53 -0700379 pm->timeout_loop = 0;
Ole Troan4e588aa2018-09-07 11:01:47 +0200380 timeout_thread_cancelled = true;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700381 set_timeout(0);
382 pthread_join(pm->timeout_thread_handle, (void **) &junk);
383 }
Ole Troandfc9b7c2017-03-06 23:51:57 +0100384
385 vl_client_disconnect();
386 vl_client_api_unmap();
Ole Troandf87f802020-11-18 19:17:48 +0100387 //vac_callback = 0;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100388
389 cleanup();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100390
391 return (0);
392}
393
394int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200395vac_read (char **p, int *l, u16 timeout)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100396{
Florin Corase86a8ed2018-01-05 03:20:25 -0800397 svm_queue_t *q;
Dave Barach39d69112019-11-27 11:42:13 -0500398 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200399 vac_main_t *pm = &vac_main;
Dave Barach59b25652017-09-10 15:04:27 -0400400 vl_api_memclnt_keepalive_t *mp;
401 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100402 uword msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100403 msgbuf_t *msgbuf;
Dave Barach59b25652017-09-10 15:04:27 -0400404 int rv;
405 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100406
Paul Vinciguerra08d82e92019-06-20 13:46:46 -0400407 /* svm_queue_sub(below) returns {-1, -2} */
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500408 if (!pm->connected_to_vlib)
409 return VAC_NOT_CONNECTED;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100410
411 *l = 0;
412
Paul Vinciguerra08d82e92019-06-20 13:46:46 -0400413 /* svm_queue_sub(below) returns {-1, -2} */
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500414 if (am->our_pid == 0)
415 return (VAC_SHM_NOT_READY);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100416
Ole Troandfc9b7c2017-03-06 23:51:57 +0100417 /* Poke timeout thread */
418 if (timeout)
419 set_timeout(timeout);
420
Damjan Marion7cd468a2016-12-19 23:05:39 +0100421 q = am->vl_input_queue;
Dave Barach59b25652017-09-10 15:04:27 -0400422
423 again:
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100424 rv = svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0);
425
Damjan Marion7cd468a2016-12-19 23:05:39 +0100426 if (rv == 0) {
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200427 VL_MSG_API_UNPOISON((void *)msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100428 u16 msg_id = ntohs(*((u16 *)msg));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100429 switch (msg_id) {
430 case VL_API_RX_THREAD_EXIT:
Ole Troan73710c72018-06-04 22:27:49 +0200431 vl_msg_api_free((void *) msg);
Ole Troande728ac2018-10-08 11:24:22 +0200432 goto error;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100433 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100434 goto error;
435 case VL_API_MEMCLNT_READ_TIMEOUT:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100436 goto error;
Dave Barach59b25652017-09-10 15:04:27 -0400437 case VL_API_MEMCLNT_KEEPALIVE:
438 /* Handle an alive-check ping from vpp. */
439 mp = (void *)msg;
440 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400441 clib_memset (rmp, 0, sizeof (*rmp));
Dave Barach59b25652017-09-10 15:04:27 -0400442 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
443 rmp->context = mp->context;
444 shmem_hdr = am->shmem_hdr;
445 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
446 vl_msg_api_free((void *) msg);
Dave Barach39d69112019-11-27 11:42:13 -0500447 /*
Dave Barach59b25652017-09-10 15:04:27 -0400448 * Python code is blissfully unaware of these pings, so
449 * act as if it never happened...
450 */
451 goto again;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100452
453 default:
454 msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
455 *l = ntohl(msgbuf->data_len);
456 if (*l == 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200457 fprintf(stderr, "Unregistered API message: %d\n", msg_id);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100458 goto error;
459 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100460 }
461 *p = (char *)msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100462
Ole Troandfc9b7c2017-03-06 23:51:57 +0100463
Damjan Marion7cd468a2016-12-19 23:05:39 +0100464 } else {
Ole Troan4e588aa2018-09-07 11:01:47 +0200465 fprintf(stderr, "Read failed with %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100466 }
Ole Troande728ac2018-10-08 11:24:22 +0200467 /* Let timeout notification thread know we're done */
468 if (timeout)
469 unset_timeout();
470
Damjan Marion7cd468a2016-12-19 23:05:39 +0100471 return (rv);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100472
473 error:
Ole Troande728ac2018-10-08 11:24:22 +0200474 if (timeout)
475 unset_timeout();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100476 vl_msg_api_free((void *) msg);
477 /* Client might forget to resume RX thread on failure */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200478 vac_rx_resume ();
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500479 return VAC_TIMEOUT;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100480}
481
482/*
483 * XXX: Makes the assumption that client_index is the first member
484 */
Ole Troan3459ece2021-09-27 17:11:34 +0200485typedef struct _vl_api_header
486{
Damjan Marion7cd468a2016-12-19 23:05:39 +0100487 u16 _vl_msg_id;
488 u32 client_index;
Ole Troan3459ece2021-09-27 17:11:34 +0200489} __attribute__ ((packed)) vl_api_header_t;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100490
Ole Troan94495f22018-08-02 11:58:12 +0200491static u32
Damjan Marion5fec1e82017-04-13 19:13:47 +0200492vac_client_index (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100493{
Dave Barach39d69112019-11-27 11:42:13 -0500494 return (vlibapi_get_main()->my_client_index);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100495}
496
497int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200498vac_write (char *p, int l)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100499{
500 int rv = -1;
Dave Barach39d69112019-11-27 11:42:13 -0500501 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100502 vl_api_header_t *mp = vl_msg_api_alloc(l);
Florin Corase86a8ed2018-01-05 03:20:25 -0800503 svm_queue_t *q;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200504 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100505
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500506 if (!pm->connected_to_vlib)
507 return VAC_NOT_CONNECTED;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100508 if (!mp) return (-1);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100509
Damjan Marion7cd468a2016-12-19 23:05:39 +0100510 memcpy(mp, p, l);
Damjan Marion5fec1e82017-04-13 19:13:47 +0200511 mp->client_index = vac_client_index();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100512 q = am->shmem_hdr->vl_input_queue;
Florin Corase86a8ed2018-01-05 03:20:25 -0800513 rv = svm_queue_add(q, (u8 *)&mp, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100514 if (rv != 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200515 fprintf(stderr, "vpe_api_write fails: %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100516 /* Clear message */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200517 vac_free(mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100518 }
519 return (rv);
520}
521
Ole Troan3cc49712017-03-08 12:02:24 +0100522int
Ole Troandf87f802020-11-18 19:17:48 +0100523vac_get_msg_index (char * name)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100524{
Ole Troandf87f802020-11-18 19:17:48 +0100525 return vl_msg_api_get_msg_index ((u8 *)name);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100526}
Ole Troan3cc49712017-03-08 12:02:24 +0100527
528int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200529vac_msg_table_max_index(void)
Ole Troan3cc49712017-03-08 12:02:24 +0100530{
531 int max = 0;
532 hash_pair_t *hp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200533 uword *h = vac_msg_table_get_hash();
Ole Troan3cc49712017-03-08 12:02:24 +0100534 hash_foreach_pair (hp, h,
535 ({
536 if (hp->value[0] > max)
537 max = hp->value[0];
538 }));
539
540 return max;
541}
542
543void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200544vac_set_error_handler (vac_error_callback_t cb)
Ole Troan3cc49712017-03-08 12:02:24 +0100545{
Ole Troanf68fccf2020-09-28 16:15:18 +0200546 assert (clib_mem_get_heap ());
Ole Troan3cc49712017-03-08 12:02:24 +0100547 if (cb) clib_error_register_handler (cb, 0);
548}
Ole Troanf68fccf2020-09-28 16:15:18 +0200549
550/*
551 * Required if application doesn't use a VPP heap.
552 */
553void
554vac_mem_init (size_t size)
555{
Ole Troan65fa0362020-09-30 10:43:00 +0200556 if (mem_initialized)
557 return;
Ole Troanf68fccf2020-09-28 16:15:18 +0200558 if (size == 0)
559 clib_mem_init (0, 1 << 30); // default
560 else
561 clib_mem_init (0, size);
Ole Troan65fa0362020-09-30 10:43:00 +0200562 mem_initialized = true;
Ole Troanf68fccf2020-09-28 16:15:18 +0200563}