]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Update capability handshake options
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 13 Mar 2009 11:49:44 +0000 (12:49 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 13 Mar 2009 11:49:44 +0000 (12:49 +0100)
Add 'capabilities' option, change default behavior to advertise ipv4,
add some checks and ignore incoming capabilities when capabilities
are disabled.

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

index 5095b78051eff4ebf6f3ee1975d387ae118d7ee2..ee4697ec5348f534b379d33600adc5680b50f366 100644 (file)
@@ -669,6 +669,8 @@ MD5 password authentication
 (RFC 2385<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2385.txt">),
 route reflectors 
 (RFC 4456<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4456.txt">),
+multiprotocol extensions
+(RFC 4760<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4760.txt">),
 and 4B AS numbers 
 (RFC 4893<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4893.txt">).
 
@@ -762,15 +764,19 @@ for each neighbor using the following configuration parameters:
        Even when disabled (off), BIRD behaves internally as AS4-aware BGP router.
        Default: on.
 
-       <tag>advertise ipv4</tag> Advertise IPv4 multiprotocol capability.
-       This is not correct behavior but it is required by some BGP
-       implementations (Cisco and Quagga). Without this option,
-       the session establishment with these implementations takes
-       more time, session is degraded (no optional capabilities)
-       and the problem is logged. When the option is used, there might
-       be compatibility issues with other BGP implementations.
-       This option is relevant to IPv4 mode only.
-       Default: disabled.
+       <tag>capabilities <m/switch/</tag> Use capability advertisement
+       to advertise optional capabilities. This is standard behavior
+       for newer BGP implementations, but there might be some older
+       BGP implementations that reject such connection attempts.
+       When disabled (off), features that request it (4B AS support)
+       are also disabled. Default: on, with automatic fallback to
+       off when received capability-related error.
+
+       <tag>advertise ipv4 <m/switch/</tag> Advertise IPv4 multiprotocol capability.
+       This is not a correct behavior according to the strict interpretation
+       of RFC 4760, but it is widespread and required by some BGP
+       implementations (Cisco and Quagga). This option is relevant
+       to IPv4 mode with enabled capability advertisement only. Default: on.
 
        <tag>disable after error <m/switch/</tag> When an error is encountered (either
        locally or by the other side), disable the instance automatically
index 558b1e8ce36658bc48b6218fa9996d2a34306d3a..f44d016bf0ccbbb8933b611e595922d5236b1342 100644 (file)
@@ -113,7 +113,7 @@ bgp_open(struct bgp_proto *p)
        }
     }
 
-  p->start_state = BSS_CONNECT;
+  p->start_state = p->cf->capabilities ? BSS_CONNECT : BSS_CONNECT_NOCAP;
   return 0;
 }
 
@@ -823,16 +823,22 @@ bgp_check(struct bgp_config *c)
 {
   if (!c->local_as)
     cf_error("Local AS number must be set");
+
   if (!c->remote_as)
     cf_error("Neighbor must be configured");
+
   if (!bgp_as4_support && c->enable_as4)
     cf_error("AS4 support disabled globally");
-  if (!c->enable_as4 && (c->local_as > 0xFFFF))
+
+  if (!bgp_as4_support && (c->local_as > 0xFFFF))
     cf_error("Local AS number out of range");
-  if (!c->enable_as4 && (c->remote_as > 0xFFFF))
-    cf_error("Neighbor AS number out of range");
+
+  if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
+    cf_error("Neighbor AS number out of range (AS4 not available)");
+
   if ((c->local_as != c->remote_as) && (c->rr_client))
     cf_error("Only internal neighbor can be RR client");
+
   if ((c->local_as == c->remote_as) && (c->rs_client))
     cf_error("Only external neighbor can be RS client");
 }
index bdad1a4ddb270495e70159e97ccc4ca3f2cfabd6..d5448a68947b096ec93e866bd121204e1fc40320 100644 (file)
@@ -25,6 +25,7 @@ struct bgp_config {
   int compare_path_lengths;            /* Use path lengths when selecting best route */
   u32 default_local_pref;              /* Default value for LOCAL_PREF attribute */
   u32 default_med;                     /* Default value for MULTI_EXIT_DISC attribute */
+  int capabilities;                    /* Enable capability handshake [RFC3392] */
   int enable_as4;                      /* Enable local support for 4B AS numbers [RFC4893] */
   u32 rr_cluster_id;                   /* Route reflector cluster ID, if different from local ID */
   int rr_client;                       /* Whether neighbor is RR client of me */
index 4b64ed5f03c8e7ce63a00d3de9295fadec1d2471..c5ea87dec0086dabb1e5225399939f0bbd8f4d31 100644 (file)
@@ -21,7 +21,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
        ERROR, START, DELAY, FORGET, WAIT, ENABLE, DISABLE, AFTER,
        BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
        BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
-       PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4)
+       PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4,
+       CAPABILITIES)
 
 CF_GRAMMAR
 
@@ -40,6 +41,8 @@ bgp_proto_start: proto_start BGP {
      BGP_CFG->error_delay_time_min = 60;
      BGP_CFG->error_delay_time_max = 300;
      BGP_CFG->enable_as4 = bgp_as4_support;
+     BGP_CFG->capabilities = 2;
+     BGP_CFG->advertise_ipv4 = 1;
  }
  ;
 
@@ -71,7 +74,8 @@ bgp_proto:
  | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
  | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
  | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
- | bgp_proto ADVERTISE IPV4 ';' { BGP_CFG->advertise_ipv4 = 1; }
+ | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
+ | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
  | bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
  ;
 
index dc3748f0915355b8a8c286b7fdfcf63e5c9c106d..184120539bfa1627a088a774b3baa0475bd1e59d 100644 (file)
@@ -104,6 +104,7 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
 #ifdef IPV6
   cap = bgp_put_cap_ipv6(conn, cap);
 #endif
+
   if (conn->want_as4_support)
     cap = bgp_put_cap_as4(conn, cap);
 
@@ -504,6 +505,7 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
 static int
 bgp_parse_options(struct bgp_conn *conn, byte *opt, int len)
 {
+  struct bgp_proto *p = conn->bgp;
   int ol;
 
   while (len > 0)
@@ -524,7 +526,10 @@ bgp_parse_options(struct bgp_conn *conn, byte *opt, int len)
       switch (opt[0])
        {
        case 2:
-         bgp_parse_capabilities(conn, opt + 2, ol);
+         if (conn->start_state == BSS_CONNECT_NOCAP)
+           BGP_TRACE(D_PACKETS, "Ignoring received capabilities");
+         else
+           bgp_parse_capabilities(conn, opt + 2, ol);
          break;
 
        default:
@@ -550,6 +555,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
   struct bgp_proto *p = conn->bgp;
   struct bgp_config *cf = p->cf;
   unsigned hold;
+  u16 base_as;
   u32 id;
 
   /* Check state */
@@ -561,7 +567,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
     { bgp_error(conn, 1, 2, pkt+16, 2); return; }
   if (pkt[19] != BGP_VERSION)
     { bgp_error(conn, 2, 1, pkt+19, 1); return; } /* RFC 1771 says 16 bits, draft-09 tells to use 8 */
-  conn->advertised_as = get_u16(pkt+20);
+  conn->advertised_as = base_as = get_u16(pkt+20);
   hold = get_u16(pkt+22);
   id = get_u32(pkt+24);
   BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%08x)", conn->advertised_as, hold, id);
@@ -575,10 +581,11 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
   if (!id || id == 0xffffffff || id == p->local_id)
     { bgp_error(conn, 2, 3, pkt+24, -4); return; }
 
+  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)
-    {
-      bgp_error(conn, 2, 2, (byte *) &(conn->advertised_as), -4); return;
-    }
+    { bgp_error(conn, 2, 2, (byte *) &(conn->advertised_as), -4); return; }
 
   /* Check the other connection */
   other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn;
@@ -963,14 +970,20 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
   bgp_store_error(conn->bgp, conn, BE_BGP_RX, (code << 16) | subcode);
 
 #ifndef IPV6
-  if ((code == 2) && ((subcode == 4) || (subcode == 7)))
-    {
+  if ((code == 2) && ((subcode == 4) || (subcode == 7))
       /* Error related to capability:
        * 4 - Peer does not support capabilities at all.
        * 7 - Peer request some capability. Strange unless it is IPv6 only peer.
-       * We try connect without capabilities
        */
-      log(L_WARN "%s: Capability related error received, capabilities disabled", p->p.name);
+      && (p->cf->capabilities == 2)
+      /* 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))
+      /* Not possible with disabled capabilities */
+    {
+      /* We try connect without capabilities */
+      log(L_WARN "%s: Capability related error received, retry with capabilities disabled", p->p.name);
       conn->bgp->start_state = BSS_CONNECT_NOCAP;
       delay = 0;
     }