Change the way ribs are porcessed. Currently all async dumpers have to call rib_dump_r() whenever progress should be made. Also creating the context for such a dump is all on the caller side. Change this to one central place. Now all that is needed is to call rib_dump_new() with the callbacks for upcall, done and throttled. done and throttled are optional. This should solve the problem of not progressing rib_dump once and for all, also it removes the sync rib_dump() function which is no longer used.
Tested on my local system but more eyes and tests very welcome. -- :wq Claudio Index: mrt.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v retrieving revision 1.86 diff -u -p -r1.86 mrt.c --- mrt.c 24 Jul 2018 10:10:58 -0000 1.86 +++ mrt.c 18 Oct 2018 12:19:53 -0000 @@ -673,10 +673,8 @@ mrt_dump_upcall(struct rib_entry *re, vo } void -mrt_done(void *ptr) +mrt_done(struct mrt *mrtbuf) { - struct mrt *mrtbuf = ptr; - mrtbuf->state = MRT_STATE_REMOVE; } Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.437 diff -u -p -r1.437 rde.c --- rde.c 18 Oct 2018 12:19:09 -0000 1.437 +++ rde.c 18 Oct 2018 12:19:54 -0000 @@ -69,34 +69,18 @@ void rde_update_log(const char *, u_in void rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *); void rde_reflector(struct rde_peer *, struct rde_aspath *); -void rde_dump_rib_as(struct prefix *, struct rde_aspath *, pid_t, - int); -void rde_dump_filter(struct prefix *, - struct ctl_show_rib_request *); -void rde_dump_filterout(struct rde_peer *, struct prefix *, - struct ctl_show_rib_request *); -void rde_dump_upcall(struct rib_entry *, void *); -void rde_dump_prefix_upcall(struct rib_entry *, void *); void rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t, enum imsg_type); void rde_dump_ctx_throttle(pid_t pid, int throttle); -void rde_dump_runner(void); -int rde_dump_pending(void); -void rde_dump_done(void *); void rde_dump_mrt_new(struct mrt *, pid_t, int); -void rde_dump_rib_free(struct rib *); -void rde_dump_mrt_free(struct rib *); -void rde_rib_free(struct rib_desc *); int rde_rdomain_import(struct rde_aspath *, struct rdomain *); void rde_reload_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_in_done(void *, u_int8_t); +static void rde_softreconfig_out_done(void *, u_int8_t); static void rde_softreconfig_done(void); static void rde_softreconfig_out(struct rib_entry *, void *); static void rde_softreconfig_in(struct rib_entry *, void *); -void rde_up_dump_upcall(struct rib_entry *, void *); void rde_update_queue_runner(void); void rde_update6_queue_runner(u_int8_t); struct rde_prefixset *rde_find_prefixset(char *, struct rde_prefixset_head *); @@ -146,7 +130,6 @@ int softreconfig; struct rde_dump_ctx { LIST_ENTRY(rde_dump_ctx) entry; - struct rib_context ribctx; struct ctl_show_rib_request req; sa_family_t af; u_int8_t throttled; @@ -156,7 +139,6 @@ LIST_HEAD(, rde_dump_ctx) rde_dump_h = L struct rde_mrt_ctx { LIST_ENTRY(rde_mrt_ctx) entry; - struct rib_context ribctx; struct mrt mrt; }; @@ -234,7 +216,6 @@ rde_main(int debug, int verbose) peer_init(peerhashsize); /* make sure the default RIBs are setup */ - rib_new("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE); rib_new("Adj-RIB-Out", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE); out_rules = calloc(1, sizeof(struct filter_head)); @@ -272,20 +253,13 @@ rde_main(int debug, int verbose) set_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se); set_pollfd(&pfd[PFD_PIPE_SESSION_CTL], ibuf_se_ctl); - if (rde_dump_pending() && - ibuf_se_ctl && ibuf_se_ctl->w.queued == 0) - timeout = 0; - if (softreconfig) + if (rib_dump_pending()) timeout = 0; i = PFD_PIPE_COUNT; for (mctx = LIST_FIRST(&rde_mrts); mctx != 0; mctx = xmctx) { xmctx = LIST_NEXT(mctx, entry); - if (mctx->mrt.state != MRT_STATE_REMOVE && - mctx->mrt.wbuf.queued == 0) - rib_dump_r(&mctx->ribctx); - if (mctx->mrt.wbuf.queued) { pfd[i].fd = mctx->mrt.wbuf.fd; pfd[i].events = POLLOUT; @@ -334,15 +308,12 @@ rde_main(int debug, int verbose) mctx = LIST_NEXT(mctx, entry); } - rde_update_queue_runner(); - for (aid = AID_INET6; aid < AID_MAX; aid++) - rde_update6_queue_runner(aid); - if (rde_dump_pending() && - ibuf_se_ctl && ibuf_se_ctl->w.queued <= 10) - rde_dump_runner(); - if (softreconfig) { - rde_reload_runner(); + if (ibuf_se && ibuf_se->w.queued < SESS_MSG_HIGH_MARK) { + rde_update_queue_runner(); + for (aid = AID_INET6; aid < AID_MAX; aid++) + rde_update6_queue_runner(aid); } + rib_dump_runner(); } /* do not clean up on shutdown on production, it takes ages. */ @@ -826,7 +797,7 @@ rde_dispatch_imsg_parent(struct imsgbuf */ in_rules = ribd->in_rules; ribd->in_rules = NULL; - rde_rib_free(ribd); + rib_free(rib); rib = rib_new(rn.name, rn.rtableid, rn.flags); ribd->in_rules = in_rules; } else @@ -2147,7 +2118,7 @@ rde_reflector(struct rde_peer *peer, str /* * control specific functions */ -void +static void rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags) { struct ctl_show_rib rib; @@ -2231,7 +2202,7 @@ rde_dump_rib_as(struct prefix *p, struct } } -void +static void rde_dump_filterout(struct rde_peer *peer, struct prefix *p, struct ctl_show_rib_request *req) { @@ -2251,7 +2222,7 @@ rde_dump_filterout(struct rde_peer *peer rde_filterstate_clean(&state); } -void +static void rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req) { struct rde_peer *peer; @@ -2296,7 +2267,7 @@ rde_dump_filter(struct prefix *p, struct } } -void +static void rde_dump_upcall(struct rib_entry *re, void *ptr) { struct prefix *p; @@ -2306,7 +2277,7 @@ rde_dump_upcall(struct rib_entry *re, vo rde_dump_filter(p, &ctx->req); } -void +static void rde_dump_prefix_upcall(struct rib_entry *re, void *ptr) { struct rde_dump_ctx *ctx = ptr; @@ -2325,6 +2296,25 @@ rde_dump_prefix_upcall(struct rib_entry rde_dump_filter(p, &ctx->req); } +static int +rde_dump_throttled(void *arg) +{ + struct rde_dump_ctx *ctx = arg; + + return (ctx->throttled != 0); +} + +static void +rde_dump_done(void *arg, u_int8_t aid) +{ + struct rde_dump_ctx *ctx = arg; + + imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, + -1, NULL, 0); + LIST_REMOVE(ctx, entry); + free(ctx); +} + void rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid, enum imsg_type type) @@ -2336,6 +2326,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req u_int8_t hostplen; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { + nomem: log_warn("rde_dump_ctx_new"); error = CTL_RES_NOMEM; imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error, @@ -2356,22 +2347,28 @@ rde_dump_ctx_new(struct ctl_show_rib_req memcpy(&ctx->req, req, sizeof(struct ctl_show_rib_request)); ctx->req.pid = pid; ctx->req.type = type; - ctx->ribctx.ctx_count = CTL_MSG_HIGH_MARK; - ctx->ribctx.ctx_rib = rib; switch (ctx->req.type) { case IMSG_CTL_SHOW_NETWORK: - ctx->ribctx.ctx_upcall = network_dump_upcall; + if (rib_dump_new(rib, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx, + network_dump_upcall, rde_dump_done, + rde_dump_throttled) == -1) + goto nomem; break; case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_RIB_AS: case IMSG_CTL_SHOW_RIB_COMMUNITY: case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY: case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: - ctx->ribctx.ctx_upcall = rde_dump_upcall; + if (rib_dump_new(rib, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx, + rde_dump_upcall, rde_dump_done, rde_dump_throttled) == -1) + goto nomem; break; case IMSG_CTL_SHOW_RIB_PREFIX: if (req->flags & F_LONGER) { - ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall; + if (rib_dump_new(rib, ctx->req.aid, CTL_MSG_HIGH_MARK, + ctx, rde_dump_prefix_upcall, rde_dump_done, + rde_dump_throttled) == -1) + goto nomem; break; } switch (req->prefix.aid) { @@ -2398,11 +2395,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req default: fatalx("rde_dump_ctx_new: unsupported imsg type"); } - ctx->ribctx.ctx_done = rde_dump_done; - ctx->ribctx.ctx_arg = ctx; - ctx->ribctx.ctx_aid = ctx->req.aid; LIST_INSERT_HEAD(&rde_dump_h, ctx, entry); - rib_dump_r(&ctx->ribctx); } void @@ -2418,52 +2411,18 @@ rde_dump_ctx_throttle(pid_t pid, int thr } } -void -rde_dump_runner(void) +static int +rde_mrt_throttled(void *arg) { - struct rde_dump_ctx *ctx, *next; + struct mrt *mrt = arg; - for (ctx = LIST_FIRST(&rde_dump_h); ctx != NULL; ctx = next) { - next = LIST_NEXT(ctx, entry); - if (!ctx->throttled) - rib_dump_r(&ctx->ribctx); - } -} - -int -rde_dump_pending(void) -{ - struct rde_dump_ctx *ctx; - - /* return true if there is at least one unthrottled context */ - LIST_FOREACH(ctx, &rde_dump_h, entry) - if (!ctx->throttled) - return (1); - - return (0); + return (mrt->wbuf.queued > SESS_MSG_LOW_MARK); } -void -rde_dump_done(void *arg) +static void +rde_mrt_done(void *ptr, u_int8_t aid) { - struct rde_dump_ctx *ctx = arg; - - imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, - -1, NULL, 0); - LIST_REMOVE(ctx, entry); - free(ctx); -} - -void -rde_dump_rib_free(struct rib *rib) -{ - struct rde_dump_ctx *ctx, *next; - - for (ctx = LIST_FIRST(&rde_dump_h); ctx != NULL; ctx = next) { - next = LIST_NEXT(ctx, entry); - if (ctx->ribctx.ctx_rib == rib) - rde_dump_done(ctx); - } + mrt_done(ptr); } void @@ -2490,37 +2449,12 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t if (ctx->mrt.type == MRT_TABLE_DUMP_V2) mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist); - ctx->ribctx.ctx_count = CTL_MSG_HIGH_MARK; - ctx->ribctx.ctx_rib = rib; - ctx->ribctx.ctx_upcall = mrt_dump_upcall; - ctx->ribctx.ctx_done = mrt_done; - ctx->ribctx.ctx_arg = &ctx->mrt; - ctx->ribctx.ctx_aid = AID_UNSPEC; + if (rib_dump_new(rib, AID_UNSPEC, CTL_MSG_HIGH_MARK, &ctx->mrt, + mrt_dump_upcall, rde_mrt_done, rde_mrt_throttled) == -1) + fatal("%s: rib_dump_new", __func__); + LIST_INSERT_HEAD(&rde_mrts, ctx, entry); rde_mrt_cnt++; - rib_dump_r(&ctx->ribctx); -} - -void -rde_dump_mrt_free(struct rib *rib) -{ - struct rde_mrt_ctx *ctx, *next; - - for (ctx = LIST_FIRST(&rde_mrts); ctx != NULL; ctx = next) { - next = LIST_NEXT(ctx, entry); - if (ctx->ribctx.ctx_rib == rib) - mrt_done(&ctx->mrt); - } -} - -void -rde_rib_free(struct rib_desc *rd) -{ - /* abort pending rib_dumps */ - rde_dump_rib_free(&rd->rib); - rde_dump_mrt_free(&rd->rib); - - rib_free(&rd->rib); } /* @@ -2635,9 +2569,7 @@ rde_generate_updates(struct rib *rib, st } } -u_char queue_buf[4096]; - -void +static void rde_up_dump_upcall(struct rib_entry *re, void *ptr) { struct rde_peer *peer = ptr; @@ -2649,6 +2581,17 @@ rde_up_dump_upcall(struct rib_entry *re, up_generate_updates(out_rules, peer, re->active, NULL); } +static void +rde_up_dump_done(void *ptr, u_int8_t aid) +{ + struct rde_peer *peer = ptr; + + if (peer->capa.grestart.restart) + up_generate_marker(peer, aid); +} + +u_char queue_buf[4096]; + void rde_update_queue_runner(void) { @@ -2844,7 +2787,6 @@ 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; @@ -2958,7 +2900,7 @@ rde_reload_done(void) switch (ribs[rid].state) { case RECONF_DELETE: - rde_rib_free(&ribs[rid]); + rib_free(&ribs[rid].rib); break; case RECONF_KEEP: if (rde_filter_equal(ribs[rid].in_rules, @@ -2985,48 +2927,37 @@ rde_reload_done(void) } log_info("RDE reconfigured"); - softreconfig++; + softreconfig = 0; 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"); + softreconfig++; + if (rib_dump_new(&ribs[RIB_ADJ_IN].rib, AID_UNSPEC, + RDE_RUNNER_ROUNDS, &ribs[RIB_ADJ_IN], rde_softreconfig_in, + rde_softreconfig_in_done, NULL) == -1) + fatal("%s: rib_dump_new", __func__); } 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 (!rib_valid(rid)) - continue; - if (ribs[rid].dumping) - rib_dump_r(&ribs[rid].ribctx); + rde_softreconfig_in_done(NULL, AID_UNSPEC); } } static void -rde_softreconfig_in_done(void *arg) +rde_softreconfig_in_done(void *arg, u_int8_t aid) { - struct rib_desc *rib = arg; + struct rib_desc *rd = arg; struct rde_peer *peer; u_int16_t rid; - /* Adj-RIB-In run is done */ - softreconfig--; - rib->dumping = 0; + if (rd != NULL) { + softreconfig--; + /* one guy done but other dumps are still running */ + if (softreconfig > 0) + return; + + log_info("softreconfig in done"); + } /* now do the Adj-RIB-Out sync */ + softreconfig = 0; for (rid = 0; rid < rib_size; rid++) { if (!rib_valid(rid)) continue; @@ -3036,26 +2967,25 @@ rde_softreconfig_in_done(void *arg) LIST_FOREACH(peer, &peerlist, peer_l) { if (peer->reconf_out) ribs[peer->rib->id].state = RECONF_RELOAD; - else if (peer->reconf_rib) + else if (peer->reconf_rib) { + u_int8_t i; + /* dump the full table to neighbors that changed rib */ - peer_dump(peer->conf.id, AID_UNSPEC); + for (i = 0; i < AID_MAX; i++) { + if (peer->capa.mp[i]) + peer_dump(peer->conf.id, i); + } + } } for (rid = 0; rid < rib_size; rid++) { if (!rib_valid(rid)) 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; + if (rib_dump_new(&ribs[rid].rib, AID_UNSPEC, + RDE_RUNNER_ROUNDS, &ribs[rid], rde_softreconfig_out, + rde_softreconfig_out_done, NULL) == -1) + fatal("%s: rib_dump_new", __func__); softreconfig++; log_info("starting softreconfig out for rib %s", ribs[rid].name); @@ -3068,13 +2998,12 @@ rde_softreconfig_in_done(void *arg) } static void -rde_softreconfig_out_done(void *arg) +rde_softreconfig_out_done(void *arg, u_int8_t aid) { 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 */ @@ -3560,14 +3489,18 @@ peer_dump(u_int32_t id, u_int8_t aid) } if (peer->conf.export_type == EXPORT_NONE) { - /* nothing */; + /* nothing to send apart from the marker */ + if (peer->capa.grestart.restart) + up_generate_marker(peer, aid); } else if (peer->conf.export_type == EXPORT_DEFAULT_ROUTE) { up_generate_default(out_rules, peer, aid); + if (peer->capa.grestart.restart) + up_generate_marker(peer, aid); } else { - rib_dump(peer->rib, rde_up_dump_upcall, peer, aid); + if (rib_dump_new(peer->rib, aid, RDE_RUNNER_ROUNDS, peer, + rde_up_dump_upcall, rde_up_dump_done, NULL) == -1) + fatal("%s: rib_dump_new", __func__); } - if (peer->capa.grestart.restart) - up_generate_marker(peer, aid); } /* End-of-RIB marker, RFC 4724 */ Index: rde.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v retrieving revision 1.197 diff -u -p -r1.197 rde.h --- rde.h 15 Oct 2018 10:44:47 -0000 1.197 +++ rde.h 18 Oct 2018 12:19:54 -0000 @@ -36,6 +36,36 @@ enum peer_state { PEER_ERR /* error occurred going to PEER_DOWN state */ }; +LIST_HEAD(prefix_list, prefix); +RB_HEAD(rib_tree, rib_entry); + +struct rib_entry { + RB_ENTRY(rib_entry) rib_e; + struct prefix_list prefix_h; + struct prefix *active; /* for fast access */ + struct pt_entry *prefix; + struct rib *__rib; /* mangled pointer with flags */ +}; + +struct rib { + struct rib_tree tree; + u_int rtableid; + u_int16_t flags; + u_int16_t id; +}; + +#define RIB_ADJ_IN 0 +#define RIB_ADJ_OUT 1 +#define RIB_LOC_START 2 + +struct rib_desc { + char name[PEER_DESCR_LEN]; + struct rib rib; + struct filter_head *in_rules; + struct filter_head *in_rules_tmp; + enum reconf_action state; +}; + /* * How do we identify peers between the session handler and the rde? * Currently I assume that we can do that with the neighbor_ip... @@ -43,7 +73,6 @@ enum peer_state { LIST_HEAD(rde_peer_head, rde_peer); LIST_HEAD(aspath_list, aspath); LIST_HEAD(attr_list, attr); -LIST_HEAD(prefix_list, prefix); TAILQ_HEAD(prefix_queue, prefix); LIST_HEAD(aspath_head, rde_aspath); TAILQ_HEAD(aspath_queue, rde_aspath); @@ -51,9 +80,6 @@ RB_HEAD(uptree_prefix, update_prefix); RB_HEAD(uptree_attr, update_attr); RB_HEAD(uptree_rib, update_rib); -struct rib_desc; -struct rib; -RB_HEAD(rib_tree, rib_entry); TAILQ_HEAD(uplist_prefix, update_prefix); TAILQ_HEAD(uplist_attr, update_attr); @@ -260,46 +286,6 @@ struct pt_entry_vpn4 { u_int8_t pad2; }; -struct rib_context { - struct rib_entry *ctx_re; - struct rib *ctx_rib; - void (*ctx_upcall)(struct rib_entry *, void *); - void (*ctx_done)(void *); - void (*ctx_wait)(void *); - void *ctx_arg; - unsigned int ctx_count; - u_int8_t ctx_aid; -}; - -struct rib_entry { - RB_ENTRY(rib_entry) rib_e; - struct prefix_list prefix_h; - struct prefix *active; /* for fast access */ - struct pt_entry *prefix; - struct rib *__rib; /* mangled pointer with flags */ -}; - -struct rib { - struct rib_tree tree; - u_int rtableid; - u_int16_t flags; - u_int16_t id; -}; - -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 -#define RIB_ADJ_OUT 1 -#define RIB_LOC_START 2 - struct prefix { LIST_ENTRY(prefix) rib_l, nexthop_l; TAILQ_ENTRY(prefix) path_l; @@ -330,7 +316,6 @@ extern struct rde_memstats rdemem; int mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *, struct rde_peer_head *); void mrt_dump_upcall(struct rib_entry *, void *); -void mrt_done(void *); /* rde.c */ void rde_send_kroute(struct rib *, struct prefix *, struct prefix *); @@ -459,9 +444,12 @@ struct rib_desc *rib_desc(struct rib *); void rib_free(struct rib *); struct rib_entry *rib_get(struct rib *, struct bgpd_addr *, int); struct rib_entry *rib_lookup(struct rib *, struct bgpd_addr *); -void rib_dump(struct rib *, void (*)(struct rib_entry *, void *), - void *, u_int8_t); -void rib_dump_r(struct rib_context *); +int rib_dump_pending(void); +void rib_dump_runner(void); +int rib_dump_new(struct rib *, u_int8_t, unsigned int, void *, + void (*)(struct rib_entry *, void *), + void (*)(void *, u_int8_t), + int (*)(void *)); static inline struct rib * re_rib(struct rib_entry *re) Index: rde_rib.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v retrieving revision 1.179 diff -u -p -r1.179 rde_rib.c --- rde_rib.c 29 Sep 2018 08:11:11 -0000 1.179 +++ rde_rib.c 18 Oct 2018 12:19:54 -0000 @@ -40,14 +40,28 @@ u_int16_t rib_size; struct rib_desc *ribs; struct rib_entry *rib_add(struct rib *, struct bgpd_addr *, int); -int rib_compare(const struct rib_entry *, const struct rib_entry *); +static inline int rib_compare(const struct rib_entry *, + const struct rib_entry *); void rib_remove(struct rib_entry *); int rib_empty(struct rib_entry *); -struct rib_entry *rib_restart(struct rib_context *); +static void rib_dump_abort(struct rib *); RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare); RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare); +struct rib_context { + LIST_ENTRY(rib_context) entry; + struct rib_entry *ctx_re; + struct rib *ctx_rib; + void (*ctx_upcall)(struct rib_entry *, void *); + void (*ctx_done)(void *, u_int8_t); + int (*ctx_throttle)(void *); + void *ctx_arg; + unsigned int ctx_count; + u_int8_t ctx_aid; +}; +LIST_HEAD(, rib_context) rib_dumps = LIST_HEAD_INITIALIZER(rib_dumps); + static int prefix_add(struct bgpd_addr *, int, struct rib *, struct rde_peer *, struct rde_aspath *, struct filterstate *, u_int8_t); @@ -78,6 +92,12 @@ rib_tree(struct rib *rib) return (&rib->tree); } +static inline int +rib_compare(const struct rib_entry *a, const struct rib_entry *b) +{ + return (pt_prefix_cmp(a->prefix, b->prefix)); +} + /* RIB specific functions */ struct rib * rib_new(char *name, u_int rtableid, u_int16_t flags) @@ -146,6 +166,8 @@ rib_free(struct rib *rib) struct rib_entry *re, *xre; struct prefix *p, *np; + rib_dump_abort(rib); + for (re = RB_MIN(rib_tree, rib_tree(rib)); re != NULL; re = xre) { xre = RB_NEXT(rib_tree, rib_tree(rib), re); @@ -177,12 +199,6 @@ rib_free(struct rib *rib) bzero(rd, sizeof(struct rib_desc)); } -int -rib_compare(const struct rib_entry *a, const struct rib_entry *b) -{ - return (pt_prefix_cmp(a->prefix, b->prefix)); -} - struct rib_entry * rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) { @@ -282,22 +298,26 @@ rib_empty(struct rib_entry *re) return LIST_EMPTY(&re->prefix_h); } -void -rib_dump(struct rib *rib, void (*upcall)(struct rib_entry *, void *), - void *arg, u_int8_t aid) +static struct rib_entry * +rib_restart(struct rib_context *ctx) { - struct rib_context *ctx; + struct rib_entry *re; - if ((ctx = calloc(1, sizeof(*ctx))) == NULL) - fatal("rib_dump"); - ctx->ctx_rib = rib; - ctx->ctx_upcall = upcall; - ctx->ctx_arg = arg; - ctx->ctx_aid = aid; - rib_dump_r(ctx); + re = ctx->ctx_re; + re_unlock(re); + + /* find first non empty element */ + while (re && rib_empty(re)) + re = RB_NEXT(rib_tree, unused, re); + + /* free the previously locked rib element if empty */ + if (rib_empty(ctx->ctx_re)) + rib_remove(ctx->ctx_re); + ctx->ctx_re = NULL; + return (re); } -void +static void rib_dump_r(struct rib_context *ctx) { struct rib_entry *re; @@ -323,28 +343,70 @@ rib_dump_r(struct rib_context *ctx) } if (ctx->ctx_done) - ctx->ctx_done(ctx->ctx_arg); - else + ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); + LIST_REMOVE(ctx, entry); + free(ctx); +} + +int +rib_dump_pending(void) +{ + struct rib_context *ctx; + + /* return true if at least one context is not throttled */ + LIST_FOREACH(ctx, &rib_dumps, entry) { + if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg)) + continue; + return 1; + } + return 0; +} + +void +rib_dump_runner(void) +{ + struct rib_context *ctx, *next; + + LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next) { + if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg)) + continue; + rib_dump_r(ctx); + } +} + +static void +rib_dump_abort(struct rib *rib) +{ + struct rib_context *ctx, *next; + + LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next) { + if (ctx->ctx_done) + ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid); + LIST_REMOVE(ctx, entry); free(ctx); + } } -struct rib_entry * -rib_restart(struct rib_context *ctx) +int +rib_dump_new(struct rib *rib, u_int8_t aid, unsigned int count, void *arg, + void (*upcall)(struct rib_entry *, void *), void (*done)(void *, u_int8_t), + int (*throttle)(void *)) { - struct rib_entry *re; + struct rib_context *ctx; - re = ctx->ctx_re; - re_unlock(re); + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) + return -1; + ctx->ctx_rib = rib; + ctx->ctx_aid = aid; + ctx->ctx_count = count; + ctx->ctx_arg = arg; + ctx->ctx_upcall = upcall; + ctx->ctx_done = done; + ctx->ctx_throttle = throttle; - /* find first non empty element */ - while (re && rib_empty(re)) - re = RB_NEXT(rib_tree, unused, re); + LIST_INSERT_HEAD(&rib_dumps, ctx, entry); - /* free the previously locked rib element if empty */ - if (rib_empty(ctx->ctx_re)) - rib_remove(ctx->ctx_re); - ctx->ctx_re = NULL; - return (re); + return 0; } /* path specific functions */ Index: session.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/session.h,v retrieving revision 1.124 diff -u -p -r1.124 session.h --- session.h 20 Sep 2018 11:06:04 -0000 1.124 +++ session.h 18 Oct 2018 12:19:54 -0000 @@ -269,7 +269,7 @@ void mrt_dump_bgp_msg(struct mrt *, vo struct peer *); void mrt_dump_state(struct mrt *, u_int16_t, u_int16_t, struct peer *); -void mrt_done(void *); +void mrt_done(struct mrt *); /* parse.y */ int parse_config(char *, struct bgpd_config *, struct peer **);