misc: fix tracedump API to match CLI behavior
When dumping packets from multiple threads using the API, first all
packets from thread 0 are dumped then all ones from thread 1, etc
Until we reach the limit specified by the API call, so we could never
get packets trace from threads with higher ids.
However, the tracedump CLI dump a maximum number of packets from all
threads, which we can expect from the API to do.
We also add a trace_clear_cache API so the client gets an answer when
he only wants to clear its packet cache.
Type: improvement
Change-Id: I0d4df8f6210a298ac3f22cd651eb4d8f445e1034
Signed-off-by: Maxime Peim <mpeim@cisco.com>
diff --git a/src/plugins/tracedump/tracedump.api b/src/plugins/tracedump/tracedump.api
index 540b066..ed6dd3f 100644
--- a/src/plugins/tracedump/tracedump.api
+++ b/src/plugins/tracedump/tracedump.api
@@ -25,7 +25,7 @@
*/
-option version = "0.1.0";
+option version = "0.2.0";
enum trace_filter_flag : u32
{
@@ -147,3 +147,49 @@
u32 packet_number;
string trace_data[];
};
+
+/** \brief trace_clear_cache
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+autoreply define trace_clear_cache {
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief trace_v2_dump
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param thread_id - specific thread to dump from, ~0 to dump from all
+ @param position - position of the first packet to dump in the per thread cache, ~0 to only clear the cache
+ @param max - maximum of packets to dump from each thread
+ @param clear_cache - dispose of any cached data before we begin
+*/
+define trace_v2_dump {
+ u32 client_index;
+ u32 context;
+
+ u32 thread_id [default=0xffffffff];
+ u32 position;
+ u32 max [default=50];
+ bool clear_cache;
+
+ option vat_help = "trace_v2_dump [thread_id <tid>] [position <pos>] [max <max>]";
+};
+
+/** \brief trace_v2_details
+ @param context - sender context, to match reply w/ request
+ @param thread_id - thread index from which the packet come from
+ @param position - position of the packet in its thread cache
+ @param more - true if there is still more packets to dump for this thread
+ @param trace_data - string packet data
+*/
+define trace_v2_details {
+ u32 context;
+
+ u32 thread_id;
+ u32 position;
+ bool more;
+
+ string trace_data[];
+};
\ No newline at end of file
diff --git a/src/plugins/tracedump/tracedump.c b/src/plugins/tracedump/tracedump.c
index 0f1612c..0c0f3b4 100644
--- a/src/plugins/tracedump/tracedump.c
+++ b/src/plugins/tracedump/tracedump.c
@@ -335,6 +335,143 @@
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++)
+ {
+ // 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);
+}
+
/* API definitions */
#include <tracedump/tracedump.api.c>
@@ -353,6 +490,7 @@
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;
}
diff --git a/src/plugins/tracedump/tracedump_test.c b/src/plugins/tracedump/tracedump_test.c
index 1a2c818..97fd409 100644
--- a/src/plugins/tracedump/tracedump_test.c
+++ b/src/plugins/tracedump/tracedump_test.c
@@ -155,6 +155,18 @@
packet_number, vl_api_format_string, (&dmp->trace_data));
}
+static void
+vl_api_trace_v2_details_t_handler (vl_api_trace_v2_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 %d", thread_id, position,
+ dmp->more);
+ fformat (stdout, "Packet %d\n%U\n\n", position, vl_api_format_string,
+ (&dmp->trace_data));
+}
static void
vl_api_trace_dump_reply_t_handler (vl_api_trace_dump_reply_t * rmp)
@@ -203,7 +215,7 @@
}
static int
-api_trace_dump (vat_main_t * vam)
+api_trace_dump (vat_main_t *vam)
{
vl_api_trace_dump_t *mp;
int ret;
@@ -220,8 +232,26 @@
return ret;
}
+static int
+api_trace_v2_dump (vat_main_t *vam)
+{
+ vl_api_trace_v2_dump_t *mp;
+ int ret;
+
+ M (TRACE_V2_DUMP, mp);
+ mp->clear_cache = 1;
+ mp->thread_id = ~0;
+ mp->position = 0;
+ mp->max = clib_host_to_net_u32 (10);
+
+ S (mp);
+
+ W (ret);
+ return ret;
+}
+
int
-api_trace_clear_capture (vat_main_t * vam)
+api_trace_clear_capture (vat_main_t *vam)
{
vl_api_trace_clear_capture_t *mp;
int ret;
@@ -232,8 +262,17 @@
return ret;
}
+static int
+api_trace_clear_cache (vat_main_t *vam)
+{
+ vl_api_trace_clear_capture_t *mp;
+ int ret;
-
+ M (TRACE_CLEAR_CACHE, mp);
+ S (mp);
+ W (ret);
+ return ret;
+}
#define vl_endianfun
#include <tracedump/tracedump.api.h>