From 08e4e1cc054b80c85026deda5f02e5479833296f Mon Sep 17 00:00:00 2001 From: claudio Date: Wed, 8 Aug 2018 13:08:54 +0000 Subject: [PATCH] Update the RIB after a config reload in the background. This moves the heavy bits into the background and so the RDE is able to process new messages more or less instantly after a configuration reload. Not all cases are covered yet but the bulk is. While the backgorund process is running no new config can be loaded. Tested by and OK benno@ --- usr.sbin/bgpd/rde.c | 116 ++++++++++++++++++++++++++++++++++++++------ usr.sbin/bgpd/rde.h | 4 +- 2 files changed, 105 insertions(+), 15 deletions(-) diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 79cf5a42545..8ee91c291fb 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.412 2018/08/08 06:54:50 benno Exp $ */ +/* $OpenBSD: rde.c,v 1.413 2018/08/08 13:08:54 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -90,7 +90,10 @@ void rde_rib_free(struct rib_desc *); int rde_rdomain_import(struct rde_aspath *, struct rdomain *); void rde_reload_done(void); -static void rde_softreconfig_done(void *); +static void rde_reload_runner(void); +static void rde_softreconfig_in_done(void *); +static void rde_softreconfig_out_done(void *); +static void rde_softreconfig_done(void); static void rde_softreconfig_out(struct rib_entry *, void *); static void rde_softreconfig_in(struct rib_entry *, void *); static void rde_softreconfig_unload_peer(struct rib_entry *, void *); @@ -132,6 +135,7 @@ struct imsgbuf *ibuf_se; struct imsgbuf *ibuf_se_ctl; struct imsgbuf *ibuf_main; struct rde_memstats rdemem; +int softreconfig; struct rde_dump_ctx { LIST_ENTRY(rde_dump_ctx) entry; @@ -322,6 +326,9 @@ rde_main(int debug, int verbose) if (rde_dump_pending() && ibuf_se_ctl && ibuf_se_ctl->w.queued <= 10) rde_dump_runner(); + if (softreconfig) { + rde_reload_runner(); + } } /* do not clean up on shutdown on production, it takes ages. */ @@ -2715,6 +2722,7 @@ rde_reload_done(void) struct rdomain *rd; struct rde_peer *peer; struct filter_head *fh; + struct rib_context *ctx; u_int16_t rid; int reload = 0; @@ -2835,14 +2843,55 @@ rde_reload_done(void) filterlist_free(ribs[rid].in_rules_tmp); ribs[rid].in_rules_tmp = NULL; } + log_info("RDE reconfigured"); + + softreconfig++; + if (reload > 0) { + ctx = &ribs[RIB_ADJ_IN].ribctx; + memset(ctx, 0, sizeof(*ctx)); + ctx->ctx_rib = &ribs[RIB_ADJ_IN].rib; + ctx->ctx_arg = &ribs[RIB_ADJ_IN]; + ctx->ctx_upcall = rde_softreconfig_in; + ctx->ctx_done = rde_softreconfig_in_done; + ctx->ctx_aid = AID_UNSPEC; + ctx->ctx_count = RDE_RUNNER_ROUNDS; + ribs[RIB_ADJ_IN].dumping = 1; + log_info("running softreconfig in"); + } else { + rde_softreconfig_in_done(&ribs[RIB_ADJ_IN]); + } +} + +static void +rde_reload_runner(void) +{ + u_int16_t rid; + + for (rid = 0; rid < rib_size; rid++) { + if (*ribs[rid].name == '\0') + continue; + if (ribs[rid].dumping) + rib_dump_r(&ribs[rid].ribctx); + } +} + +static void +rde_softreconfig_in_done(void *arg) +{ + struct rib_desc *rib = arg; + struct rde_peer *peer; + u_int16_t rid; - if (reload > 0) - rib_dump(&ribs[RIB_ADJ_IN].rib, rde_softreconfig_in, NULL, - AID_UNSPEC); + /* Adj-RIB-In run is done */ + softreconfig--; + rib->dumping = 0; /* now do the Adj-RIB-Out sync */ - for (rid = 0; rid < rib_size; rid++) + for (rid = 0; rid < rib_size; rid++) { + if (*ribs[rid].name == '\0') + continue; ribs[rid].state = RECONF_NONE; + } LIST_FOREACH(peer, &peerlist, peer_l) { if (peer->reconf_out) @@ -2852,18 +2901,53 @@ rde_reload_done(void) peer_dump(peer->conf.id, AID_UNSPEC); } - for (rid = 0; rid < rib_size; rid++) - if (ribs[rid].state == RECONF_RELOAD) - rib_dump(&ribs[rid].rib, rde_softreconfig_out, NULL, - AID_UNSPEC); + for (rid = 0; rid < rib_size; rid++) { + if (*ribs[rid].name == '\0') + continue; + if (ribs[rid].state == RECONF_RELOAD) { + struct rib_context *ctx; + + ctx = &ribs[rid].ribctx; + memset(ctx, 0, sizeof(*ctx)); + ctx->ctx_rib = &ribs[rid].rib; + ctx->ctx_arg = &ribs[rid]; + ctx->ctx_upcall = rde_softreconfig_out; + ctx->ctx_done = rde_softreconfig_out_done; + ctx->ctx_aid = AID_UNSPEC; + ctx->ctx_count = RDE_RUNNER_ROUNDS; + ribs[rid].dumping = 1; + softreconfig++; + log_info("starting softreconfig out for rib %s", + ribs[rid].name); + } + } - rde_softreconfig_done(NULL); + /* if nothing to do move to last stage */ + if (softreconfig == 0) + rde_softreconfig_done(); } static void -rde_softreconfig_done(void *arg) +rde_softreconfig_out_done(void *arg) { - u_int16_t rid; + struct rib_desc *rib = arg; + + /* this RIB dump is done */ + softreconfig--; + rib->dumping = 0; + log_info("softreconfig out done for %s", rib->name); + + /* but other dumps are still running */ + if (softreconfig > 0) + return; + + rde_softreconfig_done(); +} + +static void +rde_softreconfig_done(void) +{ + u_int16_t rid; filterlist_free(out_rules_tmp); out_rules_tmp = NULL; @@ -2876,7 +2960,7 @@ rde_softreconfig_done(void *arg) free_prefixsets(prefixsets_old); prefixsets_old = NULL; - log_info("RDE reconfigured"); + log_info("RDE soft reconfiguration done"); imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0); } @@ -2900,6 +2984,10 @@ rde_softreconfig_in(struct rib_entry *re, void *bula) asp = prefix_aspath(p); peer = prefix_peer(p); + /* skip announced networks, they are never filtered */ + if (asp->flags & F_PREFIX_ANNOUNCED) + continue; + for (i = RIB_LOC_START; i < rib_size; i++) { rib = &ribs[i]; if (rib->state != RECONF_RELOAD) diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 0e30e476559..6049bdaa60f 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.185 2018/08/08 06:54:50 benno Exp $ */ +/* $OpenBSD: rde.h,v 1.186 2018/08/08 13:08:54 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -287,9 +287,11 @@ struct rib { struct rib_desc { char name[PEER_DESCR_LEN]; struct rib rib; + struct rib_context ribctx; struct filter_head *in_rules; struct filter_head *in_rules_tmp; enum reconf_action state; + u_int8_t dumping; }; #define RIB_ADJ_IN 0 -- 2.20.1