vlib: introduce trace filter functions
[vpp.git] / src / plugins / tracedump / tracedump.c
index 17b9a42..6510a94 100644 (file)
@@ -213,12 +213,15 @@ vl_api_trace_dump_t_handler (vl_api_trace_dump_t * mp)
   iterator_position = clib_net_to_host_u32 (mp->position);
   max_records = clib_net_to_host_u32 (mp->max_records);
 
-  /* Don't overflow the existing queue space. */
-  svm_queue_t *q = rp->vl_input_queue;
-  u32 queue_slots_available = q->maxsize - q->cursize;
-  int chunk = (queue_slots_available > 0) ? queue_slots_available - 1 : 0;
-  if (chunk < max_records)
-    max_records = chunk;
+  /* Don't overflow the existing queue space for shared memory API clients. */
+  if (rp->vl_input_queue)
+    {
+      svm_queue_t *q = rp->vl_input_queue;
+      u32 queue_slots_available = q->maxsize - q->cursize;
+      int chunk = (queue_slots_available > 0) ? queue_slots_available - 1 : 0;
+      if (chunk < max_records)
+       max_records = chunk;
+    }
 
   /* Need a fresh cache for this client? */
   if (vec_len (client_trace_cache) == 0
@@ -332,6 +335,199 @@ doublebreak:;
   vec_free (s);
 }
 
+/* API message handler */
+static void
+vl_api_trace_v2_dump_t_handler (vl_api_trace_v2_dump_t *mp)
+{
+  vl_api_registration_t *rp;
+  vl_api_trace_v2_details_t *dmp;
+  tracedump_main_t *tdmp = &tracedump_main;
+  vlib_trace_header_t ***client_trace_cache, **th;
+  int i, j;
+  u32 client_index;
+  u32 first_position, max, first_thread_id, last_thread_id;
+  u32 n_threads = vlib_get_n_threads ();
+  u8 *s = 0;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+  if (rp == 0)
+    return;
+
+  client_index = rp->vl_api_registration_pool_index;
+
+  vec_validate_init_empty (tdmp->traces, client_index, 0);
+
+  client_trace_cache = tdmp->traces[client_index];
+
+  if (mp->clear_cache)
+    {
+      toss_client_cache (tdmp, client_index, client_trace_cache);
+      client_trace_cache = 0;
+    }
+
+  /* Now, where were we? */
+  first_thread_id = last_thread_id = clib_net_to_host_u32 (mp->thread_id);
+  first_position = clib_net_to_host_u32 (mp->position);
+  max = clib_net_to_host_u32 (mp->max);
+
+  if (first_thread_id == ~0)
+    {
+      first_thread_id = 0;
+      last_thread_id = n_threads - 1;
+    }
+
+  /* Don't overflow the existing queue space for shared memory API clients. */
+  if (rp->vl_input_queue)
+    {
+      svm_queue_t *q = rp->vl_input_queue;
+      u32 queue_slots_available = q->maxsize - q->cursize;
+      int chunk = (queue_slots_available > 0) ? queue_slots_available - 1 : 0;
+      /* split available slots among requested threads */
+      if (chunk < max * (last_thread_id - first_thread_id + 1))
+       max = chunk / (last_thread_id - first_thread_id + 1);
+    }
+
+  /* Need a fresh cache for this client? */
+  if (vec_len (client_trace_cache) == 0 && first_position != ~0)
+    {
+      vlib_worker_thread_barrier_sync (vlib_get_first_main ());
+
+      /* Make a slot for each worker thread */
+      vec_validate (client_trace_cache, n_threads - 1);
+      i = 0;
+
+      foreach_vlib_main ()
+       {
+         vlib_trace_main_t *tm = &this_vlib_main->trace_main;
+
+         /* Filter as directed */
+         trace_apply_filter (this_vlib_main);
+
+         pool_foreach (th, tm->trace_buffer_pool)
+           {
+             vec_add1 (client_trace_cache[i], th[0]);
+           }
+
+         /* Sort them by increasing time. */
+         if (vec_len (client_trace_cache[i]))
+           vec_sort_with_function (client_trace_cache[i], trace_cmp);
+
+         i++;
+       }
+      vlib_worker_thread_barrier_release (vlib_get_first_main ());
+    }
+
+  /* Save the cache, one way or the other */
+  tdmp->traces[client_index] = client_trace_cache;
+
+  for (i = first_thread_id;
+       i <= last_thread_id && i < vec_len (client_trace_cache); i++)
+    {
+      // dump a number of 'max' packets per thead
+      for (j = first_position;
+          j < vec_len (client_trace_cache[i]) && j < first_position + max;
+          j++)
+       {
+         th = &client_trace_cache[i][j];
+
+         vec_reset_length (s);
+
+         s =
+           format (s, "%U", format_vlib_trace, vlib_get_first_main (), th[0]);
+
+         dmp = vl_msg_api_alloc (sizeof (*dmp) + vec_len (s));
+         dmp->_vl_msg_id =
+           htons (VL_API_TRACE_V2_DETAILS + (tdmp->msg_id_base));
+         dmp->context = mp->context;
+         dmp->thread_id = ntohl (i);
+         dmp->position = ntohl (j);
+         dmp->more = j < vec_len (client_trace_cache[i]) - 1;
+         vl_api_vec_to_api_string (s, &dmp->trace_data);
+
+         vl_api_send_msg (rp, (u8 *) dmp);
+       }
+    }
+
+  vec_free (s);
+}
+
+static void
+vl_api_trace_clear_cache_t_handler (vl_api_trace_clear_cache_t *mp)
+{
+  vl_api_registration_t *rp;
+  tracedump_main_t *tdmp = &tracedump_main;
+  vlib_trace_header_t ***client_trace_cache;
+  vl_api_trace_clear_cache_reply_t *rmp;
+  u32 client_index;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+  if (rp == 0)
+    return;
+
+  client_index = rp->vl_api_registration_pool_index;
+  vec_validate_init_empty (tdmp->traces, client_index, 0);
+  client_trace_cache = tdmp->traces[client_index];
+  toss_client_cache (tdmp, client_index, client_trace_cache);
+
+  int rv = 0;
+  REPLY_MACRO (VL_API_TRACE_CLEAR_CACHE_REPLY);
+}
+
+static void
+vl_api_trace_set_filter_function_t_handler (
+  vl_api_trace_set_filter_function_t *mp)
+{
+  vl_api_trace_set_filter_function_reply_t *rmp;
+  tracedump_main_t *tdmp = &tracedump_main;
+  unformat_input_t input = { 0 };
+  vlib_is_packet_traced_fn_t *f;
+  char *filter_name;
+  int rv = 0;
+  filter_name = vl_api_from_api_to_new_c_string (&mp->filter_function_name);
+  unformat_init_cstring (&input, filter_name);
+  if (unformat (&input, "%U", unformat_vlib_trace_filter_function, &f) == 0)
+    {
+      rv = -1;
+      goto done;
+    }
+  vlib_set_trace_filter_function (f);
+done:
+  unformat_free (&input);
+  vec_free (filter_name);
+  REPLY_MACRO (VL_API_TRACE_SET_FILTER_FUNCTION_REPLY);
+}
+
+static void
+vl_api_trace_filter_function_dump_t_handler (
+  vl_api_trace_filter_function_dump_t *mp)
+{
+  vl_api_registration_t *rp;
+  vl_api_trace_filter_function_details_t *dmp;
+  tracedump_main_t *tdmp = &tracedump_main;
+  vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main;
+  vlib_trace_filter_function_registration_t *reg =
+    tfm->trace_filter_registration;
+  vlib_main_t *vm = vlib_get_main ();
+  vlib_is_packet_traced_fn_t *current =
+    vm->trace_main.current_trace_filter_function;
+  rp = vl_api_client_index_to_registration (mp->client_index);
+
+  if (rp == 0)
+    return;
+
+  while (reg)
+    {
+      dmp = vl_msg_api_alloc (sizeof (*dmp) + strlen (reg->name));
+      dmp->_vl_msg_id =
+       htons (VL_API_TRACE_FILTER_FUNCTION_DETAILS + (tdmp->msg_id_base));
+      dmp->context = mp->context;
+      vl_api_c_string_to_api_string (reg->name, &dmp->name);
+      dmp->selected = current == reg->function;
+      vl_api_send_msg (rp, (u8 *) dmp);
+      reg = reg->next;
+    }
+}
+
 /* API definitions */
 #include <tracedump/tracedump.api.c>
 
@@ -350,6 +546,7 @@ tracedump_init (vlib_main_t * vm)
   tdmp->msg_id_base = setup_message_id_table ();
 
   vl_api_set_msg_thread_safe (am, tdmp->msg_id_base + VL_API_TRACE_DUMP, 1);
+  vl_api_set_msg_thread_safe (am, tdmp->msg_id_base + VL_API_TRACE_V2_DUMP, 1);
 
   return error;
 }