blob: 542df9d414b6cb664d00266a22c2ff82b72c2443 [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
104/*
105 * Satisfy external references when -lvlib is not available.
106 */
107void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...)
108{
109 clib_warning ("vlib_cli_output called...");
110}
111
112void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200113vac_free (void * msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100114{
115 vl_msg_api_free (msg);
116}
117
118static void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200119vac_api_handler (void *msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100120{
121 u16 id = ntohs(*((u16 *)msg));
Damjan Marion7cd468a2016-12-19 23:05:39 +0100122 msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
123 int l = ntohl(msgbuf->data_len);
124 if (l == 0)
125 clib_warning("Message ID %d has wrong length: %d\n", id, l);
126
127 /* Call Python callback */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200128 ASSERT(vac_callback);
129 (vac_callback)(msg, l);
130 vac_free(msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100131}
132
133static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200134vac_rx_thread_fn (void *arg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100135{
Florin Corase86a8ed2018-01-05 03:20:25 -0800136 svm_queue_t *q;
Dave Barach59b25652017-09-10 15:04:27 -0400137 vl_api_memclnt_keepalive_t *mp;
138 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200139 vac_main_t *pm = &vac_main;
Dave Barach39d69112019-11-27 11:42:13 -0500140 api_main_t *am = vlibapi_get_main();
Dave Barach59b25652017-09-10 15:04:27 -0400141 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100142 uword msg;
143
144 q = am->vl_input_queue;
145
Ole Troandfc9b7c2017-03-06 23:51:57 +0100146 while (1)
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100147 while (!svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0))
Ole Troandfc9b7c2017-03-06 23:51:57 +0100148 {
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200149 VL_MSG_API_UNPOISON((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100150 u16 id = ntohs(*((u16 *)msg));
151 switch (id) {
152 case VL_API_RX_THREAD_EXIT:
153 vl_msg_api_free((void *) msg);
154 /* signal waiting threads that this thread is about to terminate */
155 pthread_mutex_lock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200156 rx_thread_done = true;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100157 pthread_cond_signal(&pm->terminate_cv);
158 pthread_mutex_unlock(&pm->queue_lock);
159 pthread_exit(0);
160 return 0;
161 break;
162
163 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
164 vl_msg_api_free((void * )msg);
165 /* Suspend thread and signal reader */
166 pthread_mutex_lock(&pm->queue_lock);
167 pthread_cond_signal(&pm->suspend_cv);
168 /* Wait for the resume signal */
169 pthread_cond_wait (&pm->resume_cv, &pm->queue_lock);
170 pthread_mutex_unlock(&pm->queue_lock);
171 break;
172
173 case VL_API_MEMCLNT_READ_TIMEOUT:
174 clib_warning("Received read timeout in async thread\n");
175 vl_msg_api_free((void *) msg);
176 break;
177
Dave Barach59b25652017-09-10 15:04:27 -0400178 case VL_API_MEMCLNT_KEEPALIVE:
179 mp = (void *)msg;
180 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400181 clib_memset (rmp, 0, sizeof (*rmp));
Dave Barach59b25652017-09-10 15:04:27 -0400182 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
183 rmp->context = mp->context;
184 shmem_hdr = am->shmem_hdr;
185 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
186 vl_msg_api_free((void *) msg);
187 break;
188
Ole Troandfc9b7c2017-03-06 23:51:57 +0100189 default:
Damjan Marion5fec1e82017-04-13 19:13:47 +0200190 vac_api_handler((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100191 }
192 }
193}
194
195static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200196vac_timeout_thread_fn (void *arg)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100197{
198 vl_api_memclnt_read_timeout_t *ep;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200199 vac_main_t *pm = &vac_main;
Dave Barach39d69112019-11-27 11:42:13 -0500200 api_main_t *am = vlibapi_get_main();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100201 struct timespec ts;
202 struct timeval tv;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100203 int rv;
204
Neale Ranns1d652792018-07-26 08:05:53 -0700205 while (pm->timeout_loop)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100206 {
207 /* Wait for poke */
208 pthread_mutex_lock(&pm->timeout_lock);
Ole Troande728ac2018-10-08 11:24:22 +0200209 while (!timeout_in_progress)
210 pthread_cond_wait (&pm->timeout_cv, &pm->timeout_lock);
211
212 /* Starting timer */
Ole Troandfc9b7c2017-03-06 23:51:57 +0100213 gettimeofday(&tv, NULL);
Ole Troande728ac2018-10-08 11:24:22 +0200214 ts.tv_sec = tv.tv_sec + read_timeout;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100215 ts.tv_nsec = 0;
Ole Troande728ac2018-10-08 11:24:22 +0200216
217 if (!timeout_cancelled) {
218 rv = pthread_cond_timedwait (&pm->timeout_cancel_cv,
219 &pm->timeout_lock, &ts);
220 if (rv == ETIMEDOUT && !timeout_thread_cancelled) {
Ole Troandfc9b7c2017-03-06 23:51:57 +0100221 ep = vl_msg_api_alloc (sizeof (*ep));
222 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_READ_TIMEOUT);
223 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
224 }
Ole Troande728ac2018-10-08 11:24:22 +0200225 }
226
227 pthread_mutex_unlock(&pm->timeout_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100228 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100229 pthread_exit(0);
230}
231
Ole Troandfc9b7c2017-03-06 23:51:57 +0100232void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200233vac_rx_suspend (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100234{
Dave Barach39d69112019-11-27 11:42:13 -0500235 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200236 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100237 vl_api_memclnt_rx_thread_suspend_t *ep;
238
239 if (!pm->rx_thread_handle) return;
240 pthread_mutex_lock(&pm->queue_lock);
241 if (rx_is_running)
242 {
243 ep = vl_msg_api_alloc (sizeof (*ep));
244 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_RX_THREAD_SUSPEND);
245 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700246 /* Wait for RX thread to tell us it has suspended */
Ole Troandfc9b7c2017-03-06 23:51:57 +0100247 pthread_cond_wait(&pm->suspend_cv, &pm->queue_lock);
248 rx_is_running = false;
249 }
250 pthread_mutex_unlock(&pm->queue_lock);
251}
252
253void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200254vac_rx_resume (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100255{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200256 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100257 if (!pm->rx_thread_handle) return;
258 pthread_mutex_lock(&pm->queue_lock);
Ole Troanad0697a2017-03-09 21:10:45 +0100259 if (rx_is_running) goto unlock;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100260 pthread_cond_signal(&pm->resume_cv);
261 rx_is_running = true;
Ole Troanad0697a2017-03-09 21:10:45 +0100262 unlock:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100263 pthread_mutex_unlock(&pm->queue_lock);
264}
265
Ole Troan3cc49712017-03-08 12:02:24 +0100266static uword *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200267vac_msg_table_get_hash (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100268{
Dave Barach39d69112019-11-27 11:42:13 -0500269 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100270 return (am->msg_index_by_name_and_crc);
271}
272
273int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200274vac_msg_table_size(void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100275{
Dave Barach39d69112019-11-27 11:42:13 -0500276 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100277 return hash_elts(am->msg_index_by_name_and_crc);
278}
279
280int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200281vac_connect (char * name, char * chroot_prefix, vac_callback_t cb,
Ole Troanf68fccf2020-09-28 16:15:18 +0200282 int rx_qlen)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100283{
Ole Troanc5607892019-04-10 19:32:02 +0200284 rx_thread_done = false;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100285 int rv = 0;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200286 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100287
Ole Troanf68fccf2020-09-28 16:15:18 +0200288 assert (clib_mem_get_heap ());
Ole Troandfc9b7c2017-03-06 23:51:57 +0100289 init();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100290 if (chroot_prefix != NULL)
291 vl_set_memory_root_path (chroot_prefix);
292
293 if ((rv = vl_client_api_map("/vpe-api"))) {
Ondrej Fabrye29cb672018-08-16 08:36:19 +0200294 clib_warning ("vl_client_api_map returned %d", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100295 return rv;
296 }
297
Dave Barachf9526922017-01-06 16:33:06 -0500298 if (vl_client_connect(name, 0, rx_qlen) < 0) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100299 vl_client_api_unmap();
300 return (-1);
301 }
302
303 if (cb) {
304 /* Start the rx queue thread */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200305 rv = pthread_create(&pm->rx_thread_handle, NULL, vac_rx_thread_fn, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100306 if (rv) {
307 clib_warning("pthread_create returned %d", rv);
308 vl_client_api_unmap();
309 return (-1);
310 }
Damjan Marion5fec1e82017-04-13 19:13:47 +0200311 vac_callback = cb;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100312 rx_is_running = true;
313 }
314
315 /* Start read timeout thread */
316 rv = pthread_create(&pm->timeout_thread_handle, NULL,
Damjan Marion5fec1e82017-04-13 19:13:47 +0200317 vac_timeout_thread_fn, 0);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100318 if (rv) {
319 clib_warning("pthread_create returned %d", rv);
320 vl_client_api_unmap();
321 return (-1);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100322 }
323
324 pm->connected_to_vlib = 1;
325
326 return (0);
327}
Neale Rannsc16f6b32018-06-03 21:21:19 -0700328static void
329set_timeout (unsigned short timeout)
330{
331 vac_main_t *pm = &vac_main;
332 pthread_mutex_lock(&pm->timeout_lock);
333 read_timeout = timeout;
Ole Troande728ac2018-10-08 11:24:22 +0200334 timeout_in_progress = true;
335 timeout_cancelled = false;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700336 pthread_cond_signal(&pm->timeout_cv);
337 pthread_mutex_unlock(&pm->timeout_lock);
338}
339
340static void
341unset_timeout (void)
342{
343 vac_main_t *pm = &vac_main;
344 pthread_mutex_lock(&pm->timeout_lock);
Ole Troande728ac2018-10-08 11:24:22 +0200345 timeout_in_progress = false;
346 timeout_cancelled = true;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700347 pthread_cond_signal(&pm->timeout_cancel_cv);
348 pthread_mutex_unlock(&pm->timeout_lock);
349}
350
Damjan Marion7cd468a2016-12-19 23:05:39 +0100351int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200352vac_disconnect (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100353{
Dave Barach39d69112019-11-27 11:42:13 -0500354 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200355 vac_main_t *pm = &vac_main;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700356 uword junk;
Ole Troanc5607892019-04-10 19:32:02 +0200357 int rv = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100358
Ole Troandfc9b7c2017-03-06 23:51:57 +0100359 if (!pm->connected_to_vlib) return 0;
360
361 if (pm->rx_thread_handle) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100362 vl_api_rx_thread_exit_t *ep;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100363 ep = vl_msg_api_alloc (sizeof (*ep));
364 ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT);
365 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100366
367 /* wait (with timeout) until RX thread has finished */
368 struct timespec ts;
369 struct timeval tv;
370 gettimeofday(&tv, NULL);
371 ts.tv_sec = tv.tv_sec + 5;
372 ts.tv_nsec = 0;
Ole Troanc5607892019-04-10 19:32:02 +0200373
Ole Troandfc9b7c2017-03-06 23:51:57 +0100374 pthread_mutex_lock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200375 if (rx_thread_done == false)
376 rv = pthread_cond_timedwait(&pm->terminate_cv, &pm->queue_lock, &ts);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100377 pthread_mutex_unlock(&pm->queue_lock);
Ole Troanc5607892019-04-10 19:32:02 +0200378
Ole Troandfc9b7c2017-03-06 23:51:57 +0100379 /* now join so we wait until thread has -really- finished */
380 if (rv == ETIMEDOUT)
381 pthread_cancel(pm->rx_thread_handle);
382 else
383 pthread_join(pm->rx_thread_handle, (void **) &junk);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100384 }
Neale Rannsc16f6b32018-06-03 21:21:19 -0700385 if (pm->timeout_thread_handle) {
386 /* cancel, wake then join the timeout thread */
Neale Ranns1d652792018-07-26 08:05:53 -0700387 pm->timeout_loop = 0;
Ole Troan4e588aa2018-09-07 11:01:47 +0200388 timeout_thread_cancelled = true;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700389 set_timeout(0);
390 pthread_join(pm->timeout_thread_handle, (void **) &junk);
391 }
Ole Troandfc9b7c2017-03-06 23:51:57 +0100392
393 vl_client_disconnect();
394 vl_client_api_unmap();
Ole Troandf87f802020-11-18 19:17:48 +0100395 //vac_callback = 0;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100396
397 cleanup();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100398
399 return (0);
400}
401
402int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200403vac_read (char **p, int *l, u16 timeout)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100404{
Florin Corase86a8ed2018-01-05 03:20:25 -0800405 svm_queue_t *q;
Dave Barach39d69112019-11-27 11:42:13 -0500406 api_main_t *am = vlibapi_get_main();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200407 vac_main_t *pm = &vac_main;
Dave Barach59b25652017-09-10 15:04:27 -0400408 vl_api_memclnt_keepalive_t *mp;
409 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100410 uword msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100411 msgbuf_t *msgbuf;
Dave Barach59b25652017-09-10 15:04:27 -0400412 int rv;
413 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100414
Paul Vinciguerra08d82e92019-06-20 13:46:46 -0400415 /* svm_queue_sub(below) returns {-1, -2} */
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500416 if (!pm->connected_to_vlib)
417 return VAC_NOT_CONNECTED;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100418
419 *l = 0;
420
Paul Vinciguerra08d82e92019-06-20 13:46:46 -0400421 /* svm_queue_sub(below) returns {-1, -2} */
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500422 if (am->our_pid == 0)
423 return (VAC_SHM_NOT_READY);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100424
Ole Troandfc9b7c2017-03-06 23:51:57 +0100425 /* Poke timeout thread */
426 if (timeout)
427 set_timeout(timeout);
428
Damjan Marion7cd468a2016-12-19 23:05:39 +0100429 q = am->vl_input_queue;
Dave Barach59b25652017-09-10 15:04:27 -0400430
431 again:
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100432 rv = svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0);
433
Damjan Marion7cd468a2016-12-19 23:05:39 +0100434 if (rv == 0) {
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200435 VL_MSG_API_UNPOISON((void *)msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100436 u16 msg_id = ntohs(*((u16 *)msg));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100437 switch (msg_id) {
438 case VL_API_RX_THREAD_EXIT:
Ole Troan73710c72018-06-04 22:27:49 +0200439 vl_msg_api_free((void *) msg);
Ole Troande728ac2018-10-08 11:24:22 +0200440 goto error;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100441 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100442 goto error;
443 case VL_API_MEMCLNT_READ_TIMEOUT:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100444 goto error;
Dave Barach59b25652017-09-10 15:04:27 -0400445 case VL_API_MEMCLNT_KEEPALIVE:
446 /* Handle an alive-check ping from vpp. */
447 mp = (void *)msg;
448 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400449 clib_memset (rmp, 0, sizeof (*rmp));
Dave Barach59b25652017-09-10 15:04:27 -0400450 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
451 rmp->context = mp->context;
452 shmem_hdr = am->shmem_hdr;
453 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
454 vl_msg_api_free((void *) msg);
Dave Barach39d69112019-11-27 11:42:13 -0500455 /*
Dave Barach59b25652017-09-10 15:04:27 -0400456 * Python code is blissfully unaware of these pings, so
457 * act as if it never happened...
458 */
459 goto again;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100460
461 default:
462 msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
463 *l = ntohl(msgbuf->data_len);
464 if (*l == 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200465 fprintf(stderr, "Unregistered API message: %d\n", msg_id);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100466 goto error;
467 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100468 }
469 *p = (char *)msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100470
Ole Troandfc9b7c2017-03-06 23:51:57 +0100471
Damjan Marion7cd468a2016-12-19 23:05:39 +0100472 } else {
Ole Troan4e588aa2018-09-07 11:01:47 +0200473 fprintf(stderr, "Read failed with %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100474 }
Ole Troande728ac2018-10-08 11:24:22 +0200475 /* Let timeout notification thread know we're done */
476 if (timeout)
477 unset_timeout();
478
Damjan Marion7cd468a2016-12-19 23:05:39 +0100479 return (rv);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100480
481 error:
Ole Troande728ac2018-10-08 11:24:22 +0200482 if (timeout)
483 unset_timeout();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100484 vl_msg_api_free((void *) msg);
485 /* Client might forget to resume RX thread on failure */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200486 vac_rx_resume ();
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500487 return VAC_TIMEOUT;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100488}
489
490/*
491 * XXX: Makes the assumption that client_index is the first member
492 */
Ole Troan3459ece2021-09-27 17:11:34 +0200493typedef struct _vl_api_header
494{
Damjan Marion7cd468a2016-12-19 23:05:39 +0100495 u16 _vl_msg_id;
496 u32 client_index;
Ole Troan3459ece2021-09-27 17:11:34 +0200497} __attribute__ ((packed)) vl_api_header_t;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100498
Ole Troan94495f22018-08-02 11:58:12 +0200499static u32
Damjan Marion5fec1e82017-04-13 19:13:47 +0200500vac_client_index (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100501{
Dave Barach39d69112019-11-27 11:42:13 -0500502 return (vlibapi_get_main()->my_client_index);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100503}
504
505int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200506vac_write (char *p, int l)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100507{
508 int rv = -1;
Dave Barach39d69112019-11-27 11:42:13 -0500509 api_main_t *am = vlibapi_get_main();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100510 vl_api_header_t *mp = vl_msg_api_alloc(l);
Florin Corase86a8ed2018-01-05 03:20:25 -0800511 svm_queue_t *q;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200512 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100513
Paul Vinciguerrabad47662019-12-19 18:26:29 -0500514 if (!pm->connected_to_vlib)
515 return VAC_NOT_CONNECTED;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100516 if (!mp) return (-1);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100517
Damjan Marion7cd468a2016-12-19 23:05:39 +0100518 memcpy(mp, p, l);
Damjan Marion5fec1e82017-04-13 19:13:47 +0200519 mp->client_index = vac_client_index();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100520 q = am->shmem_hdr->vl_input_queue;
Florin Corase86a8ed2018-01-05 03:20:25 -0800521 rv = svm_queue_add(q, (u8 *)&mp, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100522 if (rv != 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200523 fprintf(stderr, "vpe_api_write fails: %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100524 /* Clear message */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200525 vac_free(mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100526 }
527 return (rv);
528}
529
Ole Troan3cc49712017-03-08 12:02:24 +0100530int
Ole Troandf87f802020-11-18 19:17:48 +0100531vac_get_msg_index (char * name)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100532{
Ole Troandf87f802020-11-18 19:17:48 +0100533 return vl_msg_api_get_msg_index ((u8 *)name);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100534}
Ole Troan3cc49712017-03-08 12:02:24 +0100535
536int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200537vac_msg_table_max_index(void)
Ole Troan3cc49712017-03-08 12:02:24 +0100538{
539 int max = 0;
540 hash_pair_t *hp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200541 uword *h = vac_msg_table_get_hash();
Ole Troan3cc49712017-03-08 12:02:24 +0100542 hash_foreach_pair (hp, h,
543 ({
544 if (hp->value[0] > max)
545 max = hp->value[0];
546 }));
547
548 return max;
549}
550
551void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200552vac_set_error_handler (vac_error_callback_t cb)
Ole Troan3cc49712017-03-08 12:02:24 +0100553{
Ole Troanf68fccf2020-09-28 16:15:18 +0200554 assert (clib_mem_get_heap ());
Ole Troan3cc49712017-03-08 12:02:24 +0100555 if (cb) clib_error_register_handler (cb, 0);
556}
Ole Troanf68fccf2020-09-28 16:15:18 +0200557
558/*
559 * Required if application doesn't use a VPP heap.
560 */
561void
562vac_mem_init (size_t size)
563{
Ole Troan65fa0362020-09-30 10:43:00 +0200564 if (mem_initialized)
565 return;
Ole Troanf68fccf2020-09-28 16:15:18 +0200566 if (size == 0)
567 clib_mem_init (0, 1 << 30); // default
568 else
569 clib_mem_init (0, size);
Ole Troan65fa0362020-09-30 10:43:00 +0200570 mem_initialized = true;
Ole Troanf68fccf2020-09-28 16:15:18 +0200571}