When running something like:
        bgpctl show rib | head -5
bgpctl will exit quickly but bgpd will still do the full table walk,
sending imsg from RDE to SE and then the SE will drop them since the
connection to bgpctl died. In most cases this is not a big deal but for
the show rib commands a lot of work is done for nothing.

Introduce IMSG_CTL_TERMINATE and use it for those bgpctl commands that
are using rde_dump_ctx_new() to walk the RIB. When the RDE gets a
IMSG_CTL_TERMINATE command it will terminate the RIB walker.

Noticed and requested by job@
-- 
:wq Claudio

Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.357
diff -u -p -r1.357 bgpd.h
--- bgpd.h      11 Dec 2018 09:02:14 -0000      1.357
+++ bgpd.h      19 Dec 2018 15:34:09 -0000
@@ -437,6 +437,7 @@ enum imsg_type {
        IMSG_CTL_SHOW_TIMER,
        IMSG_CTL_LOG_VERBOSE,
        IMSG_CTL_SHOW_FIB_TABLES,
+       IMSG_CTL_TERMINATE,
        IMSG_NETWORK_ADD,
        IMSG_NETWORK_ASPATH,
        IMSG_NETWORK_ATTR,
Index: control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.91
diff -u -p -r1.91 control.c
--- control.c   28 Nov 2018 08:32:27 -0000      1.91
+++ control.c   19 Dec 2018 15:38:20 -0000
@@ -188,6 +188,9 @@ control_close(int fd)
                return (0);
        }
 
+       if (c->terminate && c->ibuf.pid)
+               imsg_ctl_rde(IMSG_CTL_TERMINATE, c->ibuf.pid, NULL, 0);
+
        msgbuf_clear(&c->ibuf.w);
        TAILQ_REMOVE(&ctl_conns, c, entry);
 
@@ -247,12 +250,12 @@ control_dispatch_msg(struct pollfd *pfd,
                        case IMSG_CTL_SHOW_NEIGHBOR:
                        case IMSG_CTL_SHOW_NEXTHOP:
                        case IMSG_CTL_SHOW_INTERFACE:
-                       case IMSG_CTL_SHOW_RIB:
-                       case IMSG_CTL_SHOW_RIB_PREFIX:
                        case IMSG_CTL_SHOW_RIB_MEM:
-                       case IMSG_CTL_SHOW_NETWORK:
                        case IMSG_CTL_SHOW_TERSE:
                        case IMSG_CTL_SHOW_TIMER:
+                       case IMSG_CTL_SHOW_NETWORK:
+                       case IMSG_CTL_SHOW_RIB:
+                       case IMSG_CTL_SHOW_RIB_PREFIX:
                                break;
                        default:
                                /* clear imsg type to prevent processing */
@@ -459,14 +462,17 @@ control_dispatch_msg(struct pollfd *pfd,
                                        break;
                                }
                                c->ibuf.pid = imsg.hdr.pid;
+                               c->terminate = 1;
                                imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid,
                                    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
                        } else
                                log_warnx("got IMSG_CTL_SHOW_RIB with "
                                    "wrong length");
                        break;
-               case IMSG_CTL_SHOW_RIB_MEM:
                case IMSG_CTL_SHOW_NETWORK:
+                       c->terminate = 1;
+                       /* FALLTHROUGH */
+               case IMSG_CTL_SHOW_RIB_MEM:
                        c->ibuf.pid = imsg.hdr.pid;
                        imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid,
                            imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
@@ -511,6 +517,10 @@ control_imsg_relay(struct imsg *imsg)
 
        if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
                return (0);
+
+       /* if command finished no need to send exit message */
+       if (imsg->hdr.type == IMSG_CTL_END || imsg->hdr.type == IMSG_CTL_RESULT)
+               c->terminate = 0;
 
        if (!c->throttled && c->ibuf.w.queued > CTL_MSG_HIGH_MARK) {
                if (imsg_ctl_rde(IMSG_XOFF, imsg->hdr.pid, NULL, 0) != -1)
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.452
diff -u -p -r1.452 rde.c
--- rde.c       11 Dec 2018 09:02:14 -0000      1.452
+++ rde.c       19 Dec 2018 15:33:55 -0000
@@ -71,7 +71,8 @@ void           rde_reflector(struct rde_peer *, 
 
 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_ctx_throttle(pid_t, int);
+void            rde_dump_ctx_terminate(pid_t);
 void            rde_dump_mrt_new(struct mrt *, pid_t, int);
 
 int             rde_rdomain_import(struct rde_aspath *, struct rdomain *);
@@ -133,7 +134,7 @@ int                  softreconfig;
 struct rde_dump_ctx {
        LIST_ENTRY(rde_dump_ctx)        entry;
        struct ctl_show_rib_request     req;
-       sa_family_t                     af;
+       u_int16_t                       rid;
        u_int8_t                        throttled;
 };
 
@@ -658,6 +659,9 @@ badnetdel:
                                rde_dump_ctx_throttle(imsg.hdr.pid, 1);
                        }
                        break;
+               case IMSG_CTL_TERMINATE:
+                       rde_dump_ctx_terminate(imsg.hdr.pid);
+                       break;
                default:
                        break;
                }
@@ -2320,6 +2324,7 @@ 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->rid = rid;
        switch (ctx->req.type) {
        case IMSG_CTL_SHOW_NETWORK:
                if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
@@ -2363,7 +2368,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
                free(ctx);
                return;
        default:
-               fatalx("rde_dump_ctx_new: unsupported imsg type");
+               fatalx("%s: unsupported imsg type", __func__);
        }
        LIST_INSERT_HEAD(&rde_dump_h, ctx, entry);
 }
@@ -2376,6 +2381,33 @@ rde_dump_ctx_throttle(pid_t pid, int thr
        LIST_FOREACH(ctx, &rde_dump_h, entry) {
                if (ctx->req.pid == pid) {
                        ctx->throttled = throttle;
+                       return;
+               }
+       }
+}
+
+void
+rde_dump_ctx_terminate(pid_t pid)
+{
+       struct rde_dump_ctx     *ctx;
+
+       LIST_FOREACH(ctx, &rde_dump_h, entry) {
+               if (ctx->req.pid == pid) {
+                       void (*upcall)(struct rib_entry *, void *);
+                       switch (ctx->req.type) {
+                       case IMSG_CTL_SHOW_NETWORK:
+                               upcall = network_dump_upcall;
+                               break;
+                       case IMSG_CTL_SHOW_RIB:
+                               upcall = rde_dump_upcall;
+                               break;
+                       case IMSG_CTL_SHOW_RIB_PREFIX:
+                               upcall = rde_dump_prefix_upcall;
+                               break;
+                       default:
+                               fatalx("%s: unsupported imsg type", __func__);
+                       }
+                       rib_dump_terminate(ctx->rid, ctx, upcall);
                        return;
                }
        }
Index: session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.125
diff -u -p -r1.125 session.h
--- session.h   24 Oct 2018 08:26:37 -0000      1.125
+++ session.h   19 Dec 2018 15:38:03 -0000
@@ -143,6 +143,7 @@ struct ctl_conn {
        struct imsgbuf          ibuf;
        int                     restricted;
        int                     throttled;
+       int                     terminate;
 };
 
 TAILQ_HEAD(ctl_conns, ctl_conn)        ctl_conns;

Reply via email to