@@ -900,13 +900,31 @@ enum node_type node_parent(enum node_type node)
900
900
/* Execute command by argument vline vector. */
901
901
static int cmd_execute_command_real (vector vline , enum cmd_filter_type filter ,
902
902
struct vty * vty ,
903
- const struct cmd_element * * cmd )
903
+ const struct cmd_element * * cmd ,
904
+ unsigned int up_level )
904
905
{
905
906
struct list * argv_list ;
906
907
enum matcher_rv status ;
907
908
const struct cmd_element * matched_element = NULL ;
909
+ unsigned int i ;
910
+ int xpath_index = vty -> xpath_index ;
911
+ int node = vty -> node ;
908
912
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 );
910
928
status = command_match (cmdgraph , vline , & argv_list , & matched_element );
911
929
912
930
if (cmd )
@@ -926,12 +944,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
926
944
}
927
945
}
928
946
947
+ for (i = 0 ; i < up_level ; i ++ )
948
+ cmd_exit (vty );
949
+
929
950
// build argv array from argv list
930
951
struct cmd_token * * argv = XMALLOC (
931
952
MTYPE_TMP , argv_list -> count * sizeof (struct cmd_token * ));
932
953
struct listnode * ln ;
933
954
struct cmd_token * token ;
934
- unsigned int i = 0 ;
955
+
956
+ i = 0 ;
935
957
for (ALL_LIST_ELEMENTS_RO (argv_list , ln , token ))
936
958
argv [i ++ ] = token ;
937
959
@@ -1012,7 +1034,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
1012
1034
vector_lookup (vline , index ));
1013
1035
1014
1036
ret = cmd_execute_command_real (shifted_vline , FILTER_RELAXED ,
1015
- vty , cmd );
1037
+ vty , cmd , 0 );
1016
1038
1017
1039
vector_free (shifted_vline );
1018
1040
vty -> node = onode ;
@@ -1021,7 +1043,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
1021
1043
}
1022
1044
1023
1045
saved_ret = ret =
1024
- cmd_execute_command_real (vline , FILTER_RELAXED , vty , cmd );
1046
+ cmd_execute_command_real (vline , FILTER_RELAXED , vty , cmd , 0 );
1025
1047
1026
1048
if (vtysh )
1027
1049
return saved_ret ;
@@ -1038,7 +1060,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
1038
1060
onode ))
1039
1061
vty -> xpath_index -- ;
1040
1062
ret = cmd_execute_command_real (vline , FILTER_RELAXED ,
1041
- vty , cmd );
1063
+ vty , cmd , 0 );
1042
1064
if (ret == CMD_SUCCESS || ret == CMD_WARNING
1043
1065
|| ret == CMD_NOT_MY_INSTANCE
1044
1066
|| ret == CMD_WARNING_CONFIG_FAILED )
@@ -1069,7 +1091,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
1069
1091
int cmd_execute_command_strict (vector vline , struct vty * vty ,
1070
1092
const struct cmd_element * * cmd )
1071
1093
{
1072
- return cmd_execute_command_real (vline , FILTER_STRICT , vty , cmd );
1094
+ return cmd_execute_command_real (vline , FILTER_STRICT , vty , cmd , 0 );
1073
1095
}
1074
1096
1075
1097
/*
@@ -1220,6 +1242,7 @@ int command_config_read_one_line(struct vty *vty,
1220
1242
{
1221
1243
vector vline ;
1222
1244
int ret ;
1245
+ unsigned up_level = 0 ;
1223
1246
1224
1247
vline = cmd_make_strvec (vty -> buf );
1225
1248
@@ -1230,36 +1253,20 @@ int command_config_read_one_line(struct vty *vty,
1230
1253
/* Execute configuration command : this is strict match */
1231
1254
ret = cmd_execute_command_strict (vline , vty , cmd );
1232
1255
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 ;
1263
1270
1264
1271
if (ret != CMD_SUCCESS &&
1265
1272
ret != CMD_WARNING &&
0 commit comments