api: fix inconsistent behaviour when adding l2fib filter entry (VPP-147)
[vpp.git] / vlib-api / vlibmemory / memory_vlib.c
index c2c14ac..5f97f16 100644 (file)
@@ -100,13 +100,28 @@ vl_msg_api_send (vl_api_registration_t * rp, u8 * elem)
     }
 }
 
-int vl_msg_api_version_check (vl_api_memclnt_create_t * mp)
-  __attribute__ ((weak));
-
-int
-vl_msg_api_version_check (vl_api_memclnt_create_t * mp)
+u8 *
+vl_api_serialize_message_table (api_main_t * am, u8 * vector)
 {
-  return 0;
+  serialize_main_t _sm, *sm = &_sm;
+  hash_pair_t *hp;
+  u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
+
+  serialize_open_vector (sm, vector);
+
+  /* serialize the count */
+  serialize_integer (sm, nmsg, sizeof (u32));
+
+  hash_foreach_pair (hp, am->msg_index_by_name_and_crc, (
+                                                         {
+                                                         serialize_likely_small_unsigned_integer
+                                                         (sm, hp->value[0]);
+                                                         serialize_cstring
+                                                         (sm,
+                                                          (char *) hp->key);
+                                                         }));
+
+  return serialize_close_vector (sm);
 }
 
 /*
@@ -120,12 +135,10 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
   vl_api_memclnt_create_reply_t *rp;
   svm_region_t *svm;
   unix_shared_memory_queue_t *q;
-  int rv;
+  int rv = 0;
   void *oldheap;
   api_main_t *am = &api_main;
-
-  /* Indicate API version mismatch if appropriate */
-  rv = vl_msg_api_version_check (mp);
+  u8 *serialized_message_table = 0;
 
   /*
    * This is tortured. Maintain a vlib-address-space private
@@ -157,6 +170,9 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
 
   svm = am->vlib_rp;
 
+  if (am->serialized_message_table_in_shmem == 0)
+    serialized_message_table = vl_api_serialize_message_table (am, 0);
+
   pthread_mutex_lock (&svm->mutex);
   oldheap = svm_push_data_heap (svm);
   *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
@@ -171,10 +187,15 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
 
   regp->name = format (0, "%s", mp->name);
   vec_add1 (regp->name, 0);
+  if (serialized_message_table)
+    am->serialized_message_table_in_shmem =
+      vec_dup (serialized_message_table);
 
   pthread_mutex_unlock (&svm->mutex);
   svm_pop_heap (oldheap);
 
+  vec_free (serialized_message_table);
+
   rp = vl_msg_api_alloc (sizeof (*rp));
   rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
   rp->handle = (uword) regp;
@@ -183,6 +204,7 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
      am->shmem_hdr->application_restarts);
   rp->context = mp->context;
   rp->response = ntohl (rv);
+  rp->message_table = (u64) am->serialized_message_table_in_shmem;
 
   vl_msg_api_send_shmem (q, (u8 *) & rp);
 }
@@ -644,9 +666,9 @@ vl_api_show_histogram_command (vlib_main_t * vm,
 
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) = {
-  .path = "show api histogram",
-  .short_help = "show api histogram",
-  .function = vl_api_show_histogram_command,
+    .path = "show api histogram",
+    .short_help = "show api histogram",
+    .function = vl_api_show_histogram_command,
 };
 /* *INDENT-ON* */
 
@@ -907,6 +929,41 @@ socket_clients:
   return 0;
 }
 
