]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: support labelled nexthops in nexthop_groups
authorMark Stapp <mjs@voltanet.io>
Wed, 27 Nov 2019 18:02:23 +0000 (13:02 -0500)
committerMark Stapp <mjs@voltanet.io>
Tue, 3 Dec 2019 21:54:35 +0000 (16:54 -0500)
Add support for labelled nexthops in nexthop-group
vtysh configuration. Also update the PBR doc where
the cli is described.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
doc/user/pbr.rst
lib/nexthop_group.c
lib/nexthop_group.h

index fab4343f50802d99d38238e4e6a9926ac8b205c8..ab4d2cc973bb36be61416dcaf82e6a6f0fe79a90 100644 (file)
@@ -39,7 +39,7 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
    sub-mode where you can specify individual nexthops.  To exit this mode type
    exit or end as per normal conventions for leaving a sub-mode.
 
-.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME]
+.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME] [label LABELS]
 
    Create a v4 or v6 nexthop.  All normal rules for creating nexthops that you
    are used to are allowed here.  The syntax was intentionally kept the same as
index 9552f895683bb14199108c8c929ee669b09b71c3..d3cc36c544788bc473ae12e95f523cd97e24fbe9 100644 (file)
 
 DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
 
+/*
+ * Internal struct used to hold nhg config strings
+ */
+struct nexthop_hold {
+       char *nhvrf_name;
+       union sockunion *addr;
+       char *intf;
+       char *labels;
+};
+
 struct nexthop_group_hooks {
        void (*new)(const char *name);
        void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -425,7 +435,11 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
        if (ret)
                return ret;
 
-       return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+       ret = nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+       if (ret)
+               return ret;
+
+       return nhgc_cmp_helper(nh1->labels, nh2->labels);
 }
 
 static void nhgl_delete(struct nexthop_hold *nh)
@@ -437,6 +451,8 @@ static void nhgl_delete(struct nexthop_hold *nh)
        if (nh->addr)
                sockunion_free(nh->addr);
 
+       XFREE(MTYPE_TMP, nh->labels);
+
        XFREE(MTYPE_TMP, nh);
 }
 
@@ -510,7 +526,8 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
 static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
                                    const char *nhvrf_name,
                                    const union sockunion *addr,
-                                   const char *intf)
+                                   const char *intf,
+                                   const char *labels)
 {
        struct nexthop_hold *nh;
 
@@ -522,6 +539,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
                nh->intf = XSTRDUP(MTYPE_TMP, intf);
        if (addr)
                nh->addr = sockunion_dup(addr);
+       if (labels)
+               nh->labels = XSTRDUP(MTYPE_TMP, labels);
 
        listnode_add_sort(nhgc->nhg_list, nh);
 }
@@ -529,7 +548,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
 static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
                                      const char *nhvrf_name,
                                      const union sockunion *addr,
-                                     const char *intf)
+                                     const char *intf,
+                                     const char *labels)
 {
        struct nexthop_hold *nh;
        struct listnode *node;
@@ -537,7 +557,8 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
        for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
                if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
                    nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
-                   nhgc_cmp_helper(intf, nh->intf) == 0)
+                   nhgc_cmp_helper(intf, nh->intf) == 0 &&
+                   nhgc_cmp_helper(labels, nh->labels) == 0)
                        break;
        }
 
@@ -551,10 +572,19 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
        nhgl_delete(nh);
 }
 
+/*
+ * Parse the config strings we support for a single nexthop. This gets used
+ * in a couple of different ways, and we distinguish between transient
+ * failures - such as a still-unprocessed interface - and fatal errors
+ * from label-string parsing.
+ */
 static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
                                        const union sockunion *addr,
-                                       const char *intf, const char *name)
+                                       const char *intf, const char *name,
+                                       const char *labels,
+                                       int *lbl_ret)
 {
+       int ret = 0;
        struct vrf *vrf;
 
        memset(nhop, 0, sizeof(*nhop));
@@ -592,16 +622,49 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
        } else
                nhop->type = NEXTHOP_TYPE_IFINDEX;
 
+       if (labels) {
+               uint8_t num = 0;
+               mpls_label_t larray[MPLS_MAX_LABELS];
+
+               ret = mpls_str2label(labels, &num, larray);
+
+               /* Return label parse result */
+               if (lbl_ret)
+                       *lbl_ret = ret;
+
+               if (ret < 0)
+                       return false;
+               else if (num > 0)
+                       nexthop_add_labels(nhop, ZEBRA_LSP_NONE,
+                                          num, larray);
+       }
+
        return true;
 }
 
