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">), (RFC 2385<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2385.txt">),
route reflectors route reflectors
(RFC 4456<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4456.txt">), (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 and 4B AS numbers
(RFC 4893<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4893.txt">). (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. Even when disabled (off), BIRD behaves internally as AS4-aware BGP router.
Default: on. Default: on.
<tag>advertise ipv4</tag> Advertise IPv4 multiprotocol capability. <tag>capabilities <m/switch/</tag> Use capability advertisement
This is not correct behavior but it is required by some BGP to advertise optional capabilities. This is standard behavior
implementations (Cisco and Quagga). Without this option, for newer BGP implementations, but there might be some older
the session establishment with these implementations takes BGP implementations that reject such connection attempts.
more time, session is degraded (no optional capabilities) When disabled (off), features that request it (4B AS support)
and the problem is logged. When the option is used, there might are also disabled. Default: on, with automatic fallback to
be compatibility issues with other BGP implementations. off when received capability-related error.
This option is relevant to IPv4 mode only.
Default: disabled. <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 <tag>disable after error <m/switch/</tag> When an error is encountered (either
locally or by the other side), disable the instance automatically 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; return 0;
} }
@ -823,16 +823,22 @@ bgp_check(struct bgp_config *c)
{ {
if (!c->local_as) if (!c->local_as)
cf_error("Local AS number must be set"); cf_error("Local AS number must be set");
if (!c->remote_as) if (!c->remote_as)
cf_error("Neighbor must be configured"); cf_error("Neighbor must be configured");
if (!bgp_as4_support && c->enable_as4) if (!bgp_as4_support && c->enable_as4)
cf_error("AS4 support disabled globally"); 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"); 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)) if ((c->local_as != c->remote_as) && (c->rr_client))
cf_error("Only internal neighbor can be RR client"); cf_error("Only internal neighbor can be RR client");
if ((c->local_as == c->remote_as) && (c->rs_client)) if ((c->local_as == c->remote_as) && (c->rs_client))
cf_error("Only external neighbor can be 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 */ int compare_path_lengths; /* Use path lengths when selecting best route */
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */ u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
u32 default_med; /* Default value for MULTI_EXIT_DISC 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] */ int enable_as4; /* Enable local support for 4B AS numbers [RFC4893] */
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */ u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
int rr_client; /* Whether neighbor is RR client of me */ 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, ERROR, START, DELAY, FORGET, WAIT, ENABLE, DISABLE, AFTER,
BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP, BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, 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 CF_GRAMMAR
@ -40,6 +41,8 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->error_delay_time_min = 60; BGP_CFG->error_delay_time_min = 60;
BGP_CFG->error_delay_time_max = 300; BGP_CFG->error_delay_time_max = 300;
BGP_CFG->enable_as4 = bgp_as4_support; 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 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 DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; } | 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; } | 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 #ifdef IPV6
cap = bgp_put_cap_ipv6(conn, cap); cap = bgp_put_cap_ipv6(conn, cap);
#endif #endif
if (conn->want_as4_support) if (conn->want_as4_support)
cap = bgp_put_cap_as4(conn, cap); cap = bgp_put_cap_as4(conn, cap);
@ -504,6 +505,7 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
static int static int
bgp_parse_options(struct bgp_conn *conn, byte *opt, int len) bgp_parse_options(struct bgp_conn *conn, byte *opt, int len)
{ {
struct bgp_proto *p = conn->bgp;
int ol; int ol;
while (len > 0) while (len > 0)
@ -524,6 +526,9 @@ bgp_parse_options(struct bgp_conn *conn, byte *opt, int len)
switch (opt[0]) switch (opt[0])
{ {
case 2: case 2:
if (conn->start_state == BSS_CONNECT_NOCAP)
BGP_TRACE(D_PACKETS, "Ignoring received capabilities");
else
bgp_parse_capabilities(conn, opt + 2, ol); bgp_parse_capabilities(conn, opt + 2, ol);
break; break;
@ -550,6 +555,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
struct bgp_proto *p = conn->bgp; struct bgp_proto *p = conn->bgp;
struct bgp_config *cf = p->cf; struct bgp_config *cf = p->cf;
unsigned hold; unsigned hold;
u16 base_as;
u32 id; u32 id;
/* Check state */ /* 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; } { bgp_error(conn, 1, 2, pkt+16, 2); return; }
if (pkt[19] != BGP_VERSION) 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 */ { 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); hold = get_u16(pkt+22);
id = get_u32(pkt+24); id = get_u32(pkt+24);
BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%08x)", conn->advertised_as, hold, id); 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) if (!id || id == 0xffffffff || id == p->local_id)
{ bgp_error(conn, 2, 3, pkt+24, -4); return; } { 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) 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 */ /* Check the other connection */
other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn; 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); bgp_store_error(conn->bgp, conn, BE_BGP_RX, (code << 16) | subcode);
#ifndef IPV6 #ifndef IPV6
if ((code == 2) && ((subcode == 4) || (subcode == 7))) if ((code == 2) && ((subcode == 4) || (subcode == 7))
{
/* Error related to capability: /* Error related to capability:
* 4 - Peer does not support capabilities at all. * 4 - Peer does not support capabilities at all.
* 7 - Peer request some capability. Strange unless it is IPv6 only peer. * 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; conn->bgp->start_state = BSS_CONNECT_NOCAP;
delay = 0; delay = 0;
} }