summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proto/bgp/bgp.c18
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/packets.c65
3 files changed, 83 insertions, 2 deletions
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