]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP: Promiscuous ASN mode
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 3 Apr 2019 13:54:50 +0000 (15:54 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 3 Apr 2019 13:54:50 +0000 (15:54 +0200)
Allow to specify just 'internal' or 'external' for remote neighbor
instead of specific ASN. In the second case that means BGP peers with
any non-local ASNs are accepted.

doc/bird.sgml
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/bgp/packets.c

index 52c9d6fd95f5aa6a38ecd3fa14bbaaadd42a30a6..9675caf05b5e7f5d6bca8416646eafc413404cb5 100644 (file)
@@ -2195,12 +2195,15 @@ using the following configuration parameters:
        <cf/local 10.0.0.1; local as 65000;/ are valid). This parameter is
        mandatory.
 
-       <tag><label id="bgp-neighbor">neighbor [<m/ip/] [port <m/number/] [as <m/number/]</tag>
+       <tag><label id="bgp-neighbor">neighbor [<m/ip/] [port <m/number/] [as <m/number/] [internal|external]</tag>
        Define neighboring router this instance will be talking to and what AS
        it is located in. In case the neighbor is in the same AS as we are, we
-       automatically switch to iBGP. Optionally, the remote port may also be
-       specified. Like <cf/local/ parameter, this parameter may also be used
-       multiple times with different sub-options. This parameter is mandatory.
+       automatically switch to IBGP. Alternatively, it is possible to specify
+       just <cf/internal/ or </cf/external/ instead of AS number, in that case
+       either local AS number, or any external AS number is accepted.
+       Optionally, the remote port may also be specified. Like <cf/local/
+       parameter, this parameter may also be used multiple times with different
+       sub-options. This parameter is mandatory.
 
        <tag><label id="bgp-iface">interface <m/string/</tag>
        Define interface we should use for link-local BGP IPv6 sessions.
index 756f0326b7ba4b5efe0a356ba0bc3614d024935f..92f41ef60d66caef70d3bb867680ca3af2c7f57c 100644 (file)
@@ -507,6 +507,10 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
   if (ipa_zero(p->local_ip))
     p->local_ip = conn->sk->saddr;
 
+  /* For promiscuous sessions */
+  if (!p->remote_as)
+    p->remote_as = conn->received_as;
+
   /* In case of LLv6 is not valid during BGP start */
   if (ipa_zero(p->link_addr) && p->neigh && p->neigh->iface && p->neigh->iface->llv6)
     p->link_addr = p->neigh->iface->llv6->ip;
@@ -1754,14 +1758,19 @@ void
 bgp_postconfig(struct proto_config *CF)
 {
   struct bgp_config *cf = (void *) CF;
-  int internal = (cf->local_as == cf->remote_as);
-  int interior = internal || cf->confederation_member;
 
   /* Do not check templates at all */
   if (cf->c.class == SYM_TEMPLATE)
     return;
 
 
+  /* Handle undefined remote_as, zero should mean unspecified external */
+  if (!cf->remote_as && (cf->peer_type == BGP_PT_INTERNAL))
+    cf->remote_as = cf->local_as;
+
+  int internal = (cf->local_as == cf->remote_as);
+  int interior = internal || cf->confederation_member;
+
   /* EBGP direct by default, IBGP multihop by default */
   if (cf->multihop < 0)
     cf->multihop = internal ? 64 : 0;
@@ -1781,8 +1790,14 @@ bgp_postconfig(struct proto_config *CF)
   if (ipa_zero(cf->remote_ip))
     cf_error("Neighbor must be configured");
 
-  if (!cf->remote_as)
-    cf_error("Remote AS number must be set");
+  if (!cf->remote_as && !cf->peer_type)
+    cf_error("Remote AS number (or peer type) must be set");
+
+  if ((cf->peer_type == BGP_PT_INTERNAL) && !internal)
+    cf_error("IBGP cannot have different ASNs");
+
+  if ((cf->peer_type == BGP_PT_EXTERNAL) &&  internal)
+    cf_error("EBGP cannot have the same ASNs");
 
   if (!cf->iface && (ipa_is_link_local(cf->local_ip) ||
                     ipa_is_link_local(cf->remote_ip)))
@@ -2242,7 +2257,7 @@ bgp_show_proto_info(struct proto *P)
 
   cli_msg(-1006, "  BGP state:          %s", bgp_state_dsc(p));
   cli_msg(-1006, "    Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
-  cli_msg(-1006, "    Neighbor AS:      %u", p->cf->remote_as);
+  cli_msg(-1006, "    Neighbor AS:      %u", p->cf->remote_as ?: p->remote_as);
 
   if (p->gr_active_num)
     cli_msg(-1006, "    Neighbor graceful restart active");
index 512410d413fbe413fe68fb2800767575296ce290..fd515cbbe6abc194299f6f08f201b4e32c12d24e 100644 (file)
@@ -83,6 +83,7 @@ struct bgp_config {
   struct iface *iface;                 /* Interface for link-local addresses */
   u16 local_port;                      /* Local listening port */
   u16 remote_port;                     /* Neighbor destination port */
+  int peer_type;                       /* Internal or external BGP (BGP_PT_*, optional) */
   int multihop;                                /* Number of hops if multihop */
   int strict_bind;                     /* Bind listening socket to local address */
   int ttl_security;                    /* Enable TTL security [RFC 5082] */
@@ -152,6 +153,9 @@ struct bgp_channel_config {
   struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
 };
 
+#define BGP_PT_INTERNAL                1
+#define BGP_PT_EXTERNAL                2
+
 #define NH_NO                  0
 #define NH_ALL                 1
 #define NH_IBGP                        2
@@ -237,6 +241,7 @@ struct bgp_conn {
   u8 state;                            /* State of connection state machine */
   u8 as4_session;                      /* Session uses 4B AS numbers in AS_PATH (both sides support it) */
   u8 ext_messages;                     /* Session uses extended message length */
+  u32 received_as;                     /* ASN received in OPEN message */
 
   struct bgp_caps *local_caps;
   struct bgp_caps *remote_caps;
index 9dea78ca2c8f661a5060ea9daf616b5d5ffd124d..c9a6af96265a23d17b2fbb2c474e06bd721904e2 100644 (file)
@@ -29,7 +29,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
        SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
        GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
        STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
-       LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY)
+       LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL)
 
 %type <i> bgp_nh
 %type <i32> bgp_afi
@@ -82,6 +82,8 @@ 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 INTERNAL { BGP_CFG->peer_type = BGP_PT_INTERNAL; }
+ | bgp_nbr_opts EXTERNAL { BGP_CFG->peer_type = BGP_PT_EXTERNAL; }
  ;
 
 bgp_cease_mask:
index fc572a21289b016442432ec3f3d5713a9c725d69..0e142a7a27416d005c907d963bb380eae4c1a477 100644 (file)
@@ -732,13 +732,18 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
     if ((as4 != asn) && (asn != AS_TRANS))
       log(L_WARN "%s: Peer advertised inconsistent AS numbers", p->p.name);
 
-    if (as4 != p->remote_as)
+    /* When remote ASN is unspecified, it must be external one */
+    if (p->remote_as ? (as4 != p->remote_as) : (as4 == p->local_as))
     { as4 = htonl(as4); bgp_error(conn, 2, 2, (byte *) &as4, 4); return; }
+
+    conn->received_as = as4;
   }
   else
   {
-    if (asn != p->remote_as)
+    if (p->remote_as ? (asn != p->remote_as) : (asn == p->local_as))
     { bgp_error(conn, 2, 2, pkt+20, 2); return; }
+
+    conn->received_as = asn;
   }
 
   /* Check the other connection */