]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Install multipath routes with weights
authorvivek <vivek@cumulusnetworks.com>
Tue, 24 Mar 2020 19:25:28 +0000 (12:25 -0700)
committervivek <vivek@cumulusnetworks.com>
Tue, 31 Mar 2020 03:12:31 +0000 (20:12 -0700)
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 <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
bgpd/bgp_mpath.c
bgpd/bgp_mpath.h
bgpd/bgp_zebra.c

index 4fe57b9bdc265db6779c11ceb560d1acd9260996..b30764d773ee6e9e74ace003a03d4d4d226be4aa 100644 (file)
@@ -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
  *
index ea82d0c44424b518f758ab9cd0f3decef84c2533..6d3df29415d981a5fdf9d17b5da231e90f066ed8 100644 (file)
@@ -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 */
index 404f17f69e4c88348c3118754b248f9c07717007..db99811d5ce6dc8d1aca1232d43bcd033b8d14d1 100644 (file)
@@ -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);
                }
        }