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

Reply via email to