On Sun, Oct 21, 2018 at 01:51:52PM +0200, Claudio Jeker wrote:
> On Thu, Oct 18, 2018 at 02:29:17PM +0200, Claudio Jeker wrote:
> > 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.
> > 
> 
> Thanks to denis@ this uncovered a bigger problem in the RDE. The RIB heads
> are currently stored in an array indexed by their id. Now if new RIBs are
> added this array may be reallocated. The problem is that the a pointer to
> that struct is stored in a few places (peer, rib entries, dump contexts)
> which is bad once such are realloc happens.
> 
> I extended this diff now to solve this issue by storing the RIB ID instead
> of rib pointers in those structs. With this I no longer get the crashes by
> adding new ribs.

New version which also solves a use-after-free bug because of peer_up ->
peer_dump and hitting peer_down quickly afterwards. Found by benno@ with a
neighbor that had a to low max-prefix limit. On peer_down any possible
peer_up_dump_upcall runners need to terminated before the peer is freed.

This following diff also includes the 'show rib out nei $FOO' patch from
yesterday.
-- 
: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 11:03:36 -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.438
diff -u -p -r1.438 rde.c
--- rde.c       22 Oct 2018 07:46:55 -0000      1.438
+++ rde.c       22 Oct 2018 21:23:24 -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;
 };
 
@@ -272,20 +254,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;
@@ -339,11 +314,7 @@ rde_main(int debug, int verbose)
                        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();
+               rib_dump_runner();
        }
 
        /* do not clean up on shutdown on production, it takes ages. */
@@ -811,7 +782,7 @@ rde_dispatch_imsg_parent(struct imsgbuf 
                            sizeof(struct rde_rib))
                                fatalx("IMSG_RECONF_RIB bad len");
                        memcpy(&rn, imsg.data, sizeof(rn));
-                       rib = rib_find(rn.name);
+                       rib = rib_byid(rib_find(rn.name));
                        if (rib == NULL)
                                rib = rib_new(rn.name, rn.rtableid, rn.flags);
                        else if (rib->rtableid != rn.rtableid ||
@@ -827,7 +798,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
@@ -870,7 +841,7 @@ rde_dispatch_imsg_parent(struct imsgbuf 
                                }
                        }
                        TAILQ_INIT(&r->set);
