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

Generated by: LCOV version 1.14