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.
This commit is contained in:
Ondrej Zajicek 2008-12-24 17:24:41 +01:00
parent 591211557f
commit 165a622727
3 changed files with 47 additions and 11 deletions

View file

@ -368,6 +368,10 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn)
static void static void
bgp_send_open(struct bgp_conn *conn) 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"); DBG("BGP: Sending open\n");
conn->sk->rx_hook = bgp_rx; conn->sk->rx_hook = bgp_rx;
conn->sk->tx_hook = bgp_tx; conn->sk->tx_hook = bgp_tx;

View file

@ -51,9 +51,10 @@ struct bgp_conn {
int packets_to_send; /* Bitmap of packet types to be sent */ int packets_to_send; /* Bitmap of packet types to be sent */
int notify_code, notify_subcode, notify_size; int notify_code, notify_subcode, notify_size;
byte *notify_data; byte *notify_data;
int error_flag; /* Error state, ignore all input */
u32 advertised_as; /* Temporary value for AS number received */ 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 */ unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
}; };

View file

@ -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+1, (p->local_as < 0xFFFF) ? p->local_as : AS_TRANS);
put_u16(buf+3, p->cf->hold_time); put_u16(buf+3, p->cf->hold_time);
put_u32(buf+5, p->local_id); 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 */ /* Skipped 3 B for length field and Capabilities parameter header */
cap = buf + 12; cap = buf + 12;
#ifdef IPV6 #ifdef IPV6
cap = bgp_put_cap_ipv6(conn, cap); cap = bgp_put_cap_ipv6(conn, cap);
#endif #endif
if (p->cf->enable_as4) if (conn->want_as4_support)
cap = bgp_put_cap_as4(conn, cap); cap = bgp_put_cap_as4(conn, cap);
cap_len = cap - buf - 12; cap_len = cap - buf - 12;
@ -418,9 +426,8 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
case 65: case 65:
if (cl != 4) if (cl != 4)
goto err; goto err;
conn->as4_support = 1; conn->peer_as4_support = 1;
if (conn->want_as4_support)
if (p->cf->enable_as4)
conn->advertised_as = get_u32(opt + 2); conn->advertised_as = get_u32(opt + 2);
break; break;
@ -501,7 +508,6 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
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);
conn->as4_support = 0; // Default value, possibly changed by capability.
if (bgp_parse_options(conn, pkt+29, pkt[28])) if (bgp_parse_options(conn, pkt+29, pkt[28]))
return; 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->hold_time = MIN(hold, p->cf->hold_time);
conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3; conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
p->remote_id = id; 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); 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); bgp_schedule_packet(conn, PKT_KEEPALIVE);
@ -820,7 +826,15 @@ static struct {
{ 3, 11, "Malformed AS_PATH" }, { 3, 11, "Malformed AS_PATH" },
{ 4, 0, "Hold timer expired" }, { 4, 0, "Hold timer expired" },
{ 5, 0, "Finite state machine error" }, { 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 static void
bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len) bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
{ {
struct bgp_proto *p = conn->bgp;
if (len < 21) if (len < 21)
{ {
bgp_error(conn, 1, 2, pkt+16, 2); 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 code = pkt[19];
unsigned subcode = pkt[20]; 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_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_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_conn_enter_close_state(conn);
bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE); bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE);
} }