+static clib_error_t *
+vl_api_status_command (vlib_main_t * vm,
+                      unformat_input_t * input, vlib_cli_command_t * cli_cmd)
+{
+  api_main_t *am = &api_main;
+
+  // check if rx_trace and tx_trace are not null pointers
+
+  if (am->rx_trace == 0)
+    {
+      vlib_cli_output (vm, "RX Trace disabled\n");
+    }
+  else
+    {
+      if (am->rx_trace->enabled == 0)
+       vlib_cli_output (vm, "RX Trace disabled\n");
+      else
+       vlib_cli_output (vm, "RX Trace enabled\n");
+    }
+
+  if (am->tx_trace == 0)
+    {
+      vlib_cli_output (vm, "TX Trace disabled\n");
+    }
+  else
+    {
+      if (am->tx_trace->enabled == 0)
+       vlib_cli_output (vm, "TX Trace disabled\n");
+      else
+       vlib_cli_output (vm, "TX Trace enabled\n");
+    }
+
+  return 0;
+}
+
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (cli_show_api_command, static) = {
     .path = "show api",
@@ -930,6 +987,14 @@ VLIB_CLI_COMMAND (cli_show_api_clients_command, static) = {
 };
 /* *INDENT-ON* */
 
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (cli_show_api_status_command, static) = {
+    .path = "show api status",
+    .short_help = "Show API trace status",
+    .function = vl_api_status_command,
+};
+/* *INDENT-ON* */
+
 static clib_error_t *
 vl_api_message_table_command (vlib_main_t * vm,
                              unformat_input_t * input,
@@ -1042,7 +1107,12 @@ vl_api_trace_print_file_cmd (vlib_main_t * vm, u32 first, u32 last,
        }
       msg_id = ntohs (msg_id);
 
-      fseek (fp, -2, SEEK_CUR);
+      if (fseek (fp, -2, SEEK_CUR) < 0)
+       {
+         vlib_cli_output (vm, "fseek failed, %s", strerror (errno));
+         fclose (fp);
+         return;
+       }
 
       /* Mild sanity check */
       if (msg_id >= vec_len (am->msg_handlers))
@@ -1171,8 +1241,22 @@ clib_error_t *
 vlibmemory_init (vlib_main_t * vm)
 {
   api_main_t *am = &api_main;
-  /* Normally NULL / 0, set by cmd line "api-segment" */
-  svm_region_init_chroot_uid_gid (am->root_path, am->api_uid, am->api_gid);
+  svm_map_region_args_t _a, *a = &_a;
+
+  memset (a, 0, sizeof (*a));
+  a->root_path = am->root_path;
+  a->name = SVM_GLOBAL_REGION_NAME;
+  a->baseva = (am->global_baseva != 0) ?
+    am->global_baseva : SVM_GLOBAL_REGION_BASEVA;
+  a->size = (am->global_size != 0) ? am->global_size : SVM_GLOBAL_REGION_SIZE;
+  a->flags = SVM_FLAGS_NODATA;
+  a->uid = am->api_uid;
+  a->gid = am->api_gid;
+  a->pvt_heap_size =
+    (am->global_pvt_heap_size !=
+     0) ? am->global_pvt_heap_size : SVM_PVT_MHEAP_SIZE;
+
+  svm_region_init_args (a);
   return 0;
 }
 
@@ -1304,16 +1388,53 @@ vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
   vl_api_rpc_call_t *mp;
   api_main_t *am = &api_main;
   vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+  unix_shared_memory_queue_t *q;
+
+  /* Main thread: call the function directly */
+  if (os_get_cpu_number () == 0)
+    {
+      vlib_main_t *vm = vlib_get_main ();
+      void (*call_fp) (void *);
+
+      vlib_worker_thread_barrier_sync (vm);
+
+      call_fp = fp;
+      call_fp (data);
+
+      vlib_worker_thread_barrier_release (vm);
+      return;
+    }
 
+  /* Any other thread, actually do an RPC call... */
   mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length);
+
   memset (mp, 0, sizeof (*mp));
   clib_memcpy (mp->data, data, data_length);
   mp->_vl_msg_id = ntohs (VL_API_RPC_CALL);
   mp->function = pointer_to_uword (fp);
   mp->need_barrier_sync = 1;
 
-  /* Use the "normal" control-plane mechanism for the main thread */
-  vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
+  /*
+   * Use the "normal" control-plane mechanism for the main thread.
+   * Well, almost. if the main input queue is full, we cannot
+   * block. Otherwise, we can expect a barrier sync timeout.
+   */
+  q = shmem_hdr->vl_input_queue;
+
+  while (pthread_mutex_trylock (&q->mutex))
+    vlib_worker_thread_barrier_check ();
+
+  while (PREDICT_FALSE (unix_shared_memory_queue_is_full (q)))
+    {
+      pthread_mutex_unlock (&q->mutex);
+      vlib_worker_thread_barrier_check ();
+      while (pthread_mutex_trylock (&q->mutex))
+       vlib_worker_thread_barrier_check ();
+    }
+
+  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
+
+  pthread_mutex_unlock (&q->mutex);
 }
 
 #define foreach_rpc_api_msg                     \