diff options
Diffstat (limited to 'src/plugins/tracedump')
-rw-r--r-- | src/plugins/tracedump/graph_cli.c | 12 | ||||
-rw-r--r-- | src/plugins/tracedump/tracedump.api | 68 | ||||
-rw-r--r-- | src/plugins/tracedump/tracedump.c | 215 | ||||
-rw-r--r-- | src/plugins/tracedump/tracedump_test.c | 95 |
4 files changed, 364 insertions, 26 deletions
diff --git a/src/plugins/tracedump/graph_cli.c b/src/plugins/tracedump/graph_cli.c index 2440295a1a7..6af4706f87d 100644 --- a/src/plugins/tracedump/graph_cli.c +++ b/src/plugins/tracedump/graph_cli.c @@ -16,7 +16,11 @@ */ #include <sys/socket.h> +#ifdef __linux__ #include <linux/if.h> +#else +#include <net/if.h> +#endif /* __linux__ */ #include <vnet/vnet.h> #include <vnet/plugin/plugin.h> @@ -75,9 +79,9 @@ graph_node_show_cmd (vlib_main_t * vm, while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "node %d", &index)) - n = vlib_get_node (vm, index); - else if (unformat (input, "node %v", &name)) - n = vlib_get_node_by_name (vm, name); + n = vlib_get_node (vm, index); + else if (unformat (input, "node %s", &name)) + n = vlib_get_node_by_name (vm, name); else if (unformat (input, "want_arcs")) want_arcs = true; @@ -132,13 +136,11 @@ graph_node_show_cmd (vlib_main_t * vm, return 0; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (graph_node_show_command, static) = { .path = "show graph", .short_help = "show graph [node <index>|<name>] [want_arcs] [input|trace_supported] [drop] [output] [punt] [handoff] [no_free] [polling] [interrupt]", .function = graph_node_show_cmd, }; -/* *INDENT-ON* */ /* diff --git a/src/plugins/tracedump/tracedump.api b/src/plugins/tracedump/tracedump.api index 540b0664074..1b3813fb184 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,69 @@ define trace_details { 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[]; +}; + +autoreply define trace_set_filter_function +{ + u32 client_index; + u32 context; + + string filter_function_name[]; +}; + +define trace_filter_function_dump { + u32 client_index; + u32 context; +}; + +define trace_filter_function_details { + u32 context; + + bool selected; + string name[]; +};
\ No newline at end of file diff --git a/src/plugins/tracedump/tracedump.c b/src/plugins/tracedump/tracedump.c index 17b9a423b53..6a26865c1f0 100644 --- a/src/plugins/tracedump/tracedump.c +++ b/src/plugins/tracedump/tracedump.c @@ -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 @@ -285,9 +288,9 @@ vl_api_trace_dump_t_handler (vl_api_trace_dump_t * mp) { /* More threads, but not more in this thread? */ if (j == (vec_len (client_trace_cache[i]) - 1)) - dmp->more_threads = 1; + last_more_threads = dmp->more_threads = 1; else - dmp->more_this_thread = 1; + last_more_this_thread = dmp->more_this_thread = 1; } /* Done, may or may not be at the end of a batch. */ dmp->done = 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,18 +546,17 @@ 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; } 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 diff --git a/src/plugins/tracedump/tracedump_test.c b/src/plugins/tracedump/tracedump_test.c index abb81059199..b813acc3ecc 100644 --- a/src/plugins/tracedump/tracedump_test.c +++ b/src/plugins/tracedump/tracedump_test.c @@ -155,6 +155,18 @@ vl_api_trace_details_t_handler (vl_api_trace_details_t * dmp) 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 @@ vl_api_trace_dump_reply_t_handler (vl_api_trace_dump_reply_t * rmp) } 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 @@ api_trace_dump (vat_main_t * vam) 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,10 +262,50 @@ api_trace_clear_capture (vat_main_t * vam) 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; +} + +static int +api_trace_set_filter_function (vat_main_t *vam) +{ + vl_api_trace_set_filter_function_t *mp; + int ret; + + M (TRACE_SET_FILTER_FUNCTION, mp); + S (mp); + W (ret); + return ret; +} +static int +api_trace_filter_function_dump (vat_main_t *vam) +{ + vl_api_trace_filter_function_dump_t *mp; + int ret; + + M (TRACE_FILTER_FUNCTION_DUMP, mp); + S (mp); + W (ret); + return ret; +} + +static void +vl_api_trace_filter_function_details_t_handler ( + vl_api_trace_filter_function_details_t *dmp) +{ + fformat (stdout, "name: %U, selected: %u\n\n", vl_api_format_string, + &dmp->name, dmp->selected); +} -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) #define vl_endianfun #include <tracedump/tracedump.api.h> #undef vl_endianfun @@ -249,13 +319,18 @@ api_trace_clear_capture (vat_main_t * vam) 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, vl_api_trace_details_t_print_json, - vl_api_trace_details_t_tojson, vl_api_trace_details_t_fromjson, - vl_api_trace_details_t_calc_size); + vl_msg_api_config (&(vl_msg_api_msg_config_t){ + .id = VL_API_TRACE_DETAILS + tracedump_test_main.msg_id_base, + .name = "trace_details", + .handler = vl_api_trace_details_t_handler, + .endian = vl_api_trace_details_t_endian, + .format_fn = vl_api_trace_details_t_format, + .size = sizeof (vl_api_trace_details_t), + .traced = 1, + .tojson = vl_api_trace_details_t_tojson, + .fromjson = vl_api_trace_details_t_fromjson, + .calc_size = vl_api_trace_details_t_calc_size, + }); } #define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE manual_setup_message_id_table |