]> git.proxmox.com Git - mirror_frr.git/blobdiff - vtysh/vtysh_config.c
Merge pull request #3281 from opensourcerouting/update-libyang-instructions
[mirror_frr.git] / vtysh / vtysh_config.c
index 3748fef54c2af870e5502894a0c619f448e8a25c..fe12f82ef28065a5c3406c790306175fb3b1aa0c 100644 (file)
@@ -73,7 +73,7 @@ static int config_cmp(struct config *c1, struct config *c2)
 
 static void config_del(struct config *config)
 {
-       list_delete_and_null(&config->line);
+       list_delete(&config->line);
        if (config->name)
                XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
        XFREE(MTYPE_VTYSH_CONFIG, config);
@@ -132,16 +132,83 @@ static void config_add_line_uniq(struct list *config, const char *line)
 }
 
 /*
- * I want to explicitly move this command to the end of the line
+ * Add a line that should only be shown once, and always show at the end of the
+ * config block.
+ *
+ * If the line already exists, it will be moved to the end of the block. If it
+ * does not exist, it will be added at the end of the block.
+ *
+ * Note that this only makes sense when there is just one such line that should
+ * show up at the very end of a config block. Furthermore, if the same block
+ * can show up from multiple daemons, all of them must make sure to print the
+ * line at the end of their config, otherwise the line will show at the end of
+ * the config for the last daemon that printed it.
+ *
+ * Here is a motivating example with the 'exit-vrf' command. Suppose we receive
+ * a config from Zebra like so:
+ *
+ * vrf BLUE
+ *    ip route A
+ *    ip route B
+ *    exit-vrf
+ *
+ * Then suppose we later receive this config from PIM:
+ *
+ * vrf BLUE
+ *    ip msdp mesh-group MyGroup member 1.2.3.4
+ *    exit-vrf
+ *
+ * Then we will combine them into one config block like so:
+ *
+ * vrf BLUE
+ *    ip route A
+ *    ip route B
+ *    ip msdp mesh-group MyGroup member 1.2.3.4
+ *    exit-vrf
+ *
+ * Because PIM also sent us an 'exit-vrf', we noticed that we already had one
+ * under the 'vrf BLUE' config block and so we moved it to the end of the
+ * config block again. If PIM had neglected to send us 'exit-vrf', the result
+ * would be this:
+ *
+ * vrf BLUE
+ *    ip route A
+ *    ip route B
+ *    exit-vrf
+ *    ip msdp mesh-group MyGroup member 1.2.3.4
+ *
+ * Therefore, daemons that share config blocks must take care to consistently
+ * print the same block terminators.
+ *
+ * Ideally this would be solved by adding a string to struct config that is
+ * always printed at the end when dumping a config. However, this would only
+ * work when the user is using integrated config. In the non-integrated config
+ * case, daemons are responsible for writing their own config files, and so the
+ * must be able to print these blocks correctly independently of vtysh, which
+ * means they are the ones that need to handle printing the block terminators
+ * and VTYSH needs to be smart enough to combine them properly.
+ *
+ * ---
+ *
+ * config
+ *    The config to add the line to
+ *
+ * line
+ *    The line to add to the end of the config
  */
-static void config_add_line_end(struct list *config, const char *line)
+static void config_add_line_uniq_end(struct list *config, const char *line)
 {
        struct listnode *node;
-       void *item = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
+       char *pnt;
 
-       listnode_add(config, item);
-       node = listnode_lookup(config, item);
-       if (node)
+       for (ALL_LIST_ELEMENTS_RO(config, node, pnt)) {
+               if (strcmp(pnt, line) == 0)
+                       break;
+       }
+
+       if (!node)
+               config_add_line(config, line);
+       else
                listnode_move_to_tail(config, node);
 }
 
@@ -158,8 +225,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
        if (c == '\0')
                return;
 
