From db2fede9904d5b2cb51abf7fa071fca27c37104d Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Wed, 27 Nov 2019 13:02:23 -0500 Subject: [PATCH] lib: support labelled nexthops in nexthop_groups 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 --- doc/user/pbr.rst | 2 +- lib/nexthop_group.c | 133 +++++++++++++++++++++++++++++++++++++------- lib/nexthop_group.h | 6 -- 3 files changed, 115 insertions(+), 26 deletions(-) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index fab4343f50..ab4d2cc973 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -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 diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 9552f89568..d3cc36c544 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -34,6 +34,16 @@ 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\ <\ $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) { diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 391775c69c..cc9988b866 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -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; -- 2.39.5