summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2008-12-24 17:24:41 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2008-12-24 17:24:41 +0100
commit165a62272720071ca5e9ed1badfddc78b7a7af10 (patch)
tree5d7a1b37cd38d25a2264527616ee58e8f1b6f97a
parent591211557f4106ed9e877fa9b80eb56ffb99fef3 (diff)
Adds support for fallback to capabilityless BGP connect
When capability related error is received, next connect will be without capabilities. Also cease error subcodes descriptions (according to [RFC4486]) are added.
-rw-r--r--proto/bgp/bgp.c4
-rw-r--r--proto/bgp/bgp.h5
-rw-r--r--proto/bgp/packets.c49
3 files changed, 47 insertions, 11 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index d1b7dee9..558b1e8c 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -368,6 +368,10 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn)
static void
bgp_send_open(struct bgp_conn *conn)
{
+ conn->start_state = conn->bgp->start_state;
+ conn->want_as4_support = conn->bgp->cf->enable_as4 && (conn->start_state != BSS_CONNECT_NOCAP);
+ conn->peer_as4_support = 0; // Default value, possibly changed by receiving capability.
+
DBG("BGP: Sending open\n");
conn->sk->rx_hook = bgp_rx;
conn->sk->tx_hook = bgp_tx;
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 5c180cce..b706caf1 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -51,9 +51,10 @@ struct bgp_conn {
int packets_to_send; /* Bitmap of packet types to be sent */
int notify_code, notify_subcode, notify_size;
byte *notify_data;
- int error_flag; /* Error state, ignore all input */
u32 advertised_as; /* Temporary value for AS number received */
- int as4_support; /* Peer supports 4B AS numbers [RFC4893] */
+ int start_state; /* protocol start_state snapshot when connection established */
+ int want_as4_support; /* Connection tries to establish AS4 session */
+ int peer_as4_support; /* Peer supports 4B AS numbers [RFC4893] */
unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
};
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 4e42d90b..27c0755e 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -69,13 +69,21 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
put_u16(buf+1, (p->local_as < 0xFFFF) ? p->local_as : AS_TRANS);
put_u16(buf+3, p->cf->hold_time);
put_u32(buf+5, p->local_id);
+
+ if (conn->start_state == BSS_CONNECT_NOCAP)
+ {
+ BGP_TRACE(D_PACKETS, "Skipping capabilities");
+ buf[9] = 0;
+ return buf + 10;
+ }
+
/* Skipped 3 B for length field and Capabilities parameter header */
cap = buf + 12;
#ifdef IPV6
cap = bgp_put_cap_ipv6(conn, cap);
#endif
- if (p->cf->enable_as4)
+ if (conn->want_as4_support)
cap = bgp_put_cap_as4(conn, cap);
cap_len = cap - buf - 12;
@@ -418,9 +426,8 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
case 65:
if (cl != 4)
goto err;
- conn->as4_support = 1;
-
- if (p->cf->enable_as4)
+ conn->peer_as4_support = 1;
+ if (conn->want_as4_support)
conn->advertised_as = get_u32(opt + 2);
break;
@@ -501,7 +508,6 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
id = get_u32(pkt+24);
BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%08x)", conn->advertised_as, hold, id);
- conn->as4_support = 0; // Default value, possibly changed by capability.
if (bgp_parse_options(conn, pkt+29, pkt[28]))
return;
@@ -548,8 +554,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
conn->hold_time = MIN(hold, p->cf->hold_time);
conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
p->remote_id = id;
- p->as4_session = p->cf->enable_as4 && conn->as4_support;
-
+ p->as4_session = conn->want_as4_support && conn->peer_as4_support;
+
DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);
bgp_schedule_packet(conn, PKT_KEEPALIVE);
@@ -820,7 +826,15 @@ static struct {
{ 3, 11, "Malformed AS_PATH" },
{ 4, 0, "Hold timer expired" },
{ 5, 0, "Finite state machine error" },
- { 6, 0, "Cease" }
+ { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */
+ { 6, 1, "Maximum number of prefixes reached" },
+ { 6, 2, "Administrative shutdown" },
+ { 6, 3, "Peer de-configured" },
+ { 6, 4, "Administrative reset" },
+ { 6, 5, "Connection rejected" },
+ { 6, 6, "Other configuration change" },
+ { 6, 7, "Connection collision resolution" },
+ { 6, 8, "Out of Resources" }
};
/**
@@ -875,6 +889,7 @@ bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subcode, b
static void
bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
{
+ struct bgp_proto *p = conn->bgp;
if (len < 21)
{
bgp_error(conn, 1, 2, pkt+16, 2);
@@ -883,9 +898,25 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
unsigned code = pkt[19];
unsigned subcode = pkt[20];
+ int delay = 1;
+
+#ifndef IPV6
+ 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
+ */
+ BGP_TRACE(D_EVENTS, "Capability related error received, capabilities disabled");
+ conn->bgp->start_state = BSS_CONNECT_NOCAP;
+ delay = 0;
+ }
+#endif
+
bgp_log_error(conn->bgp, "Received error notification", code, subcode, pkt+21, len-21);
bgp_store_error(conn->bgp, conn, BE_BGP_RX, (code << 16) | subcode);
- bgp_update_startup_delay(conn->bgp, conn, code, subcode);
+ if (delay) bgp_update_startup_delay(conn->bgp, conn, code, subcode);
bgp_conn_enter_close_state(conn);
bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE);
}