Update capability handshake options

Add 'capabilities' option, change default behavior to advertise ipv4,
add some checks and ignore incoming capabilities when capabilities
are disabled.
This commit is contained in:
Ondrej Zajicek 2009-03-13 12:49:44 +01:00
parent e3299ab148
commit e8ba557c7f
5 changed files with 54 additions and 24 deletions

View 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

View 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");
}

View 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 */

View 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; }
;

View 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;
}