From df7fb5800b3798057747873c8be245eb13f3ec36 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 6 Dec 2019 08:58:47 -0500 Subject: [PATCH 1/3] lib, zebra: Allow for installation of a weighted nexthop Linux has the idea of allowing a weight to be sent down as part of a nexthop group to allow the kernel to weight particular nexthop paths a bit more or less than others. See: http://tldp.org/HOWTO/Adv-Routing-HOWTO/lartc.rpdb.multiple-links.html Allow for installation into the kernel using the weight attribute associated with the nexthop. This code is foundational in that it just sets up the ability to do this, we do not use it yet. Further commits will allow for the pass through of this data from upper level protocols. Signed-off-by: Donald Sharp --- lib/nexthop.c | 1 + lib/nexthop.h | 3 +++ zebra/rt_netlink.c | 9 +++++++-- zebra/zebra_nhg.c | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index ce8034846f..4cb9f68e8a 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -550,6 +550,7 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, copy->ifindex = nexthop->ifindex; copy->type = nexthop->type; copy->flags = nexthop->flags; + copy->weight = nexthop->weight; memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate)); memcpy(©->src, &nexthop->src, sizeof(nexthop->src)); memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src)); diff --git a/lib/nexthop.h b/lib/nexthop.h index 72a4acedb2..040b643a84 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -110,6 +110,9 @@ struct nexthop { /* Label(s) associated with this nexthop. */ struct mpls_label_stack *nh_label; + + /* Weight of the nexthop ( for unequal cost ECMP ) */ + uint8_t weight; }; struct nexthop *nexthop_new(void); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f3a255fd29..e77c923230 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -467,6 +467,8 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nh = nexthop_from_ifindex(index, nh_vrf_id); if (nh) { + nh->weight = rtnh->rtnh_hops + 1; + if (num_labels) nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); @@ -1419,6 +1421,9 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, "nexthop via if %u", routedesc, nexthop->ifindex); } + + if (nexthop->weight) + rtnh->rtnh_hops = nexthop->weight - 1; } static inline void _netlink_mpls_build_singlepath(const char *routedesc, @@ -1921,7 +1926,7 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, if (count) { for (int i = 0; i < count; i++) { grp[i].id = z_grp[i].id; - grp[i].weight = z_grp[i].weight; + grp[i].weight = z_grp[i].weight - 1; if (IS_ZEBRA_DEBUG_KERNEL) { if (i == 0) @@ -2347,7 +2352,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, for (int i = 0; ((i < count) && (i < z_grp_size)); i++) { z_grp[i].id = n_grp[i].id; - z_grp[i].weight = n_grp[i].weight; + z_grp[i].weight = n_grp[i].weight + 1; } return count; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1a70250627..9065a265ad 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1790,7 +1790,7 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, if (!duplicate) { grp[i].id = depend->id; /* We aren't using weights for anything right now */ - grp[i].weight = 0; + grp[i].weight = depend->nhg->nexthop->weight; i++; } From bd054c1aa288b232fb0bab48af855035df5c62bc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 6 Dec 2019 10:28:05 -0500 Subject: [PATCH 2/3] lib, zebra: Allow for encode/decode of nexthop weight in pass down Add code to encode/decode the nexthop weight when we pass it down into zebra. Signed-off-by: Donald Sharp --- lib/nexthop.c | 6 ++++++ lib/zclient.c | 15 +++++++++++++++ lib/zclient.h | 3 +++ pbrd/pbr_zebra.c | 1 + sharpd/sharp_zebra.c | 2 ++ zebra/zapi_msg.c | 4 ++++ zebra/zebra_vty.c | 6 ++++++ 7 files changed, 37 insertions(+) diff --git a/lib/nexthop.c b/lib/nexthop.c index 4cb9f68e8a..718cda7355 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -118,6 +118,12 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, if (next1->type > next2->type) return 1; + if (next1->weight < next2->weight) + return -1; + + if (next1->weight > next2->weight) + return 1; + switch (next1->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV6: diff --git a/lib/zclient.c b/lib/zclient.c index 5ce1150b05..6982d287a2 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -802,6 +802,12 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, if (next1->type > next2->type) return 1; + if (next1->weight < next2->weight) + return -1; + + if (next1->weight > next2->weight) + return 1; + switch (next1->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV6: @@ -882,6 +888,9 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, } } + if (api_nh->weight) + SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT); + /* Note that we're only encoding a single octet */ stream_putc(s, nh_flags); @@ -920,6 +929,9 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, api_nh->label_num * sizeof(mpls_label_t)); } + if (api_nh->weight) + stream_putl(s, api_nh->weight); + /* Router MAC for EVPN routes. */ if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE)) stream_put(s, &(api_nh->rmac), @@ -1082,6 +1094,9 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, api_nh->label_num * sizeof(mpls_label_t)); } + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) + STREAM_GETL(s, api_nh->weight); + /* Router MAC for EVPN routes. */ if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE)) STREAM_GET(&(api_nh->rmac), s, diff --git a/lib/zclient.h b/lib/zclient.h index 9c5c65ffc5..70304127a2 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -323,6 +323,8 @@ struct zapi_nexthop { mpls_label_t labels[MPLS_MAX_LABELS]; struct ethaddr rmac; + + uint32_t weight; }; /* @@ -330,6 +332,7 @@ struct zapi_nexthop { */ #define ZAPI_NEXTHOP_FLAG_ONLINK 0x01 #define ZAPI_NEXTHOP_FLAG_LABEL 0x02 +#define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04 /* * Some of these data structures do not map easily to diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 06ad0f40a4..ec0327d74f 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -279,6 +279,7 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg, api_nh = &api->nexthops[i]; api_nh->vrf_id = nhop->vrf_id; api_nh->type = nhop->type; + api_nh->weight = nhop->weight; switch (nhop->type) { case NEXTHOP_TYPE_IPV4: api_nh->gate.ipv4 = nhop->gate.ipv4; diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 797398c791..4fc8f40ae1 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -243,6 +243,8 @@ void route_add(struct prefix *p, vrf_id_t vrf_id, api_nh = &api.nexthops[i]; api_nh->vrf_id = nh->vrf_id; api_nh->type = nh->type; + api_nh->weight = nh->weight; + switch (nh->type) { case NEXTHOP_TYPE_IPV4: api_nh->gate = nh->gate; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index e1654a1a3c..1dbe41f462 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -567,6 +567,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, api_nh = &api.nexthops[count]; api_nh->vrf_id = nexthop->vrf_id; api_nh->type = nexthop->type; + api_nh->weight = nexthop->weight; switch (nexthop->type) { case NEXTHOP_TYPE_BLACKHOLE: api_nh->bh_type = nexthop->bh_type; @@ -1544,6 +1545,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) + nexthop->weight = api_nh->weight; + /* MPLS labels for BGP-LU or Segment Routing */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && api_nh->type != NEXTHOP_TYPE_IFINDEX diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index eca86d5fe2..78fd57a6bd 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -380,6 +380,9 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, sizeof buf, 1)); } + if (nexthop->weight) + vty_out(vty, ", weight %u", nexthop->weight); + vty_out(vty, "\n"); } vty_out(vty, "\n"); @@ -1240,6 +1243,9 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) sizeof(buf), 1)); } + if (nexthop->weight) + vty_out(vty, ", weight %u", nexthop->weight); + vty_out(vty, "\n"); } From 597371a615b9f062642dfd97b4d81c05e7a9bd55 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 6 Dec 2019 12:28:38 -0500 Subject: [PATCH 3/3] lib: Add weight to nexthop for nexthop-group nexthops Add the ability to read in the weight of a nexthop and store/handle it appropriately nexthop-group BLUE nexthop 192.168.201.44 weight 33 nexthop 192.168.201.45 weight 66 nexthop 192.168.201.46 weight 99 Is appropriately read in and handled as appropriate. Signed-off-by: Donald Sharp --- lib/nexthop_group.c | 55 ++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index b810d13a5a..991843a047 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -42,6 +42,7 @@ struct nexthop_hold { union sockunion *addr; char *intf; char *labels; + uint32_t weight; }; struct nexthop_group_hooks { @@ -526,8 +527,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 *labels) + const char *intf, const char *labels, + const uint32_t weight) { struct nexthop_hold *nh; @@ -542,23 +543,26 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, if (labels) nh->labels = XSTRDUP(MTYPE_TMP, labels); + nh->weight = weight; + listnode_add_sort(nhgc->nhg_list, nh); } static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, const char *nhvrf_name, const union sockunion *addr, - const char *intf, - const char *labels) + const char *intf, const char *labels, + const uint32_t weight) { struct nexthop_hold *nh; struct listnode *node; 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(labels, nh->labels) == 0) + 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(labels, nh->labels) == 0 + && weight == nh->weight) break; } @@ -581,8 +585,8 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, 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) + const char *labels, int *lbl_ret, + uint32_t weight) { int ret = 0; struct vrf *vrf; @@ -639,6 +643,8 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, num, larray); } + nhop->weight = weight; + return true; } @@ -648,11 +654,9 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, 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)); + return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf, + nhh->nhvrf_name, nhh->labels, NULL, + nhh->weight)); } DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, @@ -664,6 +668,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, [{ \ nexthop-vrf NAME$vrf_name \ |label WORD \ + |weight (1-255) \ }]", NO_STR "Specify one of the nexthops in this ECMP group\n" @@ -674,7 +679,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, "If the nexthop is in a different vrf tell us\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") + "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") { VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); struct nexthop nhop; @@ -682,8 +689,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, int lbl_ret = 0; bool legal; - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, - label, &lbl_ret); + legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label, + &lbl_ret, weight); if (nhop.type == NEXTHOP_TYPE_IPV6 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -716,7 +723,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nh = nexthop_exists(&nhgc->nhg, &nhop); if (no) { - nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label); + nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label, + weight); if (nh) { _nexthop_del(&nhgc->nhg, nh); @@ -734,7 +742,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, _nexthop_add(&nhgc->nhg.nexthop, nh); } - nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label); + nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label, + weight); if (legal && nhg_hooks.add_nexthop) nhg_hooks.add_nexthop(nhgc, nh); @@ -794,6 +803,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) vty_out(vty, " label %s", buf); } + if (nh->weight) + vty_out(vty, " weight %u", nh->weight); + vty_out(vty, "\n"); } @@ -816,6 +828,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, if (nh->labels) vty_out(vty, " label %s", nh->labels); + if (nh->weight) + vty_out(vty, " weight %u", nh->weight); + vty_out(vty, "\n"); }