diff options
author | 2018-10-29 09:28:31 +0000 | |
---|---|---|
committer | 2018-10-29 09:28:31 +0000 | |
commit | f80c17aa8a364b3211ad966c0c9880f594a07311 (patch) | |
tree | f74c93b29317806815e44d379aaf26031f6189b7 | |
parent | Fix route-collector mode by allowing the RDE to disable the decision process (diff) | |
download | wireguard-openbsd-f80c17aa8a364b3211ad966c0c9880f594a07311.tar.xz wireguard-openbsd-f80c17aa8a364b3211ad966c0c9880f594a07311.zip |
Replace some walkers using the aspath/prefix lists with a rib_dump walker.
network_flush() is now using rib_dump_new to walk the Adj-RIB-In and
remove all dynamically added announcements. peer_flush() got generalized
and is now used also in peer_down(). It also uses a walker to remove all
prefixes of a peer but does it in a synchronous way for now.
OK benno@
-rw-r--r-- | usr.sbin/bgpd/rde.c | 153 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 93 |
3 files changed, 120 insertions, 130 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 098e8b48892..15724e65988 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.442 2018/10/29 09:22:48 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.443 2018/10/29 09:28:31 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -97,7 +97,7 @@ struct rde_peer *peer_add(u_int32_t, struct peer_config *); struct rde_peer *peer_get(u_int32_t); void peer_up(u_int32_t, struct session_up *); void peer_down(u_int32_t); -void peer_flush(struct rde_peer *, u_int8_t); +void peer_flush(struct rde_peer *, u_int8_t, time_t); void peer_stale(u_int32_t, u_int8_t); void peer_dump(u_int32_t, u_int8_t); static void peer_recv_eor(struct rde_peer *, u_int8_t); @@ -105,7 +105,8 @@ static void peer_send_eor(struct rde_peer *, u_int8_t); void network_add(struct network_config *, int); void network_delete(struct network_config *, int); -void network_dump_upcall(struct rib_entry *, void *); +static void network_dump_upcall(struct rib_entry *, void *); +static void network_flush_upcall(struct rib_entry *, void *); void rde_shutdown(void); int sa_cmp(struct bgpd_addr *, struct sockaddr *); @@ -418,7 +419,7 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf) imsg.hdr.peerid); break; } - peer_flush(peer, aid); + peer_flush(peer, aid, peer->staletime[aid]); break; case IMSG_SESSION_RESTARTED: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { @@ -434,7 +435,7 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf) break; } if (peer->staletime[aid]) - peer_flush(peer, aid); + peer_flush(peer, aid, peer->staletime[aid]); break; case IMSG_REFRESH: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { @@ -556,7 +557,10 @@ badnetdel: log_warnx("rde_dispatch: wrong imsg len"); break; } - prefix_network_clean(peerself); + if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC, + RDE_RUNNER_ROUNDS, peerself, network_flush_upcall, + NULL, NULL) == -1) + log_warn("rde_dispatch: IMSG_NETWORK_FLUSH"); break; case IMSG_FILTER_SET: if (imsg.hdr.len - IMSG_HEADER_SIZE != @@ -2953,11 +2957,10 @@ rde_reload_done(void) static void rde_softreconfig_in_done(void *arg, u_int8_t aid) { - struct rib_desc *rd = arg; - struct rde_peer *peer; - u_int16_t rid; + struct rde_peer *peer; + u_int16_t rid; - if (rd != NULL) { + if (arg != NULL) { softreconfig--; /* one guy done but other dumps are still running */ if (softreconfig > 0) @@ -3368,10 +3371,7 @@ peer_up(u_int32_t id, struct session_up *sup) * There is a race condition when doing PEER_ERR -> PEER_DOWN. * So just do a full reset of the peer here. */ - for (i = 0; i < AID_MAX; i++) { - peer->staletime[i] = 0; - peer_flush(peer, i); - } + peer_flush(peer, AID_UNSPEC, 0); up_down(peer); peer->prefix_cnt = 0; peer->state = PEER_DOWN; @@ -3408,7 +3408,6 @@ void peer_down(u_int32_t id) { struct rde_peer *peer; - struct rde_aspath *asp, *nasp; peer = peer_get(id); if (peer == NULL) { @@ -3421,49 +3420,85 @@ peer_down(u_int32_t id) /* stop all pending dumps which may depend on this peer */ rib_dump_terminate(peer->loc_rib_id, peer, rde_up_dump_upcall); - /* walk through per peer RIB list and remove all prefixes. */ - for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = nasp) { - nasp = TAILQ_NEXT(asp, peer_l); - path_remove(asp); - } - TAILQ_INIT(&peer->path_h); - peer->prefix_cnt = 0; + peer_flush(peer, AID_UNSPEC, 0); - /* Deletions are performed in path_remove() */ - rde_send_pftable_commit(); + peer->prefix_cnt = 0; LIST_REMOVE(peer, hash_l); LIST_REMOVE(peer, peer_l); free(peer); } +struct peer_flush { + struct rde_peer *peer; + time_t staletime; +}; + +static void +peer_flush_upcall(struct rib_entry *re, void *arg) +{ + struct rde_peer *peer = ((struct peer_flush *)arg)->peer; + struct rde_aspath *asp; + struct bgpd_addr addr; + struct prefix *p, *np, *rp; + time_t staletime = ((struct peer_flush *)arg)->staletime; + u_int32_t i; + u_int8_t prefixlen; + + pt_getaddr(re->prefix, &addr); + prefixlen = re->prefix->prefixlen; + LIST_FOREACH_SAFE(p, &re->prefix_h, rib_l, np) { + if (peer != prefix_peer(p)) + continue; + if (staletime && p->lastchange > staletime) + continue; + + for (i = RIB_LOC_START; i < rib_size; i++) { + if (!rib_valid(i)) + continue; + rp = prefix_get(&ribs[i].rib, peer, &addr, prefixlen); + if (rp) { + asp = prefix_aspath(rp); + if (asp->pftableid) + rde_send_pftable(asp->pftableid, &addr, + prefixlen, 1); + + prefix_destroy(rp); + rde_update_log("flush", i, peer, NULL, + &addr, prefixlen); + } + } + + prefix_destroy(p); + peer->prefix_cnt--; + } +} + /* * Flush all routes older then staletime. If staletime is 0 all routes will * be flushed. */ void -peer_flush(struct rde_peer *peer, u_int8_t aid) +peer_flush(struct rde_peer *peer, u_int8_t aid, time_t staletime) { - struct rde_aspath *asp, *nasp; - u_int32_t rprefixes; + struct peer_flush pf = { peer, staletime }; - rprefixes = 0; - /* walk through per peer RIB list and remove all stale prefixes. */ - for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = nasp) { - nasp = TAILQ_NEXT(asp, peer_l); - rprefixes += path_remove_stale(asp, aid, peer->staletime[aid]); - } + /* this dump must run synchronous, too much depends on that right now */ + if (rib_dump_new(RIB_ADJ_IN, aid, 0, &pf, peer_flush_upcall, + NULL, NULL) == -1) + fatal("%s: rib_dump_new", __func__); /* Deletions are performed in path_remove() */ rde_send_pftable_commit(); /* flushed no need to keep staletime */ - peer->staletime[aid] = 0; - - if (peer->prefix_cnt > rprefixes) - peer->prefix_cnt -= rprefixes; - else - peer->prefix_cnt = 0; + if (aid == AID_UNSPEC) { + u_int8_t i; + for (i = 0; i < AID_MAX; i++) + peer->staletime[i] = 0; + } else { + peer->staletime[aid] = 0; + } } void @@ -3480,7 +3515,7 @@ 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_flush(peer, aid, peer->staletime[aid]); peer->staletime[aid] = now = time(NULL); /* make sure new prefixes start on a higher timestamp */ @@ -3714,14 +3749,13 @@ network_delete(struct network_config *nc, int flagstatic) nc->prefixlen)) rde_update_log("withdraw announce", i, peerself, NULL, &nc->prefix, nc->prefixlen); - } if (prefix_remove(&ribs[RIB_ADJ_IN].rib, peerself, &nc->prefix, nc->prefixlen)) peerself->prefix_cnt--; } -void +static void network_dump_upcall(struct rib_entry *re, void *ptr) { struct prefix *p; @@ -3755,6 +3789,41 @@ network_dump_upcall(struct rib_entry *re, void *ptr) } } +static void +network_flush_upcall(struct rib_entry *re, void *ptr) +{ + struct rde_peer *peer = ptr; + struct rde_aspath *asp; + struct bgpd_addr addr; + struct prefix *p, *np, *rp; + u_int32_t i; + u_int8_t prefixlen; + + pt_getaddr(re->prefix, &addr); + prefixlen = re->prefix->prefixlen; + LIST_FOREACH_SAFE(p, &re->prefix_h, rib_l, np) { + if (prefix_peer(p) != peer) + continue; + asp = prefix_aspath(p); + if ((asp->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC) + continue; + + for (i = RIB_LOC_START; i < rib_size; i++) { + if (!rib_valid(i)) + continue; + rp = prefix_get(&ribs[i].rib, peer, &addr, prefixlen); + if (rp) { + prefix_destroy(rp); + rde_update_log("flush announce", i, peer, + NULL, &addr, prefixlen); + } + } + + prefix_destroy(p); + peer->prefix_cnt--; + } +} + /* clean up */ void rde_shutdown(void) diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 9be8402acb5..4cd13e1fcee 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.199 2018/10/25 15:49:42 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.200 2018/10/29 09:28:31 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -478,7 +478,6 @@ void path_hash_stats(struct rde_hashstats *); int path_update(struct rib *, struct rde_peer *, struct filterstate *, struct bgpd_addr *, int, u_int8_t); int path_compare(struct rde_aspath *, struct rde_aspath *); -void path_remove(struct rde_aspath *); u_int32_t path_remove_stale(struct rde_aspath *, u_int8_t, time_t); void path_destroy(struct rde_aspath *); int path_empty(struct rde_aspath *); @@ -499,7 +498,6 @@ struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *); void prefix_updateall(struct prefix *, enum nexthop_state, enum nexthop_state); void prefix_destroy(struct prefix *); -void prefix_network_clean(struct rde_peer *); void prefix_relink(struct prefix *, struct rde_aspath *, int); static inline struct rde_peer * diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index c4caf992379..ce25c90418d 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.181 2018/10/26 08:55:36 claudio Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.182 2018/10/29 09:28:31 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -339,8 +339,8 @@ rib_restart(struct rib_context *ctx) static void rib_dump_r(struct rib_context *ctx) { + struct rib_entry *re, *next; struct rib *rib; - struct rib_entry *re; unsigned int i; rib = rib_byid(ctx->ctx_rib_id); @@ -352,7 +352,8 @@ rib_dump_r(struct rib_context *ctx) else re = rib_restart(ctx); - for (i = 0; re != NULL; re = RB_NEXT(rib_tree, unused, re)) { + for (i = 0; re != NULL; re = next) { + next = RB_NEXT(rib_tree, unused, re); if (re->rib_id != ctx->ctx_rib_id) fatalx("%s: Unexpected RIB %u != %u.", __func__, re->rib_id, ctx->ctx_rib_id); @@ -435,6 +436,10 @@ rib_dump_new(u_int16_t id, u_int8_t aid, unsigned int count, void *arg, LIST_INSERT_HEAD(&rib_dumps, ctx, entry); + /* requested a sync traversal */ + if (count == 0) + rib_dump_r(ctx); + return 0; } @@ -664,65 +669,6 @@ path_lookup(struct rde_aspath *aspath, struct rde_peer *peer) return (NULL); } -void -path_remove(struct rde_aspath *asp) -{ - struct prefix *p, *np; - - for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = np) { - np = TAILQ_NEXT(p, path_l); - if (asp->pftableid) { - struct bgpd_addr addr; - - pt_getaddr(p->re->prefix, &addr); - /* Commit is done in peer_down() */ - rde_send_pftable(prefix_aspath(p)->pftableid, &addr, - p->re->prefix->prefixlen, 1); - } - prefix_destroy(p); - } -} - -/* remove all stale routes or if staletime is 0 remove all routes for - a specified AID. */ -u_int32_t -path_remove_stale(struct rde_aspath *asp, u_int8_t aid, time_t staletime) -{ - struct prefix *p, *np; - u_int32_t rprefixes; - - rprefixes=0; - /* - * This is called when a session flapped and during that time - * the pending updates for that peer are getting reset. - */ - for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = np) { - np = TAILQ_NEXT(p, path_l); - if (p->re->prefix->aid != aid) - continue; - - if (staletime && p->lastchange > staletime) - continue; - - if (asp->pftableid) { - struct bgpd_addr addr; - - pt_getaddr(p->re->prefix, &addr); - /* Commit is done in peer_flush() */ - rde_send_pftable(prefix_aspath(p)->pftableid, &addr, - p->re->prefix->prefixlen, 1); - } - - /* only count Adj-RIB-In */ - if (re_rib(p->re) == &ribs[RIB_ADJ_IN].rib) - rprefixes++; - - prefix_destroy(p); - } - return (rprefixes); -} - - /* * This function can only called when all prefix have been removed first. * Normally this happens directly out of the prefix removal functions. @@ -1147,29 +1093,6 @@ prefix_destroy(struct prefix *p) } /* - * helper function to clean up the dynamically added networks - */ -void -prefix_network_clean(struct rde_peer *peer) -{ - struct rde_aspath *asp, *xasp; - struct prefix *p, *xp; - - for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = xasp) { - xasp = TAILQ_NEXT(asp, peer_l); - if ((asp->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC) - continue; - for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = xp) { - xp = TAILQ_NEXT(p, path_l); - prefix_unlink(p); - prefix_free(p); - } - if (path_empty(asp)) - path_destroy(asp); - } -} - -/* * Link a prefix into the different parent objects. */ static void |