blob: b27e5b7479832cc5dcbe2ca16ad2d2a37b4fd5d9 [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;
Ole Troan4e588aa2018-09-07 11:01:47 +020075bool timeout_thread_cancelled = false;
Ole Troandfc9b7c2017-03-06 23:51:57 +010076
Ole Troan73710c72018-06-04 22:27:49 +020077/* Set to true to enable memory tracing */
78bool mem_trace = false;
79
80__attribute__((constructor))
81static void
82vac_client_constructor (void)
83{
Ole Troan73710c72018-06-04 22:27:49 +020084 clib_mem_init (0, 1 << 30);
Dave Barach6a5adc32018-07-04 10:56:23 -040085#if USE_DLMALLOC == 0
86 {
87 u8 *heap;
88 mheap_t *h;
89
90 heap = clib_mem_get_per_cpu_heap ();
91 h = mheap_header (heap);
92 /* make the main heap thread-safe */
93 h->flags |= MHEAP_FLAG_THREAD_SAFE;
94 }
95#endif
Ole Troan73710c72018-06-04 22:27:49 +020096 if (mem_trace)
97 clib_mem_trace (1);
98}
99
100__attribute__((destructor))
101static void
102vac_client_destructor (void)
103{
104 if (mem_trace)
105 fformat(stderr, "TRACE: %s",
106 format (0, "%U\n",
107 format_mheap, clib_mem_get_heap (), 1));
108}
109
110
Ole Troandfc9b7c2017-03-06 23:51:57 +0100111static void
112init (void)
113{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200114 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100115 memset(pm, 0, sizeof(*pm));
116 pthread_mutex_init(&pm->queue_lock, NULL);
117 pthread_cond_init(&pm->suspend_cv, NULL);
118 pthread_cond_init(&pm->resume_cv, NULL);
119 pthread_mutex_init(&pm->timeout_lock, NULL);
Neale Ranns1d652792018-07-26 08:05:53 -0700120 pm->timeout_loop = 1;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100121 pthread_cond_init(&pm->timeout_cv, NULL);
122 pthread_cond_init(&pm->timeout_cancel_cv, NULL);
123 pthread_cond_init(&pm->terminate_cv, NULL);
124}
125
126static void
127cleanup (void)
128{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200129 vac_main_t *pm = &vac_main;
Ole Troan73710c72018-06-04 22:27:49 +0200130 pthread_mutex_destroy(&pm->queue_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100131 pthread_cond_destroy(&pm->suspend_cv);
132 pthread_cond_destroy(&pm->resume_cv);
Ole Troan73710c72018-06-04 22:27:49 +0200133 pthread_mutex_destroy(&pm->timeout_lock);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100134 pthread_cond_destroy(&pm->timeout_cv);
135 pthread_cond_destroy(&pm->timeout_cancel_cv);
136 pthread_cond_destroy(&pm->terminate_cv);
Ole Troan73710c72018-06-04 22:27:49 +0200137 memset(pm, 0, sizeof(*pm));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100138}
Damjan Marion7cd468a2016-12-19 23:05:39 +0100139
140/*
141 * Satisfy external references when -lvlib is not available.
142 */
143void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...)
144{
145 clib_warning ("vlib_cli_output called...");
146}
147
148void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200149vac_free (void * msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100150{
151 vl_msg_api_free (msg);
152}
153
154static void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200155vac_api_handler (void *msg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100156{
157 u16 id = ntohs(*((u16 *)msg));
Damjan Marion7cd468a2016-12-19 23:05:39 +0100158 msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
159 int l = ntohl(msgbuf->data_len);
160 if (l == 0)
161 clib_warning("Message ID %d has wrong length: %d\n", id, l);
162
163 /* Call Python callback */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200164 ASSERT(vac_callback);
165 (vac_callback)(msg, l);
166 vac_free(msg);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100167}
168
169static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200170vac_rx_thread_fn (void *arg)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100171{
Florin Corase86a8ed2018-01-05 03:20:25 -0800172 svm_queue_t *q;
Dave Barach59b25652017-09-10 15:04:27 -0400173 vl_api_memclnt_keepalive_t *mp;
174 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200175 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100176 api_main_t *am = &api_main;
Dave Barach59b25652017-09-10 15:04:27 -0400177 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100178 uword msg;
179
180 q = am->vl_input_queue;
181
Ole Troandfc9b7c2017-03-06 23:51:57 +0100182 while (1)
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100183 while (!svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0))
Ole Troandfc9b7c2017-03-06 23:51:57 +0100184 {
185 u16 id = ntohs(*((u16 *)msg));
186 switch (id) {
187 case VL_API_RX_THREAD_EXIT:
188 vl_msg_api_free((void *) msg);
189 /* signal waiting threads that this thread is about to terminate */
190 pthread_mutex_lock(&pm->queue_lock);
191 pthread_cond_signal(&pm->terminate_cv);
192 pthread_mutex_unlock(&pm->queue_lock);
193 pthread_exit(0);
194 return 0;
195 break;
196
197 case VL_API_MEMCLNT_RX_THREAD_SUSPEND:
198 vl_msg_api_free((void * )msg);
199 /* Suspend thread and signal reader */
200 pthread_mutex_lock(&pm->queue_lock);
201 pthread_cond_signal(&pm->suspend_cv);
202 /* Wait for the resume signal */
203 pthread_cond_wait (&pm->resume_cv, &pm->queue_lock);
204 pthread_mutex_unlock(&pm->queue_lock);
205 break;
206
207 case VL_API_MEMCLNT_READ_TIMEOUT:
208 clib_warning("Received read timeout in async thread\n");
209 vl_msg_api_free((void *) msg);
210 break;
211
Dave Barach59b25652017-09-10 15:04:27 -0400212 case VL_API_MEMCLNT_KEEPALIVE:
213 mp = (void *)msg;
214 rmp = vl_msg_api_alloc (sizeof (*rmp));
215 memset (rmp, 0, sizeof (*rmp));
216 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
217 rmp->context = mp->context;
218 shmem_hdr = am->shmem_hdr;
219 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
220 vl_msg_api_free((void *) msg);
221 break;
222
Ole Troandfc9b7c2017-03-06 23:51:57 +0100223 default:
Damjan Marion5fec1e82017-04-13 19:13:47 +0200224 vac_api_handler((void *)msg);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100225 }
226 }
227}
228
229static void *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200230vac_timeout_thread_fn (void *arg)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100231{
232 vl_api_memclnt_read_timeout_t *ep;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200233 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100234 api_main_t *am = &api_main;
235 struct timespec ts;
236 struct timeval tv;
237 u16 timeout;
238 int rv;
239
Neale Ranns1d652792018-07-26 08:05:53 -0700240 while (pm->timeout_loop)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100241 {
242 /* Wait for poke */
243 pthread_mutex_lock(&pm->timeout_lock);
244 pthread_cond_wait (&pm->timeout_cv, &pm->timeout_lock);
245 timeout = read_timeout;
246 gettimeofday(&tv, NULL);
247 ts.tv_sec = tv.tv_sec + timeout;
248 ts.tv_nsec = 0;
249 rv = pthread_cond_timedwait (&pm->timeout_cancel_cv,
250 &pm->timeout_lock, &ts);
251 pthread_mutex_unlock(&pm->timeout_lock);
Ole Troan4e588aa2018-09-07 11:01:47 +0200252 if (rv == ETIMEDOUT && !timeout_thread_cancelled)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100253 {
254 ep = vl_msg_api_alloc (sizeof (*ep));
255 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_READ_TIMEOUT);
256 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
257 }
258 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100259 pthread_exit(0);
260}
261
Ole Troandfc9b7c2017-03-06 23:51:57 +0100262void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200263vac_rx_suspend (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100264{
265 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200266 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100267 vl_api_memclnt_rx_thread_suspend_t *ep;
268
269 if (!pm->rx_thread_handle) return;
270 pthread_mutex_lock(&pm->queue_lock);
271 if (rx_is_running)
272 {
273 ep = vl_msg_api_alloc (sizeof (*ep));
274 ep->_vl_msg_id = ntohs(VL_API_MEMCLNT_RX_THREAD_SUSPEND);
275 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
276 /* Wait for RX thread to tell us it has suspendend */
277 pthread_cond_wait(&pm->suspend_cv, &pm->queue_lock);
278 rx_is_running = false;
279 }
280 pthread_mutex_unlock(&pm->queue_lock);
281}
282
283void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200284vac_rx_resume (void)
Ole Troandfc9b7c2017-03-06 23:51:57 +0100285{
Damjan Marion5fec1e82017-04-13 19:13:47 +0200286 vac_main_t *pm = &vac_main;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100287 if (!pm->rx_thread_handle) return;
288 pthread_mutex_lock(&pm->queue_lock);
Ole Troanad0697a2017-03-09 21:10:45 +0100289 if (rx_is_running) goto unlock;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100290 pthread_cond_signal(&pm->resume_cv);
291 rx_is_running = true;
Ole Troanad0697a2017-03-09 21:10:45 +0100292 unlock:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100293 pthread_mutex_unlock(&pm->queue_lock);
294}
295
Ole Troan3cc49712017-03-08 12:02:24 +0100296static uword *
Damjan Marion5fec1e82017-04-13 19:13:47 +0200297vac_msg_table_get_hash (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100298{
299 api_main_t *am = &api_main;
300 return (am->msg_index_by_name_and_crc);
301}
302
303int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200304vac_msg_table_size(void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100305{
306 api_main_t *am = &api_main;
307 return hash_elts(am->msg_index_by_name_and_crc);
308}
309
310int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200311vac_connect (char * name, char * chroot_prefix, vac_callback_t cb,
Dave Barachf9526922017-01-06 16:33:06 -0500312 int rx_qlen)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100313{
314 int rv = 0;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200315 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100316
Ole Troandfc9b7c2017-03-06 23:51:57 +0100317 init();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100318 if (chroot_prefix != NULL)
319 vl_set_memory_root_path (chroot_prefix);
320
321 if ((rv = vl_client_api_map("/vpe-api"))) {
Ondrej Fabrye29cb672018-08-16 08:36:19 +0200322 clib_warning ("vl_client_api_map returned %d", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100323 return rv;
324 }
325
Dave Barachf9526922017-01-06 16:33:06 -0500326 if (vl_client_connect(name, 0, rx_qlen) < 0) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100327 vl_client_api_unmap();
328 return (-1);
329 }
330
331 if (cb) {
332 /* Start the rx queue thread */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200333 rv = pthread_create(&pm->rx_thread_handle, NULL, vac_rx_thread_fn, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100334 if (rv) {
335 clib_warning("pthread_create returned %d", rv);
336 vl_client_api_unmap();
337 return (-1);
338 }
Damjan Marion5fec1e82017-04-13 19:13:47 +0200339 vac_callback = cb;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100340 rx_is_running = true;
341 }
342
343 /* Start read timeout thread */
344 rv = pthread_create(&pm->timeout_thread_handle, NULL,
Damjan Marion5fec1e82017-04-13 19:13:47 +0200345 vac_timeout_thread_fn, 0);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100346 if (rv) {
347 clib_warning("pthread_create returned %d", rv);
348 vl_client_api_unmap();
349 return (-1);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100350 }
351
352 pm->connected_to_vlib = 1;
353
354 return (0);
355}
356
Neale Rannsc16f6b32018-06-03 21:21:19 -0700357static void
358set_timeout (unsigned short timeout)
359{
360 vac_main_t *pm = &vac_main;
361 pthread_mutex_lock(&pm->timeout_lock);
362 read_timeout = timeout;
363 pthread_cond_signal(&pm->timeout_cv);
364 pthread_mutex_unlock(&pm->timeout_lock);
365}
366
367static void
368unset_timeout (void)
369{
370 vac_main_t *pm = &vac_main;
371 pthread_mutex_lock(&pm->timeout_lock);
372 pthread_cond_signal(&pm->timeout_cancel_cv);
373 pthread_mutex_unlock(&pm->timeout_lock);
374}
375
Damjan Marion7cd468a2016-12-19 23:05:39 +0100376int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200377vac_disconnect (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100378{
379 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200380 vac_main_t *pm = &vac_main;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700381 uword junk;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100382
Ole Troandfc9b7c2017-03-06 23:51:57 +0100383 if (!pm->connected_to_vlib) return 0;
384
385 if (pm->rx_thread_handle) {
Damjan Marion7cd468a2016-12-19 23:05:39 +0100386 vl_api_rx_thread_exit_t *ep;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100387 ep = vl_msg_api_alloc (sizeof (*ep));
388 ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT);
389 vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100390
391 /* wait (with timeout) until RX thread has finished */
392 struct timespec ts;
393 struct timeval tv;
394 gettimeofday(&tv, NULL);
395 ts.tv_sec = tv.tv_sec + 5;
396 ts.tv_nsec = 0;
397 pthread_mutex_lock(&pm->queue_lock);
398 int rv = pthread_cond_timedwait(&pm->terminate_cv, &pm->queue_lock, &ts);
399 pthread_mutex_unlock(&pm->queue_lock);
400 /* now join so we wait until thread has -really- finished */
401 if (rv == ETIMEDOUT)
402 pthread_cancel(pm->rx_thread_handle);
403 else
404 pthread_join(pm->rx_thread_handle, (void **) &junk);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100405 }
Neale Rannsc16f6b32018-06-03 21:21:19 -0700406 if (pm->timeout_thread_handle) {
407 /* cancel, wake then join the timeout thread */
Neale Ranns1d652792018-07-26 08:05:53 -0700408 pm->timeout_loop = 0;
Ole Troan4e588aa2018-09-07 11:01:47 +0200409 timeout_thread_cancelled = true;
Neale Rannsc16f6b32018-06-03 21:21:19 -0700410 set_timeout(0);
411 pthread_join(pm->timeout_thread_handle, (void **) &junk);
412 }
Ole Troandfc9b7c2017-03-06 23:51:57 +0100413
414 vl_client_disconnect();
415 vl_client_api_unmap();
Damjan Marion5fec1e82017-04-13 19:13:47 +0200416 vac_callback = 0;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100417
418 cleanup();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100419
420 return (0);
421}
422
423int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200424vac_read (char **p, int *l, u16 timeout)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100425{
Florin Corase86a8ed2018-01-05 03:20:25 -0800426 svm_queue_t *q;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100427 api_main_t *am = &api_main;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200428 vac_main_t *pm = &vac_main;
Dave Barach59b25652017-09-10 15:04:27 -0400429 vl_api_memclnt_keepalive_t *mp;
430 vl_api_memclnt_keepalive_reply_t *rmp;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100431 uword msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100432 msgbuf_t *msgbuf;
Dave Barach59b25652017-09-10 15:04:27 -0400433 int rv;
434 vl_shmem_hdr_t *shmem_hdr;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100435
436 if (!pm->connected_to_vlib) return -1;
437
438 *l = 0;
439
440 if (am->our_pid == 0) return (-1);
441
Ole Troandfc9b7c2017-03-06 23:51:57 +0100442 /* Poke timeout thread */
443 if (timeout)
444 set_timeout(timeout);
445
Damjan Marion7cd468a2016-12-19 23:05:39 +0100446 q = am->vl_input_queue;
Dave Barach59b25652017-09-10 15:04:27 -0400447
448 again:
Mohsin Kazmi3fca5672018-01-04 18:57:26 +0100449 rv = svm_queue_sub(q, (u8 *)&msg, SVM_Q_WAIT, 0);
450
Damjan Marion7cd468a2016-12-19 23:05:39 +0100451 if (rv == 0) {
452 u16 msg_id = ntohs(*((u16 *)msg));
Ole Troandfc9b7c2017-03-06 23:51:57 +0100453 switch (msg_id) {
454 case VL_API_RX_THREAD_EXIT:
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:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100458 goto error;
459 case VL_API_MEMCLNT_READ_TIMEOUT:
Ole Troandfc9b7c2017-03-06 23:51:57 +0100460 goto error;
Dave Barach59b25652017-09-10 15:04:27 -0400461 case VL_API_MEMCLNT_KEEPALIVE:
462 /* Handle an alive-check ping from vpp. */
463 mp = (void *)msg;
464 rmp = vl_msg_api_alloc (sizeof (*rmp));
465 memset (rmp, 0, sizeof (*rmp));
466 rmp->_vl_msg_id = ntohs(VL_API_MEMCLNT_KEEPALIVE_REPLY);
467 rmp->context = mp->context;
468 shmem_hdr = am->shmem_hdr;
469 vl_msg_api_send_shmem(shmem_hdr->vl_input_queue, (u8 *)&rmp);
470 vl_msg_api_free((void *) msg);
471 /*
472 * Python code is blissfully unaware of these pings, so
473 * act as if it never happened...
474 */
475 goto again;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100476
477 default:
478 msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data));
479 *l = ntohl(msgbuf->data_len);
480 if (*l == 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200481 fprintf(stderr, "Unregistered API message: %d\n", msg_id);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100482 goto error;
483 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100484 }
485 *p = (char *)msg;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100486
487 /* Let timeout notification thread know we're done */
488 unset_timeout();
489
Damjan Marion7cd468a2016-12-19 23:05:39 +0100490 } else {
Ole Troan4e588aa2018-09-07 11:01:47 +0200491 fprintf(stderr, "Read failed with %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100492 }
493 return (rv);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100494
495 error:
496 vl_msg_api_free((void *) msg);
497 /* Client might forget to resume RX thread on failure */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200498 vac_rx_resume ();
Ole Troandfc9b7c2017-03-06 23:51:57 +0100499 return -1;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100500}
501
502/*
503 * XXX: Makes the assumption that client_index is the first member
504 */
505typedef VL_API_PACKED(struct _vl_api_header {
506 u16 _vl_msg_id;
507 u32 client_index;
508}) vl_api_header_t;
509
510static unsigned int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200511vac_client_index (void)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100512{
513 return (api_main.my_client_index);
514}
515
516int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200517vac_write (char *p, int l)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100518{
519 int rv = -1;
520 api_main_t *am = &api_main;
521 vl_api_header_t *mp = vl_msg_api_alloc(l);
Florin Corase86a8ed2018-01-05 03:20:25 -0800522 svm_queue_t *q;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200523 vac_main_t *pm = &vac_main;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100524
525 if (!pm->connected_to_vlib) return -1;
526 if (!mp) return (-1);
Ole Troandfc9b7c2017-03-06 23:51:57 +0100527
Damjan Marion7cd468a2016-12-19 23:05:39 +0100528 memcpy(mp, p, l);
Damjan Marion5fec1e82017-04-13 19:13:47 +0200529 mp->client_index = vac_client_index();
Damjan Marion7cd468a2016-12-19 23:05:39 +0100530 q = am->shmem_hdr->vl_input_queue;
Florin Corase86a8ed2018-01-05 03:20:25 -0800531 rv = svm_queue_add(q, (u8 *)&mp, 0);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100532 if (rv != 0) {
Ole Troan4e588aa2018-09-07 11:01:47 +0200533 fprintf(stderr, "vpe_api_write fails: %d\n", rv);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100534 /* Clear message */
Damjan Marion5fec1e82017-04-13 19:13:47 +0200535 vac_free(mp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100536 }
537 return (rv);
538}
539
Ole Troan3cc49712017-03-08 12:02:24 +0100540int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200541vac_get_msg_index (unsigned char * name)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100542{
Florin Corase86a8ed2018-01-05 03:20:25 -0800543 return vl_msg_api_get_msg_index (name);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100544}
Ole Troan3cc49712017-03-08 12:02:24 +0100545
546int
Damjan Marion5fec1e82017-04-13 19:13:47 +0200547vac_msg_table_max_index(void)
Ole Troan3cc49712017-03-08 12:02:24 +0100548{
549 int max = 0;
550 hash_pair_t *hp;
Damjan Marion5fec1e82017-04-13 19:13:47 +0200551 uword *h = vac_msg_table_get_hash();
Ole Troan3cc49712017-03-08 12:02:24 +0100552 hash_foreach_pair (hp, h,
553 ({
554 if (hp->value[0] > max)
555 max = hp->value[0];
556 }));
557
558 return max;
559}
560
561void
Damjan Marion5fec1e82017-04-13 19:13:47 +0200562vac_set_error_handler (vac_error_callback_t cb)
Ole Troan3cc49712017-03-08 12:02:24 +0100563{
564 if (cb) clib_error_register_handler (cb, 0);
565}