tracedump_main_t tracedump_main;
+
+static void
+vl_api_trace_set_filters_t_handler (vl_api_trace_set_filters_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ tracedump_main_t *tdmp = &tracedump_main;
+ u32 node_index = clib_net_to_host_u32 (mp->node_index);
+ u32 flag = clib_net_to_host_u32 (mp->flag);
+ u32 count = clib_net_to_host_u32 (mp->count);
+ vl_api_trace_set_filters_reply_t *rmp;
+ int rv = 0;
+
+ if (flag == TRACE_FF_NONE)
+ {
+ count = node_index = 0;
+ }
+ else if (flag != TRACE_FF_INCLUDE_NODE && flag != TRACE_FF_EXCLUDE_NODE)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto done;
+ }
+
+ vlib_node_t *node;
+ node = vlib_get_node (vm, node_index);
+ if (!node)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ goto done;
+ }
+
+ trace_filter_set (node_index, flag, count);
+
+done:
+ REPLY_MACRO (VL_API_TRACE_SET_FILTERS_REPLY);
+}
+
+
+static void
+vl_api_trace_capture_packets_t_handler (vl_api_trace_capture_packets_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ tracedump_main_t *tdmp = &tracedump_main;
+ u32 add = clib_net_to_host_u32 (mp->max_packets);
+ u32 node_index = clib_net_to_host_u32 (mp->node_index);
+ u8 filter = mp->use_filter;
+ u8 verbose = mp->verbose;
+ u8 pre_clear = mp->pre_capture_clear;
+ vl_api_trace_capture_packets_reply_t *rmp;
+ int rv = 0;
+
+ if (!vnet_trace_placeholder)
+ vec_validate_aligned (vnet_trace_placeholder, 2048,
+ CLIB_CACHE_LINE_BYTES);
+
+ vlib_node_t *node;
+ node = vlib_get_node (vm, node_index);
+ if (!node)
+ {
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ goto done;
+ }
+
+ if ((node->flags & VLIB_NODE_FLAG_TRACE_SUPPORTED) == 0)
+ {
+ /* FIXME: Make a new, better error like "UNSUPPORTED_NODE_OPERATION"? */
+ rv = VNET_API_ERROR_NO_SUCH_NODE;
+ goto done;
+ }
+
+ if (pre_clear)
+ vlib_trace_stop_and_clear ();
+
+ trace_update_capture_options (add, node_index, filter, verbose);
+
+done:
+ REPLY_MACRO (VL_API_TRACE_CAPTURE_PACKETS_REPLY);
+}
+
+
+static void
+vl_api_trace_clear_capture_t_handler (vl_api_trace_clear_capture_t * mp)
+{
+ vl_api_trace_clear_capture_reply_t *rmp;
+ tracedump_main_t *tdmp = &tracedump_main;
+
+ vlib_trace_stop_and_clear ();
+
+ int rv = 0;
+ REPLY_MACRO (VL_API_TRACE_CLEAR_CAPTURE_REPLY);
+}
+
+
+
static int
trace_cmp (void *a1, void *a2)
{
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 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
&& (iterator_thread_id != ~0 || iterator_position != ~0))
{
- vlib_worker_thread_barrier_sync (&vlib_global_main);
+ vlib_worker_thread_barrier_sync (vlib_get_first_main ());
/* Make a slot for each worker thread */
- vec_validate (client_trace_cache, vec_len (vlib_mains) - 1);
+ vec_validate (client_trace_cache, vlib_get_n_threads () - 1);
i = 0;
- /* *INDENT-OFF* */
- foreach_vlib_main (
- ({
- vlib_trace_main_t *tm = &this_vlib_main->trace_main;
+ foreach_vlib_main ()
+ {
+ vlib_trace_main_t *tm = &this_vlib_main->trace_main;
- /* Filter as directed */
- trace_apply_filter(this_vlib_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]);
- }));
+ 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);
+ /* 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);
+ i++;
+ }
+ vlib_worker_thread_barrier_release (vlib_get_first_main ());
}
/* Save the cache, one way or the other */
vec_reset_length (s);
- s = format (s, "Packet %d\n%U\n\n", j + 1, format_vlib_trace,
- &vlib_global_main, th[0]);
+ 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 =
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->packet_number = htonl (j);
dmp->more_threads = 0;
dmp->more_this_thread = 0;
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>
/* 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;
+ 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;
}