diff options
| -rw-r--r-- | bgpd/bgp_attr.h | 1 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 41 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 2 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 32 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 4 |
5 files changed, 76 insertions, 4 deletions
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 5fec4be29c..a6964c4653 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -263,6 +263,7 @@ struct attr { #define BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED (1 << 4) #define BATTR_RMAP_IPV6_LL_NHOP_CHANGED (1 << 5) #define BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED (1 << 6) +#define BATTR_RMAP_LINK_BW_SET (1 << 7) /* Router Reflector related structure. */ struct cluster_list { diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 0fbbc885b9..1ab59e62cb 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1268,3 +1268,44 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) return NULL; } + + +struct ecommunity *ecommunity_replace_linkbw(as_t as, + struct ecommunity *ecom, + uint64_t cum_bw) +{ + struct ecommunity *new; + struct ecommunity_val lb_eval; + const uint8_t *eval; + uint8_t type; + uint32_t cur_bw; + + /* Nothing to replace if link-bandwidth doesn't exist or + * is non-transitive - just return existing extcommunity. + */ + new = ecom; + if (!ecom || !ecom->size) + return new; + + eval = ecommunity_linkbw_present(ecom, &cur_bw); + if (!eval) + return new; + + type = *eval; + if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE) + return new; + + /* Transitive link-bandwidth exists, replace with the passed + * (cumulative) bandwidth value. We need to create a new + * extcommunity for this - refer to AS-Path replace function + * for reference. + */ + if (cum_bw > 0xFFFFFFFF) + cum_bw = 0xFFFFFFFF; + encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, + false, &lb_eval); + new = ecommunity_dup(ecom); + ecommunity_add_val(new, &lb_eval, true, true); + + return new; +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 094c677ff9..7deae8e746 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -238,6 +238,8 @@ extern void bgp_remove_ecomm_from_aggregate_hash( extern void bgp_aggr_ecommunity_remove(void *arg); extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw); +extern struct ecommunity *ecommunity_replace_linkbw(as_t as, + struct ecommunity *ecom, uint64_t cum_bw); static inline void ecommunity_strip_rts(struct ecommunity *ecom) { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e853351928..8bb4bb075b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1560,6 +1560,8 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, afi_t afi; safi_t safi; int samepeer_safe = 0; /* for synthetic mplsvpns routes */ + bool nh_reset = false; + uint64_t cum_bw; if (DISABLE_BGP_ANNOUNCE) return false; @@ -1983,12 +1985,14 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, PEER_FLAG_FORCE_NEXTHOP_SELF)) { if (!reflect || CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_FORCE_NEXTHOP_SELF)) + PEER_FLAG_FORCE_NEXTHOP_SELF)) { subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 : p->family), attr); + nh_reset = true; + } } else if (peer->sort == BGP_PEER_EBGP) { /* Can also reset the nexthop if announcing to EBGP, but * only if @@ -1999,22 +2003,26 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, if ((p->family == AF_INET) && (!bgp_subgrp_multiaccess_check_v4( piattr->nexthop, - subgrp, from))) + subgrp, from))) { subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 : p->family), attr); + nh_reset = true; + } if ((p->family == AF_INET6) && (!bgp_subgrp_multiaccess_check_v6( piattr->mp_nexthop_global, - subgrp, from))) + subgrp, from))) { subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 : p->family), attr); + nh_reset = true; + } @@ -2032,6 +2040,7 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, "%s: BGP_PATH_ANNC_NH_SELF, family=%s", __func__, family2str(family)); subgroup_announce_reset_nhop(family, attr); + nh_reset = true; } } @@ -2044,10 +2053,25 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, * the same interface. */ if (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi)) { - if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) + if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { subgroup_announce_reset_nhop(AF_INET6, attr); + nh_reset = true; + } } + /* + * When the next hop is set to ourselves, if all multipaths have + * link-bandwidth announce the cumulative bandwidth as that makes + * the most sense. However, don't modify if the link-bandwidth has + * been explicitly set by user policy. + */ + if (nh_reset && + bgp_path_info_mpath_chkwtd(pi) && + (cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 && + !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) + attr->ecommunity = ecommunity_replace_linkbw( + bgp->as, attr->ecommunity, cum_bw); + return true; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 7552ff2a66..7f23f6beca 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2609,6 +2609,10 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, path->attr->ecommunity = new_ecom; path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); + /* Mark that route-map has set link bandwidth; used in attribute + * setting decisions. + */ + SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET); return RMAP_OKAY; } |