-       /* printf ("[%s]\n", line); */
-
        switch (c) {
        /* Suppress exclamation points ! and commented lines. The !s are
         * generated
@@ -178,13 +243,21 @@ void vtysh_config_parse_line(void *arg, const char *line)
                        } else if (strncmp(line, " ip multicast boundary",
                                           strlen(" ip multicast boundary"))
                                   == 0) {
-                               config_add_line_end(config->line, line);
+                               config_add_line_uniq_end(config->line, line);
+                       } else if (strncmp(line, " ip igmp query-interval",
+                                          strlen(" ip igmp query-interval")) == 0) {
+                               config_add_line_uniq_end(config->line, line);
                        } else if (config->index == LINK_PARAMS_NODE
                                   && strncmp(line, "  exit-link-params",
                                              strlen("  exit"))
                                              == 0) {
                                config_add_line(config->line, line);
                                config->index = INTERFACE_NODE;
+                       } else if (config->index == VRF_NODE
+                                  && strncmp(line, " exit-vrf",
+                                             strlen(" exit-vrf"))
+                                             == 0) {
+                               config_add_line_uniq_end(config->line, line);
                        } else if (config->index == RMAP_NODE
                                   || config->index == INTERFACE_NODE
                                   || config->index == LOGICALROUTER_NODE
@@ -236,6 +309,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
                else if (strncmp(line, "router isis", strlen("router isis"))
                         == 0)
                        config = config_get(ISIS_NODE, line);
+               else if (strncmp(line, "router openfabric", strlen("router openfabric"))
+                        == 0)
+                       config = config_get(OPENFABRIC_NODE, line);
                else if (strncmp(line, "route-map", strlen("route-map")) == 0)
                        config = config_get(RMAP_NODE, line);
                else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
@@ -259,18 +335,18 @@ void vtysh_config_parse_line(void *arg, const char *line)
                                 strlen("ipv6 prefix-list"))
                         == 0)
                        config = config_get(PREFIX_IPV6_NODE, line);
-               else if (strncmp(line, "ip as-path access-list",
-                                strlen("ip as-path access-list"))
+               else if (strncmp(line, "bgp as-path access-list",
+                                strlen("bgp as-path access-list"))
                         == 0)
                        config = config_get(AS_LIST_NODE, line);
-               else if (strncmp(line, "ip community-list",
-                                strlen("ip community-list"))
+               else if (strncmp(line, "bgp community-list",
+                                strlen("bgp community-list"))
                                 == 0
-                        || strncmp(line, "ip extcommunity-list",
-                                   strlen("ip extcommunity-list"))
+                        || strncmp(line, "bgp extcommunity-list",
+                                   strlen("bgp extcommunity-list"))
                                    == 0
-                        || strncmp(line, "ip large-community-list",
-                                   strlen("ip large-community-list"))
+                        || strncmp(line, "bgp large-community-list",
+                                   strlen("bgp large-community-list"))
                                    == 0)
                        config = config_get(COMMUNITY_LIST_NODE, line);
                else if (strncmp(line, "ip route", strlen("ip route")) == 0)
@@ -290,6 +366,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
                        config = config_get(FORWARDING_NODE, line);
                else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
                        config = config_get(VRF_DEBUG_NODE, line);
+               else if (strncmp(line, "debug northbound",
+                                strlen("debug northbound"))
+                        == 0)
+                       config = config_get(NORTHBOUND_DEBUG_NODE, line);
                else if (strncmp(line, "debug", strlen("debug")) == 0)
                        config = config_get(DEBUG_NODE, line);
                else if (strncmp(line, "password", strlen("password")) == 0
@@ -309,6 +389,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
                        config = config_get(PROTOCOL_NODE, line);
                else if (strncmp(line, "mpls", strlen("mpls")) == 0)
                        config = config_get(MPLS_NODE, line);
+               else if (strncmp(line, "bfd", strlen("bfd")) == 0)
+                       config = config_get(BFD_NODE, line);
                else {
                        if (strncmp(line, "log", strlen("log")) == 0
                            || strncmp(line, "hostname", strlen("hostname"))
@@ -333,10 +415,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
         || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE                  \
         || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE                  \
         || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE      \
-        || (I) == MPLS_NODE)
+        || (I) == NORTHBOUND_DEBUG_NODE || (I) == MPLS_NODE)
 
 /* Display configuration to file pointer. */
-void vtysh_config_dump(FILE *fp)
+void vtysh_config_dump(void)
 {
        struct listnode *node, *nnode;
        struct listnode *mnode, *mnnode;
@@ -345,12 +427,10 @@ void vtysh_config_dump(FILE *fp)
        char *line;
        unsigned int i;
 
-       for (ALL_LIST_ELEMENTS(config_top, node, nnode, line)) {
-               fprintf(fp, "%s\n", line);
-               fflush(fp);
-       }
-       fprintf(fp, "!\n");
-       fflush(fp);
+       for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
+               vty_out(vty, "%s\n", line);
+
+       vty_out(vty, "!\n");
 
        for (i = 0; i < vector_active(configvec); i++)
                if ((master = vector_slot(configvec, i)) != NULL) {
@@ -367,28 +447,21 @@ void vtysh_config_dump(FILE *fp)
                                    && list_isempty(config->line))
                                        continue;
 
-                               fprintf(fp, "%s\n", config->name);
-                               fflush(fp);
+                               vty_out(vty, "%s\n", config->name);
 
                                for (ALL_LIST_ELEMENTS(config->line, mnode,
-                                                      mnnode, line)) {
-                                       fprintf(fp, "%s\n", line);
-                                       fflush(fp);
-                               }
-                               if (!NO_DELIMITER(i)) {
-                                       fprintf(fp, "!\n");
-                                       fflush(fp);
-                               }
-                       }
-                       if (NO_DELIMITER(i)) {
-                               fprintf(fp, "!\n");
-                               fflush(fp);
+                                                      mnnode, line))
+                                       vty_out(vty, "%s\n", line);
+                               if (!NO_DELIMITER(i))
+                                       vty_out(vty, "!\n");
                        }
+                       if (NO_DELIMITER(i))
+                               vty_out(vty, "!\n");
                }
 
        for (i = 0; i < vector_active(configvec); i++)
                if ((master = vector_slot(configvec, i)) != NULL) {
-                       list_delete_and_null(&master);
+                       list_delete(&master);
                        vector_slot(configvec, i) = NULL;
                }
        list_delete_all_node(config_top);