LCOV - code coverage report
Current view: top level - vpp-api/vapi - vapi.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 420 566 74.2 %
Date: 2023-07-05 22:20:52 Functions: 43 53 81.1 %

          Line data    Source code
       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             :   bool is_dump;
      67             : } vapi_req_t;
      68             : 
      69             : static const u32 context_counter_mask = (1 << 31);
      70             : 
      71             : typedef struct
      72             : {
      73             :   vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, vapi_msg_id_t id,
      74             :                       void *payload);
      75             :   void *ctx;
      76             : } vapi_generic_cb_with_ctx;
      77             : 
      78             : typedef struct
      79             : {
      80             :   vapi_error_e (*cb) (vapi_ctx_t ctx, void *callback_ctx, void *payload);
      81             :   void *ctx;
      82             : } vapi_event_cb_with_ctx;
      83             : 
      84             : struct vapi_ctx_s
      85             : {
      86             :   vapi_mode_e mode;
      87             :   int requests_size;            /* size of the requests array (circular queue) */
      88             :   int requests_start;           /* index of first request */
      89             :   int requests_count;           /* number of used slots */
      90             :   vapi_req_t *requests;
      91             :   u32 context_counter;
      92             :   vapi_generic_cb_with_ctx generic_cb;
      93             :   vapi_event_cb_with_ctx *event_cbs;
      94             :   u16 *vapi_msg_id_t_to_vl_msg_id;
      95             :   u16 vl_msg_id_max;
      96             :   vapi_msg_id_t *vl_msg_id_to_vapi_msg_t;
      97             :   bool connected;
      98             :   bool handle_keepalives;
      99             :   pthread_mutex_t requests_mutex;
     100             : 
     101             :   svm_queue_t *vl_input_queue;
     102             :   u32 my_client_index;
     103             :   /** client message index hash table */
     104             :   uword *msg_index_by_name_and_crc;
     105             : };
     106             : 
     107             : u32
     108         289 : vapi_gen_req_context (vapi_ctx_t ctx)
     109             : {
     110         289 :   ++ctx->context_counter;
     111         289 :   ctx->context_counter %= context_counter_mask;
     112         289 :   return ctx->context_counter | context_counter_mask;
     113             : }
     114             : 
     115             : size_t
     116           0 : vapi_get_request_count (vapi_ctx_t ctx)
     117             : {
     118           0 :   return ctx->requests_count;
     119             : }
     120             : 
     121             : bool
     122         310 : vapi_requests_full (vapi_ctx_t ctx)
     123             : {
     124         310 :   return (ctx->requests_count == ctx->requests_size);
     125             : }
     126             : 
     127             : bool
     128      297428 : vapi_requests_empty (vapi_ctx_t ctx)
     129             : {
     130      297428 :   return (0 == ctx->requests_count);
     131             : }
     132             : 
     133             : static int
     134        1353 : vapi_requests_end (vapi_ctx_t ctx)
     135             : {
     136        1353 :   return (ctx->requests_start + ctx->requests_count) % ctx->requests_size;
     137             : }
     138             : 
     139             : void
     140         289 : vapi_store_request (vapi_ctx_t ctx, u32 context, bool is_dump,
     141             :                     vapi_cb_t callback, void *callback_ctx)
     142             : {
     143         289 :   assert (!vapi_requests_full (ctx));
     144             :   /* if the mutex is not held, bad things will happen */
     145         289 :   assert (0 != pthread_mutex_trylock (&ctx->requests_mutex));
     146         289 :   const int requests_end = vapi_requests_end (ctx);
     147         289 :   vapi_req_t *slot = &ctx->requests[requests_end];
     148         289 :   slot->is_dump = is_dump;
     149         289 :   slot->context = context;
     150         289 :   slot->callback = callback;
     151         289 :   slot->callback_ctx = callback_ctx;
     152             :   VAPI_DBG ("stored@%d: context:%x (start is @%d)", requests_end, context,
     153             :             ctx->requests_start);
     154         289 :   ++ctx->requests_count;
     155         289 :   assert (!vapi_requests_empty (ctx));
     156         289 : }
     157             : 
     158             : #if VAPI_DEBUG_ALLOC
     159             : struct to_be_freed_s;
     160             : struct to_be_freed_s
     161             : {
     162             :   void *v;
     163             :   struct to_be_freed_s *next;
     164             : };
     165             : 
     166             : static struct to_be_freed_s *to_be_freed = NULL;
     167             : 
     168             : void
     169             : vapi_add_to_be_freed (void *v)
     170             : {
     171             :   struct to_be_freed_s *prev = NULL;
     172             :   struct to_be_freed_s *tmp;
     173             :   tmp = to_be_freed;
     174             :   while (tmp && tmp->v)
     175             :     {
     176             :       prev = tmp;
     177             :       tmp = tmp->next;
     178             :     }
     179             :   if (!tmp)
     180             :     {
     181             :       if (!prev)
     182             :         {
     183             :           tmp = to_be_freed = calloc (1, sizeof (*to_be_freed));
     184             :         }
     185             :       else
     186             :         {
     187             :           tmp = prev->next = calloc (1, sizeof (*to_be_freed));
     188             :         }
     189             :     }
     190             :   VAPI_DBG ("To be freed %p", v);
     191             :   tmp->v = v;
     192             : }
     193             : 
     194             : void
     195             : vapi_trace_free (void *v)
     196             : {
     197             :   struct to_be_freed_s *tmp = to_be_freed;
     198             :   while (tmp && tmp->v != v)
     199             :     {
     200             :       tmp = tmp->next;
     201             :     }
     202             :   if (tmp && tmp->v == v)
     203             :     {
     204             :       VAPI_DBG ("Freed %p", v);
     205             :       tmp->v = NULL;
     206             :     }
     207             :   else
     208             :     {
     209             :       VAPI_ERR ("Trying to free untracked pointer %p", v);
     210             :       abort ();
     211             :     }
     212             : }
     213             : 
     214             : void
     215             : vapi_to_be_freed_validate ()
     216             : {
     217             :   struct to_be_freed_s *tmp = to_be_freed;
     218             :   while (tmp)
     219             :     {
     220             :       if (tmp->v)
     221             :         {
     222             :           VAPI_ERR ("Unfreed msg %p!", tmp->v);
     223             :         }
     224             :       tmp = tmp->next;
     225             :     }
     226             : }
     227             : 
     228             : #endif
     229             : 
     230             : void *
     231         457 : vapi_msg_alloc (vapi_ctx_t ctx, size_t size)
     232             : {
     233         457 :   if (!ctx->connected)
     234             :     {
     235           1 :       return NULL;
     236             :     }
     237         456 :   void *rv = vl_msg_api_alloc_as_if_client_or_null (size);
     238         456 :   if (rv)
     239             :     {
     240         456 :       clib_memset (rv, 0, size);
     241             :     }
     242         456 :   return rv;
     243             : }
     244             : 
     245             : void
     246        1107 : vapi_msg_free (vapi_ctx_t ctx, void *msg)
     247             : {
     248        1107 :   if (!ctx->connected)
     249             :     {
     250           0 :       return;
     251             :     }
     252             : #if VAPI_DEBUG_ALLOC
     253             :   vapi_trace_free (msg);
     254             : #endif
     255        1107 :   vl_msg_api_free (msg);
     256             : }
     257             : 
     258             : vapi_msg_id_t
     259          40 : vapi_lookup_vapi_msg_id_t (vapi_ctx_t ctx, u16 vl_msg_id)
     260             : {
     261          40 :   if (vl_msg_id <= ctx->vl_msg_id_max)
     262             :     {
     263          40 :       return ctx->vl_msg_id_to_vapi_msg_t[vl_msg_id];
     264             :     }
     265           0 :   return VAPI_INVALID_MSG_ID;
     266             : }
     267             : 
     268             : vapi_error_e
     269          19 : vapi_ctx_alloc (vapi_ctx_t * result)
     270             : {
     271          19 :   vapi_ctx_t ctx = calloc (1, sizeof (struct vapi_ctx_s));
     272          19 :   if (!ctx)
     273             :     {
     274           0 :       return VAPI_ENOMEM;
     275             :     }
     276          19 :   ctx->context_counter = 0;
     277          19 :   ctx->vapi_msg_id_t_to_vl_msg_id =
     278          19 :     malloc (__vapi_metadata.count *
     279             :             sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
     280          19 :   if (!ctx->vapi_msg_id_t_to_vl_msg_id)
     281             :     {
     282           0 :       goto fail;
     283             :     }
     284          19 :   clib_memset (ctx->vapi_msg_id_t_to_vl_msg_id, ~0,
     285             :                __vapi_metadata.count *
     286             :                sizeof (*ctx->vapi_msg_id_t_to_vl_msg_id));
     287          19 :   ctx->event_cbs = calloc (__vapi_metadata.count, sizeof (*ctx->event_cbs));
     288          19 :   if (!ctx->event_cbs)
     289             :     {
     290           0 :       goto fail;
     291             :     }
     292          19 :   pthread_mutex_init (&ctx->requests_mutex, NULL);
     293          19 :   *result = ctx;
     294          19 :   return VAPI_OK;
     295           0 : fail:
     296           0 :   vapi_ctx_free (ctx);
     297           0 :   return VAPI_ENOMEM;
     298             : }
     299             : 
     300             : void
     301          19 : vapi_ctx_free (vapi_ctx_t ctx)
     302             : {
     303          19 :   assert (!ctx->connected);
     304          19 :   free (ctx->requests);
     305          19 :   free (ctx->vapi_msg_id_t_to_vl_msg_id);
     306          19 :   free (ctx->event_cbs);
     307          19 :   free (ctx->vl_msg_id_to_vapi_msg_t);
     308          19 :   pthread_mutex_destroy (&ctx->requests_mutex);
     309          19 :   free (ctx);
     310          19 : }
     311             : 
     312             : bool
     313         120 : vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t id)
     314             : {
     315         120 :   return vapi_lookup_vl_msg_id (ctx, id) != UINT16_MAX;
     316             : }
     317             : 
     318             : /* Cut and paste to avoid adding dependency to client library */
     319             : __clib_nosanitize_addr static void
     320          18 : VL_API_VEC_UNPOISON (const void *v)
     321             : {
     322          18 :   const vec_header_t *vh = &((vec_header_t *) v)[-1];
     323          18 :   clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
     324          18 : }
     325             : 
     326             : static void
     327          36 : vapi_api_name_and_crc_free (vapi_ctx_t ctx)
     328             : {
     329             :   int i;
     330          36 :   u8 **keys = 0;
     331             :   hash_pair_t *hp;
     332             : 
     333          36 :   if (!ctx->msg_index_by_name_and_crc)
     334          18 :     return;
     335      105084 :   hash_foreach_pair (hp, ctx->msg_index_by_name_and_crc,
     336             :                      ({ vec_add1 (keys, (u8 *) hp->key); }));
     337       31356 :   for (i = 0; i < vec_len (keys); i++)
     338       31338 :     vec_free (keys[i]);
     339          18 :   vec_free (keys);
     340          18 :   hash_free (ctx->msg_index_by_name_and_crc);
     341             : }
     342             : 
     343             : static void
     344          18 : vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
     345             :                                         vl_api_memclnt_create_v2_reply_t *mp)
     346             : {
     347          18 :   serialize_main_t _sm, *sm = &_sm;
     348             :   u8 *tblv;
     349             :   u32 nmsgs;
     350             :   int i;
     351             :   u8 *name_and_crc;
     352             :   u32 msg_index;
     353             : 
     354          18 :   ctx->my_client_index = mp->index;
     355             : 
     356             :   /* Clean out any previous hash table (unlikely) */
     357          18 :   vapi_api_name_and_crc_free (ctx);
     358             : 
     359          18 :   ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
     360             : 
     361             :   /* Recreate the vnet-side API message handler table */
     362          18 :   tblv = uword_to_pointer (mp->message_table, u8 *);
     363          18 :   unserialize_open_data (sm, tblv, vec_len (tblv));
     364          18 :   unserialize_integer (sm, &nmsgs, sizeof (u32));
     365             : 
     366          18 :   VL_API_VEC_UNPOISON (tblv);
     367             : 
     368       31356 :   for (i = 0; i < nmsgs; i++)
     369             :     {
     370       31338 :       msg_index = unserialize_likely_small_unsigned_integer (sm);
     371       31338 :       unserialize_cstring (sm, (char **) &name_and_crc);
     372       62676 :       hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc, msg_index);
     373             :     }
     374          18 : }
     375             : 
     376             : static void
     377          18 : vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
     378             :                                      vl_api_memclnt_delete_reply_t *mp)
     379             : {
     380             :   void *oldheap;
     381          18 :   oldheap = vl_msg_push_heap ();
     382          18 :   svm_queue_free (ctx->vl_input_queue);
     383          18 :   vl_msg_pop_heap (oldheap);
     384             : 
     385          18 :   ctx->my_client_index = ~0;
     386          18 :   ctx->vl_input_queue = 0;
     387          18 : }
     388             : 
     389             : static int
     390          18 : vapi_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
     391             :                      int input_queue_size, bool keepalive)
     392             : {
     393             :   vl_api_memclnt_create_v2_t *mp;
     394             :   vl_api_memclnt_create_v2_reply_t *rp;
     395             :   svm_queue_t *vl_input_queue;
     396             :   vl_shmem_hdr_t *shmem_hdr;
     397          18 :   int rv = 0;
     398             :   void *oldheap;
     399          18 :   api_main_t *am = vlibapi_get_main ();
     400             : 
     401          18 :   shmem_hdr = am->shmem_hdr;
     402             : 
     403          18 :   if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
     404             :     {
     405           0 :       clib_warning ("shmem_hdr / input queue NULL");
     406           0 :       return -1;
     407             :     }
     408             : 
     409          18 :   clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
     410          18 :   VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
     411             : 
     412          18 :   oldheap = vl_msg_push_heap ();
     413             :   vl_input_queue =
     414          18 :     svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
     415          18 :   vl_msg_pop_heap (oldheap);
     416             : 
     417          18 :   ctx->my_client_index = ~0;
     418          18 :   ctx->vl_input_queue = vl_input_queue;
     419             : 
     420          18 :   mp = vl_msg_api_alloc_as_if_client (sizeof (vl_api_memclnt_create_v2_t));
     421          18 :   clib_memset (mp, 0, sizeof (*mp));
     422          18 :   mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2);
     423          18 :   mp->ctx_quota = ctx_quota;
     424          18 :   mp->input_queue = (uword) vl_input_queue;
     425          18 :   strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
     426          18 :   mp->keepalive = keepalive;
     427             : 
     428          18 :   vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
     429             : 
     430             :   while (1)
     431           0 :     {
     432             :       int qstatus;
     433             :       struct timespec ts, tsrem;
     434             :       int i;
     435             : 
     436             :       /* Wait up to 10 seconds */
     437          37 :       for (i = 0; i < 1000; i++)
     438             :         {
     439             :           qstatus =
     440          37 :             svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
     441          37 :           if (qstatus == 0)
     442          18 :             goto read_one_msg;
     443          19 :           ts.tv_sec = 0;
     444          19 :           ts.tv_nsec = 10000 * 1000; /* 10 ms */
     445          19 :           while (nanosleep (&ts, &tsrem) < 0)
     446           0 :             ts = tsrem;
     447             :         }
     448             :       /* Timeout... */
     449           0 :       return -1;
     450             : 
     451          18 :     read_one_msg:
     452          18 :       VL_MSG_API_UNPOISON (rp);
     453          18 :       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
     454             :         {
     455           0 :           clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
     456           0 :           continue;
     457             :         }
     458          18 :       rv = clib_net_to_host_u32 (rp->response);
     459          18 :       vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
     460          18 :       break;
     461             :     }
     462          18 :   return (rv);
     463             : }
     464             : 
     465             : static void
     466          18 : vapi_client_send_disconnect (vapi_ctx_t ctx, u8 do_cleanup)
     467             : {
     468             :   vl_api_memclnt_delete_t *mp;
     469             :   vl_shmem_hdr_t *shmem_hdr;
     470          18 :   api_main_t *am = vlibapi_get_main ();
     471             : 
     472          18 :   ASSERT (am->vlib_rp);
     473          18 :   shmem_hdr = am->shmem_hdr;
     474          18 :   ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
     475             : 
     476          18 :   mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
     477          18 :   clib_memset (mp, 0, sizeof (*mp));
     478          18 :   mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
     479          18 :   mp->index = ctx->my_client_index;
     480          18 :   mp->do_cleanup = do_cleanup;
     481             : 
     482          18 :   vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
     483          18 : }
     484             : 
     485             : static int
     486           0 : vapi_client_disconnect (vapi_ctx_t ctx)
     487             : {
     488             :   vl_api_memclnt_delete_reply_t *rp;
     489             :   svm_queue_t *vl_input_queue;
     490             :   time_t begin;
     491             :   msgbuf_t *msgbuf;
     492             : 
     493           0 :   vl_input_queue = ctx->vl_input_queue;
     494           0 :   vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
     495             : 
     496             :   /*
     497             :    * Have to be careful here, in case the client is disconnecting
     498             :    * because e.g. the vlib process died, or is unresponsive.
     499             :    */
     500           0 :   begin = time (0);
     501             :   while (1)
     502           0 :     {
     503             :       time_t now;
     504             : 
     505           0 :       now = time (0);
     506             : 
     507           0 :       if (now >= (begin + 2))
     508             :         {
     509           0 :           clib_warning ("peer unresponsive, give up");
     510           0 :           ctx->my_client_index = ~0;
     511           0 :           return -1;
     512             :         }
     513           0 :       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
     514           0 :         continue;
     515             : 
     516           0 :       VL_MSG_API_UNPOISON (rp);
     517             : 
     518             :       /* drain the queue */
     519           0 :       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
     520             :         {
     521           0 :           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
     522           0 :           msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
     523           0 :           vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
     524           0 :           continue;
     525             :         }
     526           0 :       msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
     527           0 :       vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
     528           0 :       break;
     529             :     }
     530             : 
     531           0 :   vapi_api_name_and_crc_free (ctx);
     532           0 :   return 0;
     533             : }
     534             : 
     535             : u32
     536        2819 : vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
     537             : {
     538             :   uword *p;
     539             : 
     540        2819 :   if (ctx->msg_index_by_name_and_crc)
     541             :     {
     542        2819 :       p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
     543        2819 :       if (p)
     544        2751 :         return p[0];
     545             :     }
     546          68 :   return ~0;
     547             : }
     548             : 
     549             : vapi_error_e
     550          17 : vapi_connect (vapi_ctx_t ctx, const char *name, const char *chroot_prefix,
     551             :               int max_outstanding_requests, int response_queue_size,
     552             :               vapi_mode_e mode, bool handle_keepalives)
     553             : {
     554             :   int rv;
     555             : 
     556          17 :   if (response_queue_size <= 0 || max_outstanding_requests <= 0)
     557             :     {
     558           0 :       return VAPI_EINVAL;
     559             :     }
     560          17 :   if (!clib_mem_get_per_cpu_heap () && !clib_mem_init (0, 1024 * 1024 * 32))
     561             :     {
     562           0 :       return VAPI_ENOMEM;
     563             :     }
     564             : 
     565          17 :   ctx->requests_size = max_outstanding_requests;
     566          17 :   const size_t size = ctx->requests_size * sizeof (*ctx->requests);
     567          17 :   void *tmp = realloc (ctx->requests, size);
     568          17 :   if (!tmp)
     569             :     {
     570           0 :       return VAPI_ENOMEM;
     571             :     }
     572          17 :   ctx->requests = tmp;
     573          17 :   clib_memset (ctx->requests, 0, size);
     574             :   /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
     575          17 :   ctx->requests_start = ctx->requests_count = 0;
     576             : 
     577          17 :   if (chroot_prefix)
     578             :     {
     579             :       VAPI_DBG ("set memory root path `%s'", chroot_prefix);
     580          17 :       vl_set_memory_root_path ((char *) chroot_prefix);
     581             :     }
     582             :   static char api_map[] = "/vpe-api";
     583             :   VAPI_DBG ("client api map `%s'", api_map);
     584          17 :   if ((rv = vl_map_shmem (api_map, 0 /* is_vlib */)) < 0)
     585             :     {
     586           0 :       return VAPI_EMAP_FAIL;
     587             :     }
     588             :   VAPI_DBG ("connect client `%s'", name);
     589          17 :   if (vapi_client_connect (ctx, (char *) name, 0, response_queue_size, true) <
     590             :       0)
     591             :     {
     592           0 :       vl_client_api_unmap ();
     593           0 :       return VAPI_ECON_FAIL;
     594             :     }
     595             : #if VAPI_DEBUG_CONNECT
     596             :   VAPI_DBG ("start probing messages");
     597             : #endif
     598             : 
     599             :   int i;
     600        2791 :   for (i = 0; i < __vapi_metadata.count; ++i)
     601        2774 :     {
     602        2774 :       vapi_message_desc_t *m = __vapi_metadata.msgs[i];
     603        2774 :       u8 scratch[m->name_with_crc_len + 1];
     604        2774 :       memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
     605        2774 :       u32 id = vapi_api_get_msg_index (ctx, scratch);
     606             : 
     607        2774 :       if (VAPI_INVALID_MSG_ID != id)
     608             :         {
     609        2706 :           if (id > UINT16_MAX)
     610             :             {
     611             :               VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
     612             :                         UINT16_MAX);
     613           0 :               rv = VAPI_EINVAL;
     614           0 :               goto fail;
     615             :             }
     616        2706 :           if (id > ctx->vl_msg_id_max)
     617             :             {
     618             :               vapi_msg_id_t *tmp =
     619         391 :                 realloc (ctx->vl_msg_id_to_vapi_msg_t,
     620         391 :                          sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
     621         391 :               if (!tmp)
     622             :                 {
     623           0 :                   rv = VAPI_ENOMEM;
     624           0 :                   goto fail;
     625             :                 }
     626         391 :               ctx->vl_msg_id_to_vapi_msg_t = tmp;
     627         391 :               ctx->vl_msg_id_max = id;
     628             :             }
     629        2706 :           ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
     630        2706 :           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
     631             : #if VAPI_DEBUG_CONNECT
     632             :           VAPI_DBG ("Message `%s' has vl_msg_id `%u'", m->name_with_crc,
     633             :                     (unsigned) id);
     634             : #endif
     635             :         }
     636             :       else
     637             :         {
     638          68 :           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
     639             :           VAPI_DBG ("Message `%s' not available", m->name_with_crc);
     640             :         }
     641             :     }
     642             : #if VAPI_DEBUG_CONNECT
     643             :   VAPI_DBG ("finished probing messages");
     644             : #endif
     645          17 :   if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
     646          17 :       !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
     647             :     {
     648             :       VAPI_ERR (
     649             :         "control ping or control ping reply not available, cannot connect");
     650           0 :       rv = VAPI_EINCOMPATIBLE;
     651           0 :       goto fail;
     652             :     }
     653          17 :   ctx->mode = mode;
     654          17 :   ctx->connected = true;
     655          17 :   if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
     656             :     {
     657          17 :       ctx->handle_keepalives = handle_keepalives;
     658             :     }
     659             :   else
     660             :     {
     661           0 :       ctx->handle_keepalives = false;
     662             :     }
     663          17 :   return VAPI_OK;
     664           0 : fail:
     665           0 :   vapi_client_disconnect (ctx);
     666           0 :   vl_client_api_unmap ();
     667           0 :   return rv;
     668             : }
     669             : 
     670             : /*
     671             :  * API client running in the same process as VPP
     672             :  */
     673             : vapi_error_e
     674           1 : vapi_connect_from_vpp (vapi_ctx_t ctx, const char *name,
     675             :                        int max_outstanding_requests, int response_queue_size,
     676             :                        vapi_mode_e mode, bool handle_keepalives)
     677             : {
     678             :   int rv;
     679             : 
     680           1 :   if (response_queue_size <= 0 || max_outstanding_requests <= 0)
     681             :     {
     682           0 :       return VAPI_EINVAL;
     683             :     }
     684             : 
     685           1 :   ctx->requests_size = max_outstanding_requests;
     686           1 :   const size_t size = ctx->requests_size * sizeof (*ctx->requests);
     687           1 :   void *tmp = realloc (ctx->requests, size);
     688           1 :   if (!tmp)
     689             :     {
     690           0 :       return VAPI_ENOMEM;
     691             :     }
     692           1 :   ctx->requests = tmp;
     693           1 :   clib_memset (ctx->requests, 0, size);
     694             :   /* coverity[MISSING_LOCK] - 177211 requests_mutex is not needed here */
     695           1 :   ctx->requests_start = ctx->requests_count = 0;
     696             : 
     697             :   VAPI_DBG ("connect client `%s'", name);
     698           1 :   if (vapi_client_connect (ctx, (char *) name, 0, response_queue_size,
     699             :                            handle_keepalives) < 0)
     700             :     {
     701           0 :       return VAPI_ECON_FAIL;
     702             :     }
     703             : 
     704             :   int i;
     705          46 :   for (i = 0; i < __vapi_metadata.count; ++i)
     706          45 :     {
     707          45 :       vapi_message_desc_t *m = __vapi_metadata.msgs[i];
     708          45 :       u8 scratch[m->name_with_crc_len + 1];
     709          45 :       memcpy (scratch, m->name_with_crc, m->name_with_crc_len + 1);
     710          45 :       u32 id = vapi_api_get_msg_index (ctx, scratch);
     711          45 :       if (VAPI_INVALID_MSG_ID != id)
     712             :         {
     713          45 :           if (id > UINT16_MAX)
     714             :             {
     715             :               VAPI_ERR ("Returned vl_msg_id `%u' > UINT16MAX `%u'!", id,
     716             :                         UINT16_MAX);
     717           0 :               rv = VAPI_EINVAL;
     718           0 :               goto fail;
     719             :             }
     720          45 :           if (id > ctx->vl_msg_id_max)
     721             :             {
     722             :               vapi_msg_id_t *tmp =
     723          23 :                 realloc (ctx->vl_msg_id_to_vapi_msg_t,
     724          23 :                          sizeof (*ctx->vl_msg_id_to_vapi_msg_t) * (id + 1));
     725          23 :               if (!tmp)
     726             :                 {
     727           0 :                   rv = VAPI_ENOMEM;
     728           0 :                   goto fail;
     729             :                 }
     730          23 :               ctx->vl_msg_id_to_vapi_msg_t = tmp;
     731          23 :               ctx->vl_msg_id_max = id;
     732             :             }
     733          45 :           ctx->vl_msg_id_to_vapi_msg_t[id] = m->id;
     734          45 :           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = id;
     735             :         }
     736             :       else
     737             :         {
     738           0 :           ctx->vapi_msg_id_t_to_vl_msg_id[m->id] = UINT16_MAX;
     739             :           VAPI_DBG ("Message `%s' not available", m->name_with_crc);
     740             :         }
     741             :     }
     742           1 :   if (!vapi_is_msg_available (ctx, vapi_msg_id_control_ping) ||
     743           1 :       !vapi_is_msg_available (ctx, vapi_msg_id_control_ping_reply))
     744             :     {
     745             :       VAPI_ERR (
     746             :         "control ping or control ping reply not available, cannot connect");
     747           0 :       rv = VAPI_EINCOMPATIBLE;
     748           0 :       goto fail;
     749             :     }
     750           1 :   ctx->mode = mode;
     751           1 :   ctx->connected = true;
     752           1 :   if (vapi_is_msg_available (ctx, vapi_msg_id_memclnt_keepalive))
     753             :     {
     754           1 :       ctx->handle_keepalives = handle_keepalives;
     755             :     }
     756             :   else
     757             :     {
     758           0 :       ctx->handle_keepalives = false;
     759             :     }
     760           1 :   return VAPI_OK;
     761           0 : fail:
     762           0 :   vapi_client_disconnect (ctx);
     763           0 :   return rv;
     764             : }
     765             : 
     766             : vapi_error_e
     767           1 : vapi_disconnect_from_vpp (vapi_ctx_t ctx)
     768             : {
     769           1 :   if (!ctx->connected)
     770             :     {
     771           0 :       return VAPI_EINVAL;
     772             :     }
     773             :   vl_api_memclnt_delete_reply_t *rp;
     774             :   svm_queue_t *vl_input_queue;
     775             :   time_t begin;
     776           1 :   vl_input_queue = ctx->vl_input_queue;
     777           1 :   vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
     778             : 
     779             :   /*
     780             :    * Have to be careful here, in case the client is disconnecting
     781             :    * because e.g. the vlib process died, or is unresponsive.
     782             :    */
     783           1 :   begin = time (0);
     784           1 :   vapi_error_e rv = VAPI_OK;
     785             :   while (1)
     786      220692 :     {
     787             :       time_t now;
     788             : 
     789      220693 :       now = time (0);
     790             : 
     791      220693 :       if (now >= (begin + 2))
     792             :         {
     793           0 :           clib_warning ("peer unresponsive, give up");
     794           0 :           ctx->my_client_index = ~0;
     795           0 :           rv = VAPI_ENORESP;
     796           0 :           goto fail;
     797             :         }
     798      220693 :       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
     799      220692 :         continue;
     800             : 
     801           1 :       VL_MSG_API_UNPOISON (rp);
     802             : 
     803             :       /* drain the queue */
     804           1 :       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
     805             :         {
     806           0 :           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
     807           0 :           vl_msg_api_free (rp);
     808           0 :           continue;
     809             :         }
     810           1 :       vapi_memclnt_delete_reply_t_handler (
     811             :         ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
     812           1 :       break;
     813             :     }
     814           1 : fail:
     815           1 :   vapi_api_name_and_crc_free (ctx);
     816             : 
     817           1 :   ctx->connected = false;
     818           1 :   return rv;
     819             : }
     820             : 
     821             : vapi_error_e
     822          17 : vapi_disconnect (vapi_ctx_t ctx)
     823             : {
     824          17 :   if (!ctx->connected)
     825             :     {
     826           0 :       return VAPI_EINVAL;
     827             :     }
     828             : 
     829             :   vl_api_memclnt_delete_reply_t *rp;
     830             :   svm_queue_t *vl_input_queue;
     831             :   time_t begin;
     832          17 :   vl_input_queue = ctx->vl_input_queue;
     833          17 :   vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
     834             : 
     835             :   /*
     836             :    * Have to be careful here, in case the client is disconnecting
     837             :    * because e.g. the vlib process died, or is unresponsive.
     838             :    */
     839          17 :   begin = time (0);
     840          17 :   vapi_error_e rv = VAPI_OK;
     841             :   while (1)
     842      385557 :     {
     843             :       time_t now;
     844             : 
     845      385574 :       now = time (0);
     846             : 
     847      385574 :       if (now >= (begin + 2))
     848             :         {
     849           0 :           clib_warning ("peer unresponsive, give up");
     850           0 :           ctx->my_client_index = ~0;
     851           0 :           rv = VAPI_ENORESP;
     852           0 :           goto fail;
     853             :         }
     854      385574 :       if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
     855      385557 :         continue;
     856             : 
     857          17 :       VL_MSG_API_UNPOISON (rp);
     858             : 
     859             :       /* drain the queue */
     860          17 :       if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
     861             :         {
     862           0 :           clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
     863           0 :           vl_msg_api_free (rp);
     864           0 :           continue;
     865             :         }
     866          17 :       vapi_memclnt_delete_reply_t_handler (
     867             :         ctx, (void *) rp /*, ntohl (msgbuf->data_len)*/);
     868          17 :       break;
     869             :     }
     870          17 : fail:
     871          17 :   vapi_api_name_and_crc_free (ctx);
     872             : 
     873          17 :   vl_client_api_unmap ();
     874             : #if VAPI_DEBUG_ALLOC
     875             :   vapi_to_be_freed_validate ();
     876             : #endif
     877          17 :   ctx->connected = false;
     878          17 :   return rv;
     879             : }
     880             : 
     881             : vapi_error_e
     882           0 : vapi_get_fd (vapi_ctx_t ctx, int *fd)
     883             : {
     884           0 :   return VAPI_ENOTSUP;
     885             : }
     886             : 
     887             : vapi_error_e
     888         185 : vapi_send (vapi_ctx_t ctx, void *msg)
     889             : {
     890         185 :   vapi_error_e rv = VAPI_OK;
     891         185 :   if (!ctx || !msg || !ctx->connected)
     892             :     {
     893           3 :       rv = VAPI_EINVAL;
     894           3 :       goto out;
     895             :     }
     896             :   int tmp;
     897         182 :   svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
     898             : #if VAPI_DEBUG
     899             :   unsigned msgid = be16toh (*(u16 *) msg);
     900             :   if (msgid <= ctx->vl_msg_id_max)
     901             :     {
     902             :       vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
     903             :       if (id < __vapi_metadata.count)
     904             :         {
     905             :           VAPI_DBG ("send msg@%p:%u[%s]", msg, msgid,
     906             :                     __vapi_metadata.msgs[id]->name);
     907             :         }
     908             :       else
     909             :         {
     910             :           VAPI_DBG ("send msg@%p:%u[UNKNOWN]", msg, msgid);
     911             :         }
     912             :     }
     913             :   else
     914             :     {
     915             :       VAPI_DBG ("send msg@%p:%u[UNKNOWN]", msg, msgid);
     916             :     }
     917             : #endif
     918         182 :   tmp = svm_queue_add (q, (u8 *) & msg,
     919         182 :                        VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
     920         182 :   if (tmp < 0)
     921             :     {
     922           0 :       rv = VAPI_EAGAIN;
     923             :     }
     924             :   else
     925         182 :     VL_MSG_API_POISON (msg);
     926         185 : out:
     927             :   VAPI_DBG ("vapi_send() rv = %d", rv);
     928         185 :   return rv;
     929             : }
     930             : 
     931             : vapi_error_e
     932         136 : vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2)
     933             : {
     934         136 :   vapi_error_e rv = VAPI_OK;
     935         136 :   if (!ctx || !msg1 || !msg2 || !ctx->connected)
     936             :     {
     937           0 :       rv = VAPI_EINVAL;
     938           0 :       goto out;
     939             :     }
     940         136 :   svm_queue_t *q = vlibapi_get_main ()->shmem_hdr->vl_input_queue;
     941             : #if VAPI_DEBUG
     942             :   unsigned msgid1 = be16toh (*(u16 *) msg1);
     943             :   unsigned msgid2 = be16toh (*(u16 *) msg2);
     944             :   const char *name1 = "UNKNOWN";
     945             :   const char *name2 = "UNKNOWN";
     946             :   if (msgid1 <= ctx->vl_msg_id_max)
     947             :     {
     948             :       vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid1];
     949             :       if (id < __vapi_metadata.count)
     950             :         {
     951             :           name1 = __vapi_metadata.msgs[id]->name;
     952             :         }
     953             :     }
     954             :   if (msgid2 <= ctx->vl_msg_id_max)
     955             :     {
     956             :       vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid2];
     957             :       if (id < __vapi_metadata.count)
     958             :         {
     959             :           name2 = __vapi_metadata.msgs[id]->name;
     960             :         }
     961             :     }
     962             :   VAPI_DBG ("send two: %u[%s], %u[%s]", msgid1, name1, msgid2, name2);
     963             : #endif
     964         136 :   int tmp = svm_queue_add2 (q, (u8 *) & msg1, (u8 *) & msg2,
     965         136 :                             VAPI_MODE_BLOCKING == ctx->mode ? 0 : 1);
     966         136 :   if (tmp < 0)
     967             :     {
     968           0 :       rv = VAPI_EAGAIN;
     969             :     }
     970             :   else
     971         136 :     VL_MSG_API_POISON (msg1);
     972         136 : out:
     973             :   VAPI_DBG ("vapi_send() rv = %d", rv);
     974         136 :   return rv;
     975             : }
     976             : 
     977             : vapi_error_e
     978      308005 : vapi_recv (vapi_ctx_t ctx, void **msg, size_t * msg_size,
     979             :            svm_q_conditional_wait_t cond, u32 time)
     980             : {
     981      308005 :   if (!ctx || !ctx->connected || !msg || !msg_size)
     982             :     {
     983           3 :       return VAPI_EINVAL;
     984             :     }
     985      308002 :   vapi_error_e rv = VAPI_OK;
     986             :   uword data;
     987             : 
     988      308002 :   svm_queue_t *q = ctx->vl_input_queue;
     989             : 
     990      308002 : again:
     991             :   VAPI_DBG ("doing shm queue sub");
     992             : 
     993      308002 :   int tmp = svm_queue_sub (q, (u8 *) & data, cond, time);
     994             : 
     995      308002 :   if (tmp == 0)
     996             :     {
     997        1107 :       VL_MSG_API_UNPOISON ((void *) data);
     998             : #if VAPI_DEBUG_ALLOC
     999             :       vapi_add_to_be_freed ((void *) data);
    1000             : #endif
    1001        1107 :       msgbuf_t *msgbuf =
    1002        1107 :         (msgbuf_t *) ((u8 *) data - offsetof (msgbuf_t, data));
    1003        1107 :       if (!msgbuf->data_len)
    1004             :         {
    1005           0 :           vapi_msg_free (ctx, (u8 *) data);
    1006           0 :           return VAPI_EAGAIN;
    1007             :         }
    1008        1107 :       *msg = (u8 *) data;
    1009        1107 :       *msg_size = ntohl (msgbuf->data_len);
    1010             : #if VAPI_DEBUG
    1011             :       unsigned msgid = be16toh (*(u16 *) * msg);
    1012             :       if (msgid <= ctx->vl_msg_id_max)
    1013             :         {
    1014             :           vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[msgid];
    1015             :           if (id < __vapi_metadata.count)
    1016             :             {
    1017             :               VAPI_DBG ("recv msg@%p:%u[%s]", *msg, msgid,
    1018             :                         __vapi_metadata.msgs[id]->name);
    1019             :             }
    1020             :           else
    1021             :             {
    1022             :               VAPI_DBG ("recv msg@%p:%u[UNKNOWN]", *msg, msgid);
    1023             :             }
    1024             :         }
    1025             :       else
    1026             :         {
    1027             :           VAPI_DBG ("recv msg@%p:%u[UNKNOWN]", *msg, msgid);
    1028             :         }
    1029             : #endif
    1030        1107 :       if (ctx->handle_keepalives)
    1031             :         {
    1032        1107 :           unsigned msgid = be16toh (*(u16 *) * msg);
    1033        1107 :           if (msgid ==
    1034        1107 :               vapi_lookup_vl_msg_id (ctx, vapi_msg_id_memclnt_keepalive))
    1035             :             {
    1036           0 :               vapi_msg_memclnt_keepalive_reply *reply = NULL;
    1037             :               do
    1038             :                 {
    1039           0 :                   reply = vapi_msg_alloc (ctx, sizeof (*reply));
    1040             :                 }
    1041           0 :               while (!reply);
    1042           0 :               reply->header.context = vapi_get_client_index (ctx);
    1043           0 :               reply->header._vl_msg_id =
    1044           0 :                 vapi_lookup_vl_msg_id (ctx,
    1045             :                                        vapi_msg_id_memclnt_keepalive_reply);
    1046           0 :               reply->payload.retval = 0;
    1047           0 :               vapi_msg_memclnt_keepalive_reply_hton (reply);
    1048           0 :               while (VAPI_EAGAIN == vapi_send (ctx, reply));
    1049           0 :               vapi_msg_free (ctx, *msg);
    1050           0 :               goto again;
    1051             :             }
    1052             :         }
    1053             :     }
    1054             :   else
    1055             :     {
    1056      306895 :       rv = VAPI_EAGAIN;
    1057             :     }
    1058      308002 :   return rv;
    1059             : }
    1060             : 
    1061             : vapi_error_e
    1062           0 : vapi_wait (vapi_ctx_t ctx)
    1063             : {
    1064           0 :   svm_queue_lock (ctx->vl_input_queue);
    1065           0 :   svm_queue_wait (ctx->vl_input_queue);
    1066           0 :   svm_queue_unlock (ctx->vl_input_queue);
    1067             : 
    1068           0 :   return VAPI_OK;
    1069             : }
    1070             : 
    1071             : static vapi_error_e
    1072        1064 : vapi_dispatch_response (vapi_ctx_t ctx, vapi_msg_id_t id,
    1073             :                         u32 context, void *msg)
    1074             : {
    1075             :   int mrv;
    1076        1064 :   if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
    1077             :     {
    1078             :       VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
    1079           0 :       return VAPI_MUTEX_FAILURE;
    1080             :     }
    1081        1064 :   int tmp = ctx->requests_start;
    1082        1064 :   const int requests_end = vapi_requests_end (ctx);
    1083        1065 :   while (ctx->requests[tmp].context != context && tmp != requests_end)
    1084             :     {
    1085           1 :       ++tmp;
    1086           1 :       if (tmp == ctx->requests_size)
    1087             :         {
    1088           0 :           tmp = 0;
    1089             :         }
    1090             :     }
    1091             :   VAPI_DBG ("dispatch, search from %d, %s at %d", ctx->requests_start,
    1092             :             ctx->requests[tmp].context == context ? "matched" : "stopped",
    1093             :             tmp);
    1094        1064 :   vapi_error_e rv = VAPI_OK;
    1095        1064 :   if (ctx->requests[tmp].context == context)
    1096             :     {
    1097        1065 :       while (ctx->requests_start != tmp)
    1098             :         {
    1099             :           VAPI_ERR ("No response to req with context=%u",
    1100             :                     (unsigned) ctx->requests[tmp].context);
    1101           1 :           ctx->requests[ctx->requests_start].callback (ctx, ctx->requests
    1102           1 :                                                        [ctx->
    1103             :                                                         requests_start].callback_ctx,
    1104             :                                                        VAPI_ENORESP, true,
    1105             :                                                        NULL);
    1106           1 :           clib_memset (&ctx->requests[ctx->requests_start], 0,
    1107             :                        sizeof (ctx->requests[ctx->requests_start]));
    1108           1 :           ++ctx->requests_start;
    1109           1 :           --ctx->requests_count;
    1110           1 :           if (ctx->requests_start == ctx->requests_size)
    1111             :             {
    1112           0 :               ctx->requests_start = 0;
    1113             :             }
    1114             :         }
    1115             :       // now ctx->requests_start == tmp
    1116        1064 :       int payload_offset = vapi_get_payload_offset (id);
    1117        1064 :       void *payload = ((u8 *) msg) + payload_offset;
    1118        1064 :       bool is_last = true;
    1119        1064 :       if (ctx->requests[tmp].is_dump)
    1120             :         {
    1121         908 :           if (vapi_msg_id_control_ping_reply == id)
    1122             :             {
    1123         132 :               payload = NULL;
    1124             :             }
    1125             :           else
    1126             :             {
    1127         776 :               is_last = false;
    1128             :             }
    1129             :         }
    1130        1064 :       if (payload_offset != -1)
    1131             :         {
    1132        1064 :           rv = ctx->requests[tmp].callback (
    1133        1064 :             ctx, ctx->requests[tmp].callback_ctx, VAPI_OK, is_last, payload);
    1134             :         }
    1135             :       else
    1136             :         {
    1137             :           /* this is a message without payload, so bend the callback a little
    1138             :            */
    1139             :           rv =
    1140           0 :             ((vapi_error_e (*)(vapi_ctx_t, void *, vapi_error_e, bool))
    1141           0 :              ctx->requests[tmp].callback) (ctx,
    1142           0 :                                            ctx->requests[tmp].callback_ctx,
    1143             :                                            VAPI_OK, is_last);
    1144             :         }
    1145        1064 :       if (is_last)
    1146             :         {
    1147         288 :           clib_memset (&ctx->requests[ctx->requests_start], 0,
    1148             :                        sizeof (ctx->requests[ctx->requests_start]));
    1149         288 :           ++ctx->requests_start;
    1150         288 :           --ctx->requests_count;
    1151         288 :           if (ctx->requests_start == ctx->requests_size)
    1152             :             {
    1153           4 :               ctx->requests_start = 0;
    1154             :             }
    1155             :         }
    1156             :       VAPI_DBG ("after dispatch, req start = %d, end = %d, count = %d",
    1157             :                 ctx->requests_start, requests_end, ctx->requests_count);
    1158             :     }
    1159        1064 :   if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
    1160             :     {
    1161             :       VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
    1162             :                 strerror (mrv));
    1163           0 :       abort ();                 /* this really shouldn't happen */
    1164             :     }
    1165        1064 :   return rv;
    1166             : }
    1167             : 
    1168             : static vapi_error_e
    1169           2 : vapi_dispatch_event (vapi_ctx_t ctx, vapi_msg_id_t id, void *msg)
    1170             : {
    1171           2 :   if (ctx->event_cbs[id].cb)
    1172             :     {
    1173           0 :       return ctx->event_cbs[id].cb (ctx, ctx->event_cbs[id].ctx, msg);
    1174             :     }
    1175           2 :   else if (ctx->generic_cb.cb)
    1176             :     {
    1177           1 :       return ctx->generic_cb.cb (ctx, ctx->generic_cb.ctx, id, msg);
    1178             :     }
    1179             :   else
    1180             :     {
    1181             :       VAPI_DBG
    1182             :         ("No handler/generic handler for msg id %u[%s], message ignored",
    1183             :          (unsigned) id, __vapi_metadata.msgs[id]->name);
    1184             :     }
    1185           1 :   return VAPI_OK;
    1186             : }
    1187             : 
    1188             : bool
    1189        1106 : vapi_msg_is_with_context (vapi_msg_id_t id)
    1190             : {
    1191        1106 :   assert (id <= __vapi_metadata.count);
    1192        1106 :   return __vapi_metadata.msgs[id]->has_context;
    1193             : }
    1194             : 
    1195             : static int
    1196        1066 : vapi_verify_msg_size (vapi_msg_id_t id, void *buf, uword buf_size)
    1197             : {
    1198        1066 :   assert (id < __vapi_metadata.count);
    1199        1066 :   return __vapi_metadata.msgs[id]->verify_msg_size (buf, buf_size);
    1200             : }
    1201             : 
    1202             : vapi_error_e
    1203      307961 : vapi_dispatch_one (vapi_ctx_t ctx)
    1204             : {
    1205             :   VAPI_DBG ("vapi_dispatch_one()");
    1206             :   void *msg;
    1207             :   uword size;
    1208      307961 :   svm_q_conditional_wait_t cond =
    1209      307961 :     vapi_is_nonblocking (ctx) ? SVM_Q_NOWAIT : SVM_Q_WAIT;
    1210      307961 :   vapi_error_e rv = vapi_recv (ctx, &msg, &size, cond, 0);
    1211      307961 :   if (VAPI_OK != rv)
    1212             :     {
    1213             :       VAPI_DBG ("vapi_recv failed with rv=%d", rv);
    1214      306895 :       return rv;
    1215             :     }
    1216        1066 :   u16 vpp_id = be16toh (*(u16 *) msg);
    1217        1066 :   if (vpp_id > ctx->vl_msg_id_max)
    1218             :     {
    1219             :       VAPI_ERR ("Unknown msg ID received, id `%u', out of range <0,%u>",
    1220             :                 (unsigned) vpp_id, (unsigned) ctx->vl_msg_id_max);
    1221           0 :       vapi_msg_free (ctx, msg);
    1222           0 :       return VAPI_EINVAL;
    1223             :     }
    1224        1066 :   if (VAPI_INVALID_MSG_ID == (unsigned) ctx->vl_msg_id_to_vapi_msg_t[vpp_id])
    1225             :     {
    1226             :       VAPI_ERR ("Unknown msg ID received, id `%u' marked as not supported",
    1227             :                 (unsigned) vpp_id);
    1228           0 :       vapi_msg_free (ctx, msg);
    1229           0 :       return VAPI_EINVAL;
    1230             :     }
    1231        1066 :   const vapi_msg_id_t id = ctx->vl_msg_id_to_vapi_msg_t[vpp_id];
    1232        1066 :   if (vapi_verify_msg_size (id, msg, size))
    1233             :     {
    1234           0 :       vapi_msg_free (ctx, msg);
    1235           0 :       return VAPI_EINVAL;
    1236             :     }
    1237             :   u32 context;
    1238        1066 :   vapi_get_swap_to_host_func (id) (msg);
    1239        1066 :   if (vapi_msg_is_with_context (id))
    1240             :     {
    1241        1066 :       context = *(u32 *) (((u8 *) msg) + vapi_get_context_offset (id));
    1242             :       /* is this a message originating from VAPI? */
    1243             :       VAPI_DBG ("dispatch, context is %x", context);
    1244        1066 :       if (context & context_counter_mask)
    1245             :         {
    1246        1064 :           rv = vapi_dispatch_response (ctx, id, context, msg);
    1247        1064 :           goto done;
    1248             :         }
    1249             :     }
    1250           2 :   rv = vapi_dispatch_event (ctx, id, msg);
    1251             : 
    1252        1066 : done:
    1253        1066 :   vapi_msg_free (ctx, msg);
    1254        1066 :   return rv;
    1255             : }
    1256             : 
    1257             : vapi_error_e
    1258      296075 : vapi_dispatch (vapi_ctx_t ctx)
    1259             : {
    1260      296075 :   vapi_error_e rv = VAPI_OK;
    1261      297139 :   while (!vapi_requests_empty (ctx))
    1262             :     {
    1263      296861 :       rv = vapi_dispatch_one (ctx);
    1264      296861 :       if (VAPI_OK != rv)
    1265             :         {
    1266      295797 :           return rv;
    1267             :         }
    1268             :     }
    1269         278 :   return rv;
    1270             : }
    1271             : 
    1272             : void
    1273           0 : vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
    1274             :                    vapi_event_cb callback, void *callback_ctx)
    1275             : {
    1276           0 :   vapi_event_cb_with_ctx *c = &ctx->event_cbs[id];
    1277           0 :   c->cb = callback;
    1278           0 :   c->ctx = callback_ctx;
    1279           0 : }
    1280             : 
    1281             : void
    1282           0 : vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id)
    1283             : {
    1284           0 :   vapi_set_event_cb (ctx, id, NULL, NULL);
    1285           0 : }
    1286             : 
    1287             : void
    1288           1 : vapi_set_generic_event_cb (vapi_ctx_t ctx, vapi_generic_event_cb callback,
    1289             :                            void *callback_ctx)
    1290             : {
    1291           1 :   ctx->generic_cb.cb = callback;
    1292           1 :   ctx->generic_cb.ctx = callback_ctx;
    1293           1 : }
    1294             : 
    1295             : void
    1296           1 : vapi_clear_generic_event_cb (vapi_ctx_t ctx)
    1297             : {
    1298           1 :   ctx->generic_cb.cb = NULL;
    1299           1 :   ctx->generic_cb.ctx = NULL;
    1300           1 : }
    1301             : 
    1302             : u16
    1303        1683 : vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id)
    1304             : {
    1305        1683 :   assert (id < __vapi_metadata.count);
    1306        1683 :   return ctx->vapi_msg_id_t_to_vl_msg_id[id];
    1307             : }
    1308             : 
    1309             : int
    1310         456 : vapi_get_client_index (vapi_ctx_t ctx)
    1311             : {
    1312         456 :   return ctx->my_client_index;
    1313             : }
    1314             : 
    1315             : bool
    1316      308539 : vapi_is_nonblocking (vapi_ctx_t ctx)
    1317             : {
    1318      308539 :   return (VAPI_MODE_NONBLOCKING == ctx->mode);
    1319             : }
    1320             : 
    1321             : size_t
    1322           0 : vapi_get_max_request_count (vapi_ctx_t ctx)
    1323             : {
    1324           0 :   return ctx->requests_size - 1;
    1325             : }
    1326             : 
    1327             : int
    1328        1064 : vapi_get_payload_offset (vapi_msg_id_t id)
    1329             : {
    1330        1064 :   assert (id < __vapi_metadata.count);
    1331        1064 :   return __vapi_metadata.msgs[id]->payload_offset;
    1332             : }
    1333             : 
    1334        1066 : void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *msg)
    1335             : {
    1336        1066 :   assert (id < __vapi_metadata.count);
    1337        1066 :   return __vapi_metadata.msgs[id]->swap_to_host;
    1338             : }
    1339             : 
    1340           0 : void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *msg)
    1341             : {
    1342           0 :   assert (id < __vapi_metadata.count);
    1343           0 :   return __vapi_metadata.msgs[id]->swap_to_be;
    1344             : }
    1345             : 
    1346             : size_t
    1347        1106 : vapi_get_context_offset (vapi_msg_id_t id)
    1348             : {
    1349        1106 :   assert (id < __vapi_metadata.count);
    1350        1106 :   return __vapi_metadata.msgs[id]->context_offset;
    1351             : }
    1352             : 
    1353             : vapi_msg_id_t
    1354       52318 : vapi_register_msg (vapi_message_desc_t * msg)
    1355             : {
    1356       52318 :   int i = 0;
    1357     1410050 :   for (i = 0; i < __vapi_metadata.count; ++i)
    1358             :     {
    1359     1380550 :       if (!strcmp
    1360     1380550 :           (msg->name_with_crc, __vapi_metadata.msgs[i]->name_with_crc))
    1361             :         {
    1362             :           /* this happens if somebody is linking together several objects while
    1363             :            * using the static inline headers, just fill in the already
    1364             :            * assigned id here so that all the objects are in sync */
    1365       22815 :           msg->id = __vapi_metadata.msgs[i]->id;
    1366       22815 :           return msg->id;
    1367             :         }
    1368             :     }
    1369       29503 :   vapi_msg_id_t id = __vapi_metadata.count;
    1370       29503 :   ++__vapi_metadata.count;
    1371       29503 :   __vapi_metadata.msgs =
    1372       29503 :     realloc (__vapi_metadata.msgs,
    1373       29503 :              sizeof (*__vapi_metadata.msgs) * __vapi_metadata.count);
    1374       29503 :   __vapi_metadata.msgs[id] = msg;
    1375       29503 :   size_t s = strlen (msg->name_with_crc);
    1376       29503 :   if (s > __vapi_metadata.max_len_name_with_crc)
    1377             :     {
    1378        2951 :       __vapi_metadata.max_len_name_with_crc = s;
    1379             :     }
    1380       29503 :   msg->id = id;
    1381       29503 :   return id;
    1382             : }
    1383             : 
    1384             : vapi_error_e
    1385         289 : vapi_producer_lock (vapi_ctx_t ctx)
    1386             : {
    1387             :   int mrv;
    1388         289 :   if (0 != (mrv = pthread_mutex_lock (&ctx->requests_mutex)))
    1389             :     {
    1390             :       VAPI_DBG ("pthread_mutex_lock() failed, rv=%d:%s", mrv, strerror (mrv));
    1391             :       (void) mrv;               /* avoid warning if the above debug is not enabled */
    1392           0 :       return VAPI_MUTEX_FAILURE;
    1393             :     }
    1394         289 :   return VAPI_OK;
    1395             : }
    1396             : 
    1397             : vapi_error_e
    1398         289 : vapi_producer_unlock (vapi_ctx_t ctx)
    1399             : {
    1400             :   int mrv;
    1401         289 :   if (0 != (mrv = pthread_mutex_unlock (&ctx->requests_mutex)))
    1402             :     {
    1403             :       VAPI_DBG ("pthread_mutex_unlock() failed, rv=%d:%s", mrv,
    1404             :                 strerror (mrv));
    1405             :       (void) mrv;               /* avoid warning if the above debug is not enabled */
    1406           0 :       return VAPI_MUTEX_FAILURE;
    1407             :     }
    1408         289 :   return VAPI_OK;
    1409             : }
    1410             : 
    1411             : size_t
    1412           6 : vapi_get_message_count ()
    1413             : {
    1414           6 :   return __vapi_metadata.count;
    1415             : }
    1416             : 
    1417             : const char *
    1418           0 : vapi_get_msg_name (vapi_msg_id_t id)
    1419             : {
    1420           0 :   return __vapi_metadata.msgs[id]->name;
    1421             : }
    1422             : 
    1423             : void
    1424           0 : vapi_stop_rx_thread (vapi_ctx_t ctx)
    1425             : {
    1426           0 :   if (!ctx || !ctx->connected || !ctx->vl_input_queue)
    1427             :     {
    1428           0 :       return;
    1429             :     }
    1430             : 
    1431           0 :   vl_client_stop_rx_thread (ctx->vl_input_queue);
    1432             : }
    1433             : /*
    1434             :  * fd.io coding-style-patch-verification: ON
    1435             :  *
    1436             :  * Local Variables:
    1437             :  * eval: (c-set-style "gnu")
    1438             :  * End:
    1439             :  */

Generated by: LCOV version 1.14