summaryrefslogtreecommitdiffstats
path: root/proto/bgp/packets.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2008-12-19 01:34:39 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2008-12-19 01:34:39 +0100
commit11b32d911715cbfb3ce4c87685b1388e4b0de1c4 (patch)
tree48b86083df70a669f0abeaaeab7f89d94d952edb /proto/bgp/packets.c
parentb933281ed5efb9ad9375c3ea41ee2412b9f89c15 (diff)
downloadbird-11b32d911715cbfb3ce4c87685b1388e4b0de1c4.tar
bird-11b32d911715cbfb3ce4c87685b1388e4b0de1c4.zip
Major changes to BGP
Fixes two race conditions causing crash of Bird, several unhandled cases during BGP initialization, and some other bugs. Also changes handling of startup delay to be more useful and implement reporting of last error in 'show protocols' command.
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c109
1 files changed, 61 insertions, 48 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 00cdf03..4e42d90 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -17,6 +17,8 @@
#include "lib/unaligned.h"
#include "lib/socket.h"
+#include "nest/cli.h"
+
#include "bgp.h"
static byte *
@@ -318,7 +320,8 @@ bgp_fire_tx(struct bgp_conn *conn)
if (s & (1 << PKT_SCHEDULE_CLOSE))
{
- bgp_close_conn(conn);
+ /* We can finally close connection and enter idle state */
+ bgp_conn_enter_idle_state(conn);
return 0;
}
if (s & (1 << PKT_NOTIFICATION))
@@ -371,8 +374,17 @@ bgp_schedule_packet(struct bgp_conn *conn, int type)
DBG("BGP: Scheduling packet type %d\n", type);
conn->packets_to_send |= 1 << type;
if (conn->sk && conn->sk->tpos == conn->sk->tbuf)
- while (bgp_fire_tx(conn))
- ;
+ ev_schedule(conn->tx_ev);
+}
+
+void
+bgp_kick_tx(void *vconn)
+{
+ struct bgp_conn *conn = vconn;
+
+ DBG("BGP: kicking TX\n");
+ while (bgp_fire_tx(conn))
+ ;
}
void
@@ -406,9 +418,9 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
case 65:
if (cl != 4)
goto err;
- p->as4_support = 1;
- p->as4_session = p->cf->enable_as4;
- if (p->as4_session)
+ conn->as4_support = 1;
+
+ if (p->cf->enable_as4)
conn->advertised_as = get_u32(opt + 2);
break;
@@ -477,7 +489,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
/* Check state */
if (conn->state != BS_OPENSENT)
- { bgp_error(conn, 5, 0, NULL, 0); }
+ { bgp_error(conn, 5, 0, NULL, 0); return; }
/* Check message contents */
if (len < 29 || len != 29 + pkt[28])
@@ -489,7 +501,7 @@ 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);
- p->remote_id = id; // ???
+ conn->as4_support = 0; // Default value, possibly changed by capability.
if (bgp_parse_options(conn, pkt+29, pkt[28]))
return;
@@ -499,7 +511,6 @@ 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 != p->remote_as)
{
bgp_error(conn, 2, 2, (byte *) &(conn->advertised_as), -4); return;
@@ -513,6 +524,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
case BS_CONNECT:
case BS_ACTIVE:
case BS_OPENSENT:
+ case BS_CLOSE:
break;
case BS_OPENCONFIRM:
if ((p->local_id < id) == (conn == &p->incoming_conn))
@@ -532,19 +544,13 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
bug("bgp_rx_open: Unknown state");
}
- /* Make this connection primary */
- conn->primary = 1;
- p->conn = conn;
-
/* Update our local variables */
- if (hold < p->cf->hold_time)
- conn->hold_time = hold;
- else
- conn->hold_time = p->cf->hold_time;
+ conn->hold_time = MIN(hold, p->cf->hold_time);
conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
- // p->remote_as = conn->advertised_as;
p->remote_id = id;
- DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id);
+ p->as4_session = p->cf->enable_as4 && conn->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);
bgp_start_timer(conn->hold_timer, conn->hold_time);
@@ -817,24 +823,41 @@ static struct {
{ 6, 0, "Cease" }
};
+/**
+ * bgp_error_dsc - return BGP error description
+ * @buff: temporary buffer
+ * @code: BGP error code
+ * @subcode: BGP error subcode
+ *
+ * bgp_error_dsc() returns error description for BGP errors
+ * which might be static string or given temporary buffer.
+ */
+const byte *
+bgp_error_dsc(byte *buff, unsigned code, unsigned subcode)
+{
+ unsigned i;
+ for (i=0; i < ARRAY_SIZE(bgp_msg_table); i++)
+ if (bgp_msg_table[i].major == code && bgp_msg_table[i].minor == subcode)
+ {
+ return bgp_msg_table[i].msg;
+ }
+
+ bsprintf(buff, "Unknown error %d.%d", code, subcode);
+ return buff;
+}
+
void
bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len)
{
- byte *name, namebuf[16];
+ const byte *name;
+ byte namebuf[32];
byte *t, argbuf[36];
unsigned i;
if (code == 6 && !subcode) /* Don't report Cease messages */
return;
- bsprintf(namebuf, "%d.%d", code, subcode);
- name = namebuf;
- for (i=0; i < ARRAY_SIZE(bgp_msg_table); i++)
- if (bgp_msg_table[i].major == code && bgp_msg_table[i].minor == subcode)
- {
- name = bgp_msg_table[i].msg;
- break;
- }
+ name = bgp_error_dsc(namebuf, code, subcode);
t = argbuf;
if (len)
{
@@ -857,10 +880,13 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len)
bgp_error(conn, 1, 2, pkt+16, 2);
return;
}
- bgp_log_error(conn->bgp, "Received error notification", pkt[19], pkt[20], pkt+21, len-21);
- conn->error_flag = 1;
- if (conn->primary)
- proto_notify_state(&conn->bgp->p, PS_STOP);
+
+ unsigned code = pkt[19];
+ unsigned subcode = pkt[20];
+ 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);
+ bgp_conn_enter_close_state(conn);
bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE);
}
@@ -874,10 +900,7 @@ bgp_rx_keepalive(struct bgp_conn *conn)
switch (conn->state)
{
case BS_OPENCONFIRM:
- DBG("BGP: UP!!!\n");
- conn->state = BS_ESTABLISHED;
- bgp_attr_init(conn->bgp);
- proto_notify_state(&conn->bgp->p, PS_UP);
+ bgp_conn_enter_established_state(conn);
break;
case BS_ESTABLISHED:
break;
@@ -930,18 +953,8 @@ bgp_rx(sock *sk, int size)
DBG("BGP: RX hook: Got %d bytes\n", size);
while (end >= pkt_start + BGP_HEADER_LENGTH)
{
- if (conn->error_flag)
- {
- /*
- * We still need to remember the erroneous packet, so that
- * we can generate error notifications properly. To avoid
- * subsequent reads rewriting the buffer, we just reset the
- * rx_hook.
- */
- DBG("BGP: Error, dropping input\n");
- sk->rx_hook = NULL;
- return 0;
- }
+ if ((conn->state == BS_CLOSE) || (conn->sk != sk))
+ return 0;
for(i=0; i<16; i++)
if (pkt_start[i] != 0xff)
{