[PATCH,RFC 1/3] BGP: Implement secondary remote AS number support.

Lennert Buytenhek buytenh at wantstofly.org
Thu Mar 9 15:29:40 CET 2017


When carrying out a BGP topology migration such as an AS renumbering
or an AS merge, which involves changing the local AS being reported
by one or both ends of a BGP session, being able to avoid the need
to reconfigure both peers at the same time can significantly reduce
the complexity of such a migration.

Also, if the peers are managed by different administrative entities,
it might not even be possible to reconfigure both peers as closely
together in time as you would like.

One way to make this easier is to allow configuring two local AS numbers
on a BGP session, one AS number to try first, and another AS number to
fall back to if connecting with the preferred AS number gives us back a
NOTIFICATION with OPEN message error "Bad Peer AS" from the peer.  You
can then add this option on your end of the BGP session, and then ask
your peer to reconfigure their end, and the session will remain up in
the time interval between your change and the peer's change.  However,
doing it this way adds quite some complexity to the BGP connection
state machine.

An easier way of achieving the same thing is to allow specifying two
different AS numbers that we will accept from the peer, and let the BGP
session establish if the peer sends us either one of those AS numbers
as its local AS.  You would then first reconfigure one or both peer(s)
to accept a secondary remote AS number in addition to the one that is
currently being used, and then reconfigure one or both peer(s) to
change the local AS number being sent in the OPEN message.  This is
both easier to implement and avoids the unnecessary but unavoidable
reconnection attempts that stem from the fact that we cannot know that
we are going to be trying to OPEN the connection using a local AS that
our peer does not expect before it sends us a "Bad Peer AS".

This patch implements the latter option, and this functionality is
enabled by specifying two different remote AS numbers for a peer in
the neighbor statement.  Instead of specifying:

	neighbor 1.2.3.4 as 12345;

Specify this:

	neighbor 1.2.3.4 as 12345 as 23456;

Which will allow peer 1.2.3.4 to connect to us using either AS 12345
or AS 23456.

(bird's config grammar already allows specifying multiple remote AS
numbers for a peer, and it will use the last AS number you specify
this way if you do that.  With this patch, it will use the last two
AS numbers you specify.)
---
 proto/bgp/bgp.c     | 17 +++++++++--------
 proto/bgp/bgp.h     |  2 +-
 proto/bgp/config.Y  |  2 +-
 proto/bgp/packets.c |  8 ++++++--
 4 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 0f1c944..bceae4a 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1278,8 +1278,6 @@ bgp_init(struct proto_config *C)
 
   p->cf = c;
   p->local_as = c->local_as;
-  p->remote_as = c->remote_as;
-  p->is_internal = (c->local_as == c->remote_as);
   p->rs_client = c->rs_client;
   p->rr_client = c->rr_client;
   p->igp_table = get_igp_table(c);
@@ -1291,8 +1289,6 @@ bgp_init(struct proto_config *C)
 void
 bgp_check_config(struct bgp_config *c)
 {
-  int internal = (c->local_as == c->remote_as);
-
   /* Do not check templates at all */
   if (c->c.class == SYM_TEMPLATE)
     return;
@@ -1300,7 +1296,12 @@ bgp_check_config(struct bgp_config *c)
 
   /* EBGP direct by default, IBGP multihop by default */
   if (c->multihop < 0)
-    c->multihop = internal ? 64 : 0;
+    {
+      if (c->local_as != c->remote_as || (c->remote_as2 != 0 && c->local_as != c->remote_as2))
+	c->multihop = 0;
+      else
+	c->multihop = 64;
+    }
 
   /* Different default for gw_mode */
   if (!c->gw_mode)
@@ -1330,13 +1331,13 @@ bgp_check_config(struct bgp_config *c)
   if (!ipa_is_link_local(c->remote_ip) != !c->iface)
     cf_error("Link-local address and interface scope must be used together");
 
-  if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
+  if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF || c->remote_as2 > 0xFFFF))
     cf_error("Neighbor AS number out of range (AS4 not available)");
 
-  if (!internal && c->rr_client)
+  if (c->rr_client && (c->local_as != c->remote_as || (c->remote_as2 != 0 && c->local_as != c->remote_as2)))
     cf_error("Only internal neighbor can be RR client");
 
-  if (internal && c->rs_client)
+  if (c->rs_client && (c->local_as == c->remote_as || c->local_as == c->remote_as2))
     cf_error("Only external neighbor can be RS client");
 
   if (c->multihop && (c->gw_mode == GW_DIRECT))
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index e47a0eb..0b8cb46 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -19,7 +19,7 @@ struct eattr;
 
 struct bgp_config {
   struct proto_config c;
-  u32 local_as, remote_as;
+  u32 local_as, remote_as, remote_as2;
   ip_addr remote_ip;
   ip_addr source_addr;			/* Source address to use */
   struct iface *iface;			/* Interface for link-local addresses */
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 55c602f..8cf70c1 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -61,7 +61,7 @@ bgp_proto_start: proto_start BGP {
 bgp_nbr_opts:
    /* empty */
  | bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number");  }
- | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
+ | bgp_nbr_opts AS expr { BGP_CFG->remote_as2 = BGP_CFG->remote_as; BGP_CFG->remote_as = $3; }
  ;
 
 bgp_proto:
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index d100b7d..e402288 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -966,7 +966,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
   if ((conn->advertised_as != base_as) && (base_as != AS_TRANS))
     log(L_WARN "%s: Peer advertised inconsistent AS numbers", p->p.name);
 
-  if (conn->advertised_as != p->remote_as)
+  if (conn->advertised_as != p->cf->remote_as && conn->advertised_as != p->cf->remote_as2)
     {
       if (conn->peer_as4_support)
 	{
@@ -979,6 +979,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
       return;
     }
 
+  p->remote_as = conn->advertised_as;
+  p->is_internal = (p->local_as == p->remote_as);
+
   /* Check the other connection */
   other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
   switch (other->state)
@@ -1550,7 +1553,8 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
       /* Capabilities are not explicitly enabled or disabled, therefore heuristic is used */
       && (conn->start_state == BSS_CONNECT)
       /* Failed connection attempt have used capabilities */
-      && (p->cf->remote_as <= 0xFFFF))
+      && (p->cf->remote_as <= 0xFFFF)
+      && (p->cf->remote_as2 <= 0xFFFF))
       /* Not possible with disabled capabilities */
     {
       /* We try connect without capabilities */
-- 
2.9.3


More information about the Bird-users mailing list