From 52fa5f21b911aaf1c50feb560dd3683b83625d2f Mon Sep 17 00:00:00 2001 From: Mohammed Hawari Date: Fri, 26 May 2023 14:52:50 +0200 Subject: [PATCH] vlib: introduce trace filter functions Change-Id: I7a988fafe98599e4fcf7cdaa307a69b9d76650f0 Signed-off-by: Mohammed Hawari Type: improvement --- src/plugins/tracedump/tracedump.api | 20 +++++ src/plugins/tracedump/tracedump.c | 55 ++++++++++++ src/plugins/tracedump/tracedump_test.c | 32 +++++++ src/vlib/trace.c | 152 ++++++++++++++++++++++++++++++--- src/vlib/trace.h | 37 ++++++++ src/vlib/trace_funcs.h | 7 +- src/vnet/classify/vnet_classify.c | 7 +- 7 files changed, 292 insertions(+), 18 deletions(-) diff --git a/src/plugins/tracedump/tracedump.api b/src/plugins/tracedump/tracedump.api index ed6dd3f13bd..1b3813fb184 100644 --- a/src/plugins/tracedump/tracedump.api +++ b/src/plugins/tracedump/tracedump.api @@ -192,4 +192,24 @@ define trace_v2_details { 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 10107ac799e..6510a948c57 100644 --- a/src/plugins/tracedump/tracedump.c +++ b/src/plugins/tracedump/tracedump.c @@ -473,6 +473,61 @@ vl_api_trace_clear_cache_t_handler (vl_api_trace_clear_cache_t *mp) 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 diff --git a/src/plugins/tracedump/tracedump_test.c b/src/plugins/tracedump/tracedump_test.c index 97fd4092d89..b813acc3ecc 100644 --- a/src/plugins/tracedump/tracedump_test.c +++ b/src/plugins/tracedump/tracedump_test.c @@ -274,6 +274,38 @@ api_trace_clear_cache (vat_main_t *vam) 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_endianfun #include #undef vl_endianfun diff --git a/src/vlib/trace.c b/src/vlib/trace.c index 49b521eb886..c6a0ef7ec0d 100644 --- a/src/vlib/trace.c +++ b/src/vlib/trace.c @@ -612,18 +612,6 @@ vlib_trace_cli_reference (void) { } -int -vnet_is_packet_traced (vlib_buffer_t * b, - u32 classify_table_index, int func) -__attribute__ ((weak)); - -int -vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func) -{ - clib_warning ("BUG: STUB called"); - return 1; -} - void * vlib_add_trace (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_buffer_t * b, u32 n_data_bytes) @@ -631,8 +619,148 @@ vlib_add_trace (vlib_main_t * vm, return vlib_add_trace_inline (vm, r, b, n_data_bytes); } +vlib_is_packet_traced_fn_t * +vlib_is_packet_traced_function_from_name (const char *name) +{ + vlib_trace_filter_function_registration_t *reg = + vlib_trace_filter_main.trace_filter_registration; + while (reg) + { + if (clib_strcmp (reg->name, name) == 0) + break; + reg = reg->next; + } + if (!reg) + return 0; + return reg->function; +} + +static vlib_is_packet_traced_fn_t * +vlib_is_packet_traced_default_function () +{ + vlib_trace_filter_function_registration_t *reg = + vlib_trace_filter_main.trace_filter_registration; + vlib_trace_filter_function_registration_t *tmp_reg = reg; + while (reg) + { + if (reg->priority > tmp_reg->priority) + tmp_reg = reg; + reg = reg->next; + } + return tmp_reg->function; +} + +static clib_error_t * +vlib_trace_filter_function_init (vlib_main_t *vm) +{ + vlib_is_packet_traced_fn_t *default_fn = + vlib_is_packet_traced_default_function (); + foreach_vlib_main () + { + vlib_trace_main_t *tm = &this_vlib_main->trace_main; + tm->current_trace_filter_function = default_fn; + } + return 0; +} + +vlib_trace_filter_main_t vlib_trace_filter_main; + +VLIB_INIT_FUNCTION (vlib_trace_filter_function_init); + +static clib_error_t * +show_trace_filter_function (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main; + vlib_trace_main_t *tm = &vm->trace_main; + vlib_is_packet_traced_fn_t *current_trace_filter_fn = + tm->current_trace_filter_function; + vlib_trace_filter_function_registration_t *reg = + tfm->trace_filter_registration; + + while (reg) + { + vlib_cli_output (vm, "%sname:%s description: %s priority: %u", + reg->function == current_trace_filter_fn ? "(*) " : "", + reg->name, reg->description, reg->priority); + reg = reg->next; + } + return 0; +} + +VLIB_CLI_COMMAND (show_trace_filter_function_cli, static) = { + .path = "show trace filter function", + .short_help = "show trace filter function", + .function = show_trace_filter_function, +}; + +uword +unformat_vlib_trace_filter_function (unformat_input_t *input, va_list *args) +{ + vlib_is_packet_traced_fn_t **res = + va_arg (*args, vlib_is_packet_traced_fn_t **); + vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main; + + vlib_trace_filter_function_registration_t *reg = + tfm->trace_filter_registration; + while (reg) + { + if (unformat (input, reg->name)) + { + *res = reg->function; + return 1; + } + reg = reg->next; + } + return 0; +} + +void +vlib_set_trace_filter_function (vlib_is_packet_traced_fn_t *x) +{ + foreach_vlib_main () + { + this_vlib_main->trace_main.current_trace_filter_function = x; + } +} + +static clib_error_t * +set_trace_filter_function (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + vlib_is_packet_traced_fn_t *res = 0; + clib_error_t *error = 0; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + while (unformat_check_input (line_input) != (uword) UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_vlib_trace_filter_function, + &res)) + ; + else + { + error = clib_error_create ( + "expected valid trace filter function, got `%U'", + format_unformat_error, line_input); + goto done; + } + } + vlib_set_trace_filter_function (res); + +done: + unformat_free (line_input); + return error; +} + +VLIB_CLI_COMMAND (set_trace_filter_function_cli, static) = { + .path = "set trace filter function", + .short_help = "set trace filter function ", + .function = set_trace_filter_function, +}; /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vlib/trace.h b/src/vlib/trace.h index d045271f853..46256ce4e9e 100644 --- a/src/vlib/trace.h +++ b/src/vlib/trace.h @@ -80,6 +80,17 @@ typedef void *(vlib_add_trace_callback_t) (struct vlib_main_t *, struct vlib_buffer_t * b, u32 n_data_bytes); +typedef int (vlib_is_packet_traced_fn_t) (vlib_buffer_t *b, + u32 classify_table_index, int func); +typedef struct vlib_trace_filter_function_registration +{ + const char *name; + const char *description; + int priority; + vlib_is_packet_traced_fn_t *function; + struct vlib_trace_filter_function_registration *next; +} vlib_trace_filter_function_registration_t; + typedef struct { /* Pool of trace buffers. */ @@ -109,9 +120,32 @@ typedef struct /* a callback to enable customized addition of a new trace */ vlib_add_trace_callback_t *add_trace_callback; + vlib_is_packet_traced_fn_t *current_trace_filter_function; + } vlib_trace_main_t; format_function_t format_vlib_trace; +typedef struct +{ + vlib_trace_filter_function_registration_t *trace_filter_registration; +} vlib_trace_filter_main_t; + +extern vlib_trace_filter_main_t vlib_trace_filter_main; +#define VLIB_REGISTER_TRACE_FILTER_FUNCTION(x, ...) \ + __VA_ARGS__ vlib_trace_filter_function_registration_t \ + __vlib_trace_filter_function_##x; \ + static void __clib_constructor \ + __vlib_trace_filter_function_registration_##x (void) \ + { \ + vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main; \ + __vlib_trace_filter_function_##x.next = tfm->trace_filter_registration; \ + tfm->trace_filter_registration = &__vlib_trace_filter_function_##x; \ + } \ + __VA_ARGS__ vlib_trace_filter_function_registration_t \ + __vlib_trace_filter_function_##x + +vlib_is_packet_traced_fn_t * +vlib_is_packet_traced_function_from_name (const char *name); void trace_apply_filter (struct vlib_main_t *vm); int trace_time_cmp (void *a1, void *a2); @@ -121,6 +155,9 @@ void trace_update_capture_options (u32 add, u32 node_index, u32 filter, u8 verbose); void trace_filter_set (u32 node_index, u32 flag, u32 count); void clear_trace_buffer (void); +void vlib_set_trace_filter_function (vlib_is_packet_traced_fn_t *x); +uword unformat_vlib_trace_filter_function (unformat_input_t *input, + va_list *args); #endif /* included_vlib_trace_h */ diff --git a/src/vlib/trace_funcs.h b/src/vlib/trace_funcs.h index 3ed4768bc7b..9b45346b467 100644 --- a/src/vlib/trace_funcs.h +++ b/src/vlib/trace_funcs.h @@ -138,10 +138,7 @@ vlib_trace_next_frame (vlib_main_t * vm, nf->flags |= VLIB_FRAME_TRACE; } -void trace_apply_filter (vlib_main_t * vm); -int vnet_is_packet_traced (vlib_buffer_t * b, - u32 classify_table_index, int func); - +void trace_apply_filter (vlib_main_t *vm); /* * Mark buffer as traced and allocate trace buffer. @@ -164,7 +161,7 @@ vlib_trace_buffer (vlib_main_t * vm, if (PREDICT_FALSE (vlib_global_main.trace_filter.trace_filter_enable)) { /* See if we're supposed to trace this packet... */ - if (vnet_is_packet_traced ( + if (tm->current_trace_filter_function ( b, vlib_global_main.trace_filter.classify_table_index, 0 /* full classify */) != 1) return 0; diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c index 8ad8a6ad554..fb9a59c1f01 100644 --- a/src/vnet/classify/vnet_classify.c +++ b/src/vnet/classify/vnet_classify.c @@ -3085,7 +3085,12 @@ vnet_is_packet_traced (vlib_buffer_t * b, u32 classify_table_index, int func) { return vnet_is_packet_traced_inline (b, classify_table_index, func); } - +VLIB_REGISTER_TRACE_FILTER_FUNCTION (vnet_is_packet_traced_fn, static) = { + .name = "vnet_is_packet_traced", + .description = "classifier based filter", + .priority = 50, + .function = vnet_is_packet_traced +}; #define TEST_CODE 0 -- 2.16.6