mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-14 09:40:14 +00:00
vtysh: defer CLI tree building
We don't need the CLI tree until we actually enter the node. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
8005767b2e
commit
0e06eb8b2e
@ -86,6 +86,9 @@ vector cmdvec = NULL;
|
|||||||
/* Host information structure. */
|
/* Host information structure. */
|
||||||
struct host host;
|
struct host host;
|
||||||
|
|
||||||
|
/* for vtysh, put together CLI trees only when switching into node */
|
||||||
|
static bool defer_cli_tree;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns host.name if any, otherwise
|
* Returns host.name if any, otherwise
|
||||||
* it returns the system hostname.
|
* it returns the system hostname.
|
||||||
@ -285,6 +288,11 @@ const char *cmd_prompt(enum node_type node)
|
|||||||
return cnode->prompt;
|
return cnode->prompt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmd_defer_tree(bool val)
|
||||||
|
{
|
||||||
|
defer_cli_tree = val;
|
||||||
|
}
|
||||||
|
|
||||||
/* Install a command into a node. */
|
/* Install a command into a node. */
|
||||||
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
|
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
|
||||||
{
|
{
|
||||||
@ -319,22 +327,52 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd)
|
|||||||
|
|
||||||
assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
|
assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
|
||||||
|
|
||||||
|
if (cnode->graph_built || !defer_cli_tree) {
|
||||||
struct graph *graph = graph_new();
|
struct graph *graph = graph_new();
|
||||||
struct cmd_token *token =
|
struct cmd_token *token =
|
||||||
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
||||||
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
|
graph_new_node(graph, token,
|
||||||
|
(void (*)(void *)) & cmd_token_del);
|
||||||
|
|
||||||
cmd_graph_parse(graph, cmd);
|
cmd_graph_parse(graph, cmd);
|
||||||
cmd_graph_names(graph);
|
cmd_graph_names(graph);
|
||||||
cmd_graph_merge(cnode->cmdgraph, graph, +1);
|
cmd_graph_merge(cnode->cmdgraph, graph, +1);
|
||||||
graph_delete_graph(graph);
|
graph_delete_graph(graph);
|
||||||
|
|
||||||
|
cnode->graph_built = true;
|
||||||
|
}
|
||||||
|
|
||||||
vector_set(cnode->cmd_vector, (void *)cmd);
|
vector_set(cnode->cmd_vector, (void *)cmd);
|
||||||
|
|
||||||
if (ntype == VIEW_NODE)
|
if (ntype == VIEW_NODE)
|
||||||
_install_element(ENABLE_NODE, cmd);
|
_install_element(ENABLE_NODE, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
|
||||||
|
{
|
||||||
|
struct cmd_node *cnode = arg;
|
||||||
|
const struct cmd_element *cmd = hb->data;
|
||||||
|
struct graph *graph = graph_new();
|
||||||
|
struct cmd_token *token =
|
||||||
|
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
||||||
|
|
||||||
|
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
|
||||||
|
|
||||||
|
cmd_graph_parse(graph, cmd);
|
||||||
|
cmd_graph_names(graph);
|
||||||
|
cmd_graph_merge(cnode->cmdgraph, graph, +1);
|
||||||
|
graph_delete_graph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_finalize_node(struct cmd_node *cnode)
|
||||||
|
{
|
||||||
|
if (cnode->graph_built)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hash_iterate(cnode->cmd_hash, cmd_finalize_iter, cnode);
|
||||||
|
cnode->graph_built = true;
|
||||||
|
}
|
||||||
|
|
||||||
void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
|
void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
|
||||||
{
|
{
|
||||||
struct cmd_node *cnode;
|
struct cmd_node *cnode;
|
||||||
@ -368,15 +406,18 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
|
|||||||
|
|
||||||
vector_unset_value(cnode->cmd_vector, (void *)cmd);
|
vector_unset_value(cnode->cmd_vector, (void *)cmd);
|
||||||
|
|
||||||
|
if (cnode->graph_built) {
|
||||||
struct graph *graph = graph_new();
|
struct graph *graph = graph_new();
|
||||||
struct cmd_token *token =
|
struct cmd_token *token =
|
||||||
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
||||||
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
|
graph_new_node(graph, token,
|
||||||
|
(void (*)(void *)) & cmd_token_del);
|
||||||
|
|
||||||
cmd_graph_parse(graph, cmd);
|
cmd_graph_parse(graph, cmd);
|
||||||
cmd_graph_names(graph);
|
cmd_graph_names(graph);
|
||||||
cmd_graph_merge(cnode->cmdgraph, graph, -1);
|
cmd_graph_merge(cnode->cmdgraph, graph, -1);
|
||||||
graph_delete_graph(graph);
|
graph_delete_graph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
if (ntype == VIEW_NODE)
|
if (ntype == VIEW_NODE)
|
||||||
uninstall_element(ENABLE_NODE, cmd);
|
uninstall_element(ENABLE_NODE, cmd);
|
||||||
@ -503,6 +544,8 @@ static int config_write_host(struct vty *vty)
|
|||||||
static struct graph *cmd_node_graph(vector v, enum node_type ntype)
|
static struct graph *cmd_node_graph(vector v, enum node_type ntype)
|
||||||
{
|
{
|
||||||
struct cmd_node *cnode = vector_slot(v, ntype);
|
struct cmd_node *cnode = vector_slot(v, ntype);
|
||||||
|
|
||||||
|
cmd_finalize_node(cnode);
|
||||||
return cnode->cmdgraph;
|
return cnode->cmdgraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1506,9 +1549,10 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
|
|||||||
{
|
{
|
||||||
struct cmd_node *node = vector_slot(cmdvec, vty->node);
|
struct cmd_node *node = vector_slot(cmdvec, vty->node);
|
||||||
|
|
||||||
if (do_permute)
|
if (do_permute) {
|
||||||
|
cmd_finalize_node(node);
|
||||||
permute(vector_slot(node->cmdgraph->nodes, 0), vty);
|
permute(vector_slot(node->cmdgraph->nodes, 0), vty);
|
||||||
else {
|
} else {
|
||||||
/* loop over all commands at this node */
|
/* loop over all commands at this node */
|
||||||
const struct cmd_element *element = NULL;
|
const struct cmd_element *element = NULL;
|
||||||
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
|
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
|
||||||
@ -1551,7 +1595,10 @@ DEFUN_HIDDEN(show_cli_graph,
|
|||||||
"Dump current command space as DOT graph\n")
|
"Dump current command space as DOT graph\n")
|
||||||
{
|
{
|
||||||
struct cmd_node *cn = vector_slot(cmdvec, vty->node);
|
struct cmd_node *cn = vector_slot(cmdvec, vty->node);
|
||||||
char *dot = cmd_graph_dump_dot(cn->cmdgraph);
|
char *dot;
|
||||||
|
|
||||||
|
cmd_finalize_node(cn);
|
||||||
|
dot = cmd_graph_dump_dot(cn->cmdgraph);
|
||||||
|
|
||||||
vty_out(vty, "%s\n", dot);
|
vty_out(vty, "%s\n", dot);
|
||||||
XFREE(MTYPE_TMP, dot);
|
XFREE(MTYPE_TMP, dot);
|
||||||
|
@ -210,6 +210,9 @@ struct cmd_node {
|
|||||||
|
|
||||||
/* Hashed index of command node list, for de-dupping primarily */
|
/* Hashed index of command node list, for de-dupping primarily */
|
||||||
struct hash *cmd_hash;
|
struct hash *cmd_hash;
|
||||||
|
|
||||||
|
/* set as soon as any command is in cmdgraph */
|
||||||
|
bool graph_built;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return value of the commands. */
|
/* Return value of the commands. */
|
||||||
@ -526,6 +529,12 @@ extern void _install_element(enum node_type, const struct cmd_element *);
|
|||||||
* deprecated/hidden) are not reversed. */
|
* deprecated/hidden) are not reversed. */
|
||||||
extern void uninstall_element(enum node_type, const struct cmd_element *);
|
extern void uninstall_element(enum node_type, const struct cmd_element *);
|
||||||
|
|
||||||
|
/* construct CLI tree only when entering nodes */
|
||||||
|
extern void cmd_defer_tree(bool val);
|
||||||
|
|
||||||
|
/* finish CLI tree for node when above is true (noop otherwise) */
|
||||||
|
extern void cmd_finalize_node(struct cmd_node *node);
|
||||||
|
|
||||||
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
|
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
|
||||||
string with a space between each element (allocated using
|
string with a space between each element (allocated using
|
||||||
XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */
|
XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */
|
||||||
|
@ -395,6 +395,7 @@ DEFUN (grammar_findambig,
|
|||||||
vector_slot(cmdvec, scannode++);
|
vector_slot(cmdvec, scannode++);
|
||||||
if (!cnode)
|
if (!cnode)
|
||||||
continue;
|
continue;
|
||||||
|
cmd_finalize_node(cnode);
|
||||||
nodegraph = cnode->cmdgraph;
|
nodegraph = cnode->cmdgraph;
|
||||||
if (!nodegraph)
|
if (!nodegraph)
|
||||||
continue;
|
continue;
|
||||||
@ -466,6 +467,7 @@ DEFUN (grammar_access,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, "node %d\n", (int)cnode->node);
|
vty_out(vty, "node %d\n", (int)cnode->node);
|
||||||
|
cmd_finalize_node(cnode);
|
||||||
nodegraph = cnode->cmdgraph;
|
nodegraph = cnode->cmdgraph;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -3923,6 +3923,8 @@ void vtysh_uninit(void)
|
|||||||
|
|
||||||
void vtysh_init_vty(void)
|
void vtysh_init_vty(void)
|
||||||
{
|
{
|
||||||
|
cmd_defer_tree(true);
|
||||||
|
|
||||||
/* Make vty structure. */
|
/* Make vty structure. */
|
||||||
vty = vty_new();
|
vty = vty_new();
|
||||||
vty->type = VTY_SHELL;
|
vty->type = VTY_SHELL;
|
||||||
|
Loading…
Reference in New Issue
Block a user