blob: ab4845d5cb88fba7ff7770f739df46bc37fc9bad [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 */
15#include <stdio.h>
16#include <stdlib.h>
17#include <stddef.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <netinet/in.h>
23#include <netdb.h>
24#include <signal.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010025#include <stdbool.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010026#include <vnet/vnet.h>
27#include <vlib/vlib.h>
28#include <vlib/unix/unix.h>
29#include <vlibapi/api.h>
30#include <vlibmemory/api.h>
31
32#include <vpp/api/vpe_msg_enum.h>
33
Damjan Marion5fec1e82017-04-13 19:13:47 +020034#include "vppapiclient.h"
Damjan Marion7cd468a2016-12-19 23:05:39 +010035
Ole Troandfc9b7c2017-03-06 23:51:57 +010036/*
37 * Asynchronous mode:
38 * Client registers a callback. All messages are sent to the callback.
39 * Synchronous mode:
40 * Client calls blocking read().
41 * Clients are expected to collate events on a queue.
Damjan Marion5fec1e82017-04-13 19:13:47 +020042 * vac_write() -> suspends RX thread
43 * vac_read() -> resumes RX thread
Ole Troandfc9b7c2017-03-06 23:51:57 +010044 */
45
Damjan Marion7cd468a2016-12-19 23:05:39 +010046#define vl_typedefs /* define message structures */
47#include <vpp/api/vpe_all_api_h.h>
48#undef vl_typedefs
49
50#define vl_endianfun /* define message structures */
51#include <vpp/api/vpe_all_api_h.h>
52#undef vl_endianfun
53
54vlib_main_t vlib_global_main;
55vlib_main_t **vlib_mains;
56
57typedef struct {
Damjan Marion7cd468a2016-12-19 23:05:39 +010058 u8 connected_to_vlib;
Damjan Marion7cd468a2016-12-19 23:05:39 +010059 pthread_t rx_thread_handle;
Ole Troandfc9b7c2017-03-06 23:51:57 +010060 pthread_t timeout_thread_handle;
61 pthread_mutex_t queue_lock;
62 pthread_cond_t suspend_cv;
63 pthread_cond_t resume_cv;
64 pthread_mutex_t timeout_lock;
Neale Ranns1d652792018-07-26 08:05:53 -070065 u8 timeout_loop;
Ole Troandfc9b7c2017-03-06 23:51:57 +010066 pthread_cond_t timeout_cv;
67 pthread_cond_t timeout_cancel_cv;
68 pthread_cond_t terminate_cv;
Damjan Marion5fec1e82017-04-13 19:13:47 +020069} vac_main_t;
Damjan Marion7cd468a2016-12-19 23:05:39 +010070
Damjan Marion5fec1e82017-04-13 19:13:47 +020071vac_main_t vac_main;
72vac_callback_t vac_callback;
Ole Troandfc9b7c2017-03-06 23:51:57 +010073u16 read_timeout = 0;
74bool rx_is_running = false;
75
Ole Troan73710c72018-06-04 22:27:49 +020076/* Set to true to enable memory tracing */
77bool mem_trace = false;
78
79__attribute__((constructor))
80static void
81vac_client_constructor (void)
82{
Ole Troan73710c72018-06-04 22:27:49 +020083 clib_mem_init (0, 1 << 30);
Dave Barach6a5adc32018-07-04 10:56:23 -040084#if USE_DLMALLOC == 0
85 {
86 u8 *heap;
87 mheap_t *h;
88
89 heap = clib_mem_get_per_cpu_heap ();
90 h = mheap_header (heap);
91 /* make the main heap thread-safe */
92 h->flags |= MHEAP_FLAG_THREAD_SAFE;
93 }
94#endif
Ole Troan73710c72018-06-04 22:27:49 +020095 if (mem_trace)
96 clib_mem_trace (1);
97}
98
99__attribute__((destructor))
100static void
101vac_client_destructor (void)
102{
103 if (mem_trace)
104 fformat(stderr, "TRACE: %s",
105 format (0, "%U\n",
106 format_mheap, clib_mem_get_heap (), 1));
107}
108
109
Ole Troandfc9b7c2017-03-06 23:51:57 +0100110static void
111init (void)
112{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200113 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100114 memset(pm, 0, sizeof(*pm));
115 pthread_mutex_init(&pm->queue_lock, NULL);
116 pthread_cond_init(&pm->suspend_cv, NULL);
117 pthread_cond_init(&pm->resume_cv, NULL);
118 pthread_mutex_init(&pm->timeout_lock, NULL);
Neale Ranns1d652792018-07-26 08:05:53 -0700119 pm->timeout_loop = 1;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100120 pthread_cond_init(&pm->timeout_cv, NULL);
121 pthread_cond_init(&pm->timeout_cancel_cv, NULL);
122 pthread_cond_init(&pm->terminate_cv, NULL);
123}
124
125static void
126cleanup (void)
127{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200128 vac_main_t *pm = &vac_main;
Ole Troan73710c72018-06-04 22:27:49 +0200129 pthread_mutex_destroy(&pm->queue_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100130 pthread_cond_destroy(&pm->suspend_cv);
131 pthread_cond_destroy(&pm->resume_cv);
Ole Troan73710c72018-06-04 22:27:49 +0200132 pthread_mutex_destroy(&pm->timeout_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100133 pthread_cond_destroy(&pm->timeout_cv);
134 pthread_cond_destroy(&pm->timeout_cancel_cv);
135 pthread_cond_destroy(&pm->terminate_cv);
Ole Troan73710c72018-06-04 22:27:49 +0200136 memset(pm, 0, sizeof(*pm));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100137}
Damjan Marion7cd468a2016-12-19 23:05:39 +0100138
139/*
140 * Satisfy external references when -lvlib is not available.
141 */
142void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...)
143{
144 clib_warning ("vlib_cli_output called...");
145}
146
147void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200148vac_free (void * msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100149{
150 vl_msg_api_free (msg);
151}
152
153static void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200154vac_api_handler (void *msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100155{
156 u16 id = ntohs(*((u16 *)msg));
Damjan Marion7cd468a2016-12-19 23:05:39 +0100157 msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
158 int l = ntohl(msgbuf->data_len);
159 if (l == 0)
160 clib_warning("Message ID %d has wrong length: %d\n", id, l);
161
162 /* Call Python callback */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200163 ASSERT(vac_callback);
164 (vac_callback)(msg, l);
165 vac_free(msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100166}
167
168static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200169vac_rx_thread_fn (void *arg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100170{
Florin Corase86a8ed2018-01-05 03:20:25 -0800171 svm_queue_t *q;
Dave Barach59b25652017-09-10 15:04:27 -0400172 vl_api_memclnt_keepalive_t *mp;
173 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200174 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100175 api_main_t *am = &api_main;
Dave Barach59b25652017-09-10 15:04:27 -0400176 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100177 uword msg;
178
179 q = am->vl_input_queue;
180
Ole Troandfc9b7c2017-03-06 23:51:57 +0100181 while (1)
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100182 while (!svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0))
Ole Troandfc9b7c2017-03-06 23:51:57 +0100183 {
184 u16 id = ntohs(*((u16 *)msg));
185 switch (id) {
186 case VL_API_RX_THREAD_EXIT:
187 vl_msg_api_free((void *) msg);
188 /* signal waiting threads that this thread is about to terminate */
189 pthread_mutex_lock(&pm->queue_lock);
190 pthread_cond_signal(&pm->terminate_cv);
191 pthread_mutex_unlock(&pm->queue_lock);
192 pthread_exit(0);
193 return 0;
194 break;
195
196 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
197 vl_msg_api_free((void * )msg);
198 /* Suspend thread and signal reader */
199 pthread_mutex_lock(&pm->queue_lock);
200 pthread_cond_signal(&pm->suspend_cv);
201 /* Wait for the resume signal */
202 pthread_cond_wait (&pm->resume_cv, &pm->queue_lock);
203 pthread_mutex_unlock(&pm->queue_lock);
204 break;
205
206 case VL_API_MEMCLNT_READ_TIMEOUT:
207 clib_warning("Received read timeout in async thread\n");
208 vl_msg_api_free((void *) msg);
209 break;
210
Dave Barach59b25652017-09-10 15:04:27 -0400211 case VL_API_MEMCLNT_KEEPALIVE:
212 mp = (void *)msg;
213 rmp = vl_msg_api_alloc (sizeof (*rmp));
214 memset (rmp, 0, sizeof (*rmp));
215 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
216 rmp->context = mp->context;
217 shmem_hdr = am->shmem_hdr;
218 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
219 vl_msg_api_free((void *) msg);
220 break;
221
Ole Troandfc9b7c2017-03-06 23:51:57 +0100222 default:
Damjan Marion5fec1e82017-04-13 19:13:47 +0200223 vac_api_handler((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100224 }
225 }
226}
227
228static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200229vac_timeout_thread_fn (void *arg)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100230{
231 vl_api_memclnt_read_timeout_t *ep;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200232 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100233 api_main_t *am = &api_main;
234 struct timespec ts;
235 struct timeval tv;
236 u16 timeout;
237 int rv;
238
Neale Ranns1d652792018-07-26 08:05:53 -0700239 while (pm->timeout_loop)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100240 {
241 /* Wait for poke */
242 pthread_mutex_lock(&pm->timeout_lock);
243 pthread_cond_wait (&pm->timeout_cv, &pm->timeout_lock);
244 timeout = read_timeout;
245 gettimeofday(&tv, NULL);
246 ts.tv_sec = tv.tv_sec + timeout;
247 ts.tv_nsec = 0;
248 rv = pthread_cond_timedwait (&pm->timeout_cancel_cv,
249 &pm->timeout_lock, &ts);
250 pthread_mutex_unlock(&pm->timeout_lock);
251 if (rv == ETIMEDOUT)
252 {
253 ep = vl_msg_api_alloc (sizeof (*ep));
254 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_READ_TIMEOUT);
255 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
256 }
257 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100258 pthread_exit(0);
259}
260
Ole Troandfc9b7c2017-03-06 23:51:57 +0100261void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200262vac_rx_suspend (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100263{
264 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200265 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100266 vl_api_memclnt_rx_thread_suspend_t *ep;
267
268 if (!pm->rx_thread_handle) return;
269 pthread_mutex_lock(&pm->queue_lock);
270 if (rx_is_running)
271 {
272 ep = vl_msg_api_alloc (sizeof (*ep));
273 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_RX_THREAD_SUSPEND);
274 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
275 /* Wait for RX thread to tell us it has suspendend */
276 pthread_cond_wait(&pm->suspend_cv, &pm->queue_lock);
277 rx_is_running = false;
278 }
279 pthread_mutex_unlock(&pm->queue_lock);
280}
281
282void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200283vac_rx_resume (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100284{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200285 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100286 if (!pm->rx_thread_handle) return;
287 pthread_mutex_lock(&pm->queue_lock);
Ole Troanad0697a2017-03-09 21:10:45 +0100288 if (rx_is_running) goto unlock;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100289 pthread_cond_signal(&pm->resume_cv);
290 rx_is_running = true;
Ole Troanad0697a2017-03-09 21:10:45 +0100291 unlock:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100292 pthread_mutex_unlock(&pm->queue_lock);
293}
294
Ole Troan3cc49712017-03-08 12:02:24 +0100295static uword *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200296vac_msg_table_get_hash (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100297{
298 api_main_t *am = &api_main;
299 return (am->msg_index_by_name_and_crc);
300}
301
302int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200303vac_msg_table_size(void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100304{
305 api_main_t *am = &api_main;
306 return hash_elts(am->msg_index_by_name_and_crc);
307}
308
309int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200310vac_connect (char * name, char * chroot_prefix, vac_callback_t cb,
Dave Barachf9526922017-01-06 16:33:06 -0500311 int rx_qlen)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100312{
313 int rv = 0;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200314 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100315
Ole Troandfc9b7c2017-03-06 23:51:57 +0100316 init();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100317 if (chroot_prefix != NULL)
318 vl_set_memory_root_path (chroot_prefix);
319
320 if ((rv = vl_client_api_map("/vpe-api"))) {
Ondrej Fabrye29cb672018-08-16 08:36:19 +0200321 clib_warning ("vl_client_api_map returned %d", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100322 return rv;
323 }
324
Dave Barachf9526922017-01-06 16:33:06 -0500325 if (vl_client_connect(name, 0, rx_qlen) < 0) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100326 vl_client_api_unmap();
327 return (-1);
328 }
329
330 if (cb) {
331 /* Start the rx queue thread */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200332 rv = pthread_create(&pm->rx_thread_handle, NULL, vac_rx_thread_fn, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100333 if (rv) {
334 clib_warning("pthread_create returned %d", rv);
335 vl_client_api_unmap();
336 return (-1);
337 }
Damjan Marion5fec1e82017-04-13 19:13:47 +0200338 vac_callback = cb;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100339 rx_is_running = true;
340 }
341
342 /* Start read timeout thread */
343 rv = pthread_create(&pm->timeout_thread_handle, NULL,
Damjan Marion5fec1e82017-04-13 19:13:47 +0200344 vac_timeout_thread_fn, 0);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100345 if (rv) {
346 clib_warning("pthread_create returned %d", rv);
347 vl_client_api_unmap();
348 return (-1);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100349 }
350
351 pm->connected_to_vlib = 1;
352
353 return (0);
354}
355
Neale Rannsc16f6b32018-06-03 21:21:19 -0700356static void
357set_timeout (unsigned short timeout)
358{
359 vac_main_t *pm = &vac_main;
360 pthread_mutex_lock(&pm->timeout_lock);
361 read_timeout = timeout;
362 pthread_cond_signal(&pm->timeout_cv);
363 pthread_mutex_unlock(&pm->timeout_lock);
364}
365
366static void
367unset_timeout (void)
368{
369 vac_main_t *pm = &vac_main;
370 pthread_mutex_lock(&pm->timeout_lock);
371 pthread_cond_signal(&pm->timeout_cancel_cv);
372 pthread_mutex_unlock(&pm->timeout_lock);
373}
374
Damjan Marion7cd468a2016-12-19 23:05:39 +0100375int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200376vac_disconnect (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100377{
378 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200379 vac_main_t *pm = &vac_main;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700380 uword junk;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100381
Ole Troandfc9b7c2017-03-06 23:51:57 +0100382 if (!pm->connected_to_vlib) return 0;
383
384 if (pm->rx_thread_handle) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100385 vl_api_rx_thread_exit_t *ep;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100386 ep = vl_msg_api_alloc (sizeof (*ep));
387 ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT);
388 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100389
390 /* wait (with timeout) until RX thread has finished */
391 struct timespec ts;
392 struct timeval tv;
393 gettimeofday(&tv, NULL);
394 ts.tv_sec = tv.tv_sec + 5;
395 ts.tv_nsec = 0;
396 pthread_mutex_lock(&pm->queue_lock);
397 int rv = pthread_cond_timedwait(&pm->terminate_cv, &pm->queue_lock, &ts);
398 pthread_mutex_unlock(&pm->queue_lock);
399 /* now join so we wait until thread has -really- finished */
400 if (rv == ETIMEDOUT)
401 pthread_cancel(pm->rx_thread_handle);
402 else
403 pthread_join(pm->rx_thread_handle, (void **) &junk);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100404 }
Neale Rannsc16f6b32018-06-03 21:21:19 -0700405 if (pm->timeout_thread_handle) {
406 /* cancel, wake then join the timeout thread */
Ondrej Fabrye29cb672018-08-16 08:36:19 +0200407 clib_warning("vac_disconnect cancel");
Neale Ranns1d652792018-07-26 08:05:53 -0700408 pm->timeout_loop = 0;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700409 set_timeout(0);
410 pthread_join(pm->timeout_thread_handle, (void **) &junk);
411 }
Ole Troandfc9b7c2017-03-06 23:51:57 +0100412
413 vl_client_disconnect();
414 vl_client_api_unmap();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200415 vac_callback = 0;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100416
417 cleanup();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100418
419 return (0);
420}
421
422int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200423vac_read (char **p, int *l, u16 timeout)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100424{
Florin Corase86a8ed2018-01-05 03:20:25 -0800425 svm_queue_t *q;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100426 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200427 vac_main_t *pm = &vac_main;
Dave Barach59b25652017-09-10 15:04:27 -0400428 vl_api_memclnt_keepalive_t *mp;
429 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100430 uword msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100431 msgbuf_t *msgbuf;
Dave Barach59b25652017-09-10 15:04:27 -0400432 int rv;
433 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100434
435 if (!pm->connected_to_vlib) return -1;
436
437 *l = 0;
438
439 if (am->our_pid == 0) return (-1);
440
Ole Troandfc9b7c2017-03-06 23:51:57 +0100441 /* Poke timeout thread */
442 if (timeout)
443 set_timeout(timeout);
444
Damjan Marion7cd468a2016-12-19 23:05:39 +0100445 q = am->vl_input_queue;
Dave Barach59b25652017-09-10 15:04:27 -0400446
447 again:
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100448 rv = svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0);
449
Damjan Marion7cd468a2016-12-19 23:05:39 +0100450 if (rv == 0) {
451 u16 msg_id = ntohs(*((u16 *)msg));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100452 switch (msg_id) {
453 case VL_API_RX_THREAD_EXIT:
454 printf("Received thread exit\n");
Ole Troan73710c72018-06-04 22:27:49 +0200455 vl_msg_api_free((void *) msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100456 return -1;
457 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
458 printf("Received thread suspend\n");
459 goto error;
460 case VL_API_MEMCLNT_READ_TIMEOUT:
461 printf("Received read timeout %ds\n", timeout);
462 goto error;
Dave Barach59b25652017-09-10 15:04:27 -0400463 case VL_API_MEMCLNT_KEEPALIVE:
464 /* Handle an alive-check ping from vpp. */
465 mp = (void *)msg;
466 rmp = vl_msg_api_alloc (sizeof (*rmp));
467 memset (rmp, 0, sizeof (*rmp));
468 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
469 rmp->context = mp->context;
470 shmem_hdr = am->shmem_hdr;
471 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
472 vl_msg_api_free((void *) msg);
473 /*
474 * Python code is blissfully unaware of these pings, so
475 * act as if it never happened...
476 */
477 goto again;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100478
479 default:
480 msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
481 *l = ntohl(msgbuf->data_len);
482 if (*l == 0) {
483 printf("Unregistered API message: %d\n", msg_id);
484 goto error;
485 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100486 }
487 *p = (char *)msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100488
489 /* Let timeout notification thread know we're done */
490 unset_timeout();
491
Damjan Marion7cd468a2016-12-19 23:05:39 +0100492 } else {
493 printf("Read failed with %d\n", rv);
494 }
495 return (rv);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100496
497 error:
498 vl_msg_api_free((void *) msg);
499 /* Client might forget to resume RX thread on failure */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200500 vac_rx_resume ();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100501 return -1;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100502}
503
504/*
505 * XXX: Makes the assumption that client_index is the first member
506 */
507typedef VL_API_PACKED(struct _vl_api_header {
508 u16 _vl_msg_id;
509 u32 client_index;
510}) vl_api_header_t;
511
512static unsigned int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200513vac_client_index (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100514{
515 return (api_main.my_client_index);
516}
517
518int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200519vac_write (char *p, int l)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100520{
521 int rv = -1;
522 api_main_t *am = &api_main;
523 vl_api_header_t *mp = vl_msg_api_alloc(l);
Florin Corase86a8ed2018-01-05 03:20:25 -0800524 svm_queue_t *q;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200525 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100526
527 if (!pm->connected_to_vlib) return -1;
528 if (!mp) return (-1);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100529
Damjan Marion7cd468a2016-12-19 23:05:39 +0100530 memcpy(mp, p, l);
Damjan Marion5fec1e82017-04-13 19:13:47 +0200531 mp->client_index = vac_client_index();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100532 q = am->shmem_hdr->vl_input_queue;
Florin Corase86a8ed2018-01-05 03:20:25 -0800533 rv = svm_queue_add(q, (u8 *)&mp, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100534 if (rv != 0) {
Ole Troandfc9b7c2017-03-06 23:51:57 +0100535 clib_warning("vpe_api_write fails: %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100536 /* Clear message */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200537 vac_free(mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100538 }
539 return (rv);
540}
541
Ole Troan3cc49712017-03-08 12:02:24 +0100542int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200543vac_get_msg_index (unsigned char * name)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100544{
Florin Corase86a8ed2018-01-05 03:20:25 -0800545 return vl_msg_api_get_msg_index (name);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100546}
Ole Troan3cc49712017-03-08 12:02:24 +0100547
548int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200549vac_msg_table_max_index(void)
Ole Troan3cc49712017-03-08 12:02:24 +0100550{
551 int max = 0;
552 hash_pair_t *hp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200553 uword *h = vac_msg_table_get_hash();
Ole Troan3cc49712017-03-08 12:02:24 +0100554 hash_foreach_pair (hp, h,
555 ({
556 if (hp->value[0] > max)
557 max = hp->value[0];
558 }));
559
560 return max;
561}
562
563void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200564vac_set_error_handler (vac_error_callback_t cb)
Ole Troan3cc49712017-03-08 12:02:24 +0100565{
566 if (cb) clib_error_register_handler (cb, 0);
567}