summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-01-10 08:32:09 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-01-10 08:32:09 +0000
commitfce2b1cfa0b07aef6627a0618da0d65ec4f29b7f (patch)
treec156ef3a658e95db1f5a5e177431cf23d239c5b8
parentd54e1167d78f62b0109d6a69baae56b38ebc910c (diff)
Generate a EoR marker in the update list instead of sending it independent
of the actual update dump. This will get us the right barrier and the EoR is no longer sent way before the actual dump. Currently a nop since graceful restart is turned off (unless you have announce restart yes in the config). put it in henning@
-rw-r--r--usr.sbin/bgpd/rde.c56
-rw-r--r--usr.sbin/bgpd/rde.h5
-rw-r--r--usr.sbin/bgpd/rde_update.c71
3 files changed, 108 insertions, 24 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index cb98b3cf7e3..37758de3aa4 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.281 2010/01/10 00:15:09 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.282 2010/01/10 08:32:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -2394,7 +2394,7 @@ void
rde_update_queue_runner(void)
{
struct rde_peer *peer;
- int r, sent, max = RDE_RUNNER_ROUNDS;
+ int r, sent, max = RDE_RUNNER_ROUNDS, eor = 0;
u_int16_t len, wd_len, wpos;
len = sizeof(queue_buf) - MSGSIZE_HEADER;
@@ -2418,20 +2418,38 @@ rde_update_queue_runner(void)
/* now bgp path attributes */
r = up_dump_attrnlri(queue_buf + wpos, len - wpos,
peer);
- wpos += r;
-
- if (wpos == 4)
- /*
- * No packet to send. The 4 bytes are the
- * needed withdraw and path attribute length.
- */
- continue;
+ switch (r) {
+ case -1:
+ eor = 1;
+ if (wd_len == 0) {
+ /* no withdraws queued just send EoR */
+ peer_send_eor(peer, AID_INET);
+ continue;
+ }
+ break;
+ case 2:
+ if (wd_len == 0) {
+ /*
+ * No packet to send. No withdraws and
+ * no path attributes. Skip.
+ */
+ continue;
+ }
+ /* FALLTHROUGH */
+ default:
+ wpos += r;
+ break;
+ }
/* finally send message to SE */
if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
0, -1, queue_buf, wpos) == -1)
fatal("imsg_compose error");
sent++;
+ if (eor) {
+ eor = 0;
+ peer_send_eor(peer, AID_INET);
+ }
}
max -= sent;
} while (sent != 0 && max > 0);
@@ -2442,7 +2460,7 @@ rde_update6_queue_runner(void)
{
struct rde_peer *peer;
u_char *b;
- int sent, max = RDE_RUNNER_ROUNDS / 2;
+ int r, sent, max = RDE_RUNNER_ROUNDS / 2;
u_int16_t len;
/* first withdraws ... */
@@ -2477,10 +2495,18 @@ rde_update6_queue_runner(void)
if (peer->state != PEER_UP)
continue;
len = sizeof(queue_buf) - MSGSIZE_HEADER;
- b = up_dump_mp_reach(queue_buf, &len, peer);
-
- if (b == NULL)
+ r = up_dump_mp_reach(queue_buf, &len, peer);
+ switch (r) {
+ case -2:
continue;
+ case -1:
+ peer_send_eor(peer, AID_INET6);
+ continue;
+ default:
+ b = queue_buf + r;
+ break;
+ }
+
/* finally send message to SE */
if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
0, -1, b, len) == -1)
@@ -2748,7 +2774,7 @@ peer_dump(u_int32_t id, u_int8_t aid)
else
rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid);
if (peer->capa.restart)
- peer_send_eor(peer, aid);
+ up_generate_marker(peer, aid);
}
/* End-of-RIB marker, RFC 4724 */
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 32ad0b951af..0d66294c990 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.127 2010/01/10 00:15:09 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.128 2010/01/10 08:32:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -421,11 +421,12 @@ void up_generate_updates(struct filter_head *, struct rde_peer *,
struct prefix *, struct prefix *);
void up_generate_default(struct filter_head *, struct rde_peer *,
u_int8_t);
+int up_generate_marker(struct rde_peer *, u_int8_t);
int up_dump_prefix(u_char *, int, struct uplist_prefix *,
struct rde_peer *);
int up_dump_attrnlri(u_char *, int, struct rde_peer *);
u_char *up_dump_mp_unreach(u_char *, u_int16_t *, struct rde_peer *);
-u_char *up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *);
+int up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *);
/* rde_prefix.c */
#define pt_empty(pt) ((pt)->refcnt == 0)
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 22aaa2443fe..b78b3a49616 100644
--- a/usr.sbin/bgpd/rde_update.c
+++ b/usr.sbin/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.75 2010/01/09 22:59:42 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.76 2010/01/10 08:32:08 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -478,6 +478,53 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
path_put(asp);
}
+/* generate a EoR marker in the update list. This is a horrible hack. */
+int
+up_generate_marker(struct rde_peer *peer, u_int8_t aid)
+{
+ struct update_attr *ua;
+ struct update_attr *na = NULL;
+ struct uplist_attr *upl = NULL;
+
+ ua = calloc(1, sizeof(struct update_attr));
+ if (ua == NULL)
+ fatal("up_generate_marker");
+
+
+ switch (aid) {
+ case AID_INET:
+ upl = &peer->updates;
+ break;
+ case AID_INET6:
+ upl = &peer->updates6;
+ break;
+ default:
+ fatalx("up_generate_marker: unknown AID");
+ }
+
+ /* 1. search for attr */
+ if ((na = RB_FIND(uptree_attr, &peer->up_attrs, ua)) == NULL) {
+ /* 1.1 if not found -> add */
+ TAILQ_INIT(&ua->prefix_h);
+ if (RB_INSERT(uptree_attr, &peer->up_attrs, ua) != NULL) {
+ log_warnx("uptree_attr insert failed");
+ /* cleanup */
+ free(ua);
+ return (-1);
+ }
+ TAILQ_INSERT_TAIL(upl, ua, attr_l);
+ peer->up_acnt++;
+ } else {
+ /* 1.2 if found -> use that, free ua */
+ free(ua);
+ ua = na;
+ /* move to end of update queue */
+ TAILQ_REMOVE(upl, ua, attr_l);
+ TAILQ_INSERT_TAIL(upl, ua, attr_l);
+ }
+ return (0);
+}
+
u_char up_attr_buf[4096];
/* only for IPv4 */
@@ -835,6 +882,7 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
*/
while ((upa = TAILQ_FIRST(&peer->updates)) != NULL)
if (TAILQ_EMPTY(&upa->prefix_h)) {
+ attr_len = upa->attr_len;
if (RB_REMOVE(uptree_attr, &peer->up_attrs,
upa) == NULL)
log_warnx("dequeuing update failed.");
@@ -843,6 +891,10 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
free(upa->mpattr);
free(upa);
peer->up_acnt--;
+ /* XXX horrible hack,
+ * if attr_len is 0, it is a EoR marker */
+ if (attr_len == 0)
+ return (-1);
} else
break;
@@ -948,12 +1000,12 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
return (buf + wpos);
}
-u_char *
+int
up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
{
struct update_attr *upa;
int wpos;
- u_int16_t datalen, tmp;
+ u_int16_t attr_len, datalen, tmp;
u_int8_t flags = ATTR_OPTIONAL;
/*
@@ -962,6 +1014,7 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
*/
while ((upa = TAILQ_FIRST(&peer->updates6)) != NULL)
if (TAILQ_EMPTY(&upa->prefix_h)) {
+ attr_len = upa->attr_len;
if (RB_REMOVE(uptree_attr, &peer->up_attrs,
upa) == NULL)
log_warnx("dequeuing update failed.");
@@ -970,11 +1023,15 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
free(upa->mpattr);
free(upa);
peer->up_acnt--;
+ /* XXX horrible hack,
+ * if attr_len is 0, it is a EoR marker */
+ if (attr_len == 0)
+ return (-1);
} else
break;
if (upa == NULL)
- return (NULL);
+ return (-2);
/*
* reserve space for attr len, the attributes, the
@@ -982,12 +1039,12 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
*/
wpos = 2 + 2 + upa->attr_len + 4 + upa->mpattr_len;
if (*len < wpos)
- return (NULL);
+ return (-2);
datalen = up_dump_prefix(buf + wpos, *len - wpos,
&upa->prefix_h, peer);
if (datalen == 0)
- return (NULL);
+ return (-2);
if (upa->mpattr_len == 0 || upa->mpattr == NULL)
fatalx("mulitprotocol update without MP attrs");
@@ -1035,5 +1092,5 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
}
*len = datalen + 4;
- return (buf + wpos);
+ return (wpos);
}