Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * memory_client.c - API message handling, client code.
4 : *
5 : * Copyright (c) 2010 Cisco and/or its affiliates.
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at:
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : *------------------------------------------------------------------
18 : */
19 :
20 : #include <setjmp.h>
21 :
22 : #include <svm/svm.h>
23 : #include <svm/ssvm.h>
24 : #include <vppinfra/serialize.h>
25 : #include <vppinfra/hash.h>
26 : #include <vlibmemory/memory_client.h>
27 : #include <vlibapi/api_common.h>
28 :
29 : /* A hack. vl_client_get_first_plugin_msg_id depends on it */
30 : #include <vlibmemory/socket_client.h>
31 :
32 : #include <vlibmemory/vl_memory_msg_enum.h>
33 :
34 : #define vl_typedefs /* define message structures */
35 : #include <vlibmemory/vl_memory_api_h.h>
36 : #undef vl_typedefs
37 :
38 : #define vl_endianfun /* define message structures */
39 : #include <vlibmemory/vl_memory_api_h.h>
40 : #undef vl_endianfun
41 :
42 : #define vl_calcsizefun
43 : #include <vlibmemory/vl_memory_api_h.h>
44 : #undef vl_calcsizefun
45 :
46 : /* instantiate all the print functions we know about */
47 : #define vl_printfun
48 : #include <vlibmemory/vl_memory_api_h.h>
49 : #undef vl_printfun
50 :
51 : memory_client_main_t memory_client_main;
52 : __thread memory_client_main_t *my_memory_client_main = &memory_client_main;
53 :
54 : typedef struct rx_thread_fn_arg
55 : {
56 : api_main_t *am;
57 : memory_client_main_t *mm;
58 : } rx_thread_fn_arg_t;
59 :
60 : static void *
61 29 : rx_thread_fn (void *arg)
62 : {
63 29 : rx_thread_fn_arg_t *a = (rx_thread_fn_arg_t *) arg;
64 : memory_client_main_t *mm;
65 : svm_queue_t *q;
66 :
67 29 : vlibapi_set_main (a->am);
68 29 : vlibapi_set_memory_client_main (a->mm);
69 29 : free (a);
70 :
71 29 : mm = vlibapi_get_memory_client_main ();
72 29 : q = vlibapi_get_main ()->vl_input_queue;
73 :
74 : /* So we can make the rx thread terminate cleanly */
75 29 : if (setjmp (mm->rx_thread_jmpbuf) == 0)
76 : {
77 29 : mm->rx_thread_jmpbuf_valid = 1;
78 29 : clib_mem_set_thread_index ();
79 : while (1)
80 29 : vl_msg_api_queue_handler (q);
81 : }
82 29 : pthread_exit (0);
83 : }
84 :
85 : static void
86 29 : vl_api_rx_thread_exit_t_handler (vl_api_rx_thread_exit_t * mp)
87 : {
88 29 : memory_client_main_t *mm = vlibapi_get_memory_client_main ();
89 29 : if (mm->rx_thread_jmpbuf_valid)
90 29 : longjmp (mm->rx_thread_jmpbuf, 1);
91 0 : }
92 :
93 : static void
94 58 : vl_api_name_and_crc_free (void)
95 : {
96 58 : api_main_t *am = vlibapi_get_main ();
97 : int i;
98 58 : u8 **keys = 0;
99 : hash_pair_t *hp;
100 :
101 58 : if (!am->msg_index_by_name_and_crc)
102 29 : return;
103 :
104 : /* *INDENT-OFF* */
105 169911 : hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
106 : ({
107 : vec_add1 (keys, (u8 *) hp->key);
108 : }));
109 : /* *INDENT-ON* */
110 51127 : for (i = 0; i < vec_len (keys); i++)
111 51098 : vec_free (keys[i]);
112 29 : vec_free (keys);
113 29 : hash_free (am->msg_index_by_name_and_crc);
114 : }
115 :
116 : __clib_nosanitize_addr static void
117 29 : VL_API_VEC_UNPOISON (const void *v)
118 : {
119 29 : const vec_header_t *vh = &((vec_header_t *) v)[-1];
120 29 : clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
121 29 : }
122 :
123 : static void
124 29 : vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
125 : {
126 29 : serialize_main_t _sm, *sm = &_sm;
127 29 : api_main_t *am = vlibapi_get_main ();
128 : u8 *tblv;
129 : u32 nmsgs;
130 : int i;
131 : u8 *name_and_crc;
132 : u32 msg_index;
133 :
134 29 : am->my_client_index = mp->index;
135 29 : am->my_registration = (vl_api_registration_t *) (uword) mp->handle;
136 :
137 : /* Clean out any previous hash table (unlikely) */
138 29 : vl_api_name_and_crc_free ();
139 :
140 29 : am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
141 :
142 : /* Recreate the vnet-side API message handler table */
143 29 : tblv = uword_to_pointer (mp->message_table, u8 *);
144 29 : unserialize_open_data (sm, tblv, vec_len (tblv));
145 29 : unserialize_integer (sm, &nmsgs, sizeof (u32));
146 :
147 29 : VL_API_VEC_UNPOISON (tblv);
148 :
149 51127 : for (i = 0; i < nmsgs; i++)
150 : {
151 51098 : msg_index = unserialize_likely_small_unsigned_integer (sm);
152 51098 : unserialize_cstring (sm, (char **) &name_and_crc);
153 102196 : hash_set_mem (am->msg_index_by_name_and_crc, name_and_crc, msg_index);
154 : }
155 29 : }
156 :
157 : void vl_msg_api_send_shmem (svm_queue_t * q, u8 * elem);
158 : int
159 29 : vl_client_connect (const char *name, int ctx_quota, int input_queue_size)
160 : {
161 : vl_api_memclnt_create_t *mp;
162 : vl_api_memclnt_create_reply_t *rp;
163 : svm_queue_t *vl_input_queue;
164 : vl_shmem_hdr_t *shmem_hdr;
165 29 : int rv = 0;
166 : void *oldheap;
167 29 : api_main_t *am = vlibapi_get_main ();
168 :
169 29 : if (am->my_registration)
170 : {
171 0 : clib_warning ("client %s already connected...", name);
172 0 : return -1;
173 : }
174 :
175 29 : if (am->vlib_rp == 0)
176 : {
177 0 : clib_warning ("am->vlib_rp NULL");
178 0 : return -1;
179 : }
180 :
181 29 : shmem_hdr = am->shmem_hdr;
182 :
183 29 : if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
184 : {
185 0 : clib_warning ("shmem_hdr / input queue NULL");
186 0 : return -1;
187 : }
188 :
189 29 : clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
190 29 : VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
191 :
192 29 : oldheap = vl_msg_push_heap ();
193 29 : vl_input_queue = svm_queue_alloc_and_init (input_queue_size, sizeof (uword),
194 : getpid ());
195 29 : vl_msg_pop_heap (oldheap);
196 :
197 29 : am->my_client_index = ~0;
198 29 : am->my_registration = 0;
199 29 : am->vl_input_queue = vl_input_queue;
200 :
201 29 : mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_create_t));
202 29 : clib_memset (mp, 0, sizeof (*mp));
203 29 : mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE);
204 29 : mp->ctx_quota = ctx_quota;
205 29 : mp->input_queue = (uword) vl_input_queue;
206 29 : strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
207 :
208 29 : vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
209 :
210 : while (1)
211 0 : {
212 : int qstatus;
213 : struct timespec ts, tsrem;
214 : int i;
215 :
216 : /* Wait up to 10 seconds */
217 58 : for (i = 0; i < 1000; i++)
218 : {
219 58 : qstatus = svm_queue_sub (vl_input_queue, (u8 *) & rp,
220 : SVM_Q_NOWAIT, 0);
221 58 : if (qstatus == 0)
222 29 : goto read_one_msg;
223 29 : ts.tv_sec = 0;
224 29 : ts.tv_nsec = 10000 * 1000; /* 10 ms */
225 29 : while (nanosleep (&ts, &tsrem) < 0)
226 0 : ts = tsrem;
227 : }
228 : /* Timeout... */
229 0 : clib_warning ("memclnt_create_reply timeout");
230 0 : return -1;
231 :
232 29 : read_one_msg:
233 29 : VL_MSG_API_UNPOISON (rp);
234 29 : if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_REPLY)
235 : {
236 0 : clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
237 0 : continue;
238 : }
239 29 : rv = clib_net_to_host_u32 (rp->response);
240 :
241 29 : msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
242 29 : vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
243 29 : break;
244 : }
245 29 : return (rv);
246 : }
247 :
248 : static void
249 29 : vl_api_memclnt_delete_reply_t_handler (vl_api_memclnt_delete_reply_t * mp)
250 : {
251 : void *oldheap;
252 29 : api_main_t *am = vlibapi_get_main ();
253 :
254 29 : oldheap = vl_msg_push_heap ();
255 29 : svm_queue_free (am->vl_input_queue);
256 29 : vl_msg_pop_heap (oldheap);
257 :
258 29 : am->my_client_index = ~0;
259 29 : am->my_registration = 0;
260 29 : am->vl_input_queue = 0;
261 29 : }
262 :
263 : void
264 29 : vl_client_send_disconnect (u8 do_cleanup)
265 : {
266 : vl_api_memclnt_delete_t *mp;
267 : vl_shmem_hdr_t *shmem_hdr;
268 29 : api_main_t *am = vlibapi_get_main ();
269 :
270 29 : ASSERT (am->vlib_rp);
271 29 : shmem_hdr = am->shmem_hdr;
272 29 : ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
273 :
274 29 : mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
275 29 : clib_memset (mp, 0, sizeof (*mp));
276 29 : mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
277 29 : mp->index = am->my_client_index;
278 29 : mp->handle = (uword) am->my_registration;
279 29 : mp->do_cleanup = do_cleanup;
280 :
281 29 : vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
282 29 : }
283 :
284 : int
285 29 : vl_client_disconnect (void)
286 : {
287 : vl_api_memclnt_delete_reply_t *rp;
288 : svm_queue_t *vl_input_queue;
289 29 : api_main_t *am = vlibapi_get_main ();
290 : time_t begin;
291 : msgbuf_t *msgbuf;
292 :
293 29 : vl_input_queue = am->vl_input_queue;
294 29 : vl_client_send_disconnect (0 /* wait for reply */ );
295 :
296 : /*
297 : * Have to be careful here, in case the client is disconnecting
298 : * because e.g. the vlib process died, or is unresponsive.
299 : */
300 29 : begin = time (0);
301 : while (1)
302 18015 : {
303 : time_t now;
304 :
305 18044 : now = time (0);
306 :
307 18044 : if (now >= (begin + 2))
308 : {
309 0 : clib_warning ("peer unresponsive, give up");
310 0 : am->my_client_index = ~0;
311 0 : am->my_registration = 0;
312 0 : am->shmem_hdr = 0;
313 0 : return -1;
314 : }
315 18044 : if (svm_queue_sub (vl_input_queue, (u8 *) & rp, SVM_Q_NOWAIT, 0) < 0)
316 18004 : continue;
317 :
318 40 : VL_MSG_API_UNPOISON (rp);
319 :
320 : /* drain the queue */
321 40 : if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
322 : {
323 11 : clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
324 11 : msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
325 11 : vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
326 11 : continue;
327 : }
328 29 : msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
329 29 : vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
330 29 : break;
331 : }
332 :
333 29 : vl_api_name_and_crc_free ();
334 29 : return 0;
335 : }
336 :
337 : /**
338 : * Stave off the binary API dead client reaper
339 : * Only sent to inactive clients
340 : */
341 : static void
342 0 : vl_api_memclnt_keepalive_t_handler (vl_api_memclnt_keepalive_t * mp)
343 : {
344 : vl_api_memclnt_keepalive_reply_t *rmp;
345 : api_main_t *am;
346 : vl_shmem_hdr_t *shmem_hdr;
347 :
348 0 : am = vlibapi_get_main ();
349 0 : shmem_hdr = am->shmem_hdr;
350 :
351 0 : rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
352 0 : clib_memset (rmp, 0, sizeof (*rmp));
353 0 : rmp->_vl_msg_id = ntohs (VL_API_MEMCLNT_KEEPALIVE_REPLY);
354 0 : rmp->context = mp->context;
355 0 : vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & rmp);
356 0 : }
357 :
358 : #define foreach_api_msg \
359 : _(RX_THREAD_EXIT, rx_thread_exit) \
360 : _(MEMCLNT_CREATE_REPLY, memclnt_create_reply) \
361 : _(MEMCLNT_DELETE_REPLY, memclnt_delete_reply) \
362 : _(MEMCLNT_KEEPALIVE, memclnt_keepalive)
363 :
364 : void
365 29 : vl_client_install_client_message_handlers (void)
366 : {
367 29 : api_main_t *am = vlibapi_get_main ();
368 : #define _(N, n) \
369 : vl_msg_api_config (&(vl_msg_api_msg_config_t){ \
370 : .id = VL_API_##N, \
371 : .name = #n, \
372 : .handler = vl_api_##n##_t_handler, \
373 : .endian = vl_api_##n##_t_endian, \
374 : .format_fn = vl_api_##n##_t_format, \
375 : .size = sizeof (vl_api_##n##_t), \
376 : .traced = 0, \
377 : .tojson = vl_api_##n##_t_tojson, \
378 : .fromjson = vl_api_##n##_t_fromjson, \
379 : .calc_size = vl_api_##n##_t_calc_size, \
380 : }); \
381 : am->msg_data[VL_API_##N].replay_allowed = 0;
382 29 : foreach_api_msg;
383 : #undef _
384 29 : }
385 :
386 : int
387 0 : vl_client_api_map (const char *region_name)
388 : {
389 : int rv;
390 :
391 0 : if ((rv = vl_map_shmem (region_name, 0 /* is_vlib */ )) < 0)
392 0 : return rv;
393 :
394 0 : vl_client_install_client_message_handlers ();
395 0 : return 0;
396 : }
397 :
398 : void
399 46 : vl_client_api_unmap (void)
400 : {
401 46 : vl_unmap_shmem_client ();
402 46 : }
403 :
404 : u8
405 29 : vl_mem_client_is_connected (void)
406 : {
407 29 : return (my_memory_client_main->connected_to_vlib != 0);
408 : }
409 :
410 : static int
411 29 : connect_to_vlib_internal (const char *svm_name,
412 : const char *client_name,
413 : int rx_queue_size, void *(*thread_fn) (void *),
414 : void *thread_fn_arg, int do_map)
415 : {
416 29 : int rv = 0;
417 29 : memory_client_main_t *mm = vlibapi_get_memory_client_main ();
418 29 : api_main_t *am = vlibapi_get_main ();
419 :
420 29 : if (do_map && (rv = vl_client_api_map (svm_name)))
421 : {
422 0 : clib_warning ("vl_client_api map rv %d", rv);
423 0 : return rv;
424 : }
425 :
426 29 : if (vl_client_connect (client_name, 0 /* punt quota */ ,
427 : rx_queue_size /* input queue */ ) < 0)
428 : {
429 0 : vl_client_api_unmap ();
430 0 : return -1;
431 : }
432 :
433 : /* Start the rx queue thread */
434 :
435 29 : if (thread_fn)
436 : {
437 29 : if (thread_fn == rx_thread_fn)
438 : {
439 : rx_thread_fn_arg_t *arg;
440 29 : arg = malloc (sizeof (*arg));
441 29 : arg->am = vlibapi_get_main ();
442 29 : arg->mm = vlibapi_get_memory_client_main ();
443 29 : thread_fn_arg = (void *) arg;
444 : }
445 :
446 29 : rv = pthread_create (&mm->rx_thread_handle,
447 : NULL /*attr */ , thread_fn, thread_fn_arg);
448 29 : if (rv)
449 : {
450 0 : clib_warning ("pthread_create returned %d", rv);
451 0 : am->rx_thread_handle = 0;
452 : }
453 : else
454 : {
455 29 : am->rx_thread_handle = mm->rx_thread_handle;
456 : }
457 : }
458 :
459 29 : mm->connected_to_vlib = 1;
460 29 : return 0;
461 : }
462 :
463 : int
464 0 : vl_client_connect_to_vlib (const char *svm_name,
465 : const char *client_name, int rx_queue_size)
466 : {
467 0 : return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
468 : rx_thread_fn, 0 /* thread fn arg */ ,
469 : 1 /* do map */ );
470 : }
471 :
472 : int
473 0 : vl_client_connect_to_vlib_no_rx_pthread (const char *svm_name,
474 : const char *client_name,
475 : int rx_queue_size)
476 : {
477 0 : return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
478 : 0 /* no rx_thread_fn */ ,
479 : 0 /* no thread fn arg */ ,
480 : 1 /* do map */ );
481 : }
482 :
483 : int
484 29 : vl_client_connect_to_vlib_no_map (const char *svm_name,
485 : const char *client_name, int rx_queue_size)
486 : {
487 29 : return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
488 : rx_thread_fn, 0 /* no thread fn arg */ ,
489 : 0 /* dont map */ );
490 : }
491 :
492 : int
493 0 : vl_client_connect_to_vlib_no_rx_pthread_no_map (const char *svm_name,
494 : const char *client_name,
495 : int rx_queue_size)
496 : {
497 0 : return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
498 : 0 /* no thread_fn */ ,
499 : 0 /* no thread fn arg */ ,
500 : 0 /* dont map */ );
501 : }
502 :
503 : int
504 0 : vl_client_connect_to_vlib_thread_fn (const char *svm_name,
505 : const char *client_name,
506 : int rx_queue_size,
507 : void *(*thread_fn) (void *), void *arg)
508 : {
509 0 : return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
510 : thread_fn, arg, 1 /* do map */ );
511 : }
512 :
513 : void
514 29 : vl_client_stop_rx_thread (svm_queue_t *vl_input_queue)
515 : {
516 : vl_api_rx_thread_exit_t *ep;
517 29 : ep = vl_msg_api_alloc (sizeof (*ep));
518 29 : ep->_vl_msg_id = ntohs (VL_API_RX_THREAD_EXIT);
519 29 : vl_msg_api_send_shmem (vl_input_queue, (u8 *) &ep);
520 29 : }
521 :
522 : static void
523 29 : disconnect_from_vlib_internal (u8 do_unmap)
524 : {
525 29 : memory_client_main_t *mm = vlibapi_get_memory_client_main ();
526 29 : api_main_t *am = vlibapi_get_main ();
527 : uword junk;
528 :
529 29 : if (mm->rx_thread_jmpbuf_valid)
530 : {
531 29 : vl_client_stop_rx_thread (am->vl_input_queue);
532 29 : pthread_join (mm->rx_thread_handle, (void **) &junk);
533 : }
534 29 : if (mm->connected_to_vlib)
535 : {
536 29 : vl_client_disconnect ();
537 29 : if (do_unmap)
538 0 : vl_client_api_unmap ();
539 : }
540 29 : clib_memset (mm, 0, sizeof (*mm));
541 29 : }
542 :
543 : void
544 0 : vl_client_disconnect_from_vlib (void)
545 : {
546 0 : disconnect_from_vlib_internal (1);
547 0 : }
548 :
549 : void
550 29 : vl_client_disconnect_from_vlib_no_unmap (void)
551 : {
552 29 : disconnect_from_vlib_internal (0);
553 29 : }
554 :
555 29 : static void vl_api_get_first_msg_id_reply_t_handler
556 : (vl_api_get_first_msg_id_reply_t * mp)
557 : {
558 29 : memory_client_main_t *mm = vlibapi_get_memory_client_main ();
559 29 : i32 retval = ntohl (mp->retval);
560 :
561 29 : mm->first_msg_id_reply = (retval >= 0) ? ntohs (mp->first_msg_id) : ~0;
562 29 : mm->first_msg_id_reply_ready = 1;
563 29 : }
564 :
565 : u16
566 29 : vl_client_get_first_plugin_msg_id (const char *plugin_name)
567 : {
568 : vl_api_get_first_msg_id_t *mp;
569 29 : api_main_t *am = vlibapi_get_main ();
570 29 : memory_client_main_t *mm = vlibapi_get_memory_client_main ();
571 : vl_api_msg_data_t *m =
572 29 : vl_api_get_msg_data (am, VL_API_GET_FIRST_MSG_ID_REPLY);
573 : f64 timeout;
574 : void *old_handler;
575 : clib_time_t clib_time;
576 29 : u16 rv = ~0;
577 :
578 29 : if (strlen (plugin_name) + 1 > sizeof (mp->name))
579 0 : return (rv);
580 :
581 29 : clib_memset (&clib_time, 0, sizeof (clib_time));
582 29 : clib_time_init (&clib_time);
583 :
584 : /* Push this plugin's first_msg_id_reply handler */
585 29 : old_handler = m->handler;
586 29 : m->handler = (void *) vl_api_get_first_msg_id_reply_t_handler;
587 29 : if (!m->calc_size_func)
588 : {
589 29 : m->calc_size_func =
590 : (uword (*) (void *)) vl_api_get_first_msg_id_reply_t_calc_size;
591 : }
592 :
593 : /* Ask the data-plane for the message-ID base of the indicated plugin */
594 29 : mm->first_msg_id_reply_ready = 0;
595 :
596 : /* Not using shm client */
597 29 : if (!am->my_registration)
598 : {
599 0 : mp = vl_socket_client_msg_alloc (sizeof (*mp));
600 0 : clib_memset (mp, 0, sizeof (*mp));
601 0 : mp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID);
602 0 : mp->client_index = am->my_client_index;
603 0 : strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1);
604 :
605 0 : if (vl_socket_client_write () <= 0)
606 0 : goto sock_err;
607 0 : if (vl_socket_client_read (1))
608 0 : goto sock_err;
609 :
610 0 : if (mm->first_msg_id_reply_ready == 1)
611 : {
612 0 : rv = mm->first_msg_id_reply;
613 0 : goto result;
614 : }
615 :
616 0 : sock_err:
617 : /* Restore old handler */
618 0 : m->handler = old_handler;
619 :
620 0 : return -1;
621 : }
622 : else
623 : {
624 29 : mp = vl_msg_api_alloc (sizeof (*mp));
625 29 : clib_memset (mp, 0, sizeof (*mp));
626 29 : mp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID);
627 29 : mp->client_index = am->my_client_index;
628 29 : strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1);
629 :
630 29 : vl_msg_api_send_shmem (am->shmem_hdr->vl_input_queue, (u8 *) & mp);
631 :
632 : /* Synchronously wait for the answer */
633 29 : timeout = clib_time_now (&clib_time) + 1.0;
634 228397 : while (clib_time_now (&clib_time) < timeout)
635 : {
636 228397 : if (mm->first_msg_id_reply_ready == 1)
637 : {
638 29 : rv = mm->first_msg_id_reply;
639 29 : goto result;
640 : }
641 : }
642 : /* Restore old handler */
643 0 : m->handler = old_handler;
644 :
645 0 : return rv;
646 : }
647 :
648 29 : result:
649 :
650 : /* Restore the old handler */
651 29 : m->handler = old_handler;
652 :
653 29 : if (rv == (u16) ~ 0)
654 0 : clib_warning ("plugin '%s' not registered", plugin_name);
655 :
656 29 : return rv;
657 : }
658 :
659 : /*
660 : * fd.io coding-style-patch-verification: ON
661 : *
662 : * Local Variables:
663 : * eval: (c-set-style "gnu")
664 : * End:
665 : */
|