diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 4ea148d6..e4157565 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -15,12 +15,15 @@ #include "nest/locks.h" #include "conf/conf.h" #include "lib/socket.h" +#include "lib/resource.h" #include "bgp.h" +struct linpool *bgp_linpool; /* Global temporary pool */ static sock *bgp_listen_sk; /* Global listening socket */ static int bgp_counter; /* Number of protocol instances using the listening socket */ static list bgp_list; /* List of active BGP instances */ +static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established" }; static void bgp_connect(struct bgp_proto *p); static void bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s); @@ -56,6 +59,8 @@ bgp_close(struct bgp_proto *p) { rfree(bgp_listen_sk); bgp_listen_sk = NULL; + rfree(bgp_linpool); + bgp_linpool = NULL; } /* FIXME: Automatic restart after errors? */ } @@ -275,6 +280,8 @@ bgp_start_locked(struct object_lock *lock) else bgp_listen_sk = s; } + if (!bgp_linpool) + bgp_linpool = lp_new(&root_pool, 4080); add_tail(&bgp_list, &p->bgp_node); bgp_connect(p); /* FIXME: Use neighbor cache for fast up/down transitions? */ } @@ -385,16 +392,25 @@ bgp_check(struct bgp_config *c) cf_error("Neighbor must be configured"); } +void +bgp_get_status(struct proto *P, byte *buf) +{ + struct bgp_proto *p = (struct bgp_proto *) P; + + strcpy(buf, bgp_state_names[MAX(p->incoming_conn.state, p->outgoing_conn.state)]); +} + struct protocol proto_bgp = { name: "BGP", template: "bgp%d", init: bgp_init, start: bgp_start, shutdown: bgp_shutdown, + get_status: bgp_get_status, #if 0 dump: bgp_dump, - get_status: bgp_get_status, get_route_info: bgp_get_route_info, show_route_data: bgp_show_route_data + /* FIXME: Reconfiguration */ #endif }; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 1631d123..e93b06eb 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -54,6 +54,8 @@ struct bgp_proto { #define BGP_RX_BUFFER_SIZE 4096 #define BGP_TX_BUFFER_SIZE BGP_MAX_PACKET_LENGTH +extern struct linpool *bgp_linpool; + void bgp_start_timer(struct timer *t, int value); void bgp_check(struct bgp_config *c); void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, unsigned data, unsigned len); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index e530f815..3bddbc90 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -215,14 +215,77 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) conn->state = BS_OPENCONFIRM; } +#define DECODE_PREFIX(pp, ll) do { \ + int b = *pp++; \ + int q; \ + ip_addr temp; \ + ll--; \ + if (b > BITS_PER_IP_ADDRESS) { bgp_error(conn, 3, 10, b, 0); return; } \ + q = (b+7) / 8; \ + if (ll < q) goto too_small; \ + memcpy(&temp, pp, q); \ + pp += q; \ + ll -= q; \ + n.n.prefix = ipa_and(ipa_ntoh(temp), ipa_mkmask(b)); \ + n.n.pxlen = b; \ +} while (0) + static void bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len) { + byte *withdrawn, *attrs, *nlri; + int withdrawn_len, attr_len, nlri_len; + net n; + rte e; + + DBG("BGP: UPDATE\n"); if (conn->state != BS_ESTABLISHED) { bgp_error(conn, 5, 0, conn->state, 0); return; } bgp_start_timer(conn->hold_timer, conn->hold_time); - DBG("BGP: UPDATE (ignored)\n"); + /* Find parts of the packet and check sizes */ + if (len < 23) + { + too_small: + bgp_error(conn, 1, 2, len, 2); + return; + } + withdrawn = pkt + 21; + withdrawn_len = get_u16(pkt + 19); + if (withdrawn_len + 23 > len) + goto too_small; + attrs = withdrawn + withdrawn_len + 2; + attr_len = get_u16(attrs - 2); + if (withdrawn_len + attr_len + 23 > len) + goto too_small; + nlri = attrs + attr_len; + nlri_len = len - withdrawn_len - attr_len - 23; + if (!attr_len && nlri_len) + goto too_small; + DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len); + + /* Withdraw routes */ + while (withdrawn_len) + { + DECODE_PREFIX(withdrawn, withdrawn_len); + DBG("Withdraw %I/%d\n", n.n.prefix, n.n.pxlen); + } + + if (nlri_len) + { +#if 0 + rta *a = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool); + if (a) +#endif + { + while (nlri_len) + { + DECODE_PREFIX(nlri, nlri_len); + DBG("Add %I/%d\n", n.n.prefix, n.n.pxlen); + } + } + lp_flush(bgp_linpool); + } } static void