* command.h: (struct cmd_node) Add a hash, so duplicate installs of a cmd_element to a command node can be detected. To help catch strays from the VIEW/ENABLE node consolidation particularly (installs to VIEW automatically install to ENABLE too now). * command.c: (cmd_hash_{key,cmp}) helpers for the hash - just directly on the pointer value is sufficient to catch the main problem. (install_node) setup the hash for the command node. (install_element) check for duplicate installs. The assert on the cmd_parse_format seems misplaced. (install_default_basic) separate the basic, VIEW, node default commands to here. (cmd_init) get rid of dupes, given consolidation. (cmd_terminate) clean up the node command hash.
Not done: The (struct cmd_node)'s vector could be replaced with the cmd hash, however much of the command parser depends heavily on the vector and it's a lot of work to change. A vector_lookup_value could also work, particularly if vector could be backed by a hash. The duplicate check could be disabled in releases - but useful in development. It's a little extra overhead at startup. The command initialisation overhead is already something that bites in micro-benchmarks - makes it easy for other implementations to show how much faster they are with benchmarks where other load is low enough that startup time is a factor. --- lib/command.c | 68 +++++++++++++++++++++++++++++++++++++++-------------------- lib/command.h | 6 +++++- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/lib/command.c b/lib/command.c index 1f77116..0271325 100644 --- a/lib/command.c +++ b/lib/command.c @@ -212,6 +212,18 @@ argv_concat (const char **argv, int argc, int shift) return str; } +static unsigned int +cmd_hash_key (void *p) +{ + return (uintptr_t) p; +} + +static int +cmd_hash_cmp (const void *a, const void *b) +{ + return a == b; +} + /* Install top node of command vector. */ void install_node (struct cmd_node *node, @@ -220,6 +232,7 @@ install_node (struct cmd_node *node, vector_set_index (cmdvec, node->node, node); node->func = func; node->cmd_vector = vector_init (VECTOR_MIN_SIZE); + node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp); } /* Breaking up string into each command piece. I assume given @@ -608,7 +621,11 @@ install_element (enum node_type ntype, struct cmd_element *cmd) /* cmd_init hasn't been called */ if (!cmdvec) - return; + { + fprintf (stderr, "%s called before cmd_init, breakage likely\n", + __func__); + return; + } cnode = vector_slot (cmdvec, ntype); @@ -618,13 +635,21 @@ install_element (enum node_type ntype, struct cmd_element *cmd) ntype); exit (1); } - + + if (hash_lookup (cnode->cmd_hash, cmd) != NULL) + { + fprintf (stderr, + "Multiple command installs to node %d of command:\n%s\n", + ntype, cmd->string); + return; + } + + assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern)); + vector_set (cnode->cmd_vector, cmd); if (cmd->tokens == NULL) cmd->tokens = cmd_parse_format(cmd->string, cmd->doc); - else - assert(0); - + if (ntype == VIEW_NODE) install_element (ENABLE_NODE, cmd); } @@ -4124,15 +4149,21 @@ host_config_get (void) return host.config; } -void -install_default (enum node_type node) +static void +install_default_basic (enum node_type node) { install_element (node, &config_exit_cmd); install_element (node, &config_quit_cmd); - install_element (node, &config_end_cmd); install_element (node, &config_help_cmd); install_element (node, &config_list_cmd); +} + +/* Install common/default commands for a privileged node */ +void +install_default (enum node_type node) +{ + install_element (node, &config_end_cmd); install_element (node, &config_write_terminal_cmd); install_element (node, &config_write_file_cmd); install_element (node, &config_write_memory_cmd); @@ -4152,7 +4183,7 @@ cmd_init (int terminal) /* Allocate initial top vector of commands. */ cmdvec = vector_init (VECTOR_MIN_SIZE); - + /* Default host value settings. */ host.name = NULL; host.password = NULL; @@ -4175,10 +4206,8 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_version_cmd); if (terminal) { - install_element (VIEW_NODE, &config_list_cmd); - install_element (VIEW_NODE, &config_exit_cmd); - install_element (VIEW_NODE, &config_quit_cmd); - install_element (VIEW_NODE, &config_help_cmd); + install_default_basic (VIEW_NODE); + install_element (VIEW_NODE, &config_enable_cmd); install_element (VIEW_NODE, &config_terminal_length_cmd); install_element (VIEW_NODE, &config_terminal_no_length_cmd); @@ -4186,10 +4215,6 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_commandtree_cmd); install_element (VIEW_NODE, &echo_cmd); - install_element (RESTRICTED_NODE, &config_list_cmd); - install_element (RESTRICTED_NODE, &config_exit_cmd); - install_element (RESTRICTED_NODE, &config_quit_cmd); - install_element (RESTRICTED_NODE, &config_help_cmd); install_element (RESTRICTED_NODE, &config_enable_cmd); install_element (RESTRICTED_NODE, &config_terminal_length_cmd); install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd); @@ -4205,15 +4230,9 @@ cmd_init (int terminal) install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); } install_element (ENABLE_NODE, &show_startup_config_cmd); - install_element (ENABLE_NODE, &show_version_cmd); - install_element (ENABLE_NODE, &show_commandtree_cmd); if (terminal) { - install_element (ENABLE_NODE, &config_terminal_length_cmd); - install_element (ENABLE_NODE, &config_terminal_no_length_cmd); - install_element (ENABLE_NODE, &show_logging_cmd); - install_element (ENABLE_NODE, &echo_cmd); install_element (ENABLE_NODE, &config_logmsg_cmd); install_default (CONFIG_NODE); @@ -4339,6 +4358,9 @@ cmd_terminate () cmd_terminate_element(cmd_element); vector_free (cmd_node_v); + hash_clean (cmd_node->cmd_hash, NULL); + hash_free (cmd_node->cmd_hash); + cmd_node->cmd_hash = NULL; } vector_free (cmdvec); diff --git a/lib/command.h b/lib/command.h index f575ed3..d8029fb 100644 --- a/lib/command.h +++ b/lib/command.h @@ -26,6 +26,7 @@ #include "vector.h" #include "vty.h" #include "lib/route_types.h" +#include "hash.h" /* Host configuration variable */ struct host @@ -128,7 +129,10 @@ struct cmd_node int (*func) (struct vty *); /* Vector of this node's command list. */ - vector cmd_vector; + vector cmd_vector; + + /* Hashed index of command node list, for de-dupping primarily */ + struct hash *cmd_hash; }; enum -- 2.5.5 _______________________________________________ Quagga-dev mailing list Quagga-dev@lists.quagga.net https://lists.quagga.net/mailman/listinfo/quagga-dev