Skip to content

Commit e347606

Browse files
committed
lib: correctly exit CLI nodes on file config load
The (legacy) code for reading split configs tries to execute config commands in parent nodes, but doesn't call the node_exit function when it goes up to a parent node. This breaks BGP RPKI setup (and extended syslog, which is in the next commit.) Doing this correctly is a slight bit involved since the node_exit callbacks should only be called if the command is actually executed on a parent node. Signed-off-by: David Lamparter <[email protected]>
1 parent db2baed commit e347606

File tree

2 files changed

+45
-37
lines changed

2 files changed

+45
-37
lines changed

lib/command.c

+44-37
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,31 @@ enum node_type node_parent(enum node_type node)
900900
/* Execute command by argument vline vector. */
901901
static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
902902
struct vty *vty,
903-
const struct cmd_element **cmd)
903+
const struct cmd_element **cmd,
904+
unsigned int up_level)
904905
{
905906
struct list *argv_list;
906907
enum matcher_rv status;
907908
const struct cmd_element *matched_element = NULL;
909+
unsigned int i;
910+
int xpath_index = vty->xpath_index;
911+
int node = vty->node;
908912

909-
struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
913+
/* only happens for legacy split config file load; need to check for
914+
* a match before calling node_exit handlers below
915+
*/
916+
for (i = 0; i < up_level; i++) {
917+
if (node <= CONFIG_NODE)
918+
return CMD_NO_LEVEL_UP;
919+
920+
node = node_parent(node);
921+
922+
if (xpath_index > 0
923+
&& vty_check_node_for_xpath_decrement(node, vty->node))
924+
xpath_index--;
925+
}
926+
927+
struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
910928
status = command_match(cmdgraph, vline, &argv_list, &matched_element);
911929

912930
if (cmd)
@@ -926,12 +944,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
926944
}
927945
}
928946

947+
for (i = 0; i < up_level; i++)
948+
cmd_exit(vty);
949+
929950
// build argv array from argv list
930951
struct cmd_token **argv = XMALLOC(
931952
MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
932953
struct listnode *ln;
933954
struct cmd_token *token;
934-
unsigned int i = 0;
955+
956+
i = 0;
935957
for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
936958
argv[i++] = token;
937959

@@ -1012,7 +1034,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
10121034
vector_lookup(vline, index));
10131035

10141036
ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
1015-
vty, cmd);
1037+
vty, cmd, 0);
10161038

10171039
vector_free(shifted_vline);
10181040
vty->node = onode;
@@ -1021,7 +1043,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
10211043
}
10221044

10231045
saved_ret = ret =
1024-
cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
1046+
cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
10251047

10261048
if (vtysh)
10271049
return saved_ret;
@@ -1038,7 +1060,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
10381060
onode))
10391061
vty->xpath_index--;
10401062
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
1041-
vty, cmd);
1063+
vty, cmd, 0);
10421064
if (ret == CMD_SUCCESS || ret == CMD_WARNING
10431065
|| ret == CMD_NOT_MY_INSTANCE
10441066
|| ret == CMD_WARNING_CONFIG_FAILED)
@@ -1069,7 +1091,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
10691091
int cmd_execute_command_strict(vector vline, struct vty *vty,
10701092
const struct cmd_element **cmd)
10711093
{
1072-
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
1094+
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
10731095
}
10741096

10751097
/*
@@ -1220,6 +1242,7 @@ int command_config_read_one_line(struct vty *vty,
12201242
{
12211243
vector vline;
12221244
int ret;
1245+
unsigned up_level = 0;
12231246

12241247
vline = cmd_make_strvec(vty->buf);
12251248

@@ -1230,36 +1253,20 @@ int command_config_read_one_line(struct vty *vty,
12301253
/* Execute configuration command : this is strict match */
12311254
ret = cmd_execute_command_strict(vline, vty, cmd);
12321255

1233-
// Climb the tree and try the command again at each node
1234-
if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1235-
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1236-
&& ret != CMD_SUCCESS && ret != CMD_WARNING
1237-
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
1238-
&& vty->node != CONFIG_NODE) {
1239-
int saved_node = vty->node;
1240-
int saved_xpath_index = vty->xpath_index;
1241-
1242-
while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1243-
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1244-
&& ret != CMD_SUCCESS && ret != CMD_WARNING
1245-
&& vty->node > CONFIG_NODE) {
1246-
vty->node = node_parent(vty->node);
1247-
if (vty->xpath_index > 0
1248-
&& vty_check_node_for_xpath_decrement(vty->node,
1249-
saved_node))
1250-
vty->xpath_index--;
1251-
ret = cmd_execute_command_strict(vline, vty, cmd);
1252-
}
1253-
1254-
// If climbing the tree did not work then ignore the command and
1255-
// stay at the same node
1256-
if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1257-
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1258-
&& ret != CMD_SUCCESS && ret != CMD_WARNING) {
1259-
vty->node = saved_node;
1260-
vty->xpath_index = saved_xpath_index;
1261-
}
1262-
}
1256+
/* The logic for trying parent nodes is in cmd_execute_command_real()
1257+
* since calling ->node_exit() correctly is a bit involved. This is
1258+
* also the only reason CMD_NO_LEVEL_UP exists.
1259+
*/
1260+
while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1261+
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1262+
&& ret != CMD_SUCCESS && ret != CMD_WARNING
1263+
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
1264+
&& ret != CMD_NO_LEVEL_UP)
1265+
ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
1266+
++up_level);
1267+
1268+
if (ret == CMD_NO_LEVEL_UP)
1269+
ret = CMD_ERR_NO_MATCH;
12631270

12641271
if (ret != CMD_SUCCESS &&
12651272
ret != CMD_WARNING &&

lib/command.h

+1
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ struct cmd_node {
223223
#define CMD_SUSPEND 12
224224
#define CMD_WARNING_CONFIG_FAILED 13
225225
#define CMD_NOT_MY_INSTANCE 14
226+
#define CMD_NO_LEVEL_UP 15
226227

227228
/* Argc max counts. */
228229
#define CMD_ARGC_MAX 256

0 commit comments

Comments
 (0)