]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: support backup nexthops in nexthop-groups and zapi
authorMark Stapp <mjs@voltanet.io>
Thu, 16 Jan 2020 21:25:22 +0000 (16:25 -0500)
committerMark Stapp <mjs@voltanet.io>
Fri, 27 Mar 2020 13:39:14 +0000 (09:39 -0400)
Add vty support for backup nexthops in nexthop groups. Capture
backup nexthop info in zapi route messages.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
lib/nexthop_group.c
lib/nexthop_group.h
lib/zclient.c
lib/zclient.h

index c6479cf4fff474aff4128e2407d729d6d8c0c3e0..8c3bbbdcd484350184a494c0df43473b0ffd826a 100644 (file)
@@ -43,8 +43,12 @@ struct nexthop_hold {
        char *intf;
        char *labels;
        uint32_t weight;
+       int backup_idx; /* Index of backup nexthop, if >= 0 */
 };
 
+/* Invalid/unset value for nexthop_hold's backup_idx */
+#define NHH_BACKUP_IDX_INVALID -1
+
 struct nexthop_group_hooks {
        void (*new)(const char *name);
        void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -571,11 +575,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
        return CMD_SUCCESS;
 }
 
+DEFPY(nexthop_group_backup, nexthop_group_backup_cmd,
+      "backup-group WORD$name",
+      "Specify a group name containing backup nexthops\n"
+      "The name of the backup group\n")
+{
+       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+       strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name));
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
+      "no backup-group [WORD$name]",
+      NO_STR
+      "Clear group name containing backup nexthops\n"
+      "The name of the backup group\n")
+{
+       VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+       nhgc->backup_list_name[0] = 0;
+
+       return CMD_SUCCESS;
+}
+
 static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
                                    const char *nhvrf_name,
                                    const union sockunion *addr,
                                    const char *intf, const char *labels,
-                                   const uint32_t weight)
+                                   const uint32_t weight, int backup_idx)
 {
        struct nexthop_hold *nh;
 
@@ -592,6 +621,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
 
        nh->weight = weight;
 
+       nh->backup_idx = backup_idx;
+
        listnode_add_sort(nhgc->nhg_list, nh);
 }
 
@@ -633,7 +664,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
                                        const union sockunion *addr,
                                        const char *intf, const char *name,
                                        const char *labels, int *lbl_ret,
-                                       uint32_t weight)
+                                       uint32_t weight, int backup_idx)
 {
        int ret = 0;
        struct vrf *vrf;
@@ -692,6 +723,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
 
        nhop->weight = weight;
 
+       if (backup_idx != NHH_BACKUP_IDX_INVALID) {
+               /* Validate index value */
+               if (backup_idx > NEXTHOP_BACKUP_IDX_MAX)
+                       return false;
+
+               SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+               nhop->backup_idx = backup_idx;
+       }
+
        return true;
 }
 
@@ -703,7 +743,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
 {
        return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
                                            nhh->nhvrf_name, nhh->labels, NULL,
-                                           nhh->weight));
+                                           nhh->weight, nhh->backup_idx));
 }
 
 DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -716,6 +756,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
           nexthop-vrf NAME$vrf_name \
           |label WORD \
            |weight (1-255) \
+           |backup-idx$bi_str (0-254)$idx \
        }]",
       NO_STR
       "Specify one of the nexthops in this ECMP group\n"
@@ -728,16 +769,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
       "Specify label(s) for this nexthop\n"
       "One or more labels in the range (16-1048575) separated by '/'\n"
       "Weight to be used by the nexthop for purposes of ECMP\n"
-      "Weight value to be used\n")
+      "Weight value to be used\n"
+      "Backup nexthop index in another group\n"
+      "Nexthop index value\n")
 {
        VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
        struct nexthop nhop;
        struct nexthop *nh;
        int lbl_ret = 0;
        bool legal;
+       int backup_idx = idx;
+       bool add_update = false;
+
+       if (bi_str == NULL)
+               backup_idx = NHH_BACKUP_IDX_INVALID;
 
        legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
-                                           &lbl_ret, weight);
+                                           &lbl_ret, weight, backup_idx);
 
        if (nhop.type == NEXTHOP_TYPE_IPV6
            && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -769,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
 
        nh = nexthop_exists(&nhgc->nhg, &nhop);
 
-       if (no) {
+       if (no || nh) {
+               /* Remove or replace cases */
+
+               /* Remove existing config */
                nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
                                          weight);
                if (nh) {
+                       /* Remove nexthop object */
                        _nexthop_del(&nhgc->nhg, nh);
 
                        if (nhg_hooks.del_nexthop)
                                nhg_hooks.del_nexthop(nhgc, nh);
 
                        nexthop_free(nh);
+                       nh = NULL;
                }
-       } else if (!nh) {
-               /* must be adding new nexthop since !no and !nexthop_exists */
+       }
+
+       add_update = !no;
+
+       if (add_update) {
+               /* Add or replace cases */
+
+               /* If valid config, add nexthop object */
                if (legal) {
                        nh = nexthop_new();
 
@@ -789,8 +848,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
                        _nexthop_add(&nhgc->nhg.nexthop, nh);
                }
 
+               /* Save config always */
                nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
-                                       weight);
+                                       weight, backup_idx);
 
                if (legal && nhg_hooks.add_nexthop)
                        nhg_hooks.add_nexthop(nhgc, nh);
