From bf26b80eba15278f45ec6060dd209fc6c22f3369 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 25 Jul 2019 11:35:06 -0400 Subject: [PATCH] bgpd: stop removing and replacing private asn if it matches the peer Problems reported that if multiple peers have "remove-private-AS replace-AS" with each other and all are using private asns, the as-path gets hosed and continues to grow when a prefix is removed. This fix disallows removing and replacing the private asn if it matches the peer's ASN so that normal as-path loop prevention will operate correctly. Ticket: CM-25489 Signed-off-by: Don Slice --- bgpd/bgp_aspath.c | 23 ++++++++++------------- bgpd/bgp_aspath.h | 5 +++-- bgpd/bgp_route.c | 6 +++--- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 05577cb8bd..cf0d28887e 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1232,7 +1232,8 @@ struct aspath *aspath_replace_specific_asn(struct aspath *aspath, } /* Replace all private ASNs with our own ASN */ -struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) +struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn, + as_t peer_asn) { struct aspath *new; struct assegment *seg; @@ -1244,7 +1245,9 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) int i; for (i = 0; i < seg->length; i++) { - if (BGP_AS_IS_PRIVATE(seg->as[i])) + /* Don't replace if public ASN or peer's ASN */ + if (BGP_AS_IS_PRIVATE(seg->as[i]) + && (seg->as[i] != peer_asn)) seg->as[i] = asn; } seg = seg->next; @@ -1255,7 +1258,7 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn) } /* Remove all private ASNs */ -struct aspath *aspath_remove_private_asns(struct aspath *aspath) +struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn) { struct aspath *new; struct assegment *seg; @@ -1282,16 +1285,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath) } } - // The entire segment is private so skip it - if (!public) { - seg = seg->next; - continue; - } - // The entire segment is public so copy it - else if (public == seg->length) { + if (public == seg->length) new_seg = assegment_dup(seg); - } // The segment is a mix of public and private ASNs. Copy as many // spots as @@ -1301,8 +1297,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath) new_seg = assegment_new(seg->type, public); j = 0; for (i = 0; i < seg->length; i++) { - // ASN is public - if (!BGP_AS_IS_PRIVATE(seg->as[i])) { + // keep ASN if public or matches peer's ASN + if (!BGP_AS_IS_PRIVATE(seg->as[i]) + || (seg->as[i] == peer_asn)) { new_seg->as[j] = seg->as[i]; j++; } diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 6f3d94cdb3..f84b3740c9 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -112,8 +112,9 @@ extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, as_t our_asn); extern struct aspath *aspath_replace_private_asns(struct aspath *aspath, - as_t asn); -extern struct aspath *aspath_remove_private_asns(struct aspath *aspath); + as_t asn, as_t peer_asn); +extern struct aspath *aspath_remove_private_asns(struct aspath *aspath, + as_t peer_asn); extern int aspath_firstas_check(struct aspath *, as_t); extern int aspath_confed_check(struct aspath *); extern int aspath_left_confed_check(struct aspath *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index aa02cc3c63..51c50f710e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1366,7 +1366,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) attr->aspath = aspath_replace_private_asns( - attr->aspath, bgp->as); + attr->aspath, bgp->as, peer->as); // The entire aspath consists of private ASNs so create // an empty aspath @@ -1377,7 +1377,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, // the private ASNs else attr->aspath = aspath_remove_private_asns( - attr->aspath); + attr->aspath, peer->as); } // 'all' was not specified so the entire aspath must be private @@ -1388,7 +1388,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi, peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) attr->aspath = aspath_replace_private_asns( - attr->aspath, bgp->as); + attr->aspath, bgp->as, peer->as); else attr->aspath = aspath_empty_get(); }