summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-03-13 12:49:44 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2009-03-13 12:49:44 +0100
commite8ba557c7f66aaf02dd24f554fba8b3607c2b3d5 (patch)
tree64f1e9d86256b1603e8713b973cf8e666aaf2f80 /proto
parente3299ab14877de6ce688050e550c44cd4e85b212 (diff)
Update capability handshake options
Add 'capabilities' option, change default behavior to advertise ipv4, add some checks and ignore incoming capabilities when capabilities are disabled.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/bgp.c14
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/bgp/config.Y8
-rw-r--r--proto/bgp/packets.c31
4 files changed, 39 insertions, 15 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 558b1e8c..f44d016b 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -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");
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index bdad1a4d..d5448a68 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -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 */
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 4b64ed5f..c5ea87de 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -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; }
;
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index dc3748f0..18412053 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -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;
}