diff options
author | Josh Bailey <joshb@google.com> | 2011-07-20 20:49:11 -0700 |
---|---|---|
committer | Josh Bailey <joshb@google.com> | 2011-07-20 20:49:11 -0700 |
commit | 0b597ef00ec7c7eebd836e2b1d5a266efcd60005 (patch) | |
tree | 818852fc775358cadb0178c15226af63cfb06759 /bgpd/bgp_mpath.c | |
parent | 6918e74b97fd40f947ebd2eded9ab24b8569d3b8 (diff) |
bgpd: When advertising a multipath route, the attribute set to be
advertised is based on the bestpath attribute set, but the
following attributes are aggregated from the attribute sets
of the multipath constituents:
- AS_PATH
- ORIGIN
- COMMUNITIES
- EXTENDED COMMUNITIES
In addition the route is advertised with the NEXT_HOP set
to the router's interface IP address, instead of the NEXT_HOP
of the best path. This is to ensure that traffic will go to this
router so it can be fanned out via the multipath route.
* bgpd/ecommunity.c
* ecommunity_uniq_sort(): Make this function externally accessible
* bgpd/ecommunity.h
* Add external declaration for ecommunity_uniq_sort()
* bgpd/bgp_mpath.c
* bgp_info_nexthop_cmp(): Replace calls to bgp_attr_extra_get()
to avoid unwanted memory allocation
* bgp_info_mpath_free(): Free aggregate attribute for multipath
* bgp_info_mpath_attr(): Lookup aggregate attribute of a multipath route
* bgp_info_mpath_attr_set(): Set aggregate attribute of a multipath route
* bgp_info_mpath_aggregate_update(): Update the aggregate attribute
of a multipath route
* bgpd/bgp_mpath.h
* bgp_info_mpath: Add pointer to hold aggregate attribute of a multipath
* Add external declarations for new functions
* bgpd/bgp_route.c
* bgp_announce_check(): Use aggregate attribute when announcing multipath
route
* bgp_announce_check_rsclient(): Use aggregate attribute when announcing
multipath route
* bgp_best_selection(): After updating multipath set, update the
multipath aggregate attribute
Diffstat (limited to 'bgpd/bgp_mpath.c')
-rw-r--r-- | bgpd/bgp_mpath.c | 193 |
1 files changed, 191 insertions, 2 deletions
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 7944c55f..44823c4b 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -34,6 +34,9 @@ #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_mpath.h" /* @@ -103,8 +106,8 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) struct attr_extra *ae1, *ae2; int compare; - ae1 = bgp_attr_extra_get (bi1->attr); - ae2 = bgp_attr_extra_get (bi2->attr); + ae1 = bi1->attr->extra; + ae2 = bi2->attr->extra; compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); @@ -226,6 +229,8 @@ bgp_info_mpath_free (struct bgp_info_mpath **mpath) { if (mpath && *mpath) { + if ((*mpath)->mp_attr) + bgp_attr_unintern ((*mpath)->mp_attr); XFREE (MTYPE_BGP_MPATH_INFO, *mpath); *mpath = NULL; } @@ -351,6 +356,37 @@ bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count) } /* + * bgp_info_mpath_attr + * + * Given bestpath bgp_info, return aggregated attribute set used + * for advertising the multipath route + */ +struct attr * +bgp_info_mpath_attr (struct bgp_info *binfo) +{ + if (!binfo->mpath) + return NULL; + return binfo->mpath->mp_attr; +} + +/* + * bgp_info_mpath_attr_set + * + * Sets the aggregated attribute into bestpath's mpath element + */ +static void +bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr) +{ + struct bgp_info_mpath *mpath; + if (!attr && !binfo->mpath) + return; + mpath = bgp_info_mpath_get (binfo); + if (!mpath) + return; + mpath->mp_attr = attr; +} + +/* * bgp_info_mpath_update * * Compare and sync up the multipath list with the mp_list generated by @@ -538,3 +574,156 @@ bgp_mp_dmed_deselect (struct bgp_info *dmed_best) UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG); assert (bgp_info_mpath_first (dmed_best) == 0); } + +/* + * bgp_info_mpath_aggregate_update + * + * Set the multipath aggregate attribute. We need to see if the + * aggregate has changed and then set the ATTR_CHANGED flag on the + * bestpath info so that a peer update will be generated. The + * change is detected by generating the current attribute, + * interning it, and then comparing the interned pointer with the + * current value. We can skip this generate/compare step if there + * is no change in multipath selection and no attribute change in + * any multipath. + */ +void +bgp_info_mpath_aggregate_update (struct bgp_info *new_best, + struct bgp_info *old_best) +{ + struct bgp_info *mpinfo; + struct aspath *aspath; + struct aspath *asmerge; + struct attr *new_attr, *old_attr; + u_char origin, attr_chg; + struct community *community, *commerge; + struct ecommunity *ecomm, *ecommerge; + struct attr_extra *ae; + struct attr attr = { 0 }; + + if (old_best && (old_best != new_best) && + (old_attr = bgp_info_mpath_attr (old_best))) + { + bgp_attr_unintern (old_attr); + bgp_info_mpath_attr_set (old_best, NULL); + } + + if (!new_best) + return; + + if (!bgp_info_mpath_count (new_best)) + { + if ((new_attr = bgp_info_mpath_attr (new_best))) + { + bgp_attr_unintern (new_attr); + bgp_info_mpath_attr_set (new_best, NULL); + SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); + } + return; + } + + /* + * Bail out here if the following is true: + * - MULTIPATH_CHG bit is not set on new_best, and + * - ATTR_CHANGED bit is not set on new_best or any of the multipaths + */ + attr_chg = 0; + if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) + attr_chg = 1; + else + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) + { + attr_chg = 1; + break; + } + } + if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && !attr_chg) + { + assert (bgp_info_mpath_attr (new_best)); + return; + } + + bgp_attr_dup (&attr, new_best->attr); + + /* aggregate attribute from multipath constituents */ + aspath = aspath_dup (attr.aspath); + origin = attr.origin; + community = attr.community ? community_dup (attr.community) : NULL; + ae = attr.extra; + ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; + + for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath); + aspath_free (aspath); + aspath = asmerge; + + if (origin < mpinfo->attr->origin) + origin = mpinfo->attr->origin; + + if (mpinfo->attr->community) + { + if (community) + { + commerge = community_merge (community, mpinfo->attr->community); + community = community_uniq_sort (commerge); + community_free (commerge); + } + else + community = community_dup (mpinfo->attr->community); + } + + ae = mpinfo->attr->extra; + if (ae && ae->ecommunity) + { + if (ecomm) + { + ecommerge = ecommunity_merge (ecomm, ae->ecommunity); + ecomm = ecommunity_uniq_sort (ecommerge); + ecommunity_free (ecommerge); + } + else + ecomm = ecommunity_dup (ae->ecommunity); + } + } + + attr.aspath = aspath; + attr.origin = origin; + if (community) + { + attr.community = community; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + } + if (ecomm) + { + ae = bgp_attr_extra_get (&attr); + ae->ecommunity = ecomm; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } + + /* Zap multipath attr nexthop so we set nexthop to self */ + attr.nexthop.s_addr = 0; +#ifdef HAVE_IPV6 + if (attr.extra) + memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); +#endif /* HAVE_IPV6 */ + + /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ + + new_attr = bgp_attr_intern (&attr); + bgp_attr_extra_free (&attr); + + if (new_attr != bgp_info_mpath_attr (new_best)) + { + if ((old_attr = bgp_info_mpath_attr (new_best))) + bgp_attr_unintern (old_attr); + bgp_info_mpath_attr_set (new_best, new_attr); + SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); + } + else + bgp_attr_unintern (new_attr); +} |