From 4e30bc2bfec5ead773e37388d6f407022570262f Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 24 Mar 2020 12:25:28 -0700 Subject: [PATCH] bgpd: Install multipath routes with weights Perform weighted ECMP if the multipaths have link bandwidth. This involves assigning weights to each of the next hops associated with the prefix based on the link bandwidth of the corresponding path as a factor of the total (cumulative) link bandwidth for the prefix. The weight values used are between 1 and 100. Weights are assigned only if all paths in the multipath have link bandwidth, otherwise any bandwidths are ignored and regular ECMP is performed. This is as recommended in https://tools.ietf.org/html/draft-ietf-idr-link-bandwidth A subsequent commit will implement additional (user-configurable) behaviors. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Don Slice --- bgpd/bgp_mpath.c | 26 ++++++++++++++++++++++++++ bgpd/bgp_mpath.h | 2 ++ bgpd/bgp_zebra.c | 24 ++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 4fe57b9bd..b30764d77 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -443,6 +443,32 @@ struct attr *bgp_path_info_mpath_attr(struct bgp_path_info *path) return path->mpath->mp_attr; } +/* + * bgp_path_info_chkwtd + * + * Given bestpath bgp_path_info, return if we should attempt to + * do weighted ECMP or not + */ +bool bgp_path_info_mpath_chkwtd(struct bgp_path_info *path) +{ + if (!path->mpath) + return false; + return (path->mpath->mp_flags & BGP_MP_LB_ALL); +} + +/* + * bgp_path_info_mpath_attr + * + * Given bestpath bgp_path_info, return cumulative bandwidth + * computed for all multipaths with bandwidth info + */ +uint64_t bgp_path_info_mpath_cumbw(struct bgp_path_info *path) +{ + if (!path->mpath) + return 0; + return path->mpath->cum_bw; +} + /* * bgp_path_info_mpath_attr_set * diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index ea82d0c44..6d3df2941 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -86,5 +86,7 @@ bgp_path_info_mpath_next(struct bgp_path_info *path); /* Accessors for multipath information */ extern uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path); extern struct attr *bgp_path_info_mpath_attr(struct bgp_path_info *path); +extern bool bgp_path_info_mpath_chkwtd(struct bgp_path_info *path); +extern uint64_t bgp_path_info_mpath_cumbw(struct bgp_path_info *path); #endif /* _QUAGGA_BGP_MPATH_H */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 404f17f69..db99811d5 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1148,6 +1148,12 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, return true; } +static uint32_t bgp_zebra_nhop_weight(uint32_t bw, uint64_t tot_bw) +{ + uint64_t tmp = (uint64_t)bw * 100; + return ((uint32_t)(tmp / tot_bw)); +} + void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, struct bgp_path_info *info, struct bgp *bgp, afi_t afi, safi_t safi) @@ -1170,6 +1176,8 @@ void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, char buf_prefix[PREFIX_STRLEN]; /* filled in if we are debugging */ bool is_evpn; int nh_updated; + bool do_wt_ecmp; + uint64_t cum_bw = 0; /* Don't try to install if we're not connected to Zebra or Zebra doesn't * know of this instance. @@ -1240,6 +1248,12 @@ void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, /* Metric is currently based on the best-path only */ metric = info->attr->med; + + /* Determine if we're doing weighted ECMP or not */ + do_wt_ecmp = bgp_path_info_mpath_chkwtd(info); + if (do_wt_ecmp) + cum_bw = bgp_path_info_mpath_cumbw(info); + for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { if (valid_nh_count >= multipath_num) break; @@ -1356,6 +1370,11 @@ void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, } memcpy(&api_nh->rmac, &(mpinfo->attr->rmac), sizeof(struct ethaddr)); + + /* Update next hop's weight for weighted ECMP */ + if (do_wt_ecmp) + api_nh->weight = bgp_zebra_nhop_weight( + mpinfo->attr->link_bw, cum_bw); valid_nh_count++; } @@ -1435,9 +1454,10 @@ void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", prefix_mac2str(&api_nh->rmac, buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u %s %s", + zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s", i + 1, nh_buf, api_nh->ifindex, - api_nh->vrf_id, label_buf, eth_buf); + api_nh->vrf_id, api_nh->weight, + label_buf, eth_buf); } } -- 2.39.5