+/*
+ * Wrapper to parse the strings in a 'nexthop_hold'
+ */
+static bool nexthop_group_parse_nhh(struct nexthop *nhop,
+                                   const struct nexthop_hold *nhh)
+{
+       return (nexthop_group_parse_nexthop(nhop, nhh->addr,
+                                           nhh->intf,
+                                           nhh->nhvrf_name,
+                                           nhh->labels,
+                                           NULL));
+}
+
 DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
       "[no] nexthop\
         <\
          <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
          |INTERFACE$intf\
        >\
-       [nexthop-vrf NAME$vrf_name]",
+       [{ \
+          nexthop-vrf NAME$vrf_name \
+          |label WORD \
+       }]",
       NO_STR
       "Specify one of the nexthops in this ECMP group\n"
       "v4 Address\n"
@@ -609,14 +672,18 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
       "Interface to use\n"
       "Interface to use\n"
       "If the nexthop is in a different vrf tell us\n"
-      "The nexthop-vrf Name\n")
+      "The nexthop-vrf Name\n"
+      "Specify label(s) for this nexthop\n"
+      "One or more labels in the range (16-1048575) separated by '/'\n")
 {
        VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
        struct nexthop nhop;
        struct nexthop *nh;
+       int lbl_ret = 0;
        bool legal;
 
-       legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name);
+       legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name,
+                                           label, &lbl_ret);
 
        if (nhop.type == NEXTHOP_TYPE_IPV6
            && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -625,10 +692,31 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       /* Handle label-string errors */
+       if (!legal && lbl_ret < 0) {
+               switch (lbl_ret) {
+               case -1:
+                       vty_out(vty, "%% Malformed label(s)\n");
+                       break;
+               case -2:
+                       vty_out(vty,
+                               "%% Cannot use reserved label(s) (%d-%d)\n",
+                               MPLS_LABEL_RESERVED_MIN,
+                               MPLS_LABEL_RESERVED_MAX);
+                       break;
+               case -3:
+                       vty_out(vty,
+                               "%% Too many labels. Enter %d or fewer\n",
+                               MPLS_MAX_LABELS);
+                       break;
+               }
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        nh = nexthop_exists(&nhgc->nhg, &nhop);
 
        if (no) {
-               nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf);
+               nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label);
                if (nh) {
                        _nexthop_del(&nhgc->nhg, nh);
 
@@ -646,7 +734,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
                        _nexthop_add(&nhgc->nhg.nexthop, nh);
                }
 
-               nexthop_group_save_nhop(nhgc, vrf_name, addr, intf);
+               nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label);
 
                if (legal && nhg_hooks.add_nexthop)
                        nhg_hooks.add_nexthop(nhgc, nh);
@@ -696,6 +784,16 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
                vrf = vrf_lookup_by_id(nh->vrf_id);
                vty_out(vty, " nexthop-vrf %s", vrf->name);
        }
+
+       if (nh->nh_label && nh->nh_label->num_labels > 0) {
+               char buf[200];
+
+               mpls_label2str(nh->nh_label->num_labels,
+                              nh->nh_label->label,
+                              buf, sizeof(buf), 0);
+               vty_out(vty, " label %s", buf);
+       }
+
        vty_out(vty, "\n");
 }
 
@@ -715,6 +813,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
        if (nh->nhvrf_name)
                vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
 
+       if (nh->labels)
+               vty_out(vty, " label %s", nh->labels);
+
        vty_out(vty, "\n");
 }
 
@@ -751,9 +852,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
                        struct nexthop nhop;
                        struct nexthop *nh;
 
-                       if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
-                                                        nhh->intf,
-                                                        nhh->nhvrf_name))
+                       if (!nexthop_group_parse_nhh(&nhop, nhh))
                                continue;
 
                        nh = nexthop_exists(&nhgc->nhg, &nhop);
@@ -787,9 +886,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
                        struct nexthop nhop;
                        struct nexthop *nh;
 
-                       if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
-                                                        nhh->intf,
-                                                        nhh->nhvrf_name))
+                       if (!nexthop_group_parse_nhh(&nhop, nhh))
                                continue;
 
                        nh = nexthop_exists(&nhgc->nhg, &nhop);
@@ -824,9 +921,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
                        for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
                                struct nexthop nhop;
 
-                               if (!nexthop_group_parse_nexthop(
-                                           &nhop, nhh->addr, nhh->intf,
-                                           nhh->nhvrf_name))
+                               if (!nexthop_group_parse_nhh(&nhop, nhh))
                                        continue;
 
                                switch (nhop.type) {
index 391775c69c3945bdbe7406c801e129814e8e7153..cc9988b86667e5f598e7950a2205d53f652c95ac 100644 (file)
@@ -70,12 +70,6 @@ void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
        (nhop) = nexthop_next(nhop)
 
 
-struct nexthop_hold {
-       char *nhvrf_name;
-       union sockunion *addr;
-       char *intf;
-};
-
 struct nexthop_group_cmd {
 
        RB_ENTRY(nexthop_group_cmd) nhgc_entry;