summaryrefslogtreecommitdiffstats
path: root/src/plugins/tracedump/tracedump.c
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2020-07-07 17:33:38 -0400
committerDamjan Marion <dmarion@me.com>2020-07-16 21:39:50 +0000
commit65b65a4692c84462ecf500806795ea0350073e18 (patch)
tree7c502a71b7ab710d0b6bc1448c78f1ade0f4392b /src/plugins/tracedump/tracedump.c
parentac0326fc5ae7ac4a8126bbc2f496a92fcfe4755e (diff)
misc: add tracedump API plugin
Type: feature Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I586547508003b95eaa74e18e4a5ac6f72986822c
Diffstat (limited to 'src/plugins/tracedump/tracedump.c')
-rw-r--r--src/plugins/tracedump/tracedump.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/plugins/tracedump/tracedump.c b/src/plugins/tracedump/tracedump.c
new file mode 100644
index 00000000000..87e6cf6ac5f
--- /dev/null
+++ b/src/plugins/tracedump/tracedump.c
@@ -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:
+ */