summaryrefslogtreecommitdiff
path: root/lib/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c200
1 files changed, 85 insertions, 115 deletions
diff --git a/lib/command.c b/lib/command.c
index 9dac60599c..ea66a17bb0 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -74,6 +74,7 @@ const struct message tokennames[] = {
item(JOIN_TKN),
item(START_TKN),
item(END_TKN),
+ item(NEG_ONLY_TKN),
{0},
};
/* clang-format on */
@@ -85,6 +86,9 @@ vector cmdvec = NULL;
/* Host information structure. */
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
* it returns the system hostname.
@@ -160,6 +164,9 @@ static bool vty_check_node_for_xpath_decrement(enum node_type target_node,
|| node == BGP_FLOWSPECV6_NODE))
return false;
+ if (target_node == INTERFACE_NODE && node == LINK_PARAMS_NODE)
+ return false;
+
return true;
}
@@ -281,6 +288,11 @@ const char *cmd_prompt(enum node_type node)
return cnode->prompt;
}
+void cmd_defer_tree(bool val)
+{
+ defer_cli_tree = val;
+}
+
/* Install a command into a node. */
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
{
@@ -315,20 +327,50 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd)
assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
+ if (cnode->graph_built || !defer_cli_tree) {
+ 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);
+
+ cnode->graph_built = true;
+ }
+
+ vector_set(cnode->cmd_vector, (void *)cmd);
+
+ if (ntype == VIEW_NODE)
+ _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);
+}
- vector_set(cnode->cmd_vector, (void *)cmd);
+void cmd_finalize_node(struct cmd_node *cnode)
+{
+ if (cnode->graph_built)
+ return;
- if (ntype == VIEW_NODE)
- _install_element(ENABLE_NODE, cmd);
+ 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)
@@ -364,15 +406,18 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
vector_unset_value(cnode->cmd_vector, (void *)cmd);
- 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);
+ if (cnode->graph_built) {
+ 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);
+ cmd_graph_parse(graph, cmd);
+ cmd_graph_names(graph);
+ cmd_graph_merge(cnode->cmdgraph, graph, -1);
+ graph_delete_graph(graph);
+ }
if (ntype == VIEW_NODE)
uninstall_element(ENABLE_NODE, cmd);
@@ -499,6 +544,8 @@ static int config_write_host(struct vty *vty)
static struct graph *cmd_node_graph(vector v, enum node_type ntype)
{
struct cmd_node *cnode = vector_slot(v, ntype);
+
+ cmd_finalize_node(cnode);
return cnode->cmdgraph;
}
@@ -849,96 +896,13 @@ char **cmd_complete_command(vector vline, struct vty *vty, int *status)
/* MUST eventually converge on CONFIG_NODE */
enum node_type node_parent(enum node_type node)
{
- enum node_type ret;
+ struct cmd_node *cnode;
assert(node > CONFIG_NODE);
- switch (node) {
- case BGP_VPNV4_NODE:
- case BGP_VPNV6_NODE:
- case BGP_FLOWSPECV4_NODE:
- case BGP_FLOWSPECV6_NODE:
- case BGP_VRF_POLICY_NODE:
- case BGP_VNC_DEFAULTS_NODE:
- case BGP_VNC_NVE_GROUP_NODE:
- case BGP_VNC_L2_GROUP_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV4L_NODE:
- case BGP_IPV6_NODE:
- case BGP_IPV6M_NODE:
- case BGP_EVPN_NODE:
- case BGP_IPV6L_NODE:
- case BMP_NODE:
- ret = BGP_NODE;
- break;
- case BGP_EVPN_VNI_NODE:
- ret = BGP_EVPN_NODE;
- break;
- case KEYCHAIN_KEY_NODE:
- ret = KEYCHAIN_NODE;
- break;
- case LINK_PARAMS_NODE:
- ret = INTERFACE_NODE;
- break;
- case LDP_IPV4_NODE:
- case LDP_IPV6_NODE:
- ret = LDP_NODE;
- break;
- case LDP_IPV4_IFACE_NODE:
- ret = LDP_IPV4_NODE;
- break;
- case LDP_IPV6_IFACE_NODE:
- ret = LDP_IPV6_NODE;
- break;
- case LDP_PSEUDOWIRE_NODE:
- ret = LDP_L2VPN_NODE;
- break;
- case BFD_PEER_NODE:
- ret = BFD_NODE;
- break;
- case BFD_PROFILE_NODE:
- ret = BFD_NODE;
- break;
- case SR_TRAFFIC_ENG_NODE:
- ret = SEGMENT_ROUTING_NODE;
- break;
- case SR_SEGMENT_LIST_NODE:
- ret = SR_TRAFFIC_ENG_NODE;
- break;
- case SR_POLICY_NODE:
- ret = SR_TRAFFIC_ENG_NODE;
- break;
- case SR_CANDIDATE_DYN_NODE:
- ret = SR_POLICY_NODE;
- break;
- case PCEP_NODE:
- ret = SR_TRAFFIC_ENG_NODE;
- break;
- case PCEP_PCE_CONFIG_NODE:
- ret = PCEP_NODE;
- break;
- case PCEP_PCE_NODE:
- ret = PCEP_NODE;
- break;
- case PCEP_PCC_NODE:
- ret = PCEP_NODE;
- break;
- case SRV6_NODE:
- ret = SEGMENT_ROUTING_NODE;
- break;
- case SRV6_LOCS_NODE:
- ret = SRV6_NODE;
- break;
- case SRV6_LOC_NODE:
- ret = SRV6_LOCS_NODE;
- break;
- default:
- ret = CONFIG_NODE;
- break;
- }
+ cnode = vector_lookup(cmdvec, node);
- return ret;
+ return cnode->parent_node;
}
/* Execute command by argument vline vector. */
@@ -1585,9 +1549,10 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
{
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);
- else {
+ } else {
/* loop over all commands at this node */
const struct cmd_element *element = NULL;
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
@@ -1630,7 +1595,10 @@ DEFUN_HIDDEN(show_cli_graph,
"Dump current command space as DOT graph\n")
{
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);
XFREE(MTYPE_TMP, dot);
@@ -2419,28 +2387,30 @@ DEFUN(find,
}
#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
-DEFUN(script,
- script_cmd,
- "script SCRIPT",
- "Test command - execute a script\n"
- "Script name (same as filename in /etc/frr/scripts/\n")
+DEFUN(script, script_cmd, "script SCRIPT FUNCTION",
+ "Test command - execute a function in a script\n"
+ "Script name (same as filename in /etc/frr/scripts/)\n"
+ "Function name (in the script)\n")
{
struct prefix p;
(void)str2prefix("1.2.3.4/24", &p);
- struct frrscript *fs = frrscript_load(argv[1]->arg, NULL);
+ struct frrscript *fs = frrscript_new(argv[1]->arg);
- if (fs == NULL) {
- vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n",
- argv[1]->arg);
- } else {
- int ret = frrscript_call(fs, ("p", &p));
- char buf[40];
- prefix2str(&p, buf, sizeof(buf));
- vty_out(vty, "p: %s\n", buf);
- vty_out(vty, "Script result: %d\n", ret);
+ if (frrscript_load(fs, argv[2]->arg, NULL)) {
+ vty_out(vty,
+ "/etc/frr/scripts/%s.lua or function '%s' not found\n",
+ argv[1]->arg, argv[2]->arg);
}
+ int ret = frrscript_call(fs, argv[2]->arg, ("p", &p));
+ char buf[40];
+ prefix2str(&p, buf, sizeof(buf));
+ vty_out(vty, "p: %s\n", buf);
+ vty_out(vty, "Script result: %d\n", ret);
+
+ frrscript_delete(fs);
+
return CMD_SUCCESS;
}
#endif