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 **);

Reply via email to