@@ -853,6 +913,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
        if (nh->weight)
                vty_out(vty, " weight %u", nh->weight);
 
+       if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
+               vty_out(vty, " backup-idx %d", nh->backup_idx);
+
        vty_out(vty, "\n");
 }
 
@@ -878,6 +941,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
        if (nh->weight)
                vty_out(vty, " weight %u", nh->weight);
 
+       if (nh->backup_idx != NHH_BACKUP_IDX_INVALID)
+               vty_out(vty, " backup-idx %d", nh->backup_idx);
+
        vty_out(vty, "\n");
 }
 
@@ -891,6 +957,10 @@ static int nexthop_group_write(struct vty *vty)
 
                vty_out(vty, "nexthop-group %s\n", nhgc->name);
 
+               if (nhgc->backup_list_name[0])
+                       vty_out(vty, " backup-group %s\n",
+                               nhgc->backup_list_name);
+
                for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
                        vty_out(vty, " ");
                        nexthop_group_write_nexthop_internal(vty, nh);
@@ -1071,6 +1141,8 @@ void nexthop_group_init(void (*new)(const char *name),
        install_element(CONFIG_NODE, &no_nexthop_group_cmd);
 
        install_default(NH_GROUP_NODE);
+       install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd);
+       install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);
        install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
 
        memset(&nhg_hooks, 0, sizeof(nhg_hooks));
index 76e1e64ca5fe83512b3ad1a76672ac99b6a87036..3a5a1299c1d0a02e1ddf3726d64cceb3d6b2ee78 100644 (file)
@@ -81,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,
        (nhop) = nexthop_next(nhop)
 
 
+#define NHGC_NAME_SIZE 80
+
 struct nexthop_group_cmd {
 
        RB_ENTRY(nexthop_group_cmd) nhgc_entry;
 
-       char name[80];
+       char name[NHGC_NAME_SIZE];
+
+       /* Name of group containing backup nexthops (if set) */
+       char backup_list_name[NHGC_NAME_SIZE];
 
        struct nexthop_group nhg;
 
index 53ca4e1327e88dc44095d18fb9d8b23a0b0329be..55b8d29a4d8ecc75ac9beb1569c4056ed0e9b3eb 100644 (file)
@@ -904,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
                }
        }
 
+       /* If present, set 'weight' flag before encoding flags */
        if (api_nh->weight)
                SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT);
 
@@ -1479,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
                                   znh->labels);
        }
 
+       if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+               SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
+               n->backup_idx = znh->backup_idx;
+       }
+
        return n;
 }
 
@@ -1510,9 +1516,30 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
                SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
        }
 
+       if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+               SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+               znh->backup_idx = nh->backup_idx;
+       }
+
        return 0;
 }
 
+/*
+ * Wrapper that converts backup nexthop
+ */
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+                                    const struct nexthop *nh)
+{
+       int ret;
+
+       /* Ensure that zapi flags are correct: backups don't have backups */
+       ret = zapi_nexthop_from_nexthop(znh, nh);
+       if (ret == 0)
+               UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+
+       return ret;
+}
+
 /*
  * Decode the nexthop-tracking update message
  */
index a2ee264be3d192457c06e41902dd4fbd9224a62a..e747809f162fff5bc57826de51c49c0bcd07e3ab 100644 (file)
@@ -783,10 +783,12 @@ bool zapi_iptable_notify_decode(struct stream *s,
                uint32_t *unique,
                enum zapi_iptable_notify_owner *note);
 
-extern struct nexthop *nexthop_from_zapi_nexthop(
-       const struct zapi_nexthop *znh);
+extern struct nexthop *
+nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh);
 int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
                              const struct nexthop *nh);
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+                                    const struct nexthop *nh);
 extern bool zapi_nexthop_update_decode(struct stream *s,
                                       struct zapi_route *nhr);