diff options
Diffstat (limited to 'src/vlib')
-rw-r--r-- | src/vlib/cli.c | 252 | ||||
-rw-r--r-- | src/vlib/cli.h | 6 |
2 files changed, 209 insertions, 49 deletions
diff --git a/src/vlib/cli.c b/src/vlib/cli.c index 131a5931ac2..ec27c481374 100644 --- a/src/vlib/cli.c +++ b/src/vlib/cli.c @@ -44,6 +44,9 @@ #include <unistd.h> #include <ctype.h> +/** \file src/vlib/cli.c Debug CLI Implementation + */ + int vl_api_set_elog_trace_api_messages (int enable); int vl_api_get_elog_trace_api_messages (void); @@ -642,6 +645,7 @@ vlib_cli_dispatch_sub_commands (vlib_main_t * vm, if (!c->is_mp_safe) vlib_worker_thread_barrier_sync (vm); + c->hit_counter++; c_error = c->function (vm, si, c); if (!c->is_mp_safe) @@ -1550,55 +1554,6 @@ done: } #endif -static int -cli_path_compare (void *a1, void *a2) -{ - u8 **s1 = a1; - u8 **s2 = a2; - - if ((vec_len (*s1) < vec_len (*s2)) && - memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0) - return -1; - - - if ((vec_len (*s1) > vec_len (*s2)) && - memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0) - return 1; - - return vec_cmp (*s1, *s2); -} - -static clib_error_t * -show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vlib_cli_main_t *cm = &vm->cli_main; - vlib_cli_command_t *cli; - u8 **paths = 0, **s; - - /* *INDENT-OFF* */ - vec_foreach (cli, cm->commands) - if (vec_len (cli->path) > 0) - vec_add1 (paths, (u8 *) cli->path); - - vec_sort_with_function (paths, cli_path_compare); - - vec_foreach (s, paths) - vlib_cli_output (vm, "%v", *s); - /* *INDENT-ON* */ - - vec_free (paths); - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_cli_command, static) = { - .path = "show cli", - .short_help = "Show cli commands", - .function = show_cli_cmd_fn, -}; -/* *INDENT-ON* */ - static clib_error_t * elog_trace_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -1722,6 +1677,205 @@ VLIB_CLI_COMMAND (suspend_command, static) = .path = "suspend", .short_help = "suspend debug CLI for 30ms", .function = suspend_command_fn, + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + + +static int +sort_cmds_by_path (void *a1, void *a2) +{ + u32 *index1 = a1; + u32 *index2 = a2; + vlib_main_t *vm = vlib_get_main (); + vlib_cli_main_t *cm = &vm->cli_main; + vlib_cli_command_t *c1, *c2; + int i, lmin; + + c1 = vec_elt_at_index (cm->commands, *index1); + c2 = vec_elt_at_index (cm->commands, *index2); + + lmin = vec_len (c1->path); + lmin = (vec_len (c2->path) >= lmin) ? lmin : vec_len (c2->path); + + for (i = 0; i < lmin; i++) + { + if (c1->path[i] < c2->path[i]) + return -1; + else if (c1->path[i] > c2->path[i]) + return 1; + } + + return 0; +} + +typedef struct +{ + vlib_cli_main_t *cm; + u32 parent_command_index; + int show_mp_safe; + int show_not_mp_safe; + int show_hit; + int clear_hit; +} vlib_cli_walk_args_t; + +static void +cli_recursive_walk (vlib_cli_walk_args_t * aa) +{ + vlib_cli_command_t *parent; + vlib_cli_sub_command_t *sub; + vlib_cli_walk_args_t _a, *a = &_a; + vlib_cli_main_t *cm; + int i; + + /* Copy args into this stack frame */ + *a = *aa; + cm = a->cm; + + parent = vec_elt_at_index (cm->commands, a->parent_command_index); + + if (parent->function) + { + if (((a->show_mp_safe && parent->is_mp_safe) + || (a->show_not_mp_safe && !parent->is_mp_safe)) + && (a->show_hit == 0 || parent->hit_counter)) + { + vec_add1 (cm->sort_vector, a->parent_command_index); + } + + if (a->clear_hit) + parent->hit_counter = 0; + } + + for (i = 0; i < vec_len (parent->sub_commands); i++) + { + sub = vec_elt_at_index (parent->sub_commands, i); + a->parent_command_index = sub->index; + cli_recursive_walk (a); + } +} + +static u8 * +format_mp_safe (u8 * s, va_list * args) +{ + vlib_cli_main_t *cm = va_arg (*args, vlib_cli_main_t *); + int show_mp_safe = va_arg (*args, int); + int show_not_mp_safe = va_arg (*args, int); + int show_hit = va_arg (*args, int); + int clear_hit = va_arg (*args, int); + vlib_cli_command_t *c; + vlib_cli_walk_args_t _a, *a = &_a; + int i; + char *format_string = "\n%v"; + + if (show_hit) + format_string = "\n%v: %u"; + + vec_reset_length (cm->sort_vector); + + a->cm = cm; + a->parent_command_index = 0; + a->show_mp_safe = show_mp_safe; + a->show_not_mp_safe = show_not_mp_safe; + a->show_hit = show_hit; + a->clear_hit = clear_hit; + + cli_recursive_walk (a); + + vec_sort_with_function (cm->sort_vector, sort_cmds_by_path); + + for (i = 0; i < vec_len (cm->sort_vector); i++) + { + c = vec_elt_at_index (cm->commands, cm->sort_vector[i]); + s = format (s, format_string, c->path, c->hit_counter); + } + + return s; +} + + +static clib_error_t * +show_cli_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + int show_mp_safe = 0; + int show_not_mp_safe = 0; + int show_hit = 0; + int clear_hit = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "mp-safe")) + show_mp_safe = 1; + if (unformat (input, "not-mp-safe")) + show_not_mp_safe = 1; + else if (unformat (input, "hit")) + show_hit = 1; + else if (unformat (input, "clear-hit")) + clear_hit = 1; + else + break; + } + + /* default set: all cli commands */ + if (clear_hit == 0 && (show_mp_safe + show_not_mp_safe) == 0) + show_mp_safe = show_not_mp_safe = 1; + + vlib_cli_output (vm, "%U", format_mp_safe, &vm->cli_main, + show_mp_safe, show_not_mp_safe, show_hit, clear_hit); + if (clear_hit) + vlib_cli_output (vm, "hit counters cleared..."); + + return 0; +} + +/*? + * Displays debug cli command information + * + * @cliexpar + * @cliexstart{show cli [mp-safe][not-mp-safe][hit][clear-hit]} + * + * "show cli" displays the entire debug cli: + * + * abf attach + * abf policy + * adjacency counters + * api trace + * app ns + * bfd key del + * ... and so on ... + * + * "show cli mp-safe" displays mp-safe debug CLI commands: + * + * abf policy + * binary-api + * create vhost-user + * exec + * ip container + * ip mroute + * ip probe-neighbor + * ip route + * ip scan-neighbor + * ip table + * ip6 table + * + * "show cli not-mp-safe" displays debug CLI commands + * which cause worker thread barrier synchronization + * + * "show cli hit" displays commands which have been executed. Qualify + * as desired with "mp-safe" or "not-mp-safe". + * + * "show cli clear-hit" clears the per-command hit counters. + * @cliexend +?*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_cli_command, static) = +{ + .path = "show cli", + .short_help = "show cli [mp-safe][not-mp-safe][hit][clear-hit]", + .function = show_cli_command_fn, + .is_mp_safe = 1, }; /* *INDENT-ON* */ diff --git a/src/vlib/cli.h b/src/vlib/cli.h index 13216dc4025..6d6d7e2b7fa 100644 --- a/src/vlib/cli.h +++ b/src/vlib/cli.h @@ -126,6 +126,8 @@ typedef struct vlib_cli_command_t /* List of CLI commands, built by constructors */ struct vlib_cli_command_t *next_cli_command; + /* Hit counter */ + u32 hit_counter; } vlib_cli_command_t; typedef void (vlib_cli_output_function_t) (uword arg, @@ -149,6 +151,10 @@ typedef struct /* registration list added by constructors */ vlib_cli_command_t *cli_command_registrations; + + /* index vector, to sort commands, etc. */ + u32 *sort_vector; + } vlib_cli_main_t; #ifndef CLIB_MARCH_VARIANT |