diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ed2b3c9235..6a7db87ec4 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1132,6 +1132,7 @@ static int evpn_es_route_select_install(struct bgp *bgp, old_select->attr->nexthop); } UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); bgp_zebra_clear_route_change_flags(rn); return ret; } @@ -1152,6 +1153,7 @@ static int evpn_es_route_select_install(struct bgp *bgp, bgp_path_info_set_flag(rn, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(rn, new_select, BGP_PATH_ATTR_CHANGED); UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } if (new_select && new_select->type == ZEBRA_ROUTE_BGP @@ -1211,6 +1213,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, bgp, vpn, (const struct prefix_evpn *)bgp_node_get_prefix(rn), old_select); UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); bgp_zebra_clear_route_change_flags(rn); return ret; } @@ -1230,6 +1233,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, bgp_path_info_set_flag(rn, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(rn, new_select, BGP_PATH_ATTR_CHANGED); UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } if (new_select && new_select->type == ZEBRA_ROUTE_BGP diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index b30764d773..a3d40849ce 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -500,7 +500,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, { uint16_t maxpaths, mpath_count, old_mpath_count; uint32_t bwval; - uint64_t cum_bw; + uint64_t cum_bw, old_cum_bw; struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; @@ -513,7 +513,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, mpath_count = 0; cur_mpath = NULL; old_mpath_count = 0; - cum_bw = 0; + old_cum_bw = cum_bw = 0; prev_mpath = new_best; mp_node = listhead(mp_list); debug = bgp_debug_bestpath(rn); @@ -530,6 +530,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (old_best) { cur_mpath = bgp_path_info_mpath_first(old_best); old_mpath_count = bgp_path_info_mpath_count(old_best); + old_cum_bw = bgp_path_info_mpath_cumbw(old_best); bgp_path_info_mpath_count_set(old_best, 0); bgp_path_info_mpath_lb_update(old_best, false, false, 0); bgp_path_info_mpath_dequeue(old_best); @@ -537,9 +538,10 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (debug) zlog_debug( - "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d", + "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64, rn, new_best ? new_best->peer->host : "NONE", - mp_list ? listcount(mp_list) : 0, old_mpath_count); + mp_list ? listcount(mp_list) : 0, + old_mpath_count, old_cum_bw); /* * We perform an ordered walk through both lists in parallel. @@ -728,6 +730,9 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (mpath_changed || (bgp_path_info_mpath_count(new_best) != old_mpath_count)) SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG); + if ((mpath_count - 1) != old_mpath_count || + old_cum_bw != cum_bw) + SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG); } } @@ -752,6 +757,7 @@ void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best) bgp_path_info_mpath_count_set(dmed_best, 0); UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG); assert(bgp_path_info_mpath_first(dmed_best) == NULL); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9a3ab0d8ee..e853351928 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2394,7 +2394,8 @@ bool bgp_zebra_has_route_changed(struct bgp_node *rn, * when the best path has an attribute change anyway. */ if (CHECK_FLAG(selected->flags, BGP_PATH_IGP_CHANGED) - || CHECK_FLAG(selected->flags, BGP_PATH_MULTIPATH_CHG)) + || CHECK_FLAG(selected->flags, BGP_PATH_MULTIPATH_CHG) + || CHECK_FLAG(selected->flags, BGP_PATH_LINK_BW_CHG)) return true; /* @@ -2563,12 +2564,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp, afi, safi); } } - UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); - bgp_zebra_clear_route_change_flags(rn); /* If there is a change of interest to peers, reannounce the * route. */ if (CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) + || CHECK_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG) || CHECK_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED)) { group_announce_route(bgp, afi, safi, rn, new_select); @@ -2583,6 +2583,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, UNSET_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED); } + UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); + bgp_zebra_clear_route_change_flags(rn); UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED); return; } @@ -2613,6 +2616,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp_path_info_set_flag(rn, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(rn, new_select, BGP_PATH_ATTR_CHANGED); UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG); + UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } #if ENABLE_BGP_VNC diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 9438b328ad..bdcb2cdf6a 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -237,6 +237,7 @@ struct bgp_path_info { #define BGP_PATH_MULTIPATH_CHG (1 << 12) #define BGP_PATH_RIB_ATTR_CHG (1 << 13) #define BGP_PATH_ANNC_NH_SELF (1 << 14) +#define BGP_PATH_LINK_BW_CHG (1 << 15) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ uint8_t type; @@ -477,6 +478,10 @@ static inline void prep_for_rmap_apply(struct bgp_path_info *dst_pi, dst_pi->peer = peer; dst_pi->attr = attr; dst_pi->net = rn; + dst_pi->flags = src_pi->flags; + dst_pi->type = src_pi->type; + dst_pi->sub_type = src_pi->sub_type; + dst_pi->mpath = src_pi->mpath; if (src_pi->extra) { memcpy(dst_pie, src_pi->extra, sizeof(struct bgp_path_info_extra)); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index ffcb65555b..7552ff2a66 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -63,6 +63,7 @@ #include "bgpd/bgp_pbr.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_encap_types.h" +#include "bgpd/bgp_mpath.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -2552,6 +2553,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, struct ecommunity ecom_lb = {0}; struct ecommunity_val lb_eval; uint32_t bw_bytes = 0; + uint16_t mpath_count = 0; struct ecommunity *new_ecom; struct ecommunity *old_ecom; as_t as; @@ -2566,8 +2568,27 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, /* Build link bandwidth extended community */ as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as; - if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) + if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) { bw_bytes = ((uint64_t)(rels->bw * 1000 * 1000))/8; + } else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) { + /* process this only for the best path. */ + if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) + return RMAP_OKAY; + + bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path); + if (!bw_bytes) + return RMAP_OKAY; + + } else if (rels->lb_type == RMAP_ECOMM_LB_SET_NUM_MPATH) { + + /* process this only for the best path. */ + if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) + return RMAP_OKAY; + + bw_bytes = ((uint64_t)(peer->bgp->lb_ref_bw * 1000 * 1000))/8; + mpath_count = bgp_path_info_mpath_count(path) + 1; + bw_bytes *= mpath_count; + } encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6534ac1900..d1363b70a4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2970,6 +2970,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; + bgp->lb_ref_bw = BGP_LINK_BW_REF_BW; bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; bgp_addpath_init_bgp_data(&bgp->tx_addpath); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 2b67a39efd..24ea66b5a1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -395,6 +395,14 @@ struct bgp { #define BGP_UPDATE_DELAY_MIN 0 #define BGP_UPDATE_DELAY_MAX 3600 + /* Reference bandwidth for BGP link-bandwidth. Used when + * the LB value has to be computed based on some other + * factor (e.g., number of multipaths for the prefix) + * Value is in Mbps + */ + uint32_t lb_ref_bw; +#define BGP_LINK_BW_REF_BW 1 + /* BGP flags. */ uint32_t flags; #define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)