summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2019-10-30 05:27:50 +0000
committerclaudio <claudio@openbsd.org>2019-10-30 05:27:50 +0000
commit7ef8321bb317ec181d4ed595ae415b017ac7e9cc (patch)
tree0223468aa9f87bc19acedbb42d4bd2f914697813 /usr.sbin/bgpd
parentdrm/amdgpu: Bail earlier when amdgpu.cik_/si_support is not set to 1 (diff)
downloadwireguard-openbsd-7ef8321bb317ec181d4ed595ae415b017ac7e9cc.tar.xz
wireguard-openbsd-7ef8321bb317ec181d4ed595ae415b017ac7e9cc.zip
Add PREFIX_FLAG_STALE to mark prefixes in the Adj-RIB-Out as stale during
graceful reload. At the same time extend peer_dump() to force all updates getting sent by adding every entry in the Adj-RIB-Out to the update tree unless they are PREFIX_FLAG_DEAD or PREFIX_FLAG_STALE. The latter will be removed during that stage since peer_dump() just did a full update of the Adj-RIB-Out. Also fix prefix_withdraw to check the correct prefix flags before removing a prefix from the update or withdraw tree. OK benno@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/rde.c75
-rw-r--r--usr.sbin/bgpd/rde.h9
-rw-r--r--usr.sbin/bgpd/rde_rib.c28
3 files changed, 84 insertions, 28 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 4d60707bc55..36c882b5b66 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.489 2019/09/27 14:50:39 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.490 2019/10/30 05:27:50 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -2828,15 +2828,44 @@ rde_up_flush_upcall(struct prefix *p, void *ptr)
}
static void
-rde_up_dump_done(void *ptr, u_int8_t aid)
+rde_up_adjout_force_upcall(struct prefix *p, void *ptr)
+{
+ if (p->flags & PREFIX_FLAG_STALE) {
+ /* remove stale entries */
+ prefix_adjout_destroy(p);
+ } else if (p->flags & PREFIX_FLAG_DEAD) {
+ /* ignore dead prefixes, they will go away soon */
+ } else if ((p->flags & PREFIX_FLAG_MASK) == 0) {
+ /* put entries on the update queue if not allready on a queue */
+ p->flags |= PREFIX_FLAG_UPDATE;
+ if (RB_INSERT(prefix_tree, &prefix_peer(p)->updates[p->pt->aid],
+ p) != NULL)
+ fatalx("%s: RB tree invariant violated", __func__);
+ }
+}
+
+static void
+rde_up_adjout_force_done(void *ptr, u_int8_t aid)
{
struct rde_peer *peer = ptr;
+ /* Adj-RIB-Out ready, unthrottle peer and inject EOR */
peer->throttled = 0;
if (peer->capa.grestart.restart)
prefix_add_eor(peer, aid);
}
+static void
+rde_up_dump_done(void *ptr, u_int8_t aid)
+{
+ struct rde_peer *peer = ptr;
+
+ /* force out all updates of Adj-RIB-Out for this peer */
+ if (prefix_dump_new(peer, aid, 0, peer, rde_up_adjout_force_upcall,
+ rde_up_adjout_force_done, NULL) == -1)
+ fatal("%s: prefix_dump_new", __func__);
+}
+
u_char queue_buf[4096];
int
@@ -3387,16 +3416,17 @@ rde_softreconfig_in(struct rib_entry *re, void *bula)
static void
rde_softreconfig_out(struct rib_entry *re, void *bula)
{
- struct prefix *new = re->active;
+ struct prefix *p = re->active;
struct rde_peer *peer;
- if (new == NULL)
+ if (p == NULL)
+ /* no valid path for prefix */
return;
LIST_FOREACH(peer, &peerlist, peer_l) {
if (peer->loc_rib_id == re->rib_id && peer->reconf_out)
/* Regenerate all updates. */
- up_generate_updates(out_rules, peer, new, new);
+ up_generate_updates(out_rules, peer, p, p);
}
}
@@ -3668,6 +3698,22 @@ peer_adjout_clear_upcall(struct prefix *p, void *arg)
prefix_adjout_destroy(p);
}
+static void
+peer_adjout_stale_upcall(struct prefix *p, void *arg)
+{
+ if (p->flags & PREFIX_FLAG_DEAD) {
+ return;
+ } else if (p->flags & PREFIX_FLAG_WITHDRAW) {
+ /* no need to keep stale withdraws, they miss all attributes */
+ prefix_adjout_destroy(p);
+ return;
+ } else if (p->flags & PREFIX_FLAG_UPDATE) {
+ RB_REMOVE(prefix_tree, &prefix_peer(p)->updates[p->pt->aid], p);
+ p->flags &= ~PREFIX_FLAG_UPDATE;
+ }
+ p->flags |= PREFIX_FLAG_STALE;
+}
+
void
peer_up(u_int32_t id, struct session_up *sup)
{
@@ -3680,8 +3726,7 @@ peer_up(u_int32_t id, struct session_up *sup)
return;
}
- if (peer->state != PEER_DOWN && peer->state != PEER_NONE &&
- peer->state != PEER_UP) {
+ if (peer->state == PEER_ERR) {
/*
* There is a race condition when doing PEER_ERR -> PEER_DOWN.
* So just do a full reset of the peer here.
@@ -3831,12 +3876,18 @@ peer_stale(u_int32_t id, u_int8_t aid)
/* flush the now even staler routes out */
if (peer->staletime[aid])
peer_flush(peer, aid, peer->staletime[aid]);
+
peer->staletime[aid] = now = time(NULL);
+ peer->state = PEER_DOWN;
+
+ /* mark Adj-RIB-Out stale for this peer */
+ if (prefix_dump_new(peer, AID_UNSPEC, 0, NULL,
+ peer_adjout_stale_upcall, NULL, NULL) == -1)
+ fatal("%s: prefix_dump_new", __func__);
/* make sure new prefixes start on a higher timestamp */
- do {
+ while (now >= time(NULL))
sleep(1);
- } while (now >= time(NULL));
}
void
@@ -3856,13 +3907,13 @@ peer_dump(u_int32_t id, u_int8_t aid)
prefix_add_eor(peer, aid);
} else if (peer->conf.export_type == EXPORT_DEFAULT_ROUTE) {
up_generate_default(out_rules, peer, aid);
- if (peer->capa.grestart.restart)
- prefix_add_eor(peer, aid);
+ rde_up_dump_done(peer, aid);
} else {
if (rib_dump_new(peer->loc_rib_id, aid, RDE_RUNNER_ROUNDS, peer,
rde_up_dump_upcall, rde_up_dump_done, NULL) == -1)
fatal("%s: rib_dump_new", __func__);
- peer->throttled = 1; /* XXX throttle peer until dump is done */
+ /* throttle peer until dump is done */
+ peer->throttled = 1;
}
}
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 3faaa61a6dd..d01097b02d4 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.226 2019/08/14 11:57:21 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.227 2019/10/30 05:27:50 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -324,10 +324,11 @@ struct prefix {
u_int8_t nhflags;
u_int8_t eor;
u_int8_t flags;
-#define PREFIX_FLAG_WITHDRAW 0x01 /* queued for withdraw */
-#define PREFIX_FLAG_UPDATE 0x02 /* queued for update */
+#define PREFIX_FLAG_WITHDRAW 0x01 /* enqueued on withdraw queue */
+#define PREFIX_FLAG_UPDATE 0x02 /* enqueued on update queue */
#define PREFIX_FLAG_DEAD 0x04 /* locked but removed */
-#define PREFIX_FLAG_MASK 0x07 /* mask for the three prefix types */
+#define PREFIX_FLAG_STALE 0x08 /* stale entry (graceful reload) */
+#define PREFIX_FLAG_MASK 0x0f /* mask for the prefix types */
#define PREFIX_NEXTHOP_LINKED 0x40 /* prefix is linked onto nexthop list */
#define PREFIX_FLAG_LOCKED 0x80 /* locked by rib walker */
};
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index e7a4afae87d..bd95924a84d 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.209 2019/10/29 06:47:04 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.210 2019/10/30 05:27:50 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -1169,6 +1169,7 @@ prefix_adjout_update(struct rde_peer *peer, struct filterstate *state,
/* nothing changed */
p->validation_state = vstate;
p->lastchange = time(NULL);
+ p->flags &= ~PREFIX_FLAG_STALE;
return 0;
}
@@ -1235,12 +1236,24 @@ int
prefix_adjout_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
int prefixlen)
{
- struct prefix *p;
+ struct prefix *p;
p = prefix_lookup(peer, prefix, prefixlen);
if (p == NULL) /* Got a dummy withdrawn request. */
return (0);
+ /* already a withdraw, shortcut */
+ if (p->flags & PREFIX_FLAG_WITHDRAW) {
+ p->lastchange = time(NULL);
+ p->flags &= ~PREFIX_FLAG_STALE;
+ return (0);
+ }
+ /* pending update just got withdrawn */
+ if (p->flags & PREFIX_FLAG_UPDATE)
+ RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p);
+ /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
+ p->flags &= ~PREFIX_FLAG_MASK;
+
/* remove nexthop ref ... */
nexthop_unref(p->nexthop);
p->nexthop = NULL;
@@ -1260,15 +1273,6 @@ prefix_adjout_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
p->lastchange = time(NULL);
- if (p->flags & PREFIX_FLAG_MASK) {
- struct prefix_tree *prefix_head;
- /* p is a pending update or withdraw, remove first */
- prefix_head = p->flags & PREFIX_FLAG_UPDATE ?
- &peer->updates[prefix->aid] :
- &peer->withdraws[prefix->aid];
- RB_REMOVE(prefix_tree, prefix_head, p);
- p->flags &= ~PREFIX_FLAG_MASK;
- }
p->flags |= PREFIX_FLAG_WITHDRAW;
if (RB_INSERT(prefix_tree, &peer->withdraws[prefix->aid], p) != NULL)
fatalx("%s: RB tree invariant violated", __func__);
@@ -1308,7 +1312,7 @@ prefix_adjout_destroy(struct prefix *p)
RB_REMOVE(prefix_tree, &peer->withdraws[p->pt->aid], p);
else if (p->flags & PREFIX_FLAG_UPDATE)
RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p);
- /* nothing needs to be done for PREFIX_FLAG_DEAD */
+ /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
p->flags &= ~PREFIX_FLAG_MASK;