]> 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>
Tue, 27 Apr 2021 20:13:25 +0000 (22:13 +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 d8a2270bc5325e0acc450097191a8abbb20ca104..fd24909f57ecb52af48e7f9884cde942539be99e 100644 (file)
@@ -847,13 +847,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)
@@ -873,12 +890,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;
 
@@ -952,7 +973,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;
@@ -961,7 +982,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;
@@ -976,7 +997,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)
@@ -1007,7 +1028,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);
 }
 
 /*
@@ -1148,6 +1169,7 @@ int command_config_read_one_line(struct vty *vty,
 {
        vector vline;
        int ret;
+       unsigned up_level = 0;
 
        vline = cmd_make_strvec(vty->buf);
 
@@ -1158,34 +1180,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 725a2014463c64d74ac283aa43921c0550b36c5f..40dabf9fb506b76a5d29dd8aa3ed3b4a5180d66e 100644 (file)
@@ -213,6 +213,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