diff options
Diffstat (limited to 'vlib/vlib/cli.c')
-rw-r--r-- | vlib/vlib/cli.c | 1173 |
1 files changed, 0 insertions, 1173 deletions
diff --git a/vlib/vlib/cli.c b/vlib/vlib/cli.c deleted file mode 100644 index 2d141115857..00000000000 --- a/vlib/vlib/cli.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * cli.c: command line interface - * - * Copyright (c) 2008 Eliot Dresselhaus - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <vlib/vlib.h> -#include <vppinfra/cpu.h> - -/* Root of all show commands. */ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vlib_cli_show_command, static) = { - .path = "show", - .short_help = "Show commands", -}; -/* *INDENT-ON* */ - -/* Root of all clear commands. */ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = { - .path = "clear", - .short_help = "Clear commands", -}; -/* *INDENT-ON* */ - -/* Root of all set commands. */ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vlib_cli_set_command, static) = { - .path = "set", - .short_help = "Set commands", -}; -/* *INDENT-ON* */ - -/* Root of all test commands. */ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (vlib_cli_test_command, static) = { - .path = "test", - .short_help = "Test commands", -}; -/* *INDENT-ON* */ - -/* Returns bitmap of commands which match key. */ -static uword * -vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input) -{ - int i, n; - uword *match = 0; - vlib_cli_parse_position_t *p; - - unformat_skip_white_space (input); - - for (i = 0;; i++) - { - uword k; - - k = unformat_get_input (input); - switch (k) - { - case 'a' ... 'z': - case 'A' ... 'Z': - case '0' ... '9': - case '-': - case '_': - break; - - case ' ': - case '\t': - case '\r': - case '\n': - case UNFORMAT_END_OF_INPUT: - /* White space or end of input removes any non-white - matches that were before possible. */ - if (i < vec_len (c->sub_command_positions) - && clib_bitmap_count_set_bits (match) > 1) - { - p = vec_elt_at_index (c->sub_command_positions, i); - for (n = 0; n < vec_len (p->bitmaps); n++) - match = clib_bitmap_andnot (match, p->bitmaps[n]); - } - goto done; - - default: - unformat_put_input (input); - goto done; - } - - if (i >= vec_len (c->sub_command_positions)) - { - no_match: - clib_bitmap_free (match); - return 0; - } - - p = vec_elt_at_index (c->sub_command_positions, i); - if (vec_len (p->bitmaps) == 0) - goto no_match; - - n = k - p->min_char; - if (n < 0 || n >= vec_len (p->bitmaps)) - goto no_match; - - if (i == 0) - match = clib_bitmap_dup (p->bitmaps[n]); - else - match = clib_bitmap_and (match, p->bitmaps[n]); - - if (clib_bitmap_is_zero (match)) - goto no_match; - } - -done: - return match; -} - -/* Looks for string based sub-input formatted { SUB-INPUT }. */ -uword -unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args) -{ - unformat_input_t *sub_input = va_arg (*args, unformat_input_t *); - u8 *s; - uword c; - - while (1) - { - c = unformat_get_input (i); - switch (c) - { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - break; - - case '{': - default: - /* Put back paren. */ - if (c != UNFORMAT_END_OF_INPUT) - unformat_put_input (i); - - if (c == '{' && unformat (i, "%v", &s)) - { - unformat_init_vector (sub_input, s); - return 1; - } - return 0; - } - } - return 0; -} - -static vlib_cli_command_t * -get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si) -{ - vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si); - return vec_elt_at_index (cm->commands, s->index); -} - -static uword -unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args) -{ - vlib_main_t *vm = va_arg (*args, vlib_main_t *); - vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *); - vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **); - vlib_cli_main_t *cm = &vm->cli_main; - uword *match_bitmap, is_unique, index; - - { - vlib_cli_sub_rule_t *sr; - vlib_cli_parse_rule_t *r; - vec_foreach (sr, c->sub_rules) - { - void **d; - r = vec_elt_at_index (cm->parse_rules, sr->rule_index); - vec_add2 (cm->parse_rule_data, d, 1); - vec_reset_length (d[0]); - if (r->data_size) - d[0] = _vec_resize (d[0], - /* length increment */ 1, - r->data_size, - /* header_bytes */ 0, - /* data align */ sizeof (uword)); - if (unformat_user (i, r->unformat_function, vm, d[0])) - { - *result = vec_elt_at_index (cm->commands, sr->command_index); - return 1; - } - } - } - - match_bitmap = vlib_cli_sub_command_match (c, i); - is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1; - index = ~0; - if (is_unique) - { - index = clib_bitmap_first_set (match_bitmap); - *result = get_sub_command (cm, c, index); - } - clib_bitmap_free (match_bitmap); - - return is_unique; -} - -static u8 * -format_vlib_cli_command_help (u8 * s, va_list * args) -{ - vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *); - int is_long = va_arg (*args, int); - if (is_long && c->long_help) - s = format (s, "%s", c->long_help); - else if (c->short_help) - s = format (s, "%s", c->short_help); - else - s = format (s, "%v commands", c->path); - return s; -} - -static u8 * -format_vlib_cli_parse_rule_name (u8 * s, va_list * args) -{ - vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *); - return format (s, "<%U>", format_c_identifier, r->name); -} - -static u8 * -format_vlib_cli_path (u8 * s, va_list * args) -{ - u8 *path = va_arg (*args, u8 *); - int i, in_rule; - in_rule = 0; - for (i = 0; i < vec_len (path); i++) - { - switch (path[i]) - { - case '%': - in_rule = 1; - vec_add1 (s, '<'); /* start of <RULE> */ - break; - - case '_': - /* _ -> space in rules. */ - vec_add1 (s, in_rule ? ' ' : '_'); - break; - - case ' ': - if (in_rule) - { - vec_add1 (s, '>'); /* end of <RULE> */ - in_rule = 0; - } - vec_add1 (s, ' '); - break; - - default: - vec_add1 (s, path[i]); - break; - } - } - - if (in_rule) - vec_add1 (s, '>'); /* terminate <RULE> */ - - return s; -} - -static vlib_cli_command_t * -all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index) -{ - vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index); - vlib_cli_sub_command_t *sc; - vlib_cli_sub_rule_t *sr; - - if (c->function) - vec_add1 (subs, c[0]); - - vec_foreach (sr, c->sub_rules) - subs = all_subs (cm, subs, sr->command_index); - vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index); - - return subs; -} - -static int -vlib_cli_cmp_rule (void *a1, void *a2) -{ - vlib_cli_sub_rule_t *r1 = a1; - vlib_cli_sub_rule_t *r2 = a2; - - return vec_cmp (r1->name, r2->name); -} - -static int -vlib_cli_cmp_command (void *a1, void *a2) -{ - vlib_cli_command_t *c1 = a1; - vlib_cli_command_t *c2 = a2; - - return vec_cmp (c1->path, c2->path); -} - -static clib_error_t * -vlib_cli_dispatch_sub_commands (vlib_main_t * vm, - vlib_cli_main_t * cm, - unformat_input_t * input, - uword parent_command_index) -{ - vlib_cli_command_t *parent, *c; - clib_error_t *error = 0; - unformat_input_t sub_input; - u8 *string; - uword is_main_dispatch = cm == &vm->cli_main; - - parent = vec_elt_at_index (cm->commands, parent_command_index); - if (is_main_dispatch && unformat (input, "help")) - { - uword help_at_end_of_line, i; - - help_at_end_of_line = - unformat_check_input (input) == UNFORMAT_END_OF_INPUT; - while (1) - { - c = parent; - if (unformat_user - (input, unformat_vlib_cli_sub_command, vm, c, &parent)) - ; - - else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT)) - goto unknown; - - else - break; - } - - /* help SUB-COMMAND => long format help. - "help" at end of line: show all commands. */ - if (!help_at_end_of_line) - vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c, - /* is_long */ 1); - - else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0) - vlib_cli_output (vm, "%v: no sub-commands", c->path); - - else - { - vlib_cli_sub_command_t *sc; - vlib_cli_sub_rule_t *sr, *subs; - - subs = vec_dup (c->sub_rules); - - /* Add in rules if any. */ - vec_foreach (sc, c->sub_commands) - { - vec_add2 (subs, sr, 1); - sr->name = sc->name; - sr->command_index = sc->index; - sr->rule_index = ~0; - } - - vec_sort_with_function (subs, vlib_cli_cmp_rule); - - for (i = 0; i < vec_len (subs); i++) - { - vlib_cli_command_t *d; - vlib_cli_parse_rule_t *r; - - d = vec_elt_at_index (cm->commands, subs[i].command_index); - r = - subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules, - subs - [i].rule_index) : - 0; - - if (r) - vlib_cli_output - (vm, " %-30U %U", - format_vlib_cli_parse_rule_name, r, - format_vlib_cli_command_help, d, /* is_long */ 0); - else - vlib_cli_output - (vm, " %-30v %U", - subs[i].name, - format_vlib_cli_command_help, d, /* is_long */ 0); - } - - vec_free (subs); - } - } - - else if (is_main_dispatch - && (unformat (input, "choices") || unformat (input, "?"))) - { - vlib_cli_command_t *sub, *subs; - - subs = all_subs (cm, 0, parent_command_index); - vec_sort_with_function (subs, vlib_cli_cmp_command); - vec_foreach (sub, subs) - vlib_cli_output (vm, " %-40U %U", - format_vlib_cli_path, sub->path, - format_vlib_cli_command_help, sub, /* is_long */ 0); - vec_free (subs); - } - - else if (unformat (input, "comment %v", &string)) - { - vec_free (string); - } - - else if (unformat (input, "uncomment %U", - unformat_vlib_cli_sub_input, &sub_input)) - { - error = - vlib_cli_dispatch_sub_commands (vm, cm, &sub_input, - parent_command_index); - unformat_free (&sub_input); - } - - else - if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c)) - { - unformat_input_t *si; - uword has_sub_commands = - vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0; - - si = input; - if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input)) - si = &sub_input; - - if (has_sub_commands) - error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands); - - if (has_sub_commands && !error) - /* Found valid sub-command. */ ; - - else if (c->function) - { - clib_error_t *c_error; - - /* Skip white space for benefit of called function. */ - unformat_skip_white_space (si); - - if (unformat (si, "?")) - { - vlib_cli_output (vm, " %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c, /* is_long */ - 0); - } - else - { - if (!c->is_mp_safe) - vlib_worker_thread_barrier_sync (vm); - - c_error = c->function (vm, si, c); - - if (!c->is_mp_safe) - vlib_worker_thread_barrier_release (vm); - - if (c_error) - { - error = - clib_error_return (0, "%v: %v", c->path, c_error->what); - clib_error_free (c_error); - /* Free sub input. */ - if (si != input) - unformat_free (si); - - return error; - } - } - - /* Free any previous error. */ - clib_error_free (error); - } - - else if (!error) - error = clib_error_return (0, "%v: no sub-commands", c->path); - - /* Free sub input. */ - if (si != input) - unformat_free (si); - } - - else - goto unknown; - - return error; - -unknown: - if (parent->path) - return clib_error_return (0, "%v: unknown input `%U'", parent->path, - format_unformat_error, input); - else - return clib_error_return (0, "unknown input `%U'", format_unformat_error, - input); -} - - -void vlib_unix_error_report (vlib_main_t *, clib_error_t *) - __attribute__ ((weak)); - -void -vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error) -{ -} - -/* Process CLI input. */ -void -vlib_cli_input (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_output_function_t * function, uword function_arg) -{ - vlib_process_t *cp = vlib_get_current_process (vm); - vlib_cli_main_t *cm = &vm->cli_main; - clib_error_t *error; - vlib_cli_output_function_t *save_function; - uword save_function_arg; - - save_function = cp->output_function; - save_function_arg = cp->output_function_arg; - - cp->output_function = function; - cp->output_function_arg = function_arg; - - do - { - vec_reset_length (cm->parse_rule_data); - error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */ - 0); - } - while (!error && !unformat (input, "%U", unformat_eof)); - - if (error) - { - vlib_cli_output (vm, "%v", error->what); - vlib_unix_error_report (vm, error); - clib_error_free (error); - } - - cp->output_function = save_function; - cp->output_function_arg = save_function_arg; -} - -/* Output to current CLI connection. */ -void -vlib_cli_output (vlib_main_t * vm, char *fmt, ...) -{ - vlib_process_t *cp = vlib_get_current_process (vm); - va_list va; - u8 *s; - - va_start (va, fmt); - s = va_format (0, fmt, &va); - va_end (va); - - /* Terminate with \n if not present. */ - if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n') - vec_add1 (s, '\n'); - - if ((!cp) || (!cp->output_function)) - fformat (stdout, "%v", s); - else - cp->output_function (cp->output_function_arg, s, vec_len (s)); - - vec_free (s); -} - -static clib_error_t * -show_memory_usage (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - int verbose = 0; - clib_error_t *error; - u32 index = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "verbose")) - verbose = 1; - else - { - error = clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - return error; - } - } - - /* *INDENT-OFF* */ - foreach_vlib_main ( - ({ - vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name); - vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose); - index++; - })); - /* *INDENT-ON* */ - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_memory_usage_command, static) = { - .path = "show memory", - .short_help = "Show current memory usage", - .function = show_memory_usage, -}; -/* *INDENT-ON* */ - -static clib_error_t * -show_cpu (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ -#define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c); - _("Model name", "%U", format_cpu_model_name); - _("Microarchitecture", "%U", format_cpu_uarch); - _("Flags", "%U", format_cpu_flags); - _("Base frequency", "%.2f GHz", - ((f64) vm->clib_time.clocks_per_second) * 1e-9); -#undef _ - return 0; -} - -/*? - * Displays various information about the CPU. - * - * @cliexpar - * @cliexstart{show cpu} - * Model name: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz - * Microarchitecture: Broadwell (Broadwell-EP/EX) - * Flags: sse3 ssse3 sse41 sse42 avx avx2 aes - * Base Frequency: 3.20 GHz - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_cpu_command, static) = { - .path = "show cpu", - .short_help = "Show cpu information", - .function = show_cpu, -}; - -/* *INDENT-ON* */ -static clib_error_t * -enable_disable_memory_trace (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - clib_error_t *error = 0; - int enable; - - if (!unformat_user (input, unformat_vlib_enable_disable, &enable)) - { - error = clib_error_return (0, "expecting enable/on or disable/off"); - goto done; - } - - clib_mem_trace (enable); - -done: - return error; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = { - .path = "memory-trace", - .short_help = "Enable/disable memory allocation trace", - .function = enable_disable_memory_trace, -}; -/* *INDENT-ON* */ - - -static clib_error_t * -test_heap_validate (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - clib_error_t *error = 0; - void *heap; - mheap_t *mheap; - - if (unformat (input, "on")) - { - /* *INDENT-OFF* */ - foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; - mheap = mheap_header(heap); - mheap->flags |= MHEAP_FLAG_VALIDATE; - // Turn off small object cache because it delays detection of errors - mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE; - }); - /* *INDENT-ON* */ - - } - else if (unformat (input, "off")) - { - /* *INDENT-OFF* */ - foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; - mheap = mheap_header(heap); - mheap->flags &= ~MHEAP_FLAG_VALIDATE; - mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE; - }); - /* *INDENT-ON* */ - } - else if (unformat (input, "now")) - { - /* *INDENT-OFF* */ - foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; - mheap = mheap_header(heap); - mheap_validate(heap); - }); - /* *INDENT-ON* */ - vlib_cli_output (vm, "heap validation complete"); - - } - else - { - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - } - - return error; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = { - .path = "test heap-validate", - .short_help = "<on/off/now> validate heap on future allocs/frees or right now", - .function = test_heap_validate, -}; -/* *INDENT-ON* */ - -#ifdef TEST_CODE -/* - * A trivial test harness to verify the per-process output_function - * is working correcty. - */ - -static clib_error_t * -sleep_ten_seconds (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - u16 i; - u16 my_id = rand (); - - vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id); - - for (i = 0; i < 10; i++) - { - vlib_process_wait_for_event_or_clock (vm, 1.0); - vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id); - } - vlib_cli_output (vm, "Done with sleep with id %u\n", my_id); - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (ping_command, static) = { - .path = "test sleep", - .function = sleep_ten_seconds, - .short_help = "Sleep for 10 seconds", -}; -/* *INDENT-ON* */ -#endif /* ifdef TEST_CODE */ - -static uword -vlib_cli_normalize_path (char *input, char **result) -{ - char *i = input; - char *s = 0; - uword l = 0; - uword index_of_last_space = ~0; - - while (*i != 0) - { - u8 c = *i++; - /* Multiple white space -> single space. */ - switch (c) - { - case ' ': - case '\t': - case '\n': - case '\r': - if (l > 0 && s[l - 1] != ' ') - { - vec_add1 (s, ' '); - l++; - } - break; - - default: - if (l > 0 && s[l - 1] == ' ') - index_of_last_space = vec_len (s); - vec_add1 (s, c); - l++; - break; - } - } - - /* Remove any extra space at end. */ - if (l > 0 && s[l - 1] == ' ') - _vec_len (s) -= 1; - - *result = s; - return index_of_last_space; -} - -always_inline uword -parent_path_len (char *path) -{ - word i; - for (i = vec_len (path) - 1; i >= 0; i--) - { - if (path[i] == ' ') - return i; - } - return ~0; -} - -static void -add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index) -{ - vlib_cli_command_t *p, *c; - vlib_cli_sub_command_t *sub_c; - u8 *sub_name; - word i, l; - - p = vec_elt_at_index (cm->commands, parent_index); - c = vec_elt_at_index (cm->commands, child_index); - - l = parent_path_len (c->path); - if (l == ~0) - sub_name = vec_dup ((u8 *) c->path); - else - { - ASSERT (l + 1 < vec_len (c->path)); - sub_name = 0; - vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1)); - } - - if (sub_name[0] == '%') - { - uword *q; - vlib_cli_sub_rule_t *sr; - - /* Remove %. */ - vec_delete (sub_name, 1, 0); - - if (!p->sub_rule_index_by_name) - p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32, - sizeof (sub_name[0]), - sizeof (uword)); - q = hash_get_mem (p->sub_rule_index_by_name, sub_name); - if (q) - { - sr = vec_elt_at_index (p->sub_rules, q[0]); - ASSERT (sr->command_index == child_index); - return; - } - - q = hash_get_mem (cm->parse_rule_index_by_name, sub_name); - if (!q) - { - clib_error ("reference to unknown rule `%%%v' in path `%v'", - sub_name, c->path); - return; - } - - hash_set_mem (p->sub_rule_index_by_name, sub_name, - vec_len (p->sub_rules)); - vec_add2 (p->sub_rules, sr, 1); - sr->name = sub_name; - sr->rule_index = q[0]; - sr->command_index = child_index; - return; - } - - if (!p->sub_command_index_by_name) - p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32, - sizeof (c->path[0]), - sizeof (uword)); - - /* Check if sub-command has already been created. */ - if (hash_get_mem (p->sub_command_index_by_name, sub_name)) - { - vec_free (sub_name); - return; - } - - vec_add2 (p->sub_commands, sub_c, 1); - sub_c->index = child_index; - sub_c->name = sub_name; - hash_set_mem (p->sub_command_index_by_name, sub_c->name, - sub_c - p->sub_commands); - - vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1); - for (i = 0; i < vec_len (sub_c->name); i++) - { - int n; - vlib_cli_parse_position_t *pos; - - pos = vec_elt_at_index (p->sub_command_positions, i); - - if (!pos->bitmaps) - pos->min_char = sub_c->name[i]; - - n = sub_c->name[i] - pos->min_char; - if (n < 0) - { - pos->min_char = sub_c->name[i]; - vec_insert (pos->bitmaps, -n, 0); - n = 0; - } - - vec_validate (pos->bitmaps, n); - pos->bitmaps[n] = - clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands); - } -} - -static void -vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci) -{ - uword p_len, pi, *p; - char *p_path; - vlib_cli_command_t *c, *parent; - - /* Root command (index 0) should have already been added. */ - ASSERT (vec_len (cm->commands) > 0); - - c = vec_elt_at_index (cm->commands, ci); - p_len = parent_path_len (c->path); - - /* No space? Parent is root command. */ - if (p_len == ~0) - { - add_sub_command (cm, 0, ci); - return; - } - - p_path = 0; - vec_add (p_path, c->path, p_len); - - p = hash_get_mem (cm->command_index_by_path, p_path); - - /* Parent exists? */ - if (!p) - { - /* Parent does not exist; create it. */ - vec_add2 (cm->commands, parent, 1); - parent->path = p_path; - hash_set_mem (cm->command_index_by_path, parent->path, - parent - cm->commands); - pi = parent - cm->commands; - } - else - { - pi = p[0]; - vec_free (p_path); - } - - add_sub_command (cm, pi, ci); - - /* Create parent's parent. */ - if (!p) - vlib_cli_make_parent (cm, pi); -} - -always_inline uword -vlib_cli_command_is_empty (vlib_cli_command_t * c) -{ - return (c->long_help == 0 && c->short_help == 0 && c->function == 0); -} - -clib_error_t * -vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c) -{ - vlib_cli_main_t *cm = &vm->cli_main; - clib_error_t *error = 0; - uword ci, *p; - char *normalized_path; - - if ((error = vlib_call_init_function (vm, vlib_cli_init))) - return error; - - (void) vlib_cli_normalize_path (c->path, &normalized_path); - - if (!cm->command_index_by_path) - cm->command_index_by_path = hash_create_vec ( /* initial length */ 32, - sizeof (c->path[0]), - sizeof (uword)); - - /* See if command already exists with given path. */ - p = hash_get_mem (cm->command_index_by_path, normalized_path); - if (p) - { - vlib_cli_command_t *d; - - ci = p[0]; - d = vec_elt_at_index (cm->commands, ci); - - /* If existing command was created via vlib_cli_make_parent - replaced it with callers data. */ - if (vlib_cli_command_is_empty (d)) - { - vlib_cli_command_t save = d[0]; - - ASSERT (!vlib_cli_command_is_empty (c)); - - /* Copy callers fields. */ - d[0] = c[0]; - - /* Save internal fields. */ - d->path = save.path; - d->sub_commands = save.sub_commands; - d->sub_command_index_by_name = save.sub_command_index_by_name; - d->sub_command_positions = save.sub_command_positions; - d->sub_rules = save.sub_rules; - } - else - error = - clib_error_return (0, "duplicate command name with path %v", - normalized_path); - - vec_free (normalized_path); - if (error) - return error; - } - else - { - /* Command does not exist: create it. */ - - /* Add root command (index 0). */ - if (vec_len (cm->commands) == 0) - { - /* Create command with index 0; path is empty string. */ - vec_resize (cm->commands, 1); - } - - ci = vec_len (cm->commands); - hash_set_mem (cm->command_index_by_path, normalized_path, ci); - vec_add1 (cm->commands, c[0]); - - c = vec_elt_at_index (cm->commands, ci); - c->path = normalized_path; - - /* Don't inherit from registration. */ - c->sub_commands = 0; - c->sub_command_index_by_name = 0; - c->sub_command_positions = 0; - } - - vlib_cli_make_parent (cm, ci); - return 0; -} - -clib_error_t * -vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg) -{ - vlib_cli_main_t *cm = &vm->cli_main; - vlib_cli_parse_rule_t *r; - clib_error_t *error = 0; - u8 *r_name; - uword *p; - - if (!cm->parse_rule_index_by_name) - cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32, - sizeof (r->name[0]), - sizeof (uword)); - - /* Make vector copy of name. */ - r_name = format (0, "%s", r_reg->name); - - if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name))) - { - vec_free (r_name); - return clib_error_return (0, "duplicate parse rule name `%s'", - r_reg->name); - } - - vec_add2 (cm->parse_rules, r, 1); - r[0] = r_reg[0]; - r->name = (char *) r_name; - hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules); - - return error; -} - -#if 0 -/* $$$ turn back on again someday, maybe */ -static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm, - vlib_cli_parse_rule_t * - lo, - vlib_cli_parse_rule_t * - hi) - __attribute__ ((unused)) -{ - clib_error_t *error = 0; - vlib_cli_parse_rule_t *r; - - for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0)) - { - if (!r->name || strlen (r->name) == 0) - { - error = clib_error_return (0, "parse rule with no name"); - goto done; - } - - error = vlib_cli_register_parse_rule (vm, r); - if (error) - goto done; - } - -done: - return error; -} -#endif - -static clib_error_t * -vlib_cli_init (vlib_main_t * vm) -{ - vlib_cli_main_t *cm = &vm->cli_main; - clib_error_t *error = 0; - vlib_cli_command_t *cmd; - - cmd = cm->cli_command_registrations; - - while (cmd) - { - error = vlib_cli_register (vm, cmd); - if (error) - return error; - cmd = cmd->next_cli_command; - } - return error; -} - -VLIB_INIT_FUNCTION (vlib_cli_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ |