Implement an 'internal eBGP' peer mode, where the remote peer uses a different AS number than we do, as if it were an eBGP peer, but we treat the peer as if were an AS-internal peer. This enables implementing a network setup according to the model documented in RFC7938. This makes two changes to the BGP route propagation logic: * When we are propagating a route to or from an internal eBGP peer, we will avoid resetting the MED attribute. * When comparing BGP-learned routes, we will consider routes learned from an 'internal eBGP' peer as iBGP routes as far as the RFC 4271 9.1.2.2. d) check (Prefer external peers) is concerned. --- proto/bgp/attrs.c | 22 ++++++++++++++++------ proto/bgp/bgp.h | 1 + proto/bgp/config.Y | 4 +++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index b9e2490d..478c805c 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1100,15 +1100,21 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p if (!p->is_internal && !p->rs_client) { + struct bgp_proto *new_bgp = (e->attrs->src->proto->proto == &proto_bgp) ? + (struct bgp_proto *) e->attrs->src->proto : NULL; + bgp_path_prepend(e, attrs, pool, p->local_as); /* The MULTI_EXIT_DISC attribute received from a neighboring AS MUST NOT be * propagated to other neighboring ASes. * Perhaps it would be better to undefine it. */ - a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); - if (a) - bgp_attach_attr(attrs, pool, BA_MULTI_EXIT_DISC, 0); + if (!p->cf->iebgp_peer && (new_bgp == NULL || !new_bgp->cf->iebgp_peer)) + { + a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); + if (a) + bgp_attach_attr(attrs, pool, BA_MULTI_EXIT_DISC, 0); + } } /* iBGP -> keep next_hop, eBGP multi-hop -> use source_addr, @@ -1317,9 +1323,11 @@ bgp_rte_better(rte *new, rte *old) } /* RFC 4271 9.1.2.2. d) Prefer external peers */ - if (new_bgp->is_internal > old_bgp->is_internal) + n = !!(new_bgp->is_internal || new_bgp->cf->iebgp_peer); + o = !!(old_bgp->is_internal || old_bgp->cf->iebgp_peer); + if (n > o) return 0; - if (new_bgp->is_internal < old_bgp->is_internal) + if (n < o) return 1; /* RFC 4271 9.1.2.2. e) Compare IGP metrics */ @@ -1424,7 +1432,9 @@ bgp_rte_mergable(rte *pri, rte *sec) } /* RFC 4271 9.1.2.2. d) Prefer external peers */ - if (pri_bgp->is_internal != sec_bgp->is_internal) + p = !!(pri_bgp->is_internal || pri_bgp->cf->iebgp_peer); + s = !!(sec_bgp->is_internal || sec_bgp->cf->iebgp_peer); + if (p != s) return 0; /* RFC 4271 9.1.2.2. e) Compare IGP metrics */ diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e47a0eb1..8652fae8 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -51,6 +51,7 @@ struct bgp_config { int add_path; /* Use ADD-PATH extension [RFC7911] */ int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */ int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */ + int iebgp_peer; /* Peer has different AS but should be treated as internal peer */ int gr_mode; /* Graceful restart mode (BGP_GR_*) */ int setkey; /* Set MD5 password to system SA/SP database */ unsigned gr_time; /* Graceful restart timeout */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 55c602f1..f01a6fb6 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -27,7 +27,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, - CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY) + CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY, + IEBGP_PEER) CF_GRAMMAR @@ -129,6 +130,7 @@ bgp_proto: | bgp_proto ALLOW BGP_LOCAL_PREF bool ';' { BGP_CFG->allow_local_pref = $4; } | bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; } | bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; } + | bgp_proto IEBGP_PEER bool ';' { BGP_CFG->iebgp_peer = $3; } | bgp_proto GRACEFUL RESTART bool ';' { BGP_CFG->gr_mode = $4; } | bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; } | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; } -- 2.13.4