-                       if ((rib = rib_find(r->rib)) == NULL) {
+                       if ((rib = rib_byid(rib_find(r->rib))) == NULL) {
                                log_warnx("IMSG_RECONF_FILTER: filter rule "
                                    "for nonexistent rib %s", r->rib);
                                parent_set = NULL;
@@ -2148,8 +2119,9 @@ rde_reflector(struct rde_peer *peer, str
 /*
  * control specific functions
  */
-void
-rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
+static void
+rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp,
+    struct nexthop *nexthop, pid_t pid, int flags)
 {
        struct ctl_show_rib      rib;
        struct ibuf             *wbuf;
@@ -2167,10 +2139,10 @@ rde_dump_rib_as(struct prefix *p, struct
        memcpy(&rib.remote_addr, &prefix_peer(p)->remote_addr,
            sizeof(rib.remote_addr));
        rib.remote_id = prefix_peer(p)->remote_bgpid;
-       if (prefix_nexthop(p) != NULL) {
-               memcpy(&rib.true_nexthop, &prefix_nexthop(p)->true_nexthop,
+       if (nexthop != NULL) {
+               memcpy(&rib.true_nexthop, &nexthop->true_nexthop,
                    sizeof(rib.true_nexthop));
-               memcpy(&rib.exit_nexthop, &prefix_nexthop(p)->exit_nexthop,
+               memcpy(&rib.exit_nexthop, &nexthop->exit_nexthop,
                    sizeof(rib.exit_nexthop));
        } else {
                /* announced network may have a NULL nexthop */
@@ -2190,8 +2162,7 @@ rde_dump_rib_as(struct prefix *p, struct
                rib.flags |= F_PREF_INTERNAL;
        if (asp->flags & F_PREFIX_ANNOUNCED)
                rib.flags |= F_PREF_ANNOUNCE;
-       if (prefix_nexthop(p) == NULL ||
-           prefix_nexthop(p)->state == NEXTHOP_REACH)
+       if (nexthop == NULL || nexthop->state == NEXTHOP_REACH)
                rib.flags |= F_PREF_ELIGIBLE;
        if (asp->flags & F_ATTR_LOOP)
                rib.flags &= ~F_PREF_ELIGIBLE;
@@ -2232,7 +2203,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)
 {
@@ -2247,12 +2218,13 @@ rde_dump_filterout(struct rde_peer *peer
        a = rde_filter(out_rules, peer, p, &state);
 
        if (a == ACTION_ALLOW)
-               rde_dump_rib_as(p, &state.aspath, req->pid, req->flags);
+               rde_dump_rib_as(p, &state.aspath, state.nexthop, req->pid,
+                   req->flags);
 
        rde_filterstate_clean(&state);
 }
 
-void
+static void
 rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
 {
        struct rde_peer         *peer;
@@ -2293,11 +2265,12 @@ rde_dump_filter(struct prefix *p, struct
                        return;
                if (!ovs_match(p, req->flags))
                        return;
-               rde_dump_rib_as(p, asp, req->pid, req->flags);
+               rde_dump_rib_as(p, asp, prefix_nexthop(p), req->pid,
+                   req->flags);
        }
 }
 
-void
+static void
 rde_dump_upcall(struct rib_entry *re, void *ptr)
 {
        struct prefix           *p;
@@ -2307,7 +2280,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;
@@ -2326,17 +2299,37 @@ 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)
 {
        struct rde_dump_ctx     *ctx;
-       struct rib              *rib;
        struct rib_entry        *re;
        u_int                    error;
        u_int8_t                 hostplen;
+       u_int16_t                rid;
 
        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,
@@ -2344,8 +2337,8 @@ rde_dump_ctx_new(struct ctl_show_rib_req
                return;
        }
        if (req->flags & (F_CTL_ADJ_IN | F_CTL_INVALID)) {
-               rib = &ribs[RIB_ADJ_IN].rib;
-       } else if ((rib = rib_find(req->rib)) == NULL) {
+               rid = RIB_ADJ_IN;
+       } else if ((rid = rib_find(req->rib)) == RIB_NOTFOUND) {
                log_warnx("rde_dump_ctx_new: no such rib %s", req->rib);
                error = CTL_RES_NOSUCHPEER;
                imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
@@ -2357,22 +2350,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(rid, 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(rid, 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(rid, 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) {
@@ -2387,9 +2386,10 @@ rde_dump_ctx_new(struct ctl_show_rib_req
                        fatalx("rde_dump_ctx_new: unknown af");
                }
                if (req->prefixlen == hostplen)
-                       re = rib_lookup(rib, &req->prefix);
+                       re = rib_lookup(rib_byid(rid), &req->prefix);
                else
-                       re = rib_get(rib, &req->prefix, req->prefixlen);
+                       re = rib_get(rib_byid(rid), &req->prefix,
+                           req->prefixlen);
                if (re)
                        rde_dump_upcall(re, ctx);
                imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
@@ -2399,11 +2399,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
@@ -2419,59 +2415,25 @@ rde_dump_ctx_throttle(pid_t pid, int thr
        }
 }
 
-void
-rde_dump_runner(void)
-{
-       struct rde_dump_ctx     *ctx, *next;
-
-       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);
-}
-
-void
-rde_dump_done(void *arg)
+static int
+rde_mrt_throttled(void *arg)
 {
-       struct rde_dump_ctx     *ctx = arg;
+       struct mrt      *mrt = arg;
 
-       imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
-           -1, NULL, 0);
-       LIST_REMOVE(ctx, entry);
-       free(ctx);
+       return (mrt->wbuf.queued > SESS_MSG_LOW_MARK);
 }
 
-void
-rde_dump_rib_free(struct rib *rib)
+static void
+rde_mrt_done(void *ptr, u_int8_t aid)
 {
-       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
 rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
 {
-       struct rde_mrt_ctx      *ctx;
-       struct rib              *rib;
+       struct rde_mrt_ctx *ctx;
+       u_int16_t rid;
 
        if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
                log_warn("rde_dump_mrt_new");
@@ -2481,8 +2443,8 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t 
        TAILQ_INIT(&ctx->mrt.wbuf.bufs);
        ctx->mrt.wbuf.fd = fd;
        ctx->mrt.state = MRT_STATE_RUNNING;
-       rib = rib_find(ctx->mrt.rib);
-       if (rib == NULL) {
+       rid = rib_find(ctx->mrt.rib);
+       if (rid == RIB_NOTFOUND) {
                log_warnx("non existing RIB %s for mrt dump", ctx->mrt.rib);
                free(ctx);
                return;
@@ -2491,37 +2453,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(rid, 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);
 }
 
 /*
@@ -2628,7 +2565,7 @@ rde_generate_updates(struct rib *rib, st
        LIST_FOREACH(peer, &peerlist, peer_l) {
                if (peer->conf.id == 0)
                        continue;
-               if (peer->rib != rib)
+               if (peer->loc_rib_id != rib->id)
                        continue;
                if (peer->state != PEER_UP)
                        continue;
@@ -2636,20 +2573,30 @@ 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;
 
-       if (re_rib(re) != peer->rib)
-               fatalx("King Bula: monstrous evil horror.");
+       if (re->rib_id != peer->loc_rib_id)
+               fatalx("%s: Unexpected RIB %u != %u.", __func__, re->rib_id,
+                   peer->loc_rib_id);
        if (re->active == NULL)
                return;
        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)
 {
@@ -2851,7 +2798,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;
 
@@ -2937,10 +2883,13 @@ rde_reload_done(void)
                        continue;
                peer->reconf_out = 0;
                peer->reconf_rib = 0;
-               if (peer->rib != rib_find(peer->conf.rib)) {
+               if (peer->loc_rib_id != rib_find(peer->conf.rib)) {
+                       char *p = log_fmt_peer(&peer->conf);
+                       log_debug("rib change: reloading peer %s", p);
+                       free(p);
                        up_withdraw_all(peer);
-                       peer->rib = rib_find(peer->conf.rib);
-                       if (peer->rib == NULL)
+                       peer->loc_rib_id = rib_find(peer->conf.rib);
+                       if (peer->loc_rib_id == RIB_NOTFOUND)
                                fatalx("King Bula's peer met an unknown RIB");
                        peer->reconf_rib = 1;
                        continue;
@@ -2965,7 +2914,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,
@@ -2992,48 +2941,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(RIB_ADJ_IN, 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;
@@ -3042,27 +2980,26 @@ 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)
+                       ribs[peer->loc_rib_id].state = RECONF_RELOAD;
+               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(rid, 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);
@@ -3075,13 +3012,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 */
@@ -3231,7 +3167,7 @@ rde_softreconfig_out(struct rib_entry *r
                return;
 
        LIST_FOREACH(peer, &peerlist, peer_l) {
-               if (peer->rib == re_rib(re) && peer->reconf_out)
+               if (peer->loc_rib_id == re->rib_id && peer->reconf_out)
                        rde_softreconfig_out_peer(re, peer);
        }
 }
@@ -3351,8 +3287,8 @@ peer_add(u_int32_t id, struct peer_confi
        TAILQ_INIT(&peer->path_h);
        memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
        peer->remote_bgpid = 0;
-       peer->rib = rib_find(peer->conf.rib);
-       if (peer->rib == NULL)
+       peer->loc_rib_id = rib_find(peer->conf.rib);
+       if (peer->loc_rib_id == RIB_NOTFOUND)
                fatalx("King Bula's new peer met an unknown RIB");
        peer->state = PEER_NONE;
        up_init(peer);
@@ -3486,6 +3422,8 @@ peer_down(u_int32_t id)
        peer->remote_bgpid = 0;
        peer->state = PEER_DOWN;
        up_down(peer);
+       /* 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) {
@@ -3567,14 +3505,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->loc_rib_id, 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       22 Oct 2018 21:06:33 -0000
@@ -36,6 +36,38 @@ 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;
+       u_int16_t                rib_id;
+       u_int16_t                lock;
+};
+
+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
+#define RIB_NOTFOUND   0xffff
+
+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 +75,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 +82,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);
 
@@ -72,7 +100,6 @@ struct rde_peer {
        struct uplist_prefix             withdraws[AID_MAX];
        time_t                           staletime[AID_MAX];
        struct capabilities              capa;
-       struct rib                      *rib;
        u_int64_t                        prefix_rcvd_update;
        u_int64_t                        prefix_rcvd_withdraw;
        u_int64_t                        prefix_rcvd_eor;
@@ -86,6 +113,7 @@ struct rde_peer {
        u_int32_t                        up_nlricnt;
        u_int32_t                        up_wcnt;
        enum peer_state                  state;
+       u_int16_t                        loc_rib_id;
        u_int16_t                        short_as;
        u_int16_t                        mrt_idx;
        u_int8_t                         reconf_out;    /* out filter changed */
@@ -260,46 +288,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 +318,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 *);
@@ -454,25 +441,31 @@ extern u_int16_t   rib_size;
 extern struct rib_desc *ribs;
 
 struct rib     *rib_new(char *, u_int, u_int16_t);
-struct rib     *rib_find(char *);
+struct rib     *rib_byid(u_int16_t);
+u_int16_t       rib_find(char *);
 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(u_int16_t, u_int8_t, unsigned int, void *,
+                   void (*)(struct rib_entry *, void *),
+                   void (*)(void *, u_int8_t),
+                   int (*)(void *));
+void            rib_dump_terminate(u_int16_t, void *,
+                   void (*)(struct rib_entry *, void *));
 
 static inline struct rib *
 re_rib(struct rib_entry *re)
 {
-       return (struct rib *)((intptr_t)re->__rib & ~1);
+       return rib_byid(re->rib_id);
 }
 
 static inline int
 rib_valid(u_int16_t rid)
 {
-       if (rid >= rib_size || *ribs[rid].name == '\0')
+       if (rid == RIB_NOTFOUND || rid >= rib_size || *ribs[rid].name == '\0')
                return 0;
        return 1;
 }
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   22 Oct 2018 21:13:58 -0000
@@ -40,36 +40,56 @@ 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(u_int16_t);
 
 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;
+       u_int16_t                        ctx_rib_id;
+       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);
 static int      prefix_move(struct prefix *, struct rde_peer *,
                    struct rde_aspath *, struct filterstate *, u_int8_t);
 
-static inline void
+static inline struct rib_entry *
 re_lock(struct rib_entry *re)
 {
-       re->__rib = (struct rib *)((intptr_t)re->__rib | 1);
+       if (re->lock != 0)
+               log_warnx("%s: entry already locked", __func__);
+       re->lock = 1;
+       return re;
 }
 
-static inline void
+static inline struct rib_entry *
 re_unlock(struct rib_entry *re)
 {
-       re->__rib = (struct rib *)((intptr_t)re->__rib & ~1);
+       if (re->lock == 0)
+               log_warnx("%s: entry already unlocked", __func__);
+       re->lock = 0;
+       return re;
 }
 
 static inline int
 re_is_locked(struct rib_entry *re)
 {
-       return ((intptr_t)re->__rib & 1);
+       return (re->lock != 0);
 }
 
 static inline struct rib_tree *
@@ -78,6 +98,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)
@@ -94,7 +120,7 @@ rib_new(char *name, u_int rtableid, u_in
                if ((xribs = reallocarray(ribs, id + 1,
                    sizeof(struct rib_desc))) == NULL) {
                        /* XXX this is not clever */
-                       fatal("rib_add");
+                       fatal(NULL);
                }
                ribs = xribs;
                rib_size = id + 1;
@@ -113,24 +139,33 @@ rib_new(char *name, u_int rtableid, u_in
                fatal(NULL);
        TAILQ_INIT(ribs[id].in_rules);
 
+       log_debug("%s: %s -> %u", __func__, name, id);
        return (&ribs[id].rib);
 }
 
 struct rib *
+rib_byid(u_int16_t rid)
+{
+       if (rib_valid(rid))
+               return &ribs[rid].rib;
+       return NULL;
+}
+
+u_int16_t
 rib_find(char *name)
 {
        u_int16_t id;
 
        /* no name returns the first Loc-RIB */
        if (name == NULL || *name == '\0')
-               return (&ribs[RIB_LOC_START].rib);
+               return RIB_LOC_START;
 
        for (id = 0; id < rib_size; id++) {
                if (!strcmp(ribs[id].name, name))
-                       return (&ribs[id].rib);
+                       return id;
        }
 
-       return (NULL);
+       return RIB_NOTFOUND;
 }
 
 struct rib_desc *
@@ -146,6 +181,8 @@ rib_free(struct rib *rib)
        struct rib_entry *re, *xre;
        struct prefix *p, *np;
 
+       rib_dump_abort(rib->id);
+
        for (re = RB_MIN(rib_tree, rib_tree(rib)); re != NULL; re = xre) {
                xre = RB_NEXT(rib_tree, rib_tree(rib), re);
 
@@ -177,23 +214,21 @@ 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)
 {
-       struct rib_entry xre;
+       struct rib_entry xre, *re;
        struct pt_entry *pte;
 
        pte = pt_fill(prefix, prefixlen);
        bzero(&xre, sizeof(xre));
        xre.prefix = pte;
 
-       return (RB_FIND(rib_tree, rib_tree(rib), &xre));
+       re = RB_FIND(rib_tree, rib_tree(rib), &xre);
+       if (re && re->rib_id != rib->id)
+               fatalx("%s: Unexpected RIB %u != %u.", __func__,
+                   re->rib_id, rib->id);
+       return re;
 }
 
 struct rib_entry *
@@ -240,7 +275,7 @@ rib_add(struct rib *rib, struct bgpd_add
 
        LIST_INIT(&re->prefix_h);
        re->prefix = pte;
-       re->__rib = rib;
+       re->rib_id = rib->id;
 
        if (RB_INSERT(rib_tree, rib_tree(rib), re) != NULL) {
                log_warnx("rib_add: insert failed");
@@ -282,33 +317,45 @@ 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              *rib;
        struct rib_entry        *re;
        unsigned int             i;
 
+       rib = rib_byid(ctx->ctx_rib_id);
+       if (rib == NULL)
+               fatalx("%s: rib id %u gone", __func__, ctx->ctx_rib_id);
+
        if (ctx->ctx_re == NULL)
-               re = RB_MIN(rib_tree, rib_tree(ctx->ctx_rib));
+               re = RB_MIN(rib_tree, rib_tree(rib));
        else
                re = rib_restart(ctx);
 
        for (i = 0; re != NULL; re = 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);
                if (ctx->ctx_aid != AID_UNSPEC &&
                    ctx->ctx_aid != re->prefix->aid)
                        continue;
@@ -323,28 +370,89 @@ 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(u_int16_t id)
+{
+       struct rib_context *ctx, *next;
+
+       LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next) {
+               if (id != ctx->ctx_rib_id)
+                       continue;
+               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(u_int16_t id, 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_id = id;
+       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;
+}
+
+void
+rib_dump_terminate(u_int16_t id, void *arg,
+    void (*upcall)(struct rib_entry *, void *))
+{
+       struct rib_context *ctx, *next;
+
+       LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next) {
+               if (id != ctx->ctx_rib_id || ctx->ctx_arg != arg ||
+                   ctx->ctx_upcall != upcall)
+                       continue;
+               if (ctx->ctx_done)
+                       ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid);
+               LIST_REMOVE(ctx, entry);
+               free(ctx);
+       }
 }
 
 /* path specific functions */
Index: rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.101
diff -u -p -r1.101 rde_update.c
--- rde_update.c        15 Oct 2018 10:44:47 -0000      1.101
+++ rde_update.c        21 Oct 2018 11:13:08 -0000
@@ -543,9 +543,9 @@ up_generate_default(struct filter_head *
        bzero(&p, sizeof(p));
        bzero(&addr, sizeof(addr));
        addr.aid = aid;
-       re = rib_get(peer->rib, &addr, 0);
+       re = rib_get(rib_byid(peer->loc_rib_id), &addr, 0);
        if (re == NULL)
-               re = rib_add(peer->rib, &addr, 0);
+               re = rib_add(rib_byid(peer->loc_rib_id), &addr, 0);
        p.re = re;
        p.aspath = asp;
        p.peer = peer;
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 11:03:36 -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