]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: correctly exit CLI nodes on file config load
authorDavid Lamparter <equinox@diac24.net>
Thu, 8 Apr 2021 11:35:09 +0000 (13:35 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Wed, 28 Apr 2021 07:34:10 +0000 (09:34 +0200)
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 <equinox@diac24.net>
(cherry picked from commit e3476061fe43394759668082509a2b15cf23a428)

lib/command.c
lib/command.h

index 1e950fe48334f62437557911adbd578ff45c3574..5bd1e03fc674520947f1b44ba5189097f7e38339 100644 (file)
@@ -852,13 +852,30 @@ enum node_type node_parent(enum node_type node)
 /* Execute command by argument vline vector. */
 static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
                                    struct vty *vty,
-                                   const struct cmd_element **cmd)
+                                   const struct cmd_element **cmd,
+                                   unsigned int up_level)
 {
        struct list *argv_list;
        enum matcher_rv status;
        const struct cmd_element *matched_element = NULL;
+       unsigned int i;
+       int xpath_index = vty->xpath_index;
+       int node = vty->node;
 
-       struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
+       /* only happens for legacy split config file load;  need to check for
+        * a match before calling node_exit handlers below
+        */
+       for (i = 0; i < up_level; i++) {
+               if (node <= CONFIG_NODE)
+                       return CMD_NO_LEVEL_UP;
+
+               node = node_parent(node);
+
+               if (xpath_index > 0)
+                       xpath_index--;
+       }
+
+       struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
        status = command_match(cmdgraph, vline, &argv_list, &matched_element);
 
        if (cmd)
@@ -878,12 +895,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
                }
        }
 
+       for (i = 0; i < up_level; i++)
+               cmd_exit(vty);
+
        // build argv array from argv list
        struct cmd_token **argv = XMALLOC(
                MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
        struct listnode *ln;
        struct cmd_token *token;
-       unsigned int i = 0;
+
+       i = 0;
        for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
                argv[i++] = token;
 
@@ -964,7 +985,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
                                         vector_lookup(vline, index));
 
                ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
-                                              vty, cmd);
+                                              vty, cmd, 0);
 
                vector_free(shifted_vline);
                vty->node = onode;
@@ -973,7 +994,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
        }
 
        saved_ret = ret =
-               cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
+               cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
 
        if (vtysh)
                return saved_ret;
@@ -988,7 +1009,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
                        if (vty->xpath_index > 0)
                                vty->xpath_index--;
                        ret = cmd_execute_command_real(vline, FILTER_RELAXED,
-                                                      vty, cmd);
+                                                      vty, cmd, 0);
                        if (ret == CMD_SUCCESS || ret == CMD_WARNING
                            || ret == CMD_NOT_MY_INSTANCE
                            || ret == CMD_WARNING_CONFIG_FAILED)
@@ -1019,7 +1040,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
 int cmd_execute_command_strict(vector vline, struct vty *vty,
                               const struct cmd_element **cmd)
 {
-       return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
+       return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
 }
 
 /*
@@ -1170,6 +1191,7 @@ int command_config_read_one_line(struct vty *vty,
 {
        vector vline;
        int ret;
+       unsigned up_level = 0;
 
        vline = cmd_make_strvec(vty->buf);
 
@@ -1180,34 +1202,20 @@ int command_config_read_one_line(struct vty *vty,
        /* Execute configuration command : this is strict match */
        ret = cmd_execute_command_strict(vline, vty, cmd);
 
-       // Climb the tree and try the command again at each node
-       if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
-           && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
-           && ret != CMD_SUCCESS && ret != CMD_WARNING
-           && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
-           && vty->node != CONFIG_NODE) {
-               int saved_node = vty->node;
-               int saved_xpath_index = vty->xpath_index;
-
-               while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
-                      && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
-                      && ret != CMD_SUCCESS && ret != CMD_WARNING
-                      && vty->node > CONFIG_NODE) {
-                       vty->node = node_parent(vty->node);
-                       if (vty->xpath_index > 0)
-                               vty->xpath_index--;
-                       ret = cmd_execute_command_strict(vline, vty, cmd);
-               }
-
-               // If climbing the tree did not work then ignore the command and
-               // stay at the same node
-               if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
-                   && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
-                   && ret != CMD_SUCCESS && ret != CMD_WARNING) {
-                       vty->node = saved_node;
-                       vty->xpath_index = saved_xpath_index;
-               }
-       }
+       /* The logic for trying parent nodes is in cmd_execute_command_real()
+        * since calling ->node_exit() correctly is a bit involved.  This is
+        * also the only reason CMD_NO_LEVEL_UP exists.
+        */
+       while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
+              && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
+              && ret != CMD_SUCCESS && ret != CMD_WARNING
+              && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
+              && ret != CMD_NO_LEVEL_UP)
+               ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
+                                              ++up_level);
+
+       if (ret == CMD_NO_LEVEL_UP)
+               ret = CMD_ERR_NO_MATCH;
 
        if (ret != CMD_SUCCESS &&
            ret != CMD_WARNING &&
index e20bfe3318d467b49bd97bf902233625014036e1..368e7cd1e1096c8fd643d152c9690663bf368ff9 100644 (file)
@@ -214,6 +214,7 @@ struct cmd_node {
 #define CMD_SUSPEND             12
 #define CMD_WARNING_CONFIG_FAILED 13
 #define CMD_NOT_MY_INSTANCE    14
+#define CMD_NO_LEVEL_UP 15
 
 /* Argc max counts. */
 #define CMD_ARGC_MAX   256