summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-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;
}