misc: add tracedump API plugin 11/27811/8
authorDave Barach <dave@barachs.net>
Tue, 7 Jul 2020 21:33:38 +0000 (17:33 -0400)
committerDamjan Marion <dmarion@me.com>
Thu, 16 Jul 2020 21:39:50 +0000 (21:39 +0000)
Type: feature

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I586547508003b95eaa74e18e4a5ac6f72986822c

src/plugins/tracedump/CMakeLists.txt [new file with mode: 0644]
src/plugins/tracedump/tracedump.api [new file with mode: 0644]
src/plugins/tracedump/tracedump.c [new file with mode: 0644]
src/plugins/tracedump/tracedump.h [new file with mode: 0644]
src/plugins/tracedump/tracedump_test.c [new file with mode: 0644]
src/vlib/trace.h

diff --git a/src/plugins/tracedump/CMakeLists.txt b/src/plugins/tracedump/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d0491ca
--- /dev/null
@@ -0,0 +1,28 @@
+
+# Copyright (c) <current-year> <your-organization>
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+add_vpp_plugin(tracedump
+  SOURCES
+  tracedump.c
+  tracedump.h
+
+  API_FILES
+  tracedump.api
+
+  API_TEST_SOURCES
+  tracedump_test.c
+)
+
+#  API_TEST_SOURCES
+#  tracedump_test.c
diff --git a/src/plugins/tracedump/tracedump.api b/src/plugins/tracedump/tracedump.api
new file mode 100644 (file)
index 0000000..81e6725
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * tracedump.api - streaming packet trace dump API
+ *
+ * Copyright (c) 2020 Cisco and/or its affiliates
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file tracedump.api
+ * @brief VPP control-plane API messages.
+ *
+ * This file defines VPP control-plane binary API messages which are generally
+ * called through a shared memory interface.
+ */
+
+/* Version and type recitations */
+
+option version = "0.1.0";
+
+service {
+    rpc trace_dump returns trace_dump_reply
+        stream trace_details;
+};
+
+define trace_dump {
+    /* Client identifier, set from api_main.my_client_index */
+    u32 client_index;
+
+    /* Arbitrary context, so client can match reply to request */
+    u32 context;
+
+    /* Dispose of any cached data before we begin */
+    u8 clear_cache;
+
+    /* iterator positions, both ~0 to just clear the cache */
+    u32 thread_id;
+    u32 position;
+
+    /* Max number of replies per burst */
+    u32 max_records;
+};
+
+define trace_dump_reply {
+    u32 context;
+    i32 retval;
+    u32 last_thread_id;
+    u32 last_position;
+    u8 more_this_thread;
+    u8 more_threads;
+    u8 flush_only;
+    u8 done;
+};
+
+define trace_details {
+    /* Client identifier, set from api_main.my_client_index */
+    u32 client_index;
+
+    /* Arbitrary context, so client can match reply to request */
+    u32 context;
+
+    /* Position in the cache of this record */
+    u32 thread_id;
+    u32 position;
+
+    /* More or not */
+    u8 more_this_thread;
+    u8 more_threads;
+    /* Needed when set ends in the middle of a batch */
+    u8 done;
+
+    string trace_data[];
+};
diff --git a/src/plugins/tracedump/tracedump.c b/src/plugins/tracedump/tracedump.c
new file mode 100644 (file)
index 0000000..87e6cf6
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * tracedump.c - skeleton vpp engine plug-in
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/plugin/plugin.h>
+#include <tracedump/tracedump.h>
+#include <vlib/trace.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vpp/app/version.h>
+#include <stdbool.h>
+
+#include <tracedump/tracedump.api_enum.h>
+#include <tracedump/tracedump.api_types.h>
+
+#define REPLY_MSG_ID_BASE tdmp->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+tracedump_main_t tracedump_main;
+
+static int
+trace_cmp (void *a1, void *a2)
+{
+  vlib_trace_header_t **t1 = a1;
+  vlib_trace_header_t **t2 = a2;
+  i64 dt = t1[0]->time - t2[0]->time;
+  return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
+}
+
+static void
+toss_client_cache (tracedump_main_t * tdmp, u32 client_index,
+                  vlib_trace_header_t *** client_trace_cache)
+{
+  vlib_trace_header_t **th;
+  int i;
+
+  /* Across each vlib main... */
+  for (i = 0; i < vec_len (client_trace_cache); i++)
+    {
+      th = client_trace_cache[i];
+      /* Toss the thread's cached data */
+      vec_free (th);
+    }
+  /* And toss the vector of threads */
+  vec_free (client_trace_cache);
+  tdmp->traces[client_index] = client_trace_cache;
+}
+
+/* API message handler */
+static void
+vl_api_trace_dump_t_handler (vl_api_trace_dump_t * mp)
+{
+  vl_api_registration_t *rp;
+  vl_api_trace_dump_reply_t *rmp;
+  vl_api_trace_details_t *dmp;
+  tracedump_main_t *tdmp = &tracedump_main;
+  vlib_trace_header_t ***client_trace_cache, **th;
+  int i, j;
+  u32 client_index;
+  u32 iterator_thread_id, iterator_position, max_records;
+  i32 retval = VNET_API_ERROR_NO_SUCH_ENTRY;
+  u32 last_thread_id = ~0, last_position = ~0;
+  u8 last_done = 0;
+  u8 last_more_this_thread = 0;
+  u8 last_more_threads = 0;
+  u8 *s = 0;
+
+  rp = vl_api_client_index_to_registration (mp->client_index);
+  if (rp == 0)
+    return;
+
+  /* Use the registration pool index... */
+  client_index = rp->vl_api_registration_pool_index;
+
+  vec_validate_init_empty (tdmp->traces, client_index, 0);
+
+  client_trace_cache = tdmp->traces[client_index];
+
+  /* Clear the per-client cache if requested */
+  if (mp->clear_cache)
+    {
+      toss_client_cache (tdmp, client_index, client_trace_cache);
+      client_trace_cache = 0;
+    }
+
+  /* Now, where were we? */
+  iterator_thread_id = clib_net_to_host_u32 (mp->thread_id);
+  iterator_position = clib_net_to_host_u32 (mp->position);
+  max_records = clib_net_to_host_u32 (mp->max_records);
+
+  /* Need a fresh cache for this client? */
+  if (vec_len (client_trace_cache) == 0
+      && (iterator_thread_id != ~0 || iterator_position != ~0))
+    {
+      vlib_worker_thread_barrier_sync (&vlib_global_main);
+
+      /* Make a slot for each worker thread */
+      vec_validate (client_trace_cache, vec_len (vlib_mains) - 1);
+      i = 0;
+
+      /* *INDENT-OFF* */
+      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++;
+      }));
+      /* *INDENT-ON* */
+      vlib_worker_thread_barrier_release (&vlib_global_main);
+    }
+
+  /* Save the cache, one way or the other */
+  tdmp->traces[client_index] = client_trace_cache;
+
+  for (i = iterator_thread_id; i < vec_len (client_trace_cache); i++)
+    {
+      for (j = iterator_position; j < vec_len (client_trace_cache[i]); j++)
+       {
+         if (max_records == 0)
+           break;
+
+         retval = 0;
+         th = &client_trace_cache[i][j];
+
+         vec_reset_length (s);
+
+         s = format (s, "Packet %d\n%U\n\n", j + 1, format_vlib_trace,
+                     &vlib_global_main, th[0]);
+
+         dmp = vl_msg_api_alloc (sizeof (*dmp) + vec_len (s));
+         dmp->_vl_msg_id =
+           htons (VL_API_TRACE_DETAILS + (tdmp->msg_id_base));
+         dmp->context = mp->context;
+         last_thread_id = dmp->thread_id = ntohl (i);
+         last_position = dmp->position = ntohl (j);
+         vl_api_vec_to_api_string (s, &dmp->trace_data);
+         dmp->more_threads = 0;
+         dmp->more_this_thread = 0;
+
+         /* Last record in the batch? */
+         if (max_records == 1)
+           {
+             /* More threads, but not more in this thread? */
+             if (j == (vec_len (client_trace_cache[i]) - 1))
+               dmp->more_threads = 1;
+             else
+               dmp->more_this_thread = 1;
+           }
+         /* Done, may or may not be at the end of a batch. */
+         dmp->done = 0;
+         if (i == (vec_len (client_trace_cache) - 1) &&
+             j == (vec_len (client_trace_cache[i]) - 1))
+           {
+             last_done = dmp->done = 1;
+             last_more_threads = dmp->more_threads = 0;
+             last_more_this_thread = dmp->more_this_thread = 0;
+             vl_api_send_msg (rp, (u8 *) dmp);
+             goto doublebreak;
+           }
+         last_done = dmp->done;
+         vl_api_send_msg (rp, (u8 *) dmp);
+
+         max_records--;
+       }
+      iterator_position = 0;
+    }
+
+doublebreak:;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  rmp->_vl_msg_id = htons (VL_API_TRACE_DUMP_REPLY + (tdmp->msg_id_base));
+  rmp->context = mp->context;
+  rmp->retval = clib_host_to_net_u32 (retval);
+  rmp->last_thread_id = last_thread_id;
+  rmp->last_position = last_position;
+  rmp->done = last_done;
+  rmp->more_this_thread = last_more_this_thread;
+  rmp->more_threads = last_more_threads;
+
+  /* Tag cleanup flushes to make life easy for the client */
+  if (iterator_thread_id == ~0 && iterator_position == ~0)
+    {
+      rmp->retval = 0;
+      rmp->done = 1;
+      rmp->flush_only = 1;
+    }
+  vl_api_send_msg (rp, (u8 *) rmp);
+
+  vec_free (s);
+}
+
+/* API definitions */
+#include <tracedump/tracedump.api.c>
+
+static clib_error_t *
+tracedump_init (vlib_main_t * vm)
+{
+  tracedump_main_t *tdmp = &tracedump_main;
+  api_main_t *am = vlibapi_get_main ();
+
+  clib_error_t *error = 0;
+
+  tdmp->vlib_main = vm;
+  tdmp->vnet_main = vnet_get_main ();
+
+  /* Add our API messages to the global name_crc hash table */
+  tdmp->msg_id_base = setup_message_id_table ();
+
+  am->is_mp_safe[tdmp->msg_id_base + VL_API_TRACE_DUMP] = 1;
+
+  return error;
+}
+
+VLIB_INIT_FUNCTION (tracedump_init);
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () =
+{
+  .version = VPP_BUILD_VER,
+  .description = "Streaming packet trace dump plugin",
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracedump/tracedump.h b/src/plugins/tracedump/tracedump.h
new file mode 100644 (file)
index 0000000..2bd93a2
--- /dev/null
@@ -0,0 +1,55 @@
+
+/*
+ * tracedump.h - skeleton vpp engine plug-in header file
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __included_tracedump_h__
+#define __included_tracedump_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+
+typedef struct
+{
+  /* API message ID base */
+  u16 msg_id_base;
+
+  /*
+   * cached reply data
+   * traces [client_id][thread_id][trace]
+   */
+  vlib_trace_header_t ****traces;
+
+  /* convenience */
+  vlib_main_t *vlib_main;
+  vnet_main_t *vnet_main;
+  ethernet_main_t *ethernet_main;
+} tracedump_main_t;
+
+extern tracedump_main_t tracedump_main;
+
+#endif /* __included_tracedump_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/tracedump/tracedump_test.c b/src/plugins/tracedump/tracedump_test.c
new file mode 100644 (file)
index 0000000..ba811b5
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * tracedump.c - tracedump vpp-api-test plug-in
+ *
+ * Copyright (c) <current-year> <your-organization>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+#include <vnet/api_errno.h>
+#include <stdbool.h>
+
+#define __plugin_msg_base tracedump_test_main.msg_id_base
+#include <vlibapi/vat_helper_macros.h>
+
+/* Declare message IDs */
+#include <tracedump/tracedump.api_enum.h>
+#include <tracedump/tracedump.api_types.h>
+
+typedef struct
+{
+  /* API message ID base */
+  u16 msg_id_base;
+  vat_main_t *vat_main;
+} tracedump_test_main_t;
+
+tracedump_test_main_t tracedump_test_main;
+
+static void
+vl_api_trace_details_t_handler (vl_api_trace_details_t * dmp)
+{
+  u32 thread_id, position;
+
+  thread_id = clib_net_to_host_u32 (dmp->thread_id);
+  position = clib_net_to_host_u32 (dmp->position);
+  fformat
+    (stdout,
+     "thread %d position %d more_this_thread %d more_threads %d done %d\n",
+     thread_id, position, (u32) dmp->more_this_thread,
+     (u32) dmp->more_threads, (u32) dmp->done);
+  fformat (stdout, "  %U\n", vl_api_format_string, (&dmp->trace_data));
+}
+
+
+static void
+vl_api_trace_dump_reply_t_handler (vl_api_trace_dump_reply_t * rmp)
+{
+  tracedump_test_main_t *ttm = &tracedump_test_main;
+  vat_main_t *vam = ttm->vat_main;
+  vl_api_trace_dump_t *mp;
+  i32 retval = (i32) clib_net_to_host_u32 (rmp->retval);
+  u32 thread_id, position;
+
+  if (retval != 0 || rmp->done)
+    {
+      vam->result_ready = 1;
+      vam->retval = retval;
+
+      /* Clear the cache */
+      if (retval == 0 && rmp->flush_only == 0)
+       {
+         M (TRACE_DUMP, mp);
+         mp->clear_cache = 1;
+         mp->thread_id = 0xFFFFFFFF;
+         mp->position = 0xFFFFFFFF;
+         S (mp);
+       }
+      return;
+    }
+
+  /* Figure out where the next batch starts */
+  thread_id = clib_host_to_net_u32 (rmp->last_thread_id);
+  position = clib_host_to_net_u32 (rmp->last_position);
+
+  if (rmp->more_threads)
+    {
+      position = 0;
+      thread_id++;
+    }
+  else
+    position++;
+
+  M (TRACE_DUMP, mp);
+  mp->clear_cache = 0;
+  mp->thread_id = clib_host_to_net_u32 (thread_id);
+  mp->position = clib_host_to_net_u32 (position);
+  mp->max_records = clib_host_to_net_u32 (10);
+  S (mp);
+}
+
+static int
+api_trace_dump (vat_main_t * vam)
+{
+  vl_api_trace_dump_t *mp;
+  int ret;
+
+  M (TRACE_DUMP, mp);
+  mp->clear_cache = 1;
+  mp->thread_id = 0;
+  mp->position = 0;
+  mp->max_records = clib_host_to_net_u32 (10);
+
+  S (mp);
+
+  W (ret);
+  return ret;
+}
+
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_endianfun
+#include <tracedump/tracedump.api.h>
+#undef vl_endianfun
+#define vl_printfun
+#include <tracedump/tracedump.api.h>
+#undef vl_printfun
+
+void
+manual_setup_message_id_table (vat_main_t * vam)
+{
+  vl_msg_api_set_handlers (VL_API_TRACE_DETAILS
+                          + tracedump_test_main.msg_id_base, "trace_details",
+                          vl_api_trace_details_t_handler, vl_noop_handler,
+                          vl_api_trace_details_t_endian,
+                          vl_api_trace_details_t_print,
+                          sizeof (vl_api_trace_details_t), 1);
+}
+
+#define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE manual_setup_message_id_table
+#define VL_API_TRACE_DUMP_REPLY_T_HANDLER
+
+#include <tracedump/tracedump.api_test.c>
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index f83a6d1..233c0ea 100644 (file)
@@ -112,6 +112,8 @@ typedef struct
 
 format_function_t format_vlib_trace;
 
+void trace_apply_filter (struct vlib_main_t *vm);
+
 #endif /* included_vlib_trace_h */
 
 /*