vlib: improvement to automatic core pinning
[vpp.git] / src / vpp-api / vapi / vapi.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <arpa/inet.h>
22 #include <stddef.h>
23 #include <assert.h>
24
25 #include <vpp-api/vapi/vapi_dbg.h>
26 #include <vpp-api/vapi/vapi.h>
27 #include <vpp-api/vapi/vapi_internal.h>
28 #include <vppinfra/types.h>
29 #include <vppinfra/pool.h>
30 #include <vlib/vlib.h>
31 #include <vlibapi/api_common.h>
32 #include <vlibmemory/memory_client.h>
33 #include <vlibmemory/memory_api.h>
34 #include <vlibmemory/api.h>
35
36 #include <vapi/memclnt.api.vapi.h>
37 #include <vapi/vlib.api.vapi.h>
38
39 #include <vlibmemory/vl_memory_msg_enum.h>
40
41 #define vl_typedefs /* define message structures */
42 #include <vlibmemory/vl_memory_api_h.h>
43 #undef vl_typedefs
44
45 /* we need to use control pings for some stuff and because we're forced to put
46  * the code in headers, we need a way to be able to grab the ids of these
47  * messages - so declare them here as extern */
48 vapi_msg_id_t vapi_msg_id_control_ping = 0;
49 vapi_msg_id_t vapi_msg_id_control_ping_reply = 0;
50
51 DEFINE_VAPI_MSG_IDS_MEMCLNT_API_JSON;
52 DEFINE_VAPI_MSG_IDS_VLIB_API_JSON;
53
54 struct
55 {
56   size_t count;
57   vapi_message_desc_t **msgs;
58   size_t max_len_name_with_crc;
59 } __vapi_metadata;
60
61 typedef struct
62 {
63   u32 context;
64   vapi_cb_t callback;
65   void *callback_ctx;
66   vapi_msg_id_t response_id;
67   enum vapi_request_type type;
68 } vapi_req_t;
69
70 static const u32 context_counter_mask = (1 << 31);
71
72 typedef struct
73 {
74   vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id,
75                       void *payload);
76   void *ctx;
77 } vapi_generic_cb_with_ctx;
78
79 typedef struct
80 {
81   vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, void *payload);
82   void *ctx;
83 } vapi_event_cb_with_ctx;
84
85 struct vapi_ctx_s
86 {
87   vapi_mode_e mode;
88   int requests_size;            /* size of the requests array (circular queue) */
89   int requests_start;           /* index of first request */
90   int requests_count;           /* number of used slots */
91   vapi_req_t *requests;
92   u32 context_counter;
93   vapi_generic_cb_with_ctx generic_cb;
94   vapi_event_cb_with_ctx *event_cbs;
95   u16 *vapi_msg_id_t_to_vl_msg_id;
96   u16 vl_msg_id_max;
97   vapi_msg_id_t *vl_msg_id_to_vapi_msg_t;
98   bool connected;
99   bool handle_keepalives;
100   pthread_mutex_t requests_mutex;
101   bool use_uds;
102
103   svm_queue_t *vl_input_queue;
104   clib_socket_t client_socket;
105   clib_time_t time;
106   u32 my_client_index;
107   /** client message index hash table */
108   uword *msg_index_by_name_and_crc;
109 };
110
111 u32
112 vapi_gen_req_context (vapi_ctx_t ctx)
113 {
114   ++ctx->context_counter;
115   ctx->context_counter %= context_counter_mask;
116   return ctx->context_counter | context_counter_mask;
117 }
118
119 size_t
120 vapi_get_request_count (vapi_ctx_t ctx)
121 {
122   return ctx->requests_count;
123 }
124
125 bool
126 vapi_requests_full (vapi_ctx_t ctx)
127 {
128   return (ctx->requests_count == ctx->requests_size);
129 }
130
131 bool
132 vapi_requests_empty (vapi_ctx_t ctx)
133 {
134   return (0 == ctx->requests_count);
135 }
136
137 static int
138 vapi_requests_end (vapi_ctx_t ctx)
139 {
140   return (ctx->requests_start + ctx->requests_count) % ctx->requests_size;
141 }
142
143 void
144 vapi_store_request (vapi_ctx_t ctx, u32 context, vapi_msg_id_t response_id,
145                     enum vapi_request_type request_type, vapi_cb_t callback,
146                     void *callback_ctx)
147 {
148   assert (!vapi_requests_full (ctx));
149   /* if the mutex is not held, bad things will happen */
150   assert (0 != pthread_mutex_trylock (&ctx->requests_mutex));
151   const int requests_end = vapi_requests_end (ctx);
152   vapi_req_t *slot = &ctx->requests[requests_end];
153   slot->type = request_type;
154   slot->response_id = response_id;
155   slot->context = context;
156   slot->callback = callback;
157   slot->callback_ctx = callback_ctx;
158   VAPI_DBG ("stored@%d: context:%x (start is @%d)", requests_end, context,
159             ctx->requests_start);
160   ++ctx->requests_count;
161   assert (!vapi_requests_empty (ctx));
162 }
163
164 #if VAPI_DEBUG_ALLOC
165 struct to_be_freed_s;
166 struct to_be_freed_s
167 {
168   void *v;
169   struct to_be_freed_s *next;
170 };
171
172 static struct to_be_freed_s *to_be_freed = NULL;
173
174 void
175 vapi_add_to_be_freed (void *v)
176 {
177   struct to_be_freed_s *prev = NULL;
178   struct to_be_freed_s *tmp;
179   tmp = to_be_freed;
180   while (tmp && tmp->v)
181     {
182       prev = tmp;
183       tmp = tmp->next;
184     }
185   if (!tmp)
186     {
187       if (!prev)
188         {
189           tmp = to_be_freed = calloc (1, sizeof (*to_be_freed));
190         }
191       else
192         {
193           tmp = prev->next = calloc (1, sizeof (*to_be_freed));
194         }
195     }
196   VAPI_DBG ("To be freed %p", v);
197   tmp->v = v;
198 }
199
200 void
201 vapi_trace_free (void *v)
202 {
203   struct to_be_freed_s *tmp = to_be_freed;
204   while (tmp && tmp->v != v)
205     {
206       tmp = tmp->next;
207     }
208   if (tmp && tmp->v == v)
209     {
210       VAPI_DBG ("Freed %p", v);
211       tmp->v = NULL;
212     }
213   else
214     {
215       VAPI_ERR ("Trying to free untracked pointer %p", v);
216       abort ();
217     }
218 }
219
220 void
221 vapi_to_be_freed_validate ()
222 {
223   struct to_be_freed_s *tmp = to_be_freed;
224   while (tmp)
225     {
226       if (tmp->v)
227         {
228           VAPI_ERR ("Unfreed msg %p!", tmp->v);
229         }
230       tmp = tmp->next;
231     }
232 }
233
234 #endif
235
236 static void *
237 vapi_shm_msg_alloc (vapi_ctx_t ctx, size_t size)
238 {
239   if (!ctx->connected)
240     {
241       return NULL;
242     }
243   void *rv = vl_msg_api_alloc_as_if_client_or_null (size);
244   if (rv)
245     {
246       clib_memset (rv, 0, size);
247     }
248   return rv;
249 }
250
251 static void *
252 vapi_sock_msg_alloc (size_t size)
253 {
254   u8 *rv = 0;
255   vec_validate_init_empty (rv, size - 1, 0);
256   return rv;
257 }
258
259 void *
260 vapi_msg_alloc (vapi_ctx_t ctx, size_t size)
261 {
262   if (ctx->use_uds)
263     return vapi_sock_msg_alloc (size);
264
265   return vapi_shm_msg_alloc (ctx, size);
266 }
267
268 void
269 vapi_msg_free (vapi_ctx_t ctx, void *msg)
270 {
271   if (!ctx->connected)
272     {
273       return;
274     }
275
276 #if VAPI_DEBUG_ALLOC
277   vapi_trace_free (msg);
278 #endif
279
280   if (ctx->use_uds)
281     {
282       vec_free (msg);
283     }
284   else
285     {
286       vl_msg_api_free (msg);
287     }
288 }
289
290 vapi_msg_id_t
291 vapi_lookup_vapi_msg_id_t (vapi_ctx_t ctx, u16 vl_msg_id)
292 {
293   if (vl_msg_id <= ctx->vl_msg_id_max)
294     {
295       return ctx->vl_msg_id_to_vapi_msg_t[vl_msg_id];
296     }
297   return VAPI_INVALID_MSG_ID;
298 }
299
300 vapi_error_e
301 vapi_ctx_alloc (vapi_ctx_t * result)
302 {
303   vapi_ctx_t ctx = calloc (1, sizeof (struct vapi_ctx_s));
304   if (!ctx)
305     {
306       return VAPI_ENOMEM;
307     }
308   ctx->context_counter = 0;
309   ctx->vapi_msg_id_t_to_vl_msg_id =
310     malloc (__vapi_metadata.count *
311             sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
312   if (!ctx->vapi_msg_id_t_to_vl_msg_id)
313     {
314       goto fail;
315     }
316   clib_memset (ctx->vapi_msg_id_t_to_vl_msg_id, ~0,
317                __vapi_metadata.count *
318                sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
319   ctx->event_cbs = calloc (__vapi_metadata.count, sizeof (*ctx->event_cbs));
320   if (!ctx->event_cbs)
321     {
322       goto fail;
323     }
324   pthread_mutex_init (&ctx->requests_mutex, NULL);
325   *result = ctx;
326   clib_time_init (&ctx->time);
327   return VAPI_OK;
328 fail:
329   vapi_ctx_free (ctx);
330   return VAPI_ENOMEM;
331 }
332
333 void
334 vapi_ctx_free (vapi_ctx_t ctx)
335 {
336   assert (!ctx->connected);
337   free (ctx->requests);
338   free (ctx->vapi_msg_id_t_to_vl_msg_id);
339   free (ctx->event_cbs);
340   free (ctx->vl_msg_id_to_vapi_msg_t);
341   pthread_mutex_destroy (&ctx->requests_mutex);
342   free (ctx);
343 }
344
345 bool
346 vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t id)
347 {
348   return vapi_lookup_vl_msg_id (ctx, id) != UINT16_MAX;
349 }
350
351 /* Cut and paste to avoid adding dependency to client library */
352 __clib_nosanitize_addr static void
353 VL_API_VEC_UNPOISON (const void *v)
354 {
355   const vec_header_t *vh = &((vec_header_t *) v)[-1];
356   clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
357 }
358
359 static void
360 vapi_api_name_and_crc_free (vapi_ctx_t ctx)
361 {
362   int i;
363   u8 **keys = 0;
364   hash_pair_t *hp;
365
366   if (!ctx->msg_index_by_name_and_crc)
367     return;
368   hash_foreach_pair (hp, ctx->msg_index_by_name_and_crc,
369                      ({ vec_add1 (keys, (u8 *) hp->key); }));
370   for (i = 0; i < vec_len (keys); i++)
371     vec_free (keys[i]);
372   vec_free (keys);
373   hash_free (ctx->msg_index_by_name_and_crc);
374 }
375
376 static vapi_error_e
377 vapi_sock_get_errno (int err)
378 {
379   switch (err)
380     {
381     case ENOTSOCK:
382       return VAPI_ENOTSOCK;
383     case EACCES:
384       return VAPI_EACCES;
385     case ECONNRESET:
386       return VAPI_ECONNRESET;
387     default:
388       break;
389     }
390   return VAPI_ESOCK_FAILURE;
391 }
392
393 static vapi_error_e
394 vapi_sock_send (vapi_ctx_t ctx, u8 *msg)
395 {
396   size_t n;
397   struct msghdr hdr;
398
399   const size_t len = vec_len (msg);
400   const size_t total_len = len + sizeof (msgbuf_t);
401
402   msgbuf_t msgbuf1 = {
403     .q = 0,
404     .gc_mark_timestamp = 0,
405     .data_len = htonl (len),
406   };
407
408   struct iovec bufs[2] = {
409     [0] = { .iov_base = &msgbuf1, .iov_len = sizeof (msgbuf1) },
410     [1] = { .iov_base = msg, .iov_len = len },
411   };
412
413   clib_memset (&hdr, 0, sizeof (hdr));
414   hdr.msg_iov = bufs;
415   hdr.msg_iovlen = 2;
416
417   n = sendmsg (ctx->client_socket.fd, &hdr, 0);
418   if (n < 0)
419     {
420       return vapi_sock_get_errno (errno);
421     }
422
423   if (n < total_len)
424     {
425       return VAPI_EAGAIN;
426     }
427
428   vec_free (msg);
429
430   return VAPI_OK;
431 }
432
433 static vapi_error_e
434 vapi_sock_send2 (vapi_ctx_t ctx, u8 *msg1, u8 *msg2)
435 {
436   size_t n;
437   struct msghdr hdr;
438
439   const size_t len1 = vec_len (msg1);
440   const size_t len2 = vec_len (msg2);
441   const size_t total_len = len1 + len2 + 2 * sizeof (msgbuf_t);
442
443   msgbuf_t msgbuf1 = {
444     .q = 0,
445     .gc_mark_timestamp = 0,
446     .data_len = htonl (len1),
447   };
448
449   msgbuf_t msgbuf2 = {
450     .q = 0,
451     .gc_mark_timestamp = 0,
452     .data_len = htonl (len2),
453   };
454
455   struct iovec bufs[4] = {
456     [0] = { .iov_base = &msgbuf1, .iov_len = sizeof (msgbuf1) },
457     [1] = { .iov_base = msg1, .iov_len = len1 },
458     [2] = { .iov_base = &msgbuf2, .iov_len = sizeof (msgbuf2) },
459     [3] = { .iov_base = msg2, .iov_len = len2 },
460   };
461
462   clib_memset (&hdr, 0, sizeof (hdr));
463   hdr.msg_iov = bufs;
464   hdr.msg_iovlen = 4;
465
466   n = sendmsg (ctx->client_socket.fd, &hdr, 0);
467   if (n < 0)
468     {
469       return vapi_sock_get_errno (errno);
470     }
471
472   if (n < total_len)
473     {
474       return VAPI_EAGAIN;
475     }
476
477   vec_free (msg1);
478   vec_free (msg2);
479
480   return VAPI_OK;
481 }
482
483 static vapi_error_e
484 vapi_sock_recv_internal (vapi_ctx_t ctx, u8 **vec_msg, u32 timeout)
485 {
486   clib_socket_t *sock = &ctx->client_socket;
487   u32 data_len = 0, msg_size;
488   msgbuf_t *mbp = 0;
489   ssize_t n, current_rx_index;
490   f64 deadline;
491   vapi_error_e rv = VAPI_EAGAIN;
492
493   if (ctx->client_socket.fd == 0)
494     return VAPI_ENOTSOCK;
495
496   deadline = clib_time_now (&ctx->time) + timeout;
497
498   while (1)
499     {
500       current_rx_index = vec_len (sock->rx_buffer);
501       while (current_rx_index < sizeof (*mbp))
502         {
503           vec_validate (sock->rx_buffer, sizeof (*mbp) - 1);
504           n = recv (sock->fd, sock->rx_buffer + current_rx_index,
505                     sizeof (*mbp) - current_rx_index, MSG_DONTWAIT);
506           if (n < 0)
507             {
508               if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
509                 return VAPI_EAGAIN;
510
511               if (errno == EAGAIN)
512                 continue;
513
514               clib_unix_warning ("socket_read");
515               vec_set_len (sock->rx_buffer, current_rx_index);
516               return vapi_sock_get_errno (errno);
517             }
518           current_rx_index += n;
519         }
520       vec_set_len (sock->rx_buffer, current_rx_index);
521
522       mbp = (msgbuf_t *) (sock->rx_buffer);
523       data_len = ntohl (mbp->data_len);
524       current_rx_index = vec_len (sock->rx_buffer);
525       vec_validate (sock->rx_buffer, current_rx_index + data_len);
526       mbp = (msgbuf_t *) (sock->rx_buffer);
527       msg_size = data_len + sizeof (*mbp);
528
529       while (current_rx_index < msg_size)
530         {
531           n = recv (sock->fd, sock->rx_buffer + current_rx_index,
532                     msg_size - current_rx_index, MSG_DONTWAIT);
533           if (n < 0)
534             {
535               if (errno == EAGAIN && clib_time_now (&ctx->time) >= deadline)
536                 return VAPI_EAGAIN;
537
538               if (errno == EAGAIN)
539                 continue;
540
541               clib_unix_warning ("socket_read");
542               vec_set_len (sock->rx_buffer, current_rx_index);
543               return vapi_sock_get_errno (errno);
544             }
545           current_rx_index += n;
546         }
547       vec_set_len (sock->rx_buffer, current_rx_index);
548
549       if (vec_len (sock->rx_buffer) >= data_len + sizeof (*mbp))
550         {
551           if (data_len)
552             {
553               vec_add (*vec_msg, mbp->data, data_len);
554               rv = VAPI_OK;
555             }
556           else
557             {
558               *vec_msg = 0;
559             }
560
561           if (vec_len (sock->rx_buffer) == data_len + sizeof (*mbp))
562             vec_set_len (sock->rx_buffer, 0);
563           else
564             vec_delete (sock->rx_buffer, data_len + sizeof (*mbp), 0);
565           mbp = 0;
566
567           /* Quit if we're out of data, and not expecting a ping reply */
568           if (vec_len (sock->rx_buffer) == 0)
569             break;
570         }
571     }
572   return rv;
573 }
574
575 static void
576 vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
577                                         vl_api_memclnt_create_v2_reply_t *mp)
578 {
579   serialize_main_t _sm, *sm = &_sm;
580   u8 *tblv;
581   u32 nmsgs;
582   int i;
583   u8 *name_and_crc;
584   u32 msg_index;
585
586   ctx->my_client_index = mp->index;
587
588   /* Clean out any previous hash table (unlikely) */
589   vapi_api_name_and_crc_free (ctx);
590
591   ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
592
593   /* Recreate the vnet-side API message handler table */
594   tblv = uword_to_pointer (mp->message_table, u8 *);
595   unserialize_open_data (sm, tblv, vec_len (tblv));
596   unserialize_integer (sm, &nmsgs, sizeof (u32));
597
598   VL_API_VEC_UNPOISON (tblv);
599
600   for (i = 0; i < nmsgs; i++)
601     {
602       msg_index = unserialize_likely_small_unsigned_integer (sm);
603       unserialize_cstring (sm, (char **) &name_and_crc);
604       hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc, msg_index);
605     }
606 }
607
608 static void
609 vapi_sockclnt_create_reply_t_handler (vapi_ctx_t ctx,
610                                       vl_api_sockclnt_create_reply_t *mp)
611 {
612   int i;
613   u8 *name_and_crc;
614
615   ctx->my_client_index = mp->index;
616
617   /* Clean out any previous hash table (unlikely) */
618   vapi_api_name_and_crc_free (ctx);
619
620   ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
621
622   for (i = 0; i < be16toh (mp->count); i++)
623     {
624       name_and_crc = format (0, "%s%c", mp->message_table[i].name, 0);
625       hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc,
626                     be16toh (mp->message_table[i].index));
627     }
628 }
629
630 static void
631 vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
632                                      vl_api_memclnt_delete_reply_t *mp)
633 {
634   void *oldheap;
635   oldheap = vl_msg_push_heap ();
636   svm_queue_free (ctx->vl_input_queue);
637   vl_msg_pop_heap (oldheap);
638
639   ctx->my_client_index = ~0;
640   ctx->vl_input_queue = 0;
641 }
642
643 static void
644 vapi_sockclnt_delete_reply_t_handler (vapi_ctx_t ctx,
645                                       vl_api_sockclnt_delete_reply_t *mp)
646 {
647   ctx->my_client_index = ~0;
648   ctx->vl_input_queue = 0;
649 }
650
651 static int
652 vapi_shm_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
653                          int input_queue_size, bool keepalive)
654 {
655   vl_api_memclnt_create_v2_t *mp;
656   vl_api_memclnt_create_v2_reply_t *rp;
657   svm_queue_t *vl_input_queue;
658   vl_shmem_hdr_t *shmem_hdr;
659   int rv = 0;
660   void *oldheap;
661   api_main_t *am = vlibapi_get_main ();
662
663   shmem_hdr = am->shmem_hdr;
664
665   if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
666     {
667       clib_warning ("shmem_hdr / input queue NULL");
668       return VAPI_ECON_FAIL;
669     }
670
671   clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
672   VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
673
674   oldheap = vl_msg_push_heap ();
675   vl_input_queue =
676     svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
677   vl_msg_pop_heap (oldheap);
678
679   ctx->my_client_index = ~0;
680   ctx->vl_input_queue = vl_input_queue;
681
682   mp = vl_msg_api_alloc_as_if_client (sizeof (vl_api_memclnt_create_v2_t));
683   clib_memset (mp, 0, sizeof (*mp));
684   mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2);
685   mp->ctx_quota = ctx_quota;
686   mp->input_queue = (uword) vl_input_queue;
687   strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
688   mp->keepalive = keepalive;
689
690   vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
691
692   while (1)
693     {
694       int qstatus;
695       struct timespec ts, tsrem;
696       int i;
697
698       /* Wait up to 10 seconds */
699       for (i = 0; i < 1000; i++)
700         {
701           qstatus =
702             svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
703           if (qstatus == 0)
704             goto read_one_msg;
705           ts.tv_sec = 0;
706           ts.tv_nsec = 10000 * 1000; /* 10 ms */
707           while (nanosleep (&ts, &tsrem) < 0)
708             ts = tsrem;
709         }
710       /* Timeout... */
711       return VAPI_ECON_FAIL;
712
713     read_one_msg:
714       VL_MSG_API_UNPOISON (rp);
715       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
716         {
717           clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
718           continue;
719         }
720       rv = clib_net_to_host_u32 (rp->response);
721       vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
722       break;
723     }
724   return (rv);
725 }
726
727 static int
728 vapi_sock_client_connect (vapi_ctx_t ctx, char *path, const char *name)
729 {
730   clib_error_t *error;
731   clib_socket_t *sock;
732   vl_api_sockclnt_create_t *mp;
733   vl_api_sockclnt_create_reply_t *rp;
734   int rv = 0;
735   u8 *msg = 0;
736
737   ctx->my_client_index = ~0;
738
739   if (ctx->client_socket.fd)
740     return VAPI_EINVAL;
741
742   if (name == 0)
743     return VAPI_EINVAL;
744
745   sock = &ctx->client_socket;
746   sock->config = path ? path : API_SOCKET_FILE;
747   sock->flags = CLIB_SOCKET_F_IS_CLIENT;
748
749   if ((error = clib_socket_init (sock)))
750     {
751       clib_error_report (error);
752       return VAPI_ECON_FAIL;
753     }
754
755   mp = vapi_sock_msg_alloc (sizeof (vl_api_sockclnt_create_t));
756   mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_CREATE);
757   strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
758
759   if (vapi_sock_send (ctx, (void *) mp) != VAPI_OK)
760     {
761       return VAPI_ECON_FAIL;
762     }
763
764   while (1)
765     {
766       int qstatus;
767       struct timespec ts, tsrem;
768       int i;
769
770       /* Wait up to 10 seconds */
771       for (i = 0; i < 1000; i++)
772         {
773           qstatus = vapi_sock_recv_internal (ctx, &msg, 0);
774
775           if (qstatus == 0)
776             goto read_one_msg;
777           ts.tv_sec = 0;
778           ts.tv_nsec = 10000 * 1000; /* 10 ms */
779           while (nanosleep (&ts, &tsrem) < 0)
780             ts = tsrem;
781         }
782       /* Timeout... */
783       return -1;
784
785     read_one_msg:
786       if (vec_len (msg) == 0)
787         continue;
788
789       rp = (void *) msg;
790       if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY)
791         {
792           clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
793           continue;
794         }
795       rv = clib_net_to_host_u32 (rp->response);
796       vapi_sockclnt_create_reply_t_handler (ctx, rp);
797       break;
798     }
799   return (rv);
800 }
801
802 static void
803 vapi_shm_client_send_disconnect (vapi_ctx_t ctx, u8 do_cleanup)
804 {
805   vl_api_memclnt_delete_t *mp;
806   vl_shmem_hdr_t *shmem_hdr;
807   api_main_t *am = vlibapi_get_main ();
808
809   ASSERT (am->vlib_rp);
810   shmem_hdr = am->shmem_hdr;
811   ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
812
813   mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
814   clib_memset (mp, 0, sizeof (*mp));
815   mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
816   mp->index = ctx->my_client_index;
817   mp->do_cleanup = do_cleanup;
818
819   vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
820 }
821
822 static vapi_error_e
823 vapi_sock_client_send_disconnect (vapi_ctx_t ctx)
824 {
825   vl_api_sockclnt_delete_t *mp;
826
827   mp = vapi_msg_alloc (ctx, sizeof (vl_api_sockclnt_delete_t));
828   clib_memset (mp, 0, sizeof (*mp));
829   mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_DELETE);
830   mp->client_index = ctx->my_client_index;
831
832   return vapi_sock_send (ctx, (void *) mp);
833 }
834
835 static int
836 vapi_shm_client_disconnect (vapi_ctx_t ctx)
837 {
838   vl_api_memclnt_delete_reply_t *rp;
839   svm_queue_t *vl_input_queue;
840   time_t begin;
841   msgbuf_t *msgbuf;
842
843   vl_input_queue = ctx->vl_input_queue;
844   vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
845
846   /*
847    * Have to be careful here, in case the client is disconnecting
848    * because e.g. the vlib process died, or is unresponsive.
849    */
850   begin = time (0);
851   while (1)
852     {
853       time_t now;
854
855       now = time (0);
856
857       if (now >= (begin + 2))
858         {
859           clib_warning ("peer unresponsive, give up");
860           ctx->my_client_index = ~0;
861           return VAPI_ENORESP;
862         }
863       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
864         continue;
865
866       VL_MSG_API_UNPOISON (rp);
867
868       /* drain the queue */
869       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
870         {
871           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
872           msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
873           vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
874           continue;
875         }
876       msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
877       vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
878       break;
879     }
880
881   vapi_api_name_and_crc_free (ctx);
882   return 0;
883 }
884
885 static vapi_error_e
886 vapi_sock_client_disconnect (vapi_ctx_t ctx)
887 {
888   vl_api_sockclnt_delete_reply_t *rp;
889   u8 *msg = 0;
890   msgbuf_t *msgbuf;
891   int rv;
892   f64 deadline;
893
894   deadline = clib_time_now (&ctx->time) + 2;
895
896   do
897     {
898       rv = vapi_sock_client_send_disconnect (ctx);
899     }
900   while (clib_time_now (&ctx->time) < deadline && rv != VAPI_OK);
901
902   while (1)
903     {
904       if (clib_time_now (&ctx->time) >= deadline)
905         {
906           clib_warning ("peer unresponsive, give up");
907           ctx->my_client_index = ~0;
908           return VAPI_ENORESP;
909         }
910
911       if (vapi_sock_recv_internal (ctx, &msg, 0) != VAPI_OK)
912         continue;
913
914       msgbuf = (void *) msg;
915       rp = (void *) msgbuf->data;
916       /* drain the queue */
917       if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_DELETE_REPLY)
918         {
919           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
920           msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
921           vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
922           continue;
923         }
924       msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
925       vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
926       break;
927     }
928
929   clib_socket_close (&ctx->client_socket);
930   vapi_api_name_and_crc_free (ctx);
931   return VAPI_OK;
932 }
933
934 int
935 vapi_client_disconnect (vapi_ctx_t ctx)
936 {
937   if (ctx->use_uds)
938     {
939       return vapi_sock_client_disconnect (ctx);
940     }
941   return vapi_shm_client_disconnect (ctx);
942 }
943
944 u32
945 vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
946 {
947   uword *p;
948
949   if (ctx->msg_index_by_name_and_crc)
950     {
951       p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
952       if (p)
953         return p[0];
954     }
955   return ~0;
956 }
957
958 vapi_error_e
959 vapi_connect_ex (vapi_ctx_t ctx, const char *name, const char *path,
960                  int max_outstanding_requests, int response_queue_size,
961                  vapi_mode_e mode, bool handle_keepalives, bool use_uds)
962 {
963   int rv;
964
965   if (response_queue_size <= 0 || max_outstanding_requests <= 0)
966     {
967       return VAPI_EINVAL;
968     }
969
970   if (!clib_mem_get_per_cpu_heap () && !clib_mem_init (0, 1024L * 1024 * 32))
971     {
972       return VAPI_ENOMEM;
973     }
974
975   ctx->requests_size = max_outstanding_requests;
976   const size_t size = ctx->requests_size * sizeof (*ctx->requests);
977   void *tmp = realloc (ctx->requests, size);
978   if (!tmp)
979     {
980       return VAPI_ENOMEM;
981     }
982   ctx->requests = tmp;
983   clib_memset (ctx->requests, 0, size);
984   /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
985   ctx->requests_start = ctx->requests_count = 0;
986   ctx->use_uds = use_uds;
987
988   if (use_uds)
989     {
990       if (vapi_sock_client_connect (ctx, (char *) path, name) < 0)
991         {
992           return VAPI_ECON_FAIL;
993         }
994     }
995   else
996     {
997       if (path)
998         {
999           VAPI_DBG ("set memory root path `%s'", path);
1000           vl_set_memory_root_path ((char *) path);
1001         }
1002       static char api_map[] = "/vpe-api";
1003       VAPI_DBG ("client api map `%s'", api_map);
1004       if ((rv = vl_map_shmem (api_map, 0 /* is_vlib */)) < 0)
1005         {
1006           return VAPI_EMAP_FAIL;
1007         }
1008       VAPI_DBG ("connect client `%s'", name);
1009       if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1010                                    true) < 0)
1011         {
1012           vl_client_api_unmap ();
1013           return VAPI_ECON_FAIL;
1014         }
1015 #if VAPI_DEBUG_CONNECT
1016   VAPI_DBG ("start probing messages");
1017 #endif
1018     }
1019
1020   int i;
1021   for (i = 0; i < __vapi_metadata.count; ++i)
1022     {
1023       vapi_message_desc_t *m = __vapi_metadata.msgs[i];
1024       u8 scratch[m->name_with_crc_len + 1];
1025       memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
1026       u32 id = vapi_api_get_msg_index (ctx, scratch);
1027
1028       if (VAPI_INVALID_MSG_ID != id)
1029         {
1030           if (id > UINT16_MAX)
1031             {
1032               VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1033                         UINT16_MAX);
1034               rv = VAPI_EINVAL;
1035               goto fail;
1036             }
1037           if (id > ctx->vl_msg_id_max)
1038             {
1039               vapi_msg_id_t *tmp =
1040                 realloc (ctx->vl_msg_id_to_vapi_msg_t,
1041                          sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
1042               if (!tmp)
1043                 {
1044                   rv = VAPI_ENOMEM;
1045                   goto fail;
1046                 }
1047               ctx->vl_msg_id_to_vapi_msg_t = tmp;
1048               ctx->vl_msg_id_max = id;
1049             }
1050           ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
1051           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
1052 #if VAPI_DEBUG_CONNECT
1053           VAPI_DBG ("Message `%s' has vl_msg_id `%u'", m->name_with_crc,
1054                     (unsigned) id);
1055 #endif
1056         }
1057       else
1058         {
1059           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
1060           VAPI_DBG ("Message `%s' not available", m->name_with_crc);
1061         }
1062     }
1063 #if VAPI_DEBUG_CONNECT
1064   VAPI_DBG ("finished probing messages");
1065 #endif
1066   if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1067       !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1068     {
1069       VAPI_ERR (
1070         "control ping or control ping reply not available, cannot connect");
1071       rv = VAPI_EINCOMPATIBLE;
1072       goto fail;
1073     }
1074   ctx->mode = mode;
1075   ctx->connected = true;
1076   if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1077     {
1078       ctx->handle_keepalives = handle_keepalives;
1079     }
1080   else
1081     {
1082       ctx->handle_keepalives = false;
1083     }
1084   return VAPI_OK;
1085 fail:
1086   vapi_client_disconnect (ctx);
1087   vl_client_api_unmap ();
1088   return rv;
1089 }
1090
1091 vapi_error_e
1092 vapi_connect (vapi_ctx_t ctx, const char *name, const char *chroot_prefix,
1093               int max_outstanding_requests, int response_queue_size,
1094               vapi_mode_e mode, bool handle_keepalives)
1095 {
1096   return vapi_connect_ex (ctx, name, chroot_prefix, max_outstanding_requests,
1097                           response_queue_size, mode, handle_keepalives, false);
1098 }
1099
1100 /*
1101  * API client running in the same process as VPP
1102  */
1103 vapi_error_e
1104 vapi_connect_from_vpp (vapi_ctx_t ctx, const char *name,
1105                        int max_outstanding_requests, int response_queue_size,
1106                        vapi_mode_e mode, bool handle_keepalives)
1107 {
1108   int rv;
1109
1110   if (ctx->use_uds)
1111     {
1112       return VAPI_ENOTSUP;
1113     }
1114
1115   if (response_queue_size <= 0 || max_outstanding_requests <= 0)
1116     {
1117       return VAPI_EINVAL;
1118     }
1119
1120   ctx->requests_size = max_outstanding_requests;
1121   const size_t size = ctx->requests_size * sizeof (*ctx->requests);
1122   void *tmp = realloc (ctx->requests, size);
1123   if (!tmp)
1124     {
1125       return VAPI_ENOMEM;
1126     }
1127   ctx->requests = tmp;
1128   clib_memset (ctx->requests, 0, size);
1129   /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
1130   ctx->requests_start = ctx->requests_count = 0;
1131
1132   VAPI_DBG ("connect client `%s'", name);
1133   if (vapi_shm_client_connect (ctx, (char *) name, 0, response_queue_size,
1134                                handle_keepalives) < 0)
1135     {
1136       return VAPI_ECON_FAIL;
1137     }
1138
1139   int i;
1140   for (i = 0; i < __vapi_metadata.count; ++i)
1141     {
1142       vapi_message_desc_t *m = __vapi_metadata.msgs[i];
1143       u8 scratch[m->name_with_crc_len + 1];
1144       memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
1145       u32 id = vapi_api_get_msg_index (ctx, scratch);
1146       if (VAPI_INVALID_MSG_ID != id)
1147         {
1148           if (id > UINT16_MAX)
1149             {
1150               VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
1151                         UINT16_MAX);
1152               rv = VAPI_EINVAL;
1153               goto fail;
1154             }
1155           if (id > ctx->vl_msg_id_max)
1156             {
1157               vapi_msg_id_t *tmp =
1158                 realloc (ctx->vl_msg_id_to_vapi_msg_t,
1159                          sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
1160               if (!tmp)
1161                 {
1162                   rv = VAPI_ENOMEM;
1163                   goto fail;
1164                 }
1165               ctx->vl_msg_id_to_vapi_msg_t = tmp;
1166               ctx->vl_msg_id_max = id;
1167             }
1168           ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
1169           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
1170         }
1171       else
1172         {
1173           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
1174           VAPI_DBG ("Message `%s' not available", m->name_with_crc);
1175         }
1176     }
1177   if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
1178       !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
1179     {
1180       VAPI_ERR (
1181         "control ping or control ping reply not available, cannot connect");
1182       rv = VAPI_EINCOMPATIBLE;
1183       goto fail;
1184     }
1185   ctx->mode = mode;
1186   ctx->connected = true;
1187   if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
1188     {
1189       ctx->handle_keepalives = handle_keepalives;
1190     }
1191   else
1192     {
1193       ctx->handle_keepalives = false;
1194     }
1195   return VAPI_OK;
1196 fail:
1197   vapi_client_disconnect (ctx);
1198   return rv;
1199 }
1200
1201 vapi_error_e
1202 vapi_disconnect_from_vpp (vapi_ctx_t ctx)
1203 {
1204   if (!ctx->connected)
1205     {
1206       return VAPI_EINVAL;
1207     }
1208
1209   if (ctx->use_uds)
1210     {
1211       return VAPI_ENOTSUP;
1212     }
1213
1214   vl_api_memclnt_delete_reply_t *rp;
1215   svm_queue_t *vl_input_queue;
1216   time_t begin;
1217   vl_input_queue = ctx->vl_input_queue;
1218   vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
1219
1220   /*
1221    * Have to be careful here, in case the client is disconnecting
1222    * because e.g. the vlib process died, or is unresponsive.
1223    */
1224   begin = time (0);
1225   vapi_error_e rv = VAPI_OK;
1226   while (1)
1227     {
1228       time_t now;
1229
1230       now = time (0);
1231
1232       if (now >= (begin + 2))
1233         {
1234           clib_warning ("peer unresponsive, give up");
1235           ctx->my_client_index = ~0;
1236           rv = VAPI_ENORESP;
1237           goto fail;
1238         }
1239       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1240         continue;
1241
1242       VL_MSG_API_UNPOISON (rp);
1243
1244       /* drain the queue */
1245       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1246         {
1247           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1248           vl_msg_api_free (rp);
1249           continue;
1250         }
1251       vapi_memclnt_delete_reply_t_handler (
1252         ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1253       break;
1254     }
1255 fail:
1256   vapi_api_name_and_crc_free (ctx);
1257
1258   ctx->connected = false;
1259   return rv;
1260 }
1261
1262 static vapi_error_e
1263 vapi_shm_disconnect (vapi_ctx_t ctx)
1264 {
1265   vl_api_memclnt_delete_reply_t *rp;
1266   svm_queue_t *vl_input_queue;
1267   time_t begin;
1268   vl_input_queue = ctx->vl_input_queue;
1269   vapi_shm_client_send_disconnect (ctx, 0 /* wait for reply */);
1270
1271   /*
1272    * Have to be careful here, in case the client is disconnecting
1273    * because e.g. the vlib process died, or is unresponsive.
1274    */
1275   begin = time (0);
1276   vapi_error_e rv = VAPI_OK;
1277   while (1)
1278     {
1279       time_t now;
1280
1281       now = time (0);
1282
1283       if (now >= (begin + 2))
1284         {
1285           clib_warning ("peer unresponsive, give up");
1286           ctx->my_client_index = ~0;
1287           rv = VAPI_ENORESP;
1288           goto fail;
1289         }
1290       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
1291         continue;
1292
1293       VL_MSG_API_UNPOISON (rp);
1294
1295       /* drain the queue */
1296       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
1297         {
1298           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1299           vl_msg_api_free (rp);
1300           continue;
1301         }
1302       vapi_memclnt_delete_reply_t_handler (
1303         ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1304       break;
1305     }
1306 fail:
1307   vapi_api_name_and_crc_free (ctx);
1308
1309   vl_client_api_unmap ();
1310 #if VAPI_DEBUG_ALLOC
1311   vapi_to_be_freed_validate ();
1312 #endif
1313   ctx->connected = false;
1314   return rv;
1315 }
1316
1317 static vapi_error_e
1318 vapi_sock_disconnect (vapi_ctx_t ctx)
1319 {
1320   vl_api_sockclnt_delete_reply_t *rp;
1321   time_t begin;
1322   u8 *msg = 0;
1323
1324   vapi_sock_client_send_disconnect (ctx);
1325
1326   begin = time (0);
1327   vapi_error_e rv = VAPI_OK;
1328   while (1)
1329     {
1330       time_t now;
1331
1332       now = time (0);
1333
1334       if (now >= (begin + 2))
1335         {
1336           clib_warning ("peer unresponsive, give up");
1337           ctx->my_client_index = ~0;
1338           rv = VAPI_ENORESP;
1339           goto fail;
1340         }
1341       if (vapi_sock_recv_internal (ctx, &msg, 0) < 0)
1342         continue;
1343
1344       if (vec_len (msg) == 0)
1345         continue;
1346
1347       rp = (void *) msg;
1348
1349       /* drain the queue */
1350       if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_DELETE_REPLY)
1351         {
1352           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
1353           continue;
1354         }
1355       vapi_sockclnt_delete_reply_t_handler (
1356         ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
1357       break;
1358     }
1359 fail:
1360   clib_socket_close (&ctx->client_socket);
1361   vapi_api_name_and_crc_free (ctx);
1362
1363   ctx->connected = false;
1364   return rv;
1365 }
1366
1367 vapi_error_e
1368 vapi_disconnect (vapi_ctx_t ctx)
1369 {
1370   if (!ctx->connected)
1371     {
1372       return VAPI_EINVAL;
1373     }
1374
1375   if (ctx->use_uds)
1376     {
1377       return vapi_sock_disconnect (ctx);
1378     }
1379   return vapi_shm_disconnect (ctx);
1380 }
1381
1382 vapi_error_e
1383 vapi_get_fd (vapi_ctx_t ctx, int *fd)
1384 {
1385   if (ctx->use_uds && fd)
1386     {
1387       *fd = ctx->client_socket.fd;
1388       return VAPI_OK;
1389     }
1390   return VAPI_ENOTSUP;
1391 }
1392
1393 #if VAPI_DEBUG
1394 static void
1395 vapi_debug_log (vapi_ctx_t ctx, void *msg, const char *fun)
1396 {
1397   unsigned msgid = be16toh (*(u16 *) msg);
1398   if (msgid <= ctx->vl_msg_id_max)
1399     {
1400       vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
1401       if (id < __vapi_metadata.count)
1402         {
1403           VAPI_DBG ("%s msg@%p:%u[%s]", fun, msg, msgid,
1404                     __vapi_metadata.msgs[id]->name);
1405         }
1406       else
1407         {
1408           VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1409         }
1410     }
1411   else
1412     {
1413       VAPI_DBG ("%s msg@%p:%u[UNKNOWN]", fun, msg, msgid);
1414     }
1415 }
1416 #endif
1417
1418 static vapi_error_e
1419 vapi_shm_send (vapi_ctx_t ctx, void *msg)
1420 {
1421   int rv = VAPI_OK;
1422   int tmp;
1423   svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1424 #if VAPI_DEBUG
1425   vapi_debug_log (ctx, msg, "send");
1426 #endif
1427   tmp =
1428     svm_queue_add (q, (u8 *) &msg, VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
1429   if (tmp < 0)
1430     {
1431       rv = VAPI_EAGAIN;
1432     }
1433   else
1434     VL_MSG_API_POISON (msg);
1435
1436   return rv;
1437 }
1438
1439 vapi_error_e
1440 vapi_send (vapi_ctx_t ctx, void *msg)
1441 {
1442   vapi_error_e rv = VAPI_OK;
1443   if (!ctx || !msg || !ctx->connected)
1444     {
1445       rv = VAPI_EINVAL;
1446       goto out;
1447     }
1448
1449   if (ctx->use_uds)
1450     {
1451       rv = vapi_sock_send (ctx, msg);
1452     }
1453   else
1454     {
1455       rv = vapi_shm_send (ctx, msg);
1456     }
1457
1458 out:
1459   VAPI_DBG ("vapi_send() rv = %d", rv);
1460   return rv;
1461 }
1462
1463 static vapi_error_e
1464 vapi_shm_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1465 {
1466   vapi_error_e rv = VAPI_OK;
1467   svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
1468 #if VAPI_DEBUG
1469   vapi_debug_log (ctx, msg1, "send2");
1470   vapi_debug_log (ctx, msg2, "send2");
1471 #endif
1472   int tmp = svm_queue_add2 (q, (u8 *) &msg1, (u8 *) &msg2,
1473                             VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
1474   if (tmp < 0)
1475     {
1476       rv = VAPI_EAGAIN;
1477     }
1478   else
1479     VL_MSG_API_POISON (msg1);
1480
1481   return rv;
1482 }
1483
1484 vapi_error_e
1485 vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
1486 {
1487   vapi_error_e rv = VAPI_OK;
1488   if (!ctx || !msg1 || !msg2 || !ctx->connected)
1489     {
1490       rv = VAPI_EINVAL;
1491       goto out;
1492     }
1493
1494   if (ctx->use_uds)
1495     {
1496       rv = vapi_sock_send2 (ctx, msg1, msg2);
1497     }
1498   else
1499     {
1500       rv = vapi_shm_send2 (ctx, msg1, msg2);
1501     }
1502
1503 out:
1504   VAPI_DBG ("vapi_send() rv = %d", rv);
1505   return rv;
1506 }
1507
1508 static vapi_error_e
1509 vapi_shm_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1510                svm_q_conditional_wait_t cond, u32 time)
1511 {
1512   vapi_error_e rv = VAPI_OK;
1513   uword data;
1514
1515   svm_queue_t *q = ctx->vl_input_queue;
1516
1517   VAPI_DBG ("doing shm queue sub");
1518
1519   int tmp = svm_queue_sub (q, (u8 *) & data, cond, time);
1520
1521   if (tmp != 0)
1522     {
1523       return VAPI_EAGAIN;
1524     }
1525
1526       VL_MSG_API_UNPOISON ((void *) data);
1527 #if VAPI_DEBUG_ALLOC
1528       vapi_add_to_be_freed ((void *) data);
1529 #endif
1530       msgbuf_t *msgbuf =
1531         (msgbuf_t *) ((u8 *) data - offsetof (msgbuf_t, data));
1532       if (!msgbuf->data_len)
1533         {
1534           vapi_msg_free (ctx, (u8 *) data);
1535           return VAPI_EAGAIN;
1536         }
1537       *msg = (u8 *) data;
1538       *msg_size = ntohl (msgbuf->data_len);
1539
1540 #if VAPI_DEBUG
1541       vapi_debug_log (ctx, msg, "recv");
1542 #endif
1543
1544       return rv;
1545 }
1546
1547 static vapi_error_e
1548 vapi_sock_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size, u32 time)
1549 {
1550   vapi_error_e rv = VAPI_OK;
1551   u8 *data = 0;
1552   if (time == 0 && ctx->mode == VAPI_MODE_BLOCKING)
1553     time = 1;
1554
1555   rv = vapi_sock_recv_internal (ctx, &data, time);
1556
1557   if (rv != VAPI_OK)
1558     {
1559       return rv;
1560     }
1561
1562   *msg = data;
1563   *msg_size = vec_len (data);
1564
1565 #if VAPI_DEBUG
1566   vapi_debug_log (ctx, msg, "recv");
1567 #endif
1568
1569   return rv;
1570 }
1571
1572 vapi_error_e
1573 vapi_recv (vapi_ctx_t ctx, void **msg, size_t *msg_size,
1574            svm_q_conditional_wait_t cond, u32 time)
1575 {
1576   if (!ctx || !ctx->connected || !msg || !msg_size)
1577     {
1578       return VAPI_EINVAL;
1579     }
1580   vapi_error_e rv = VAPI_OK;
1581
1582 again:
1583   if (ctx->use_uds)
1584     {
1585       rv = vapi_sock_recv (ctx, msg, msg_size, time);
1586     }
1587   else
1588     {
1589       rv = vapi_shm_recv (ctx, msg, msg_size, cond, time);
1590     }
1591
1592   if (rv != VAPI_OK)
1593     return rv;
1594
1595   if (ctx->handle_keepalives)
1596     {
1597       unsigned msgid = be16toh (*(u16 *) *msg);
1598       if (msgid == vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive))
1599         {
1600           vapi_msg_memclnt_keepalive_reply *reply = NULL;
1601           do
1602             {
1603               reply = vapi_msg_alloc (ctx, sizeof (*reply));
1604             }
1605           while (!reply);
1606           reply->header.context = vapi_get_client_index (ctx);
1607           reply->header._vl_msg_id =
1608             vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive_reply);
1609           reply->payload.retval = 0;
1610           vapi_msg_memclnt_keepalive_reply_hton (reply);
1611           while (VAPI_EAGAIN == vapi_send (ctx, reply))
1612             ;
1613           vapi_msg_free (ctx, *msg);
1614           goto again;
1615         }
1616     }
1617
1618   return rv;
1619 }
1620
1621 vapi_error_e
1622 vapi_wait (vapi_ctx_t ctx)
1623 {
1624   if (ctx->use_uds)
1625     return VAPI_ENOTSUP;
1626
1627   svm_queue_lock (ctx->vl_input_queue);
1628   svm_queue_wait (ctx->vl_input_queue);
1629   svm_queue_unlock (ctx->vl_input_queue);
1630
1631   return VAPI_OK;
1632 }
1633
1634 static vapi_error_e
1635 vapi_dispatch_response (vapi_ctx_t ctx, vapi_msg_id_t id,
1636                         u32 context, void *msg)
1637 {
1638   int mrv;
1639   if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1640     {
1641       VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1642       return VAPI_MUTEX_FAILURE;
1643     }
1644   int tmp = ctx->requests_start;
1645   const int requests_end = vapi_requests_end (ctx);
1646   while (ctx->requests[tmp].context != context && tmp != requests_end)
1647     {
1648       ++tmp;
1649       if (tmp == ctx->requests_size)
1650         {
1651           tmp = 0;
1652         }
1653     }
1654   VAPI_DBG ("dispatch, search from %d, %s at %d", ctx->requests_start,
1655             ctx->requests[tmp].context == context ? "matched" : "stopped",
1656             tmp);
1657   vapi_error_e rv = VAPI_OK;
1658   if (ctx->requests[tmp].context == context)
1659     {
1660       while (ctx->requests_start != tmp)
1661         {
1662           VAPI_ERR ("No response to req with context=%u",
1663                     (unsigned) ctx->requests[tmp].context);
1664           ctx->requests[ctx->requests_start].callback (ctx, ctx->requests
1665                                                        [ctx->
1666                                                         requests_start].callback_ctx,
1667                                                        VAPI_ENORESP, true,
1668                                                        NULL);
1669           clib_memset (&ctx->requests[ctx->requests_start], 0,
1670                        sizeof (ctx->requests[ctx->requests_start]));
1671           ++ctx->requests_start;
1672           --ctx->requests_count;
1673           if (ctx->requests_start == ctx->requests_size)
1674             {
1675               ctx->requests_start = 0;
1676             }
1677         }
1678       // now ctx->requests_start == tmp
1679       int payload_offset = vapi_get_payload_offset (id);
1680       void *payload = ((u8 *) msg) + payload_offset;
1681       bool is_last = true;
1682       switch (ctx->requests[tmp].type)
1683         {
1684         case VAPI_REQUEST_STREAM:
1685           if (ctx->requests[tmp].response_id == id)
1686             {
1687               is_last = false;
1688             }
1689           else
1690             {
1691               VAPI_DBG ("Stream response ID doesn't match current ID, move to "
1692                         "next ID");
1693               clib_memset (&ctx->requests[tmp], 0,
1694                            sizeof (ctx->requests[tmp]));
1695               ++ctx->requests_start;
1696               --ctx->requests_count;
1697               if (ctx->requests_start == ctx->requests_size)
1698                 {
1699                   ctx->requests_start = 0;
1700                 }
1701               tmp = ctx->requests_start;
1702               if (ctx->requests[tmp].context != context)
1703                 {
1704                   VAPI_ERR ("Unexpected context %u, expected context %u!",
1705                             ctx->requests[tmp].context, context);
1706                 }
1707             }
1708           break;
1709         case VAPI_REQUEST_DUMP:
1710           if (vapi_msg_id_control_ping_reply == id)
1711             {
1712               payload = NULL;
1713             }
1714           else
1715             {
1716               is_last = false;
1717             }
1718           break;
1719         case VAPI_REQUEST_REG:
1720           break;
1721         }
1722       if (payload_offset != -1)
1723         {
1724           rv = ctx->requests[tmp].callback (
1725             ctx, ctx->requests[tmp].callback_ctx, VAPI_OK, is_last, payload);
1726         }
1727       else
1728         {
1729           /* this is a message without payload, so bend the callback a little
1730            */
1731           rv =
1732             ((vapi_error_e (*)(vapi_ctx_t, void *, vapi_error_e, bool))
1733              ctx->requests[tmp].callback) (ctx,
1734                                            ctx->requests[tmp].callback_ctx,
1735                                            VAPI_OK, is_last);
1736         }
1737       if (is_last)
1738         {
1739           clib_memset (&ctx->requests[ctx->requests_start], 0,
1740                        sizeof (ctx->requests[ctx->requests_start]));
1741           ++ctx->requests_start;
1742           --ctx->requests_count;
1743           if (ctx->requests_start == ctx->requests_size)
1744             {
1745               ctx->requests_start = 0;
1746             }
1747         }
1748       VAPI_DBG ("after dispatch, req start = %d, end = %d, count = %d",
1749                 ctx->requests_start, requests_end, ctx->requests_count);
1750     }
1751   if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1752     {
1753       VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1754                 strerror (mrv));
1755       abort ();                 /* this really shouldn't happen */
1756     }
1757   return rv;
1758 }
1759
1760 static vapi_error_e
1761 vapi_dispatch_event (vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
1762 {
1763   if (ctx->event_cbs[id].cb)
1764     {
1765       return ctx->event_cbs[id].cb (ctx, ctx->event_cbs[id].ctx, msg);
1766     }
1767   else if (ctx->generic_cb.cb)
1768     {
1769       return ctx->generic_cb.cb (ctx, ctx->generic_cb.ctx, id, msg);
1770     }
1771   else
1772     {
1773       VAPI_DBG
1774         ("No handler/generic handler for msg id %u[%s], message ignored",
1775          (unsigned) id, __vapi_metadata.msgs[id]->name);
1776     }
1777   return VAPI_OK;
1778 }
1779
1780 bool
1781 vapi_msg_is_with_context (vapi_msg_id_t id)
1782 {
1783   assert (id <= __vapi_metadata.count);
1784   return __vapi_metadata.msgs[id]->has_context;
1785 }
1786
1787 static int
1788 vapi_verify_msg_size (vapi_msg_id_t id, void *buf, uword buf_size)
1789 {
1790   assert (id < __vapi_metadata.count);
1791   return __vapi_metadata.msgs[id]->verify_msg_size (buf, buf_size);
1792 }
1793
1794 vapi_error_e
1795 vapi_dispatch_one (vapi_ctx_t ctx)
1796 {
1797   VAPI_DBG ("vapi_dispatch_one()");
1798   void *msg;
1799   uword size;
1800   svm_q_conditional_wait_t cond =
1801     vapi_is_nonblocking (ctx) ? SVM_Q_NOWAIT : SVM_Q_WAIT;
1802   vapi_error_e rv = vapi_recv (ctx, &msg, &size, cond, 0);
1803   if (VAPI_OK != rv)
1804     {
1805       VAPI_DBG ("vapi_recv failed with rv=%d", rv);
1806       return rv;
1807     }
1808   u16 vpp_id = be16toh (*(u16 *) msg);
1809   if (vpp_id > ctx->vl_msg_id_max)
1810     {
1811       VAPI_ERR ("Unknown msg ID received, id `%u', out of range <0,%u>",
1812                 (unsigned) vpp_id, (unsigned) ctx->vl_msg_id_max);
1813       vapi_msg_free (ctx, msg);
1814       return VAPI_EINVAL;
1815     }
1816   if (VAPI_INVALID_MSG_ID == (unsigned) ctx->vl_msg_id_to_vapi_msg_t[vpp_id])
1817     {
1818       VAPI_ERR ("Unknown msg ID received, id `%u' marked as not supported",
1819                 (unsigned) vpp_id);
1820       vapi_msg_free (ctx, msg);
1821       return VAPI_EINVAL;
1822     }
1823   const vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[vpp_id];
1824   vapi_get_swap_to_host_func (id) (msg);
1825   if (vapi_verify_msg_size (id, msg, size))
1826     {
1827       vapi_msg_free (ctx, msg);
1828       return VAPI_EINVAL;
1829     }
1830   u32 context;
1831   if (vapi_msg_is_with_context (id))
1832     {
1833       context = *(u32 *) (((u8 *) msg) + vapi_get_context_offset (id));
1834       /* is this a message originating from VAPI? */
1835       VAPI_DBG ("dispatch, context is %x", context);
1836       if (context & context_counter_mask)
1837         {
1838           rv = vapi_dispatch_response (ctx, id, context, msg);
1839           goto done;
1840         }
1841     }
1842   rv = vapi_dispatch_event (ctx, id, msg);
1843
1844 done:
1845   vapi_msg_free (ctx, msg);
1846   return rv;
1847 }
1848
1849 vapi_error_e
1850 vapi_dispatch (vapi_ctx_t ctx)
1851 {
1852   vapi_error_e rv = VAPI_OK;
1853   while (!vapi_requests_empty (ctx))
1854     {
1855       rv = vapi_dispatch_one (ctx);
1856       if (VAPI_OK != rv)
1857         {
1858           return rv;
1859         }
1860     }
1861   return rv;
1862 }
1863
1864 void
1865 vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
1866                    vapi_event_cb callback, void *callback_ctx)
1867 {
1868   vapi_event_cb_with_ctx *c = &ctx->event_cbs[id];
1869   c->cb = callback;
1870   c->ctx = callback_ctx;
1871 }
1872
1873 void
1874 vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id)
1875 {
1876   vapi_set_event_cb (ctx, id, NULL, NULL);
1877 }
1878
1879 void
1880 vapi_set_generic_event_cb (vapi_ctx_t ctx, vapi_generic_event_cb callback,
1881                            void *callback_ctx)
1882 {
1883   ctx->generic_cb.cb = callback;
1884   ctx->generic_cb.ctx = callback_ctx;
1885 }
1886
1887 void
1888 vapi_clear_generic_event_cb (vapi_ctx_t ctx)
1889 {
1890   ctx->generic_cb.cb = NULL;
1891   ctx->generic_cb.ctx = NULL;
1892 }
1893
1894 u16
1895 vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id)
1896 {
1897   assert (id < __vapi_metadata.count);
1898   return ctx->vapi_msg_id_t_to_vl_msg_id[id];
1899 }
1900
1901 int
1902 vapi_get_client_index (vapi_ctx_t ctx)
1903 {
1904   return ctx->my_client_index;
1905 }
1906
1907 bool
1908 vapi_is_nonblocking (vapi_ctx_t ctx)
1909 {
1910   return (VAPI_MODE_NONBLOCKING == ctx->mode);
1911 }
1912
1913 size_t
1914 vapi_get_max_request_count (vapi_ctx_t ctx)
1915 {
1916   return ctx->requests_size - 1;
1917 }
1918
1919 int
1920 vapi_get_payload_offset (vapi_msg_id_t id)
1921 {
1922   assert (id < __vapi_metadata.count);
1923   return __vapi_metadata.msgs[id]->payload_offset;
1924 }
1925
1926 void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *msg)
1927 {
1928   assert (id < __vapi_metadata.count);
1929   return __vapi_metadata.msgs[id]->swap_to_host;
1930 }
1931
1932 void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *msg)
1933 {
1934   assert (id < __vapi_metadata.count);
1935   return __vapi_metadata.msgs[id]->swap_to_be;
1936 }
1937
1938 size_t
1939 vapi_get_context_offset (vapi_msg_id_t id)
1940 {
1941   assert (id < __vapi_metadata.count);
1942   return __vapi_metadata.msgs[id]->context_offset;
1943 }
1944
1945 vapi_msg_id_t
1946 vapi_register_msg (vapi_message_desc_t * msg)
1947 {
1948   int i = 0;
1949   for (i = 0; i < __vapi_metadata.count; ++i)
1950     {
1951       if (!strcmp
1952           (msg->name_with_crc, __vapi_metadata.msgs[i]->name_with_crc))
1953         {
1954           /* this happens if somebody is linking together several objects while
1955            * using the static inline headers, just fill in the already
1956            * assigned id here so that all the objects are in sync */
1957           msg->id = __vapi_metadata.msgs[i]->id;
1958           return msg->id;
1959         }
1960     }
1961   vapi_msg_id_t id = __vapi_metadata.count;
1962   ++__vapi_metadata.count;
1963   __vapi_metadata.msgs =
1964     realloc (__vapi_metadata.msgs,
1965              sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
1966   __vapi_metadata.msgs[id] = msg;
1967   size_t s = strlen (msg->name_with_crc);
1968   if (s > __vapi_metadata.max_len_name_with_crc)
1969     {
1970       __vapi_metadata.max_len_name_with_crc = s;
1971     }
1972   msg->id = id;
1973   return id;
1974 }
1975
1976 vapi_error_e
1977 vapi_producer_lock (vapi_ctx_t ctx)
1978 {
1979   int mrv;
1980   if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
1981     {
1982       VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
1983       (void) mrv;               /* avoid warning if the above debug is not enabled */
1984       return VAPI_MUTEX_FAILURE;
1985     }
1986   return VAPI_OK;
1987 }
1988
1989 vapi_error_e
1990 vapi_producer_unlock (vapi_ctx_t ctx)
1991 {
1992   int mrv;
1993   if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
1994     {
1995       VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
1996                 strerror (mrv));
1997       (void) mrv;               /* avoid warning if the above debug is not enabled */
1998       return VAPI_MUTEX_FAILURE;
1999     }
2000   return VAPI_OK;
2001 }
2002
2003 size_t
2004 vapi_get_message_count ()
2005 {
2006   return __vapi_metadata.count;
2007 }
2008
2009 const char *
2010 vapi_get_msg_name (vapi_msg_id_t id)
2011 {
2012   return __vapi_metadata.msgs[id]->name;
2013 }
2014
2015 void
2016 vapi_stop_rx_thread (vapi_ctx_t ctx)
2017 {
2018   if (!ctx || !ctx->connected || !ctx->vl_input_queue)
2019     {
2020       return;
2021     }
2022
2023   vl_client_stop_rx_thread (ctx->vl_input_queue);
2024 }
2025 /*
2026  * fd.io coding-style-patch-verification: ON
2027  *
2028  * Local Variables:
2029  * eval: (c-set-style "gnu")
2030  * End:
2031  */