Index | Thread | Search

From:
Claudio Jeker <cjeker@diehard.n-r-g.com>
Subject:
ospfd: rewrite the imsg handling part 2
To:
tech@openbsd.org
Date:
Mon, 14 Sep 2026 15:49:24 +0200

Download raw body.

Thread
  • Claudio Jeker:

    ospfd: rewrite the imsg handling part 2

Here is part 2 which extends the imsgev.c code to also handle read / write
internally.

imsgev_new() now takes a imsg_handler and and error_handler as callbacks
and calls them when imsg are available or when an error happened.

The imsg_handler now simply gets a imsg pointer and so functions like
main_dispatch_ospfe become a lot simpler.

The error handler is called with a event of EV_WRITE or EV_READ and passes
errno or 0 (for the connection close case).
ospfd does not care about any of that. Since errors are either ignored
(control socker) or are terminal.

While touching all the dispatch functions I could not help myself and also
use the imsg API properly and stop peaking at the imsg hdr or imsg->data.

As before this seems to work in my limited use case.
-- 
:wq Claudio

diff --git usr.sbin/ospfd/control.c usr.sbin/ospfd/control.c
index 396af06f422..67a83d5e7e6 100644
--- usr.sbin/ospfd/control.c
+++ usr.sbin/ospfd/control.c
@@ -38,7 +38,9 @@ TAILQ_HEAD(ctl_conns, ctl_conn)	ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns);
 
 struct ctl_conn	*control_connbyfd(int);
 struct ctl_conn	*control_connbypid(pid_t);
-void		 control_close(int);
+void		 control_close(struct ctl_conn *);
+void		 control_dispatch_imsg(struct imsg *, void *);
+void		 control_dispatch_error(struct imsgbuf *, void *, short, int);
 
 struct {
 	struct event	ev;
@@ -176,7 +178,8 @@ control_accept(int listenfd, short event, void *bula)
 		return;
 	}
 
-	if ((c->imsgbuf = imsgev_new(connfd, control_dispatch_imsg)) == NULL) {
+	if ((c->imsgbuf = imsgev_new(connfd, control_dispatch_imsg,
+	    control_dispatch_error, c)) == NULL) {
 		log_warn("imsgbuf_init");
 		close(connfd);
 		free(c);
@@ -213,15 +216,8 @@ control_connbypid(pid_t pid)
 }
 
 void
-control_close(int fd)
+control_close(struct ctl_conn *c)
 {
-	struct ctl_conn	*c;
-
-	if ((c = control_connbyfd(fd)) == NULL) {
-		log_warn("control_close: fd %d: not found", fd);
-		return;
-	}
-
 	TAILQ_REMOVE(&ctl_conns, c, entry);
 	imsgev_free(c->imsgbuf);
 
@@ -235,104 +231,74 @@ control_close(int fd)
 }
 
 void
-control_dispatch_imsg(int fd, short event, void *bula)
+control_dispatch_imsg(struct imsg *imsg, void *arg)
 {
-	struct ctl_conn	*c;
-	struct imsg	 imsg;
-	int		 n, verbose;
+	struct ctl_conn	*c = arg;
+	uint32_t	 type;
+	pid_t		 pid;
+	int		 verbose;
 	unsigned int	 ifidx;
 
-	if ((c = control_connbyfd(fd)) == NULL) {
-		log_warn("control_dispatch_imsg: fd %d: not found", fd);
-		return;
-	}
-
-	if (event & EV_READ) {
-		if (imsgbuf_read(c->imsgbuf) != 1) {
-			control_close(fd);
-			return;
-		}
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(c->imsgbuf) == -1) {
-			control_close(fd);
-			return;
-		}
-	}
-
-	for (;;) {
-		if ((n = imsgbuf_get(c->imsgbuf, &imsg)) == -1) {
-			control_close(fd);
-			return;
-		}
-
-		if (n == 0)
+	c->imsgbuf->pid = pid = imsg_get_pid(imsg);
+	type = imsg_get_type(imsg);
+	switch (type) {
+	case IMSG_CTL_FIB_COUPLE:
+	case IMSG_CTL_FIB_DECOUPLE:
+		ospfe_fib_update(type);
+		/* FALLTHROUGH */
+	case IMSG_CTL_FIB_RELOAD:
+	case IMSG_CTL_RELOAD:
+		ospfe_imsg_compose_parent(type, 0, NULL, 0);
+		break;
+	case IMSG_CTL_KROUTE:
+	case IMSG_CTL_KROUTE_ADDR:
+	case IMSG_CTL_IFINFO:
+		ospfe_imsg_forward_parent(imsg);
+		break;
+	case IMSG_CTL_SHOW_INTERFACE:
+		if (imsg_get_data(imsg, &ifidx, sizeof(ifidx)) == -1)
 			break;
 
-		c->imsgbuf->pid = imsg.hdr.pid;
-		switch (imsg.hdr.type) {
-		case IMSG_CTL_FIB_COUPLE:
-		case IMSG_CTL_FIB_DECOUPLE:
-			ospfe_fib_update(imsg.hdr.type);
-			/* FALLTHROUGH */
-		case IMSG_CTL_FIB_RELOAD:
-		case IMSG_CTL_RELOAD:
-			ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
-			break;
-		case IMSG_CTL_KROUTE:
-		case IMSG_CTL_KROUTE_ADDR:
-		case IMSG_CTL_IFINFO:
-			ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
-			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
-			break;
-		case IMSG_CTL_SHOW_INTERFACE:
-			if (imsg.hdr.len == IMSG_HEADER_SIZE +
-			    sizeof(ifidx)) {
-				memcpy(&ifidx, imsg.data, sizeof(ifidx));
-				ospfe_iface_ctl(c, ifidx);
-				imsg_compose(c->imsgbuf, IMSG_CTL_END, 0,
-				    0, -1, NULL, 0);
-			}
-			break;
-		case IMSG_CTL_SHOW_DATABASE:
-		case IMSG_CTL_SHOW_DB_EXT:
-		case IMSG_CTL_SHOW_DB_NET:
-		case IMSG_CTL_SHOW_DB_RTR:
-		case IMSG_CTL_SHOW_DB_SELF:
-		case IMSG_CTL_SHOW_DB_SUM:
-		case IMSG_CTL_SHOW_DB_ASBR:
-		case IMSG_CTL_SHOW_DB_OPAQ:
-		case IMSG_CTL_SHOW_RIB:
-		case IMSG_CTL_SHOW_SUM:
-			ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
-			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
-			break;
-		case IMSG_CTL_SHOW_NBR:
-			ospfe_nbr_ctl(c);
-			break;
-		case IMSG_CTL_LOG_VERBOSE:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE +
-			    sizeof(verbose))
-				break;
-
-			/* forward to other processes */
-			ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
-			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
-			ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
-			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
-
-			memcpy(&verbose, imsg.data, sizeof(verbose));
-			log_setverbose(verbose);
+		ospfe_iface_ctl(c, ifidx);
+		break;
+	case IMSG_CTL_SHOW_DATABASE:
+	case IMSG_CTL_SHOW_DB_EXT:
+	case IMSG_CTL_SHOW_DB_NET:
+	case IMSG_CTL_SHOW_DB_RTR:
+	case IMSG_CTL_SHOW_DB_SELF:
+	case IMSG_CTL_SHOW_DB_SUM:
+	case IMSG_CTL_SHOW_DB_ASBR:
+	case IMSG_CTL_SHOW_DB_OPAQ:
+	case IMSG_CTL_SHOW_RIB:
+	case IMSG_CTL_SHOW_SUM:
+		ospfe_imsg_forward_rde(imsg);
+		break;
+	case IMSG_CTL_SHOW_NBR:
+		ospfe_nbr_ctl(c);
+		break;
+	case IMSG_CTL_LOG_VERBOSE:
+		if (imsg_get_data(imsg, &verbose, sizeof(verbose)) == -1)
 			break;
-		default:
-			log_debug("control_dispatch_imsg: "
-			    "error handling imsg %d", imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
+
+		/* forward to other processes */
+		ospfe_imsg_forward_parent(imsg);
+		ospfe_imsg_forward_rde(imsg);
+		log_setverbose(verbose);
+		break;
+	default:
+		log_debug("control_dispatch_imsg: "
+		    "error handling imsg %d", type);
+		break;
 	}
+}
+
+void
+control_dispatch_error(struct imsgbuf *ibuf, void *arg, short event, int error)
+{
+	struct ctl_conn	*c = arg;
 
-	imsg_event_add(c->imsgbuf, imsgbuf_get_userdata(c->imsgbuf));
+	/* silently discard session, ospfctl will complain to user */
+	control_close(c);
 }
 
 int
@@ -340,9 +306,8 @@ control_imsg_relay(struct imsg *imsg)
 {
 	struct ctl_conn	*c;
 
-	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
+	if ((c = control_connbypid(imsg_get_pid(imsg))) == NULL)
 		return (0);
 
-	return (imsg_compose(c->imsgbuf, imsg->hdr.type, 0, imsg->hdr.pid,
-	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
+	return (imsg_forward(c->imsgbuf, imsg));
 }
diff --git usr.sbin/ospfd/control.h usr.sbin/ospfd/control.h
index 7608b7805e2..d0ea95f7e6f 100644
--- usr.sbin/ospfd/control.h
+++ usr.sbin/ospfd/control.h
@@ -32,7 +32,6 @@ int	control_check(char *);
 int	control_init(char *);
 int	control_listen(int);
 void	control_accept(int, short, void *);
-void	control_dispatch_imsg(int, short, void *);
 int	control_imsg_relay(struct imsg *);
 void	control_cleanup(void);
 
diff --git usr.sbin/ospfd/imsgev.c usr.sbin/ospfd/imsgev.c
index 9948006e8cb..6ee40c40800 100644
--- usr.sbin/ospfd/imsgev.c
+++ usr.sbin/ospfd/imsgev.c
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 
@@ -25,28 +26,76 @@
 
 struct imsgev {
 	struct imsgbuf		 ibuf;
-	void			(*handler)(int, short, void *);
-	struct event		 ev;
-	short			 events;
+	struct event		 rev;
+	struct event		 wev;
+	void			(*imsg_handler)(struct imsg *, void *);
+	void			(*error_handler)(struct imsgbuf *,
+				    void *, short, int);
+	void			 *arg;
 };
 
-void
-imsg_event_add(struct imsgbuf *imsgbuf, void *udata)
+static void
+imsgev_add(struct imsgbuf *imsgbuf, void *udata)
 {
 	struct imsgev *iev = udata;
 
-	iev->events = EV_READ;
-	if (imsgbuf_queuelen(&iev->ibuf) > 0)
-		iev->events |= EV_WRITE;
+	event_add(&iev->wev, NULL);
+}
+
+static void
+imsgev_write(int fd, short event, void *arg)
+{
+	struct imsgev *iev = arg;
+	struct imsgbuf *imsgbuf = &iev->ibuf;
+
+	if (event & EV_WRITE) {
+		if (imsgbuf_write(imsgbuf) == -1) {
+			iev->error_handler(imsgbuf, iev->arg, EV_WRITE, errno);
+			return;
+		}
+	}
+
+	if (imsgbuf_queuelen(imsgbuf) == 0)
+		event_del(&iev->wev);
+}
 
-	event_del(&iev->ev);
-	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler,
-	    &iev->ibuf);
-	event_add(&iev->ev, NULL);
+static void
+imsgev_read(int fd, short event, void *arg)
+{
+	struct imsgev *iev = arg;
+	struct imsgbuf *imsgbuf = &iev->ibuf;
+	struct imsg imsg;
+	int n;
+
+	if (event & EV_READ) {
+		if ((n = imsgbuf_read(imsgbuf)) == -1) {
+			iev->error_handler(imsgbuf, iev->arg, EV_READ, errno);
+			return;
+		}
+		if (n == 0) {
+			iev->error_handler(imsgbuf, iev->arg, EV_READ, 0);
+			return;
+		}
+	}
+
+	for (;;) {
+		if ((n = imsgbuf_get(imsgbuf, &imsg)) == -1) {
+			iev->error_handler(imsgbuf, iev->arg, EV_READ, errno);
+			return;
+		}
+		if (n == 0)
+			break;
+
+		iev->imsg_handler(&imsg, iev->arg);
+
+		imsg_free(&imsg);
+	}
 }
 
 struct imsgbuf *
-imsgev_new(int fd, void (*handler)(int, short, void *))
+imsgev_new(int fd, void (*imsg_handler)(struct imsg *, void *),
+    void (*error_handler)(struct imsgbuf *imsgbuf, void *, short, int),
+    void *arg)
 {
 	struct imsgev *iev;
 
@@ -59,13 +108,15 @@ imsgev_new(int fd, void (*handler)(int, short, void *))
 	}
 
 	imsgbuf_set_userdata(&iev->ibuf, iev);
-	imsgbuf_set_close_callback(&iev->ibuf, imsg_event_add);
-	iev->handler = handler;
+	imsgbuf_set_close_callback(&iev->ibuf, imsgev_add);
+	iev->imsg_handler = imsg_handler;
+	iev->error_handler = error_handler;
+	iev->arg = arg;
 
-	iev->events = EV_READ;
-	event_set(&iev->ev, fd, iev->events, iev->handler, &iev->ibuf);
-	event_add(&iev->ev, NULL);
+	event_set(&iev->rev, fd, EV_READ | EV_PERSIST, imsgev_read, iev);
+	event_set(&iev->wev, fd, EV_WRITE | EV_PERSIST, imsgev_write, iev);
 
+	event_add(&iev->rev, NULL);
 	return &iev->ibuf;
 }
 
@@ -79,6 +130,7 @@ imsgev_free(struct imsgbuf *imsgbuf)
 	close(imsgbuf->fd);
 	imsgbuf_clear(imsgbuf);
 
-	event_del(&iev->ev);
+	event_del(&iev->rev);
+	event_del(&iev->wev);
 	free(iev);
 }
diff --git usr.sbin/ospfd/imsgev.h usr.sbin/ospfd/imsgev.h
index 75c4d1c587a..bb823245e86 100644
--- usr.sbin/ospfd/imsgev.h
+++ usr.sbin/ospfd/imsgev.h
@@ -18,6 +18,6 @@
 
 #include <imsg.h>
 
-void		 imsg_event_add(struct imsgbuf *, void *);
-struct imsgbuf	*imsgev_new(int, void (*)(int, short, void *));
+struct imsgbuf	*imsgev_new(int, void (*)(struct imsg *, void *),
+		    void (*)(struct imsgbuf *, void *, short, int), void *);
 void		 imsgev_free(struct imsgbuf *);
diff --git usr.sbin/ospfd/ospfd.c usr.sbin/ospfd/ospfd.c
index 9a172415e82..8d171442527 100644
--- usr.sbin/ospfd/ospfd.c
+++ usr.sbin/ospfd/ospfd.c
@@ -52,8 +52,8 @@ void		main_sig_handler(int, short, void *);
 __dead void	usage(void);
 __dead void	ospfd_shutdown(void);
 
-void	main_dispatch_ospfe(int, short, void *);
-void	main_dispatch_rde(int, short, void *);
+void	main_dispatch_ospfe(struct imsg *, void *);
+void	main_dispatch_rde(struct imsg *, void *);
 
 int	ospf_reload(void);
 int	ospf_sendboth(enum imsg_type, void *, u_int16_t);
@@ -261,9 +261,9 @@ main(int argc, char *argv[])
 	close(pipe_ospfe2rde[1]);
 
 	if ((imsg_ospfe = imsgev_new(pipe_parent2ospfe[0],
-	    main_dispatch_ospfe)) == NULL ||
+	    main_dispatch_ospfe, ospfd_dispatch_error, NULL)) == NULL ||
 	    (imsg_rde = imsgev_new(pipe_parent2rde[0],
-	    main_dispatch_rde)) == NULL)
+	    main_dispatch_rde, ospfd_dispatch_error, NULL)) == NULL)
 		fatal(NULL);
 	imsgbuf_allow_fdpass(imsg_ospfe);
 
@@ -332,142 +332,101 @@ ospfd_shutdown(void)
 
 /* imsg handling */
 void
-main_dispatch_ospfe(int fd, short event, void *arg)
+main_dispatch_ospfe(struct imsg *imsg, void *arg)
 {
-	struct imsgbuf		*ibuf = arg;
-	struct imsg		 imsg;
+	uint32_t		 type;
 	struct demote_msg	 dmsg;
-	int			 n, shut = 0, verbose;
+	char			 ifname[IFNAMSIZ];
+	int			 verbose;
 
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
-		}
+	type = imsg_get_type(imsg);
+	switch (type) {
+	case IMSG_CTL_RELOAD:
+		if (ospf_reload() == -1)
+			log_warnx("configuration reload failed");
+		else
+			log_debug("configuration reloaded");
+		break;
+	case IMSG_CTL_FIB_COUPLE:
+		kr_fib_couple();
+		break;
+	case IMSG_CTL_FIB_DECOUPLE:
+		kr_fib_decouple();
+		break;
+	case IMSG_CTL_FIB_RELOAD:
+		kr_fib_reload();
+		break;
+	case IMSG_CTL_KROUTE:
+	case IMSG_CTL_KROUTE_ADDR:
+		kr_show_route(imsg);
+		break;
+	case IMSG_CTL_IFINFO:
+		if (imsg_get_len(imsg) == 0)
+			kr_ifinfo(NULL, imsg_get_pid(imsg));
+		else if (imsg_get_len(imsg) != IFNAMSIZ ||
+		    imsg_get_strbuf(imsg, ifname, sizeof(ifname)) == -1)
+			log_warnx("bad IFINFO request");
+		else
+			kr_ifinfo(ifname, imsg_get_pid(imsg));
+		break;
+	case IMSG_DEMOTE:
+		if (imsg_get_len(imsg) != sizeof(dmsg) ||
+		    imsg_get_strbuf(imsg, dmsg.demote_group,
+		    sizeof(dmsg.demote_group)) == -1 ||
+		    imsg_get_buf(imsg, &dmsg.level, sizeof(dmsg.level)) == -1)
+			fatalx("bad demote request from OE");
+		carp_demote_set(dmsg.demote_group, dmsg.level);
+		break;
+	case IMSG_CTL_LOG_VERBOSE:
+		if (imsg_get_data(imsg, &verbose, sizeof(verbose)) == -1)
+			log_warn("wrong imsg len");
+		else
+			log_setverbose(verbose);
+		break;
+	default:
+		log_debug("main_dispatch_ospfe: error handling imsg %d",
+		    type);
+		break;
 	}
+}
 
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("imsgbuf_get");
-		if (n == 0)
-			break;
+void
+main_dispatch_rde(struct imsg *imsg, void *arg)
+{
+	uint32_t	type;
 
-		switch (imsg.hdr.type) {
-		case IMSG_CTL_RELOAD:
-			if (ospf_reload() == -1)
-				log_warnx("configuration reload failed");
-			else
-				log_debug("configuration reloaded");
-			break;
-		case IMSG_CTL_FIB_COUPLE:
-			kr_fib_couple();
-			break;
-		case IMSG_CTL_FIB_DECOUPLE:
-			kr_fib_decouple();
-			break;
-		case IMSG_CTL_FIB_RELOAD:
-			kr_fib_reload();
-			break;
-		case IMSG_CTL_KROUTE:
-		case IMSG_CTL_KROUTE_ADDR:
-			kr_show_route(&imsg);
-			break;
-		case IMSG_CTL_IFINFO:
-			if (imsg.hdr.len == IMSG_HEADER_SIZE)
-				kr_ifinfo(NULL, imsg.hdr.pid);
-			else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ)
-				kr_ifinfo(imsg.data, imsg.hdr.pid);
-			else
-				log_warnx("IFINFO request with wrong len");
-			break;
-		case IMSG_DEMOTE:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg))
-				fatalx("invalid size of OE request");
-			memcpy(&dmsg, imsg.data, sizeof(dmsg));
-			carp_demote_set(dmsg.demote_group, dmsg.level);
-			break;
-		case IMSG_CTL_LOG_VERBOSE:
-			if (imsg_get_data(&imsg, &verbose, sizeof(verbose)) ==
-			    -1)
-				log_warn("wrong imsg len");
-			else
-				log_setverbose(verbose);
-			break;
-		default:
-			log_debug("main_dispatch_ospfe: error handling imsg %d",
-			    imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
+	type = imsg_get_type(imsg);
+	switch (type) {
+	case IMSG_KROUTE_CHANGE:
+		if (kr_change(imsg))
+			log_warn("main_dispatch_rde: error changing route");
+		break;
+	case IMSG_KROUTE_DELETE:
+		if (kr_delete(imsg))
+			log_warn("main_dispatch_rde: error deleting route");
+		break;
+	default:
+		log_debug("main_dispatch_rde: error handling imsg %d", type);
+		break;
 	}
 }
 
 void
-main_dispatch_rde(int fd, short event, void *arg)
+ospfd_dispatch_error(struct imsgbuf *ibuf, void *arg, short event, int error)
 {
-	struct imsgbuf  *ibuf = arg;
-	struct imsg	 imsg;
-	int		 n, shut = 0;
-
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
-		}
-	}
+	const char *dir, *err = "connection closed";
 
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("imsgbuf_get");
-		if (n == 0)
-			break;
+	if (event & EV_READ)
+		dir = "imsg read";
+	else
+		dir = "imsg write";
 
-		switch (imsg.hdr.type) {
-		case IMSG_KROUTE_CHANGE:
-			if (kr_change(&imsg))
-				log_warn("main_dispatch_rde: error changing "
-				    "route");
-			break;
-		case IMSG_KROUTE_DELETE:
-			if (kr_delete(&imsg))
-				log_warn("main_dispatch_rde: error deleting "
-				    "route");
-			break;
-		default:
-			log_debug("main_dispatch_rde: error handling imsg %d",
-			    imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
-	}
+	if (error)
+		err = strerror(error);
+	log_warnx("%s: %s", dir, err);
+
+	/* this pipe is dead, exit asap, cleanup is done there */
+	event_loopexit(NULL);
 }
 
 void
@@ -497,7 +456,7 @@ ospf_redistribute(struct kroute *kr, u_int32_t *metric)
 	struct in_addr		 addr;
 	struct kif		*kif;
 	struct redistribute	*r;
-	int		 	 is_default, depend_ok;
+	int			 is_default, depend_ok;
 
 	bzero(&addr, sizeof(addr));
 
@@ -682,8 +641,8 @@ ospf_reload(void)
 		return (-1);
 
 	/* No router-id was specified, keep existing value */
-        if (xconf->rtr_id.s_addr == 0)
-                xconf->rtr_id.s_addr = ospfd_conf->rtr_id.s_addr;
+	if (xconf->rtr_id.s_addr == 0)
+		xconf->rtr_id.s_addr = ospfd_conf->rtr_id.s_addr;
 
 	/* Abort the reload if rtr_id changed */
 	if (ospfd_conf->rtr_id.s_addr != xconf->rtr_id.s_addr) {
@@ -934,8 +893,7 @@ merge_interfaces(struct area *a, struct area *xa)
 		md_list_clr(&i->auth_md_list);
 		md_list_copy(&i->auth_md_list, &xi->auth_md_list);
 
-		strlcpy(i->dependon, xi->dependon,
-		        sizeof(i->dependon));
+		strlcpy(i->dependon, xi->dependon, sizeof(i->dependon));
 		i->depend_ok = xi->depend_ok;
 
 		if (i->passive != xi->passive) {
diff --git usr.sbin/ospfd/ospfd.h usr.sbin/ospfd/ospfd.h
index 7e8a9955e5b..54af367ee1b 100644
--- usr.sbin/ospfd/ospfd.h
+++ usr.sbin/ospfd/ospfd.h
@@ -606,6 +606,7 @@ u_int16_t	 rtlabel_tag2id(u_int32_t);
 void		 rtlabel_tag(u_int16_t, u_int32_t);
 
 /* ospfd.c */
+void	ospfd_dispatch_error(struct imsgbuf *, void *, short, int);
 void	main_imsg_compose_ospfe(int, pid_t, void *, u_int16_t);
 void	main_imsg_compose_ospfe_fd(int, pid_t, int);
 void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
diff --git usr.sbin/ospfd/ospfe.c usr.sbin/ospfd/ospfe.c
index 47c48cf0318..99e545fab5c 100644
--- usr.sbin/ospfd/ospfe.c
+++ usr.sbin/ospfd/ospfe.c
@@ -46,6 +46,8 @@ void		 ospfe_sig_handler(int, short, void *);
 __dead void	 ospfe_shutdown(void);
 void		 orig_rtr_lsa_all(struct area *);
 struct iface	*find_vlink(struct abr_rtr *);
+void		 ospfe_dispatch_main(struct imsg *, void *);
+void		 ospfe_dispatch_rde(struct imsg *, void *);
 
 struct ospfd_conf	*oeconf = NULL, *noeconf;
 static struct imsgbuf	*imsg_main;
@@ -153,9 +155,9 @@ ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2],
 	close(pipe_parent2rde[1]);
 
 	if ((imsg_rde = imsgev_new(pipe_ospfe2rde[0],
-	    ospfe_dispatch_rde)) == NULL ||
+	    ospfe_dispatch_rde, ospfd_dispatch_error, NULL)) == NULL ||
 	    (imsg_main = imsgev_new(pipe_parent2ospfe[1],
-	    ospfe_dispatch_main)) == NULL)
+	    ospfe_dispatch_main, ospfd_dispatch_error, NULL)) == NULL)
 		fatal(NULL);
 	imsgbuf_allow_fdpass(imsg_main);
 
@@ -239,532 +241,469 @@ ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
 	return (imsg_compose(imsg_rde, type, peerid, pid, -1, data, datalen));
 }
 
+int
+ospfe_imsg_forward_parent(struct imsg *imsg)
+{
+	return (imsg_forward(imsg_main, imsg));
+}
+
+int
+ospfe_imsg_forward_rde(struct imsg *imsg)
+{
+	return (imsg_forward(imsg_rde, imsg));
+}
+
 void
-ospfe_dispatch_main(int fd, short event, void *arg)
+ospfe_dispatch_main(struct imsg *imsg, void *arg)
 {
 	static struct area	*narea;
 	static struct iface	*niface;
-	struct ifaddrchange	*ifc;
-	struct imsg	 imsg;
-	struct imsgbuf	*ibuf = arg;
+	struct ifaddrchange	 ifc;
 	struct area	*area = NULL;
 	struct iface	*iface = NULL;
-	struct kif	*kif;
+	struct kif	 kif;
 	struct auth_md	 md;
-	int		 n, link_ok, stub_changed, shut = 0;
-
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
-		}
-	}
-
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("ospfe_dispatch_main: imsgbuf_get error");
-		if (n == 0)
-			break;
-
-		switch (imsg.hdr.type) {
-		case IMSG_IFINFO:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE +
-			    sizeof(struct kif))
-				fatalx("IFINFO imsg with wrong len");
-			kif = imsg.data;
-			link_ok = (kif->flags & IFF_UP) &&
-			    LINK_STATE_IS_UP(kif->link_state);
-
-			LIST_FOREACH(area, &oeconf->area_list, entry) {
-				LIST_FOREACH(iface, &area->iface_list, entry) {
-					if (kif->ifindex == iface->ifindex &&
-					    iface->type !=
-					    IF_TYPE_VIRTUALLINK) {
-						int prev_link_state =
-						    (iface->flags & IFF_UP) &&
-						    LINK_STATE_IS_UP(iface->linkstate);
-
-						iface->flags = kif->flags;
-						iface->linkstate =
-						    kif->link_state;
-						iface->mtu = kif->mtu;
-
-						if (link_ok == prev_link_state)
-							break;
+	uint32_t	 type;
+	int		 fd, link_ok, stub_changed;
+
+	type = imsg_get_type(imsg);
+	switch (type) {
+	case IMSG_IFINFO:
+		if (imsg_get_data(imsg, &kif, sizeof(kif)) == -1)
+			fatalx("bad IFINFO imsg received");
+		link_ok = (kif.flags & IFF_UP) &&
+		    LINK_STATE_IS_UP(kif.link_state);
+
+		LIST_FOREACH(area, &oeconf->area_list, entry) {
+			LIST_FOREACH(iface, &area->iface_list, entry) {
+				if (kif.ifindex == iface->ifindex &&
+				    iface->type != IF_TYPE_VIRTUALLINK) {
+					int prev_link_state =
+					    (iface->flags & IFF_UP) &&
+					    LINK_STATE_IS_UP(iface->linkstate);
+
+					iface->flags = kif.flags;
+					iface->linkstate = kif.link_state;
+					iface->mtu = kif.mtu;
+
+					if (link_ok == prev_link_state)
+						break;
 
-						if (link_ok) {
-							if_fsm(iface,
-							    IF_EVT_UP);
-							log_warnx("interface %s"
-							    " up", iface->name);
-						} else {
-							if_fsm(iface,
-							    IF_EVT_DOWN);
-							log_warnx("interface %s"
-							    " down",
-							    iface->name);
-						}
-					}
-					if (strcmp(kif->ifname,
-					    iface->dependon) == 0) {
-						log_warnx("interface %s"
-						    " changed state, %s"
-						    " depends on it",
-						    kif->ifname,
+					if (link_ok) {
+						if_fsm(iface, IF_EVT_UP);
+						log_warnx("interface %s up",
+						    iface->name);
+					} else {
+						if_fsm(iface, IF_EVT_DOWN);
+						log_warnx("interface %s down",
 						    iface->name);
-						iface->depend_ok =
-						    ifstate_is_up(kif);
-
-						if ((iface->flags &
-						    IFF_UP) &&
-						    LINK_STATE_IS_UP(iface->linkstate))
-							orig_rtr_lsa(iface->area);
 					}
 				}
-			}
-			break;
-		case IMSG_IFADDRADD:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE +
-			    sizeof(struct ifaddrchange))
-				fatalx("IFADDRADD imsg with wrong len");
-			ifc = imsg.data;
+				kif.ifname[sizeof(kif.ifname) - 1] = '\0';
+				if (strcmp(kif.ifname, iface->dependon) == 0) {
+					log_warnx("interface %s changed state, "
+					    " %s depends on it", kif.ifname,
+					    iface->name);
+					iface->depend_ok = ifstate_is_up(&kif);
 
-			LIST_FOREACH(area, &oeconf->area_list, entry) {
-				LIST_FOREACH(iface, &area->iface_list, entry) {
-					if (ifc->ifindex == iface->ifindex &&
-					    ifc->addr.s_addr ==
-					    iface->addr.s_addr) {
-						iface->mask = ifc->mask;
-						iface->dst = ifc->dst;
-						/*
-						 * Previous down event might
-						 * have failed if the address
-						 * was not present at that
-						 * time.
-						 */
-						if_fsm(iface, IF_EVT_DOWN);
-						if_fsm(iface, IF_EVT_UP);
-						log_warnx("interface %s:%s "
-						    "returned", iface->name,
-						    inet_ntoa(iface->addr));
-						break;
-					}
+					if ((iface->flags & IFF_UP) &&
+					    LINK_STATE_IS_UP(iface->linkstate))
+						orig_rtr_lsa(iface->area);
 				}
 			}
-			break;
-		case IMSG_IFADDRDEL:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE +
-			    sizeof(struct ifaddrchange))
-				fatalx("IFADDRDEL imsg with wrong len");
-			ifc = imsg.data;
-
-			LIST_FOREACH(area, &oeconf->area_list, entry) {
-				LIST_FOREACH(iface, &area->iface_list, entry) {
-					if (ifc->ifindex == iface->ifindex &&
-					    ifc->addr.s_addr ==
-					    iface->addr.s_addr) {
-						if_fsm(iface, IF_EVT_DOWN);
-						log_warnx("interface %s:%s "
-						    "gone", iface->name,
-						    inet_ntoa(iface->addr));
-						break;
-					}
+		}
+		break;
+	case IMSG_IFADDRADD:
+		if (imsg_get_data(imsg, &ifc, sizeof(ifc)) == -1)
+			fatalx("bad IFADDRADD imsg received");
+
+		LIST_FOREACH(area, &oeconf->area_list, entry) {
+			LIST_FOREACH(iface, &area->iface_list, entry) {
+				if (ifc.ifindex == iface->ifindex &&
+				    ifc.addr.s_addr == iface->addr.s_addr) {
+					iface->mask = ifc.mask;
+					iface->dst = ifc.dst;
+					/*
+					 * Previous down event might
+					 * have failed if the address
+					 * was not present at that
+					 * time.
+					 */
+					if_fsm(iface, IF_EVT_DOWN);
+					if_fsm(iface, IF_EVT_UP);
+					log_warnx("interface %s:%s "
+					    "returned", iface->name,
+					    inet_ntoa(iface->addr));
+					break;
 				}
 			}
-			break;
-		case IMSG_RECONF_CONF:
-			if ((noeconf = malloc(sizeof(struct ospfd_conf))) ==
-			    NULL)
-				fatal(NULL);
-			memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf));
-
-			LIST_INIT(&noeconf->area_list);
-			LIST_INIT(&noeconf->cand_list);
-			break;
-		case IMSG_RECONF_AREA:
-			if ((narea = area_new()) == NULL)
-				fatal(NULL);
-			memcpy(narea, imsg.data, sizeof(struct area));
-
-			LIST_INIT(&narea->iface_list);
-			LIST_INIT(&narea->nbr_list);
-			RB_INIT(&narea->lsa_tree);
-			SIMPLEQ_INIT(&narea->redist_list);
-
-			LIST_INSERT_HEAD(&noeconf->area_list, narea, entry);
-			break;
-		case IMSG_RECONF_IFACE:
-			if ((niface = malloc(sizeof(struct iface))) == NULL)
-				fatal(NULL);
-			memcpy(niface, imsg.data, sizeof(struct iface));
-
-			LIST_INIT(&niface->nbr_list);
-			TAILQ_INIT(&niface->ls_ack_list);
-			TAILQ_INIT(&niface->auth_md_list);
-			RB_INIT(&niface->lsa_tree);
-
-			niface->area = narea;
-			LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
-			break;
-		case IMSG_RECONF_AUTHMD:
-			if (imsg_get_data(&imsg, md.key, sizeof(md.key)) == -1)
-				fatalx(
-				    "%s IMSG_RECONF_AUTHMD could not get key",
-				    __func__);
-			md.keyid = imsg_get_id(&imsg);
-			md_list_add(&niface->auth_md_list,
-			    md.keyid, md.key);
-			break;
-		case IMSG_RECONF_END:
-			if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) !=
-			    (noeconf->flags & OSPFD_FLAG_STUB_ROUTER))
-				stub_changed = 1;
-			else
-				stub_changed = 0;
-			merge_config(oeconf, noeconf);
-			noeconf = NULL;
-			if (stub_changed)
-				orig_rtr_lsa_all(NULL);
-			break;
-		case IMSG_CTL_KROUTE:
-		case IMSG_CTL_KROUTE_ADDR:
-		case IMSG_CTL_IFINFO:
-		case IMSG_CTL_END:
-			control_imsg_relay(&imsg);
-			break;
-		case IMSG_CONTROLFD:
-			if ((fd = imsg_get_fd(&imsg)) == -1)
-				fatalx("%s: expected to receive imsg control"
-				    "fd but didn't receive any", __func__);
-			/* Listen on control socket. */
-			control_listen(fd);
-			if (pledge("stdio inet mcast", NULL) == -1)
-				fatal("pledge");
-			break;
-		default:
-			log_debug("ospfe_dispatch_main: error handling imsg %d",
-			    imsg.hdr.type);
-			break;
 		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
+		break;
+	case IMSG_IFADDRDEL:
+		if (imsg_get_data(imsg, &ifc, sizeof(ifc)) == -1)
+			fatalx("bad IFADDRADD imsg received");
+
+		LIST_FOREACH(area, &oeconf->area_list, entry) {
+			LIST_FOREACH(iface, &area->iface_list, entry) {
+				if (ifc.ifindex == iface->ifindex &&
+				    ifc.addr.s_addr == iface->addr.s_addr) {
+					if_fsm(iface, IF_EVT_DOWN);
+					log_warnx("interface %s:%s "
+					    "gone", iface->name,
+					    inet_ntoa(iface->addr));
+					break;
+				}
+			}
+		}
+		break;
+	case IMSG_RECONF_CONF:
+		if ((noeconf = malloc(sizeof(*noeconf))) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, noeconf, sizeof(*noeconf)) == -1)
+			fatalx("bad RECONF_CONF imsg received");
+
+		LIST_INIT(&noeconf->area_list);
+		LIST_INIT(&noeconf->cand_list);
+		break;
+	case IMSG_RECONF_AREA:
+		if ((narea = area_new()) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, narea, sizeof(*narea)) == -1)
+			fatalx("bad RECONF_AREA imsg received");
+
+		LIST_INIT(&narea->iface_list);
+		LIST_INIT(&narea->nbr_list);
+		RB_INIT(&narea->lsa_tree);
+		SIMPLEQ_INIT(&narea->redist_list);
+
+		LIST_INSERT_HEAD(&noeconf->area_list, narea, entry);
+		break;
+	case IMSG_RECONF_IFACE:
+		if ((niface = malloc(sizeof(*niface))) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, niface, sizeof(*niface)) == -1)
+			fatalx("bad RECONF_IFACE imsg received");
+
+		LIST_INIT(&niface->nbr_list);
+		TAILQ_INIT(&niface->ls_ack_list);
+		TAILQ_INIT(&niface->auth_md_list);
+		RB_INIT(&niface->lsa_tree);
+
+		niface->area = narea;
+		LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
+		break;
+	case IMSG_RECONF_AUTHMD:
+		if (imsg_get_data(imsg, md.key, sizeof(md.key)) == -1)
+			fatalx("bad RECONF_AUTHMD imsg received");
+		md.keyid = imsg_get_id(imsg);
+		md_list_add(&niface->auth_md_list,
+		    md.keyid, md.key);
+		break;
+	case IMSG_RECONF_END:
+		if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) !=
+		    (noeconf->flags & OSPFD_FLAG_STUB_ROUTER))
+			stub_changed = 1;
+		else
+			stub_changed = 0;
+		merge_config(oeconf, noeconf);
+		noeconf = NULL;
+		if (stub_changed)
+			orig_rtr_lsa_all(NULL);
+		break;
+	case IMSG_CTL_KROUTE:
+	case IMSG_CTL_KROUTE_ADDR:
+	case IMSG_CTL_IFINFO:
+	case IMSG_CTL_END:
+		control_imsg_relay(imsg);
+		break;
+	case IMSG_CONTROLFD:
+		if ((fd = imsg_get_fd(imsg)) == -1)
+			fatalx("expected to receive imsg control fd "
+			    "but didn't receive any");
+		/* Listen on control socket. */
+		control_listen(fd);
+		if (pledge("stdio inet mcast", NULL) == -1)
+			fatal("pledge");
+		break;
+	default:
+		log_debug("ospfe_dispatch_main: error handling imsg %d", type);
+		break;
 	}
 }
 
 void
-ospfe_dispatch_rde(int fd, short event, void *arg)
+ospfe_dispatch_rde(struct imsg *imsg, void *arg)
 {
 	struct ibuf		 buf;
 	struct lsa_hdr		 lsa_hdr;
-	struct imsgbuf		*ibuf = arg;
 	struct nbr		*nbr;
 	struct lsa_hdr		*lhp;
 	struct lsa_ref		*ref;
 	struct area		*area;
 	struct iface		*iface;
 	struct lsa_entry	*le;
-	struct imsg		 imsg;
 	struct abr_rtr		 ar;
-	int			 n, noack = 0, shut = 0;
+	uint32_t		 type, peerid;
+	int			 noack = 0;
 	u_int16_t		 age;
 
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
-		}
-	}
-
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("ospfe_dispatch_rde: imsgbuf_get error");
-		if (n == 0)
+	type = imsg_get_type(imsg);
+	peerid = imsg_get_id(imsg);
+	switch (type) {
+	case IMSG_DD:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
 
-		switch (imsg.hdr.type) {
-		case IMSG_DD:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-
-			/*
-			 * Ignore imsg when in the wrong state because a
-			 * NBR_EVT_SEQ_NUM_MIS may have been issued in between.
-			 * Luckily regetting the DB snapshot acts as a barrier
-			 * for both state and process synchronisation.
-			 */
-			if ((nbr->state & NBR_STA_FLOOD) == 0)
-				break;
+		/*
+		 * Ignore imsg when in the wrong state because a
+		 * NBR_EVT_SEQ_NUM_MIS may have been issued in between.
+		 * Luckily regetting the DB snapshot acts as a barrier
+		 * for both state and process synchronisation.
+		 */
+		if ((nbr->state & NBR_STA_FLOOD) == 0)
+			break;
 
-			/* put these on my ls_req_list for retrieval */
-			lhp = lsa_hdr_new();
-			memcpy(lhp, imsg.data, sizeof(*lhp));
-			ls_req_list_add(nbr, lhp);
+		/* put these on my ls_req_list for retrieval */
+		lhp = lsa_hdr_new();
+		if (imsg_get_data(imsg, lhp, sizeof(*lhp)) == -1)
+			fatalx("bad DD imsg received");
+		ls_req_list_add(nbr, lhp);
+		break;
+	case IMSG_DD_END:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_DD_END:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			/* see above */
-			if ((nbr->state & NBR_STA_FLOOD) == 0)
-				break;
+		/* see above */
+		if ((nbr->state & NBR_STA_FLOOD) == 0)
+			break;
 
-			nbr->dd_pending--;
-			if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) {
-				if (ls_req_list_empty(nbr))
-					nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
-				else
-					start_ls_req_tx_timer(nbr);
-			}
+		nbr->dd_pending--;
+		if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) {
+			if (ls_req_list_empty(nbr))
+				nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
+			else
+				start_ls_req_tx_timer(nbr);
+		}
+		break;
+	case IMSG_DD_BADLSA:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_DD_BADLSA:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			if (nbr->iface->self == nbr)
-				fatalx("ospfe_dispatch_rde: "
-				    "dummy neighbor got BADREQ");
+		if (nbr->iface->self == nbr)
+			fatalx("ospfe_dispatch_rde: "
+			    "dummy neighbor got BADREQ");
 
-			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
+		nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
+		break;
+	case IMSG_DB_SNAPSHOT:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
+			break;
+		if (nbr->state != NBR_STA_SNAP)	/* discard */
 			break;
-		case IMSG_DB_SNAPSHOT:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-			if (nbr->state != NBR_STA_SNAP)	/* discard */
-				break;
 
-			/* add LSA header to the neighbor db_sum_list */
-			lhp = lsa_hdr_new();
-			memcpy(lhp, imsg.data, sizeof(*lhp));
-			db_sum_list_add(nbr, lhp);
+		/* add LSA header to the neighbor db_sum_list */
+		lhp = lsa_hdr_new();
+		if (imsg_get_data(imsg, lhp, sizeof(*lhp)) == -1)
+			fatalx("bad DB_SNAPSHOT imsg received");
+		db_sum_list_add(nbr, lhp);
+		break;
+	case IMSG_DB_END:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_DB_END:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			nbr->dd_snapshot = 0;
-			if (nbr->state != NBR_STA_SNAP)
-				break;
+		nbr->dd_snapshot = 0;
+		if (nbr->state != NBR_STA_SNAP)
+			break;
 
-			/* snapshot done, start tx of dd packets */
-			nbr_fsm(nbr, NBR_EVT_SNAP_DONE);
+		/* snapshot done, start tx of dd packets */
+		nbr_fsm(nbr, NBR_EVT_SNAP_DONE);
+		break;
+	case IMSG_LS_FLOOD:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_LS_FLOOD:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			if (imsg_get_ibuf(&imsg, &buf) == -1)
-				fatalx("bad LS_FLOOD imsg received");
-
-			ref = lsa_cache_add(&buf);
-
-			if (ref->hdr.type == LSA_TYPE_EXTERNAL) {
-				/*
-				 * flood on all areas but stub areas and
-				 * virtual links
-				 */
-				LIST_FOREACH(area, &oeconf->area_list, entry) {
-				    if (area->stub)
-					    continue;
-				    LIST_FOREACH(iface, &area->iface_list,
-					entry) {
-					    noack += lsa_flood(iface, nbr, ref);
-				    }
-				}
-			} else if (ref->hdr.type == LSA_TYPE_LINK_OPAQ) {
-				/*
-				 * Flood on interface only
-				 */
-				noack += lsa_flood(nbr->iface, nbr, ref);
-			} else {
-				/*
-				 * Flood on all area interfaces. For
-				 * area 0.0.0.0 include the virtual links.
-				 */
-				area = nbr->iface->area;
-				LIST_FOREACH(iface, &area->iface_list, entry) {
-					noack += lsa_flood(iface, nbr, ref);
-				}
-				/* XXX virtual links */
-			}
+		if (imsg_get_ibuf(imsg, &buf) == -1)
+			fatalx("bad LS_FLOOD imsg received");
 
-			/* remove from ls_req_list */
-			le = ls_req_list_get(nbr, &ref->hdr);
-			if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
-				ls_req_list_free(nbr, le);
-				/*
-				 * XXX no need to ack requested lsa
-				 * the problem is that the RFC is very
-				 * unclear about this.
-				 */
-				noack = 1;
-			}
+		ref = lsa_cache_add(&buf);
 
-			if (!noack && nbr->iface != NULL &&
-			    nbr->iface->self != nbr) {
-				if (!(nbr->iface->state & IF_STA_BACKUP) ||
-				    nbr->iface->dr == nbr) {
-					/* delayed ack */
-					lhp = lsa_hdr_new();
-					memcpy(lhp, &ref->hdr, sizeof(*lhp));
-					ls_ack_list_add(nbr->iface, lhp);
-				}
+		if (ref->hdr.type == LSA_TYPE_EXTERNAL) {
+			/*
+			 * flood on all areas but stub areas and
+			 * virtual links
+			 */
+			LIST_FOREACH(area, &oeconf->area_list, entry) {
+			    if (area->stub)
+				    continue;
+			    LIST_FOREACH(iface, &area->iface_list,
+				entry) {
+				    noack += lsa_flood(iface, nbr, ref);
+			    }
 			}
+		} else if (ref->hdr.type == LSA_TYPE_LINK_OPAQ) {
+			/*
+			 * Flood on interface only
+			 */
+			noack += lsa_flood(nbr->iface, nbr, ref);
+		} else {
+			/*
+			 * Flood on all area interfaces. For
+			 * area 0.0.0.0 include the virtual links.
+			 */
+			area = nbr->iface->area;
+			LIST_FOREACH(iface, &area->iface_list, entry) {
+				noack += lsa_flood(iface, nbr, ref);
+			}
+			/* XXX virtual links */
+		}
 
-			lsa_cache_put(ref, nbr);
-			break;
-		case IMSG_LS_UPD:
-		case IMSG_LS_SNAP:
+		/* remove from ls_req_list */
+		le = ls_req_list_get(nbr, &ref->hdr);
+		if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
+			ls_req_list_free(nbr, le);
 			/*
-			 * IMSG_LS_UPD is used in two cases:
-			 * 1. as response to ls requests
-			 * 2. as response to ls updates where the DB
-			 *    is newer then the sent LSA
-			 * IMSG_LS_SNAP is used in one case:
-			 *    in EXSTART when the LSA has age MaxAge
+			 * XXX no need to ack requested lsa
+			 * the problem is that the RFC is very
+			 * unclear about this.
 			 */
-			if (imsg_get_ibuf(&imsg, &buf) == -1)
-				fatalx("bad LS_UPD/SNAP imsg received");
+			noack = 1;
+		}
 
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
+		if (!noack && nbr->iface != NULL &&
+		    nbr->iface->self != nbr) {
+			if (!(nbr->iface->state & IF_STA_BACKUP) ||
+			    nbr->iface->dr == nbr) {
+				/* delayed ack */
+				lhp = lsa_hdr_new();
+				memcpy(lhp, &ref->hdr, sizeof(*lhp));
+				ls_ack_list_add(nbr->iface, lhp);
+			}
+		}
 
-			if (nbr->iface->self == nbr)
-				break;
+		lsa_cache_put(ref, nbr);
+		break;
+	case IMSG_LS_UPD:
+	case IMSG_LS_SNAP:
+		/*
+		 * IMSG_LS_UPD is used in two cases:
+		 * 1. as response to ls requests
+		 * 2. as response to ls updates where the DB
+		 *    is newer then the sent LSA
+		 * IMSG_LS_SNAP is used in one case:
+		 *    in EXSTART when the LSA has age MaxAge
+		 */
+		if (imsg_get_ibuf(imsg, &buf) == -1)
+			fatalx("bad LS_UPD/SNAP imsg received");
+
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
+			break;
 
-			if (imsg.hdr.type == IMSG_LS_SNAP &&
-			    nbr->state != NBR_STA_SNAP)
-				break;
+		if (nbr->iface->self == nbr)
+			break;
 
-			ref = lsa_cache_add(&buf);
-			age = ref->hdr.age;
+		if (type == IMSG_LS_SNAP && nbr->state != NBR_STA_SNAP)
+			break;
 
-			if (ntohs(age) >= MAX_AGE)
-				/* add to retransmit list */
-				ls_retrans_list_add(nbr, ref, 0, 0);
-			else
-				ls_retrans_list_add(nbr, ref, 0, 1);
+		ref = lsa_cache_add(&buf);
+		age = ntohs(ref->hdr.age);
+
+		if (age >= MAX_AGE)
+			/* add to retransmit list */
+			ls_retrans_list_add(nbr, ref, 0, 0);
+		else
+			ls_retrans_list_add(nbr, ref, 0, 1);
 
-			lsa_cache_put(ref, nbr);
+		lsa_cache_put(ref, nbr);
+		break;
+	case IMSG_LS_ACK:
+		/*
+		 * IMSG_LS_ACK is used in two cases:
+		 * 1. LSA was a duplicate
+		 * 2. LS age is MaxAge and there is no current
+		 *    instance in the DB plus no neighbor in state
+		 *    Exchange or Loading
+		 */
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_LS_ACK:
-			/*
-			 * IMSG_LS_ACK is used in two cases:
-			 * 1. LSA was a duplicate
-			 * 2. LS age is MaxAge and there is no current
-			 *    instance in the DB plus no neighbor in state
-			 *    Exchange or Loading
-			 */
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			if (nbr->iface->self == nbr)
-				break;
+		if (nbr->iface->self == nbr)
+			break;
 
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr))
-				fatalx("ospfe_dispatch_rde: bad imsg size");
-			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
+		if (imsg_get_data(imsg, &lsa_hdr, sizeof(lsa_hdr)) == -1)
+			fatalx("bad LS_ACK imsg received");
 
-			/* for case one check for implied acks */
-			if (nbr->iface->state & IF_STA_DROTHER)
-				if (ls_retrans_list_del(nbr->iface->self,
-				    &lsa_hdr) == 0)
-					break;
-			if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
+		/* for case one check for implied acks */
+		if (nbr->iface->state & IF_STA_DROTHER)
+			if (ls_retrans_list_del(nbr->iface->self,
+			    &lsa_hdr) == 0)
 				break;
+		if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
+			break;
 
-			/* send a direct acknowledgement */
-			send_direct_ack(nbr->iface, nbr->addr, imsg.data,
-			    imsg.hdr.len - IMSG_HEADER_SIZE);
-
+		/* send a direct acknowledgement */
+		send_direct_ack(nbr->iface, nbr->addr, &lsa_hdr,
+		    sizeof(lsa_hdr));
+		break;
+	case IMSG_LS_BADREQ:
+		nbr = nbr_find_peerid(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_LS_BADREQ:
-			nbr = nbr_find_peerid(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			if (nbr->iface->self == nbr)
-				fatalx("ospfe_dispatch_rde: "
-				    "dummy neighbor got BADREQ");
+		if (nbr->iface->self == nbr)
+			fatalx("ospfe_dispatch_rde: "
+			    "dummy neighbor got BADREQ");
 
-			nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
-			break;
-		case IMSG_ABR_UP:
-			memcpy(&ar, imsg.data, sizeof(ar));
+		nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
+		break;
+	case IMSG_ABR_UP:
+		if (imsg_get_data(imsg, &ar, sizeof(ar)) == -1)
+			fatalx("bad ABR_UP imsg received");
 
-			if ((iface = find_vlink(&ar)) != NULL &&
-			    iface->state == IF_STA_DOWN)
-				if (if_fsm(iface, IF_EVT_UP)) {
-					log_debug("error starting interface %s",
-					    iface->name);
-				}
-			break;
-		case IMSG_ABR_DOWN:
-			memcpy(&ar, imsg.data, sizeof(ar));
+		if ((iface = find_vlink(&ar)) != NULL &&
+		    iface->state == IF_STA_DOWN)
+			if (if_fsm(iface, IF_EVT_UP)) {
+				log_debug("error starting interface %s",
+				    iface->name);
+			}
+		break;
+	case IMSG_ABR_DOWN:
+		if (imsg_get_data(imsg, &ar, sizeof(ar)) == -1)
+			fatalx("bad ABR_DOWN imsg received");
 
-			if ((iface = find_vlink(&ar)) != NULL &&
-			    iface->state == IF_STA_POINTTOPOINT)
-				if (if_fsm(iface, IF_EVT_DOWN)) {
-					log_debug("error stopping interface %s",
-					    iface->name);
-				}
-			break;
-		case IMSG_CTL_AREA:
-		case IMSG_CTL_IFACE:
-		case IMSG_CTL_END:
-		case IMSG_CTL_SHOW_DATABASE:
-		case IMSG_CTL_SHOW_DB_EXT:
-		case IMSG_CTL_SHOW_DB_NET:
-		case IMSG_CTL_SHOW_DB_RTR:
-		case IMSG_CTL_SHOW_DB_SELF:
-		case IMSG_CTL_SHOW_DB_SUM:
-		case IMSG_CTL_SHOW_DB_ASBR:
-		case IMSG_CTL_SHOW_DB_OPAQ:
-		case IMSG_CTL_SHOW_RIB:
-		case IMSG_CTL_SHOW_SUM:
-		case IMSG_CTL_SHOW_SUM_AREA:
-			control_imsg_relay(&imsg);
-			break;
-		default:
-			log_debug("ospfe_dispatch_rde: error handling imsg %d",
-			    imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
+		if ((iface = find_vlink(&ar)) != NULL &&
+		    iface->state == IF_STA_POINTTOPOINT)
+			if (if_fsm(iface, IF_EVT_DOWN)) {
+				log_debug("error stopping interface %s",
+				    iface->name);
+			}
+		break;
+	case IMSG_CTL_AREA:
+	case IMSG_CTL_IFACE:
+	case IMSG_CTL_END:
+	case IMSG_CTL_SHOW_DATABASE:
+	case IMSG_CTL_SHOW_DB_EXT:
+	case IMSG_CTL_SHOW_DB_NET:
+	case IMSG_CTL_SHOW_DB_RTR:
+	case IMSG_CTL_SHOW_DB_SELF:
+	case IMSG_CTL_SHOW_DB_SUM:
+	case IMSG_CTL_SHOW_DB_ASBR:
+	case IMSG_CTL_SHOW_DB_OPAQ:
+	case IMSG_CTL_SHOW_RIB:
+	case IMSG_CTL_SHOW_SUM:
+	case IMSG_CTL_SHOW_SUM_AREA:
+		control_imsg_relay(imsg);
+		break;
+	default:
+		log_debug("ospfe_dispatch_rde: error handling imsg %d", type);
+		break;
 	}
 }
 
@@ -883,7 +822,7 @@ orig_rtr_lsa(struct area *area)
 					rtr_link.data = 0xffffffff;
 				} else {
 					rtr_link.id = iface->addr.s_addr &
-					              iface->mask.s_addr;
+					    iface->mask.s_addr;
 					rtr_link.data = iface->mask.s_addr;
 				}
 				rtr_link.type = LINK_TYPE_STUB_NET;
@@ -950,7 +889,7 @@ orig_rtr_lsa(struct area *area)
 			    iface->linkstate == LINK_STATE_DOWN)
 				rtr_link.metric = MAX_METRIC;
 			else if (iface->dependon[0] != '\0' &&
-			         iface->depend_ok == 0)
+			    iface->depend_ok == 0)
 				rtr_link.metric = MAX_METRIC;
 			else
 				rtr_link.metric = htons(iface->metric);
@@ -1191,6 +1130,8 @@ ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
 				    ictl, sizeof(struct ctl_iface));
 			}
+
+	imsg_compose(c->imsgbuf, IMSG_CTL_END, 0, 0, -1, NULL, 0);
 }
 
 void
diff --git usr.sbin/ospfd/ospfe.h usr.sbin/ospfd/ospfe.h
index 8483cbef069..64d346ccf61 100644
--- usr.sbin/ospfd/ospfe.h
+++ usr.sbin/ospfd/ospfe.h
@@ -120,11 +120,11 @@ void	 recv_hello(struct iface *,  struct in_addr, u_int32_t,
 
 /* ospfe.c */
 pid_t		 ospfe(struct ospfd_conf *, int[2], int[2], int[2]);
-void		 ospfe_dispatch_main(int, short, void *);
-void		 ospfe_dispatch_rde(int, short, void *);
 int		 ospfe_imsg_compose_parent(int, pid_t, void *, u_int16_t);
 int		 ospfe_imsg_compose_rde(int, u_int32_t, pid_t, void *,
 		     u_int16_t);
+int		 ospfe_imsg_forward_parent(struct imsg *);
+int		 ospfe_imsg_forward_rde(struct imsg *);
 u_int32_t	 ospfe_router_id(void);
 void		 ospfe_fib_update(int);
 void		 ospfe_iface_ctl(struct ctl_conn *, unsigned int);
diff --git usr.sbin/ospfd/rde.c usr.sbin/ospfd/rde.c
index 4aad371b473..2ae0106d59b 100644
--- usr.sbin/ospfd/rde.c
+++ usr.sbin/ospfd/rde.c
@@ -40,8 +40,8 @@
 
 void		 rde_sig_handler(int sig, short, void *);
 __dead void	 rde_shutdown(void);
-void		 rde_dispatch_imsg(int, short, void *);
-void		 rde_dispatch_parent(int, short, void *);
+void		 rde_dispatch_imsg(struct imsg *, void *);
+void		 rde_dispatch_parent(struct imsg *, void *);
 void		 rde_dump_area(struct area *, int, pid_t);
 
 void		 rde_send_summary(pid_t);
@@ -159,9 +159,9 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2],
 	close(pipe_parent2ospfe[1]);
 
 	if ((imsg_ospfe = imsgev_new(pipe_ospfe2rde[1],
-	    rde_dispatch_imsg)) == NULL ||
+	    rde_dispatch_imsg, ospfd_dispatch_error, NULL)) == NULL ||
 	    (imsg_main = imsgev_new(pipe_parent2rde[1],
-	    rde_dispatch_parent)) == NULL)
+	    rde_dispatch_parent, ospfd_dispatch_error, NULL)) == NULL)
 		fatal(NULL);
 
 	evtimer_set(&rdeconf->ev, spf_timer, rdeconf);
@@ -224,10 +224,8 @@ rde_imsg_compose_ospfe(int type, u_int32_t peerid, pid_t pid, void *data,
 }
 
 void
-rde_dispatch_imsg(int fd, short event, void *arg)
+rde_dispatch_imsg(struct imsg *imsg, void *arg)
 {
-	struct imsgbuf		*ibuf = arg;
-	struct imsg		 imsg;
 	struct in_addr		 aid;
 	struct ls_req_hdr	 req_hdr;
 	struct lsa_hdr		 lsa_hdr, *db_hdr;
@@ -237,492 +235,403 @@ rde_dispatch_imsg(int fd, short event, void *arg)
 	struct area		*area;
 	struct in_addr		 addr;
 	struct vertex		*v;
-	char			*buf;
 	time_t			 now;
-	int			 n, r, state, self, error, shut = 0, verbose;
-	u_int16_t		 l;
-
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
-		}
-	}
+	size_t			 len;
+	uint32_t		 type, peerid;
+	pid_t			 pid;
+	int			 r, state, self, error, verbose;
+	uint8_t			 capa;
 
 	clock_gettime(CLOCK_MONOTONIC, &tp);
 	now = tp.tv_sec;
 
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("rde_dispatch_imsg: imsgbuf_get error");
-		if (n == 0)
-			break;
-
-		switch (imsg.hdr.type) {
-		case IMSG_NEIGHBOR_UP:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rn))
-				fatalx("invalid size of OE request");
-			memcpy(&rn, imsg.data, sizeof(rn));
+	type = imsg_get_type(imsg);
+	peerid = imsg_get_id(imsg);
+	pid = imsg_get_pid(imsg);
+	switch (type) {
+	case IMSG_NEIGHBOR_UP:
+		if (imsg_get_data(imsg, &rn, sizeof(rn)) == -1)
+			fatalx("bad NEIGHBOR_UP imsg received");
+
+		if (rde_nbr_new(peerid, &rn) == NULL)
+			fatalx("rde_dispatch_imsg: "
+			    "neighbor already exists");
+		break;
+	case IMSG_NEIGHBOR_DOWN:
+		rde_nbr_del(rde_nbr_find(peerid));
+		break;
+	case IMSG_NEIGHBOR_ADDR:
+		if (imsg_get_data(imsg, &addr, sizeof(addr)) == -1)
+			fatalx("bad NEIGHBOR_ADDR imsg received");
 
-			if (rde_nbr_new(imsg.hdr.peerid, &rn) == NULL)
-				fatalx("rde_dispatch_imsg: "
-				    "neighbor already exists");
-			break;
-		case IMSG_NEIGHBOR_DOWN:
-			rde_nbr_del(rde_nbr_find(imsg.hdr.peerid));
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_NEIGHBOR_ADDR:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(addr))
-				fatalx("invalid size of OE request");
-			memcpy(&addr, imsg.data, sizeof(addr));
 
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
+		nbr->addr.s_addr = addr.s_addr;
+		break;
+	case IMSG_NEIGHBOR_CHANGE:
+		if (imsg_get_data(imsg, &state, sizeof(state)) == -1)
+			fatalx("bad NEIGHBOR_CHANGE imsg received");
 
-			nbr->addr.s_addr = addr.s_addr;
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_NEIGHBOR_CHANGE:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(state))
-				fatalx("invalid size of OE request");
-			memcpy(&state, imsg.data, sizeof(state));
 
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-
-			nbr->state = state;
-			if (nbr->state & NBR_STA_FULL)
-				rde_req_list_free(nbr);
-			break;
-		case IMSG_NEIGHBOR_CAPA:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(u_int8_t))
-				fatalx("invalid size of OE request");
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-			nbr->capa_options = *(u_int8_t *)imsg.data;
+		nbr->state = state;
+		if (nbr->state & NBR_STA_FULL)
+			rde_req_list_free(nbr);
+		break;
+	case IMSG_NEIGHBOR_CAPA:
+		if (imsg_get_data(imsg, &capa, sizeof(capa)) == -1)
+			fatalx("bad NEIGHBOR_CAPA imsg received");
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_AREA_CHANGE:
-			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(state))
-				fatalx("invalid size of OE request");
+		nbr->capa_options = capa;
+		break;
+	case IMSG_AREA_CHANGE:
+		if (imsg_get_data(imsg, &state, sizeof(state)) == -1)
+			fatalx("bad AREA_CHANGE imsg received");
 
-			LIST_FOREACH(area, &rdeconf->area_list, entry) {
-				if (area->id.s_addr == imsg.hdr.peerid)
-					break;
-			}
-			if (area == NULL)
+		LIST_FOREACH(area, &rdeconf->area_list, entry) {
+			if (area->id.s_addr == peerid)
 				break;
-			memcpy(&state, imsg.data, sizeof(state));
-			area->active = state;
+		}
+		if (area == NULL)
+			break;
+		area->active = state;
+		break;
+	case IMSG_DB_SNAPSHOT:
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_DB_SNAPSHOT:
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
 
-			lsa_snap(nbr);
+		lsa_snap(nbr);
 
-			imsg_compose(imsg_ospfe, IMSG_DB_END,
-			    imsg.hdr.peerid, 0, -1, NULL, 0);
+		imsg_compose(imsg_ospfe, IMSG_DB_END, peerid, 0, -1, NULL, 0);
+		break;
+	case IMSG_DD:
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
 			break;
-		case IMSG_DD:
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-
-			buf = imsg.data;
-			error = 0;
-			for (l = imsg.hdr.len - IMSG_HEADER_SIZE;
-			    l >= sizeof(lsa_hdr); l -= sizeof(lsa_hdr)) {
-				memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
-				buf += sizeof(lsa_hdr);
 
-				if (lsa_hdr.type == LSA_TYPE_EXTERNAL &&
-				    nbr->area->stub) {
-					error = 1;
-					break;
-				}
-				v = lsa_find(nbr->iface, lsa_hdr.type,
-				    lsa_hdr.ls_id, lsa_hdr.adv_rtr);
-				if (v == NULL)
-					db_hdr = NULL;
-				else
-					db_hdr = &v->lsa->hdr;
-
-				if (lsa_newer(&lsa_hdr, db_hdr) > 0) {
-					/*
-					 * only request LSAs that are
-					 * newer or missing
-					 */
-					rde_req_list_add(nbr, &lsa_hdr);
-					imsg_compose(imsg_ospfe, IMSG_DD,
-					    imsg.hdr.peerid, 0, -1, &lsa_hdr,
-					    sizeof(lsa_hdr));
-				}
-			}
-			if (l != 0 && !error)
+		error = 0;
+		while (imsg_get_len(imsg) > 0) {
+			if (imsg_get_buf(imsg, &lsa_hdr,
+			    sizeof(lsa_hdr)) == -1) {
 				log_warnx("rde_dispatch_imsg: peerid %u, "
 				    "trailing garbage in Database Description "
-				    "packet", imsg.hdr.peerid);
-
-			if (!error)
-				imsg_compose(imsg_ospfe, IMSG_DD_END,
-				    imsg.hdr.peerid, 0, -1, NULL, 0);
-			else
-				imsg_compose(imsg_ospfe, IMSG_DD_BADLSA,
-				    imsg.hdr.peerid, 0, -1, NULL, 0);
-			break;
-		case IMSG_LS_REQ:
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
+				    "packet", peerid);
+				error = 1;
 				break;
-
-			buf = imsg.data;
-			for (l = imsg.hdr.len - IMSG_HEADER_SIZE;
-			    l >= sizeof(req_hdr); l -= sizeof(req_hdr)) {
-				memcpy(&req_hdr, buf, sizeof(req_hdr));
-				buf += sizeof(req_hdr);
-
-				if ((v = lsa_find(nbr->iface,
-				    ntohl(req_hdr.type), req_hdr.ls_id,
-				    req_hdr.adv_rtr)) == NULL) {
-					log_debug("rde_dispatch_imsg: "
-					    "requested LSA not found");
-					imsg_compose(imsg_ospfe,
-					    IMSG_LS_BADREQ, imsg.hdr.peerid,
-					    0, -1, NULL, 0);
-					continue;
-				}
-				imsg_compose(imsg_ospfe, IMSG_LS_UPD,
-				    imsg.hdr.peerid, 0, -1, v->lsa,
-				    ntohs(v->lsa->hdr.len));
 			}
-			if (l != 0)
-				log_warnx("rde_dispatch_imsg: peerid %u, "
-				    "trailing garbage in LS Request "
-				    "packet", imsg.hdr.peerid);
-			break;
-		case IMSG_LS_UPD:
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
-
-			lsa = malloc(imsg.hdr.len - IMSG_HEADER_SIZE);
-			if (lsa == NULL)
-				fatal(NULL);
-			memcpy(lsa, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
 
-			if (!lsa_check(nbr, lsa,
-			    imsg.hdr.len - IMSG_HEADER_SIZE)) {
-				free(lsa);
+			if (lsa_hdr.type == LSA_TYPE_EXTERNAL &&
+			    nbr->area->stub) {
+				error = 1;
 				break;
 			}
-
-			v = lsa_find(nbr->iface, lsa->hdr.type, lsa->hdr.ls_id,
-			    lsa->hdr.adv_rtr);
+			v = lsa_find(nbr->iface, lsa_hdr.type,
+			    lsa_hdr.ls_id, lsa_hdr.adv_rtr);
 			if (v == NULL)
 				db_hdr = NULL;
 			else
 				db_hdr = &v->lsa->hdr;
 
-			if (nbr->self) {
-				lsa_merge(nbr, lsa, v);
-				/* lsa_merge frees the right lsa */
-				break;
-			}
-
-			r = lsa_newer(&lsa->hdr, db_hdr);
-			if (r > 0) {
-				/* new LSA newer than DB */
-				if (v && v->flooded &&
-				    v->changed + MIN_LS_ARRIVAL >= now) {
-					free(lsa);
-					break;
-				}
-
-				rde_req_list_del(nbr, &lsa->hdr);
-
-				if (!(self = lsa_self(nbr, lsa, v)))
-					if (lsa_add(nbr, lsa))
-						/* delayed lsa */
-						break;
-
-				/* flood and perhaps ack LSA */
-				imsg_compose(imsg_ospfe, IMSG_LS_FLOOD,
-				    imsg.hdr.peerid, 0, -1, lsa,
-				    ntohs(lsa->hdr.len));
-
-				/* reflood self originated LSA */
-				if (self && v)
-					imsg_compose(imsg_ospfe,
-					    IMSG_LS_FLOOD, v->peerid, 0, -1,
-					    v->lsa, ntohs(v->lsa->hdr.len));
-				/* new LSA was not added so free it */
-				if (self)
-					free(lsa);
-			} else if (r < 0) {
+			if (lsa_newer(&lsa_hdr, db_hdr) > 0) {
 				/*
-				 * point 6 of "The Flooding Procedure"
-				 * We are violating the RFC here because
-				 * it does not make sense to reset a session
-				 * because an equal LSA is already in the table.
-				 * Only if the LSA sent is older than the one
-				 * in the table we should reset the session.
+				 * only request LSAs that are
+				 * newer or missing
 				 */
-				if (rde_req_list_exists(nbr, &lsa->hdr)) {
-					imsg_compose(imsg_ospfe,
-					    IMSG_LS_BADREQ, imsg.hdr.peerid,
-					    0, -1, NULL, 0);
-					free(lsa);
-					break;
-				}
+				rde_req_list_add(nbr, &lsa_hdr);
+				imsg_compose(imsg_ospfe, IMSG_DD, peerid,
+				    0, -1, &lsa_hdr, sizeof(lsa_hdr));
+			}
+		}
+		if (!error)
+			imsg_compose(imsg_ospfe, IMSG_DD_END,
+			    peerid, 0, -1, NULL, 0);
+		else
+			imsg_compose(imsg_ospfe, IMSG_DD_BADLSA,
+			    peerid, 0, -1, NULL, 0);
+		break;
+	case IMSG_LS_REQ:
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
+			break;
 
-				/* lsa no longer needed */
-				free(lsa);
+		while (imsg_get_len(imsg) > 0) {
+			if (imsg_get_buf(imsg, &req_hdr,
+			    sizeof(req_hdr)) == -1) {
+				log_warnx("rde_dispatch_imsg: peerid %u, "
+				    "trailing garbage in LS Request "
+				    "packet", peerid);
+				break;
+			}
 
-				/* new LSA older than DB */
-				if (ntohl(db_hdr->seq_num) == MAX_SEQ_NUM &&
-				    ntohs(db_hdr->age) == MAX_AGE)
-					/* seq-num wrap */
-					break;
+			if ((v = lsa_find(nbr->iface,
+			    ntohl(req_hdr.type), req_hdr.ls_id,
+			    req_hdr.adv_rtr)) == NULL) {
+				log_debug("LS_REQ imsg: "
+				    "requested LSA not found");
+				imsg_compose(imsg_ospfe,
+				    IMSG_LS_BADREQ, peerid, 0, -1, NULL, 0);
+				continue;
+			}
+			imsg_compose(imsg_ospfe, IMSG_LS_UPD, peerid, 0, -1,
+			    v->lsa, ntohs(v->lsa->hdr.len));
+		}
+		break;
+	case IMSG_LS_UPD:
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
+			break;
 
-				if (v->changed + MIN_LS_ARRIVAL >= now)
-					break;
+		len = imsg_get_len(imsg);
+		if ((lsa = malloc(len)) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, lsa, len) == -1)
+			fatalx("bad LS_UPD imsg received");
 
-				/* directly send current LSA, no ack */
-				imsg_compose(imsg_ospfe, IMSG_LS_UPD,
-				    imsg.hdr.peerid, 0, -1, v->lsa,
-				    ntohs(v->lsa->hdr.len));
-			} else {
-				/* LSA equal send direct ack */
-				imsg_compose(imsg_ospfe, IMSG_LS_ACK,
-				    imsg.hdr.peerid, 0, -1, &lsa->hdr,
-				    sizeof(lsa->hdr));
-				free(lsa);
-			}
+		if (!lsa_check(nbr, lsa, len)) {
+			free(lsa);
 			break;
-		case IMSG_LS_MAXAGE:
-			nbr = rde_nbr_find(imsg.hdr.peerid);
-			if (nbr == NULL)
-				break;
+		}
 
-			if (imsg.hdr.len != IMSG_HEADER_SIZE +
-			    sizeof(struct lsa_hdr))
-				fatalx("invalid size of OE request");
-			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
+		v = lsa_find(nbr->iface, lsa->hdr.type, lsa->hdr.ls_id,
+		    lsa->hdr.adv_rtr);
+		if (v == NULL)
+			db_hdr = NULL;
+		else
+			db_hdr = &v->lsa->hdr;
 
-			if (rde_nbr_loading(nbr->area))
+		if (nbr->self) {
+			lsa_merge(nbr, lsa, v);
+			/* lsa_merge frees the right lsa */
+			break;
+		}
+
+		r = lsa_newer(&lsa->hdr, db_hdr);
+		if (r > 0) {
+			/* new LSA newer than DB */
+			if (v && v->flooded &&
+			    v->changed + MIN_LS_ARRIVAL >= now) {
+				free(lsa);
 				break;
+			}
 
-			v = lsa_find(nbr->iface, lsa_hdr.type, lsa_hdr.ls_id,
-			    lsa_hdr.adv_rtr);
-			if (v == NULL)
-				db_hdr = NULL;
-			else
-				db_hdr = &v->lsa->hdr;
+			rde_req_list_del(nbr, &lsa->hdr);
+
+			if (!(self = lsa_self(nbr, lsa, v)))
+				if (lsa_add(nbr, lsa))
+					/* delayed lsa */
+					break;
 
+			/* flood and perhaps ack LSA */
+			imsg_compose(imsg_ospfe, IMSG_LS_FLOOD,
+			    peerid, 0, -1, lsa, ntohs(lsa->hdr.len));
+
+			/* reflood self originated LSA */
+			if (self && v)
+				imsg_compose(imsg_ospfe,
+				    IMSG_LS_FLOOD, v->peerid, 0, -1,
+				    v->lsa, ntohs(v->lsa->hdr.len));
+			/* new LSA was not added so free it */
+			if (self)
+				free(lsa);
+		} else if (r < 0) {
 			/*
-			 * only delete LSA if the one in the db is not newer
+			 * point 6 of "The Flooding Procedure"
+			 * We are violating the RFC here because
+			 * it does not make sense to reset a session
+			 * because an equal LSA is already in the table.
+			 * Only if the LSA sent is older than the one
+			 * in the table we should reset the session.
 			 */
-			if (lsa_newer(db_hdr, &lsa_hdr) <= 0)
-				lsa_del(nbr, &lsa_hdr);
-			break;
-		case IMSG_CTL_SHOW_DATABASE:
-		case IMSG_CTL_SHOW_DB_EXT:
-		case IMSG_CTL_SHOW_DB_NET:
-		case IMSG_CTL_SHOW_DB_RTR:
-		case IMSG_CTL_SHOW_DB_SELF:
-		case IMSG_CTL_SHOW_DB_SUM:
-		case IMSG_CTL_SHOW_DB_ASBR:
-		case IMSG_CTL_SHOW_DB_OPAQ:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE &&
-			    imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(aid)) {
-				log_warnx("rde_dispatch_imsg: wrong imsg len");
+			if (rde_req_list_exists(nbr, &lsa->hdr)) {
+				imsg_compose(imsg_ospfe,
+				    IMSG_LS_BADREQ, peerid, 0, -1, NULL, 0);
+				free(lsa);
 				break;
 			}
-			if (imsg.hdr.len == IMSG_HEADER_SIZE) {
-				LIST_FOREACH(area, &rdeconf->area_list, entry) {
-					rde_dump_area(area, imsg.hdr.type,
-					    imsg.hdr.pid);
-				}
-				lsa_dump(&asext_tree, imsg.hdr.type,
-				    imsg.hdr.pid);
-			} else {
-				memcpy(&aid, imsg.data, sizeof(aid));
-				if ((area = area_find(rdeconf, aid)) != NULL) {
-					rde_dump_area(area, imsg.hdr.type,
-					    imsg.hdr.pid);
-					if (!area->stub)
-						lsa_dump(&asext_tree,
-						    imsg.hdr.type,
-						    imsg.hdr.pid);
-				}
-			}
-			imsg_compose(imsg_ospfe, IMSG_CTL_END, 0,
-			    imsg.hdr.pid, -1, NULL, 0);
-			break;
-		case IMSG_CTL_SHOW_RIB:
-			LIST_FOREACH(area, &rdeconf->area_list, entry) {
-				imsg_compose(imsg_ospfe, IMSG_CTL_AREA,
-				    0, imsg.hdr.pid, -1,
-				    &area->id, sizeof(area->id));
 
-				rt_dump(area->id, imsg.hdr.pid, RIB_RTR);
-				rt_dump(area->id, imsg.hdr.pid, RIB_NET);
-			}
-			aid.s_addr = 0;
-			rt_dump(aid, imsg.hdr.pid, RIB_EXT);
+			/* lsa no longer needed */
+			free(lsa);
 
-			imsg_compose(imsg_ospfe, IMSG_CTL_END, 0,
-			    imsg.hdr.pid, -1, NULL, 0);
-			break;
-		case IMSG_CTL_SHOW_SUM:
-			rde_send_summary(imsg.hdr.pid);
-			LIST_FOREACH(area, &rdeconf->area_list, entry)
-				rde_send_summary_area(area, imsg.hdr.pid);
-			imsg_compose(imsg_ospfe, IMSG_CTL_END, 0,
-			    imsg.hdr.pid, -1, NULL, 0);
-			break;
-		case IMSG_CTL_LOG_VERBOSE:
-			if (imsg_get_data(&imsg, &verbose, sizeof(verbose)) ==
-			    -1)
-				log_warn("wrong imsg len");
-			else
-				log_setverbose(verbose);
-			break;
-		default:
-			log_debug("rde_dispatch_imsg: unexpected imsg %d",
-			    imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
-	}
-}
+			/* new LSA older than DB */
+			if (ntohl(db_hdr->seq_num) == MAX_SEQ_NUM &&
+			    ntohs(db_hdr->age) == MAX_AGE)
+				/* seq-num wrap */
+				break;
 
-void
-rde_dispatch_parent(int fd, short event, void *arg)
-{
-	static struct area	*narea;
-	struct iface		*niface;
-	struct imsg		 imsg;
-	struct kroute		 rr;
-	struct imsgbuf		*ibuf = arg;
-	struct redistribute	*nred;
-	int			 n, shut = 0;
+			if (v->changed + MIN_LS_ARRIVAL >= now)
+				break;
 
-	if (event & EV_READ) {
-		if ((n = imsgbuf_read(ibuf)) == -1)
-			fatal("imsgbuf_read error");
-		if (n == 0)	/* connection closed */
-			shut = 1;
-	}
-	if (event & EV_WRITE) {
-		if (imsgbuf_write(ibuf) == -1) {
-			if (errno == EPIPE)	/* connection closed */
-				shut = 1;
-			else
-				fatal("imsgbuf_write");
+			/* directly send current LSA, no ack */
+			imsg_compose(imsg_ospfe, IMSG_LS_UPD,
+			    peerid, 0, -1, v->lsa, ntohs(v->lsa->hdr.len));
+		} else {
+			/* LSA equal send direct ack */
+			imsg_compose(imsg_ospfe, IMSG_LS_ACK, peerid, 0, -1,
+			    &lsa->hdr, sizeof(lsa->hdr));
+			free(lsa);
 		}
-	}
+		break;
+	case IMSG_LS_MAXAGE:
+		nbr = rde_nbr_find(peerid);
+		if (nbr == NULL)
+			break;
+
+		if (imsg_get_data(imsg, &lsa_hdr, sizeof(lsa_hdr)) == -1)
+			fatalx("bad LS_MAXAGE imsg received");
 
-	for (;;) {
-		if ((n = imsgbuf_get(ibuf, &imsg)) == -1)
-			fatal("rde_dispatch_parent: imsgbuf_get error");
-		if (n == 0)
+		if (rde_nbr_loading(nbr->area))
 			break;
 
-		switch (imsg.hdr.type) {
-		case IMSG_NETWORK_ADD:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(rr)) {
-				log_warnx("rde_dispatch_parent: "
-				    "wrong imsg len");
-				break;
+		v = lsa_find(nbr->iface, lsa_hdr.type, lsa_hdr.ls_id,
+		    lsa_hdr.adv_rtr);
+		if (v == NULL)
+			db_hdr = NULL;
+		else
+			db_hdr = &v->lsa->hdr;
+
+		/*
+		 * only delete LSA if the one in the db is not newer
+		 */
+		if (lsa_newer(db_hdr, &lsa_hdr) <= 0)
+			lsa_del(nbr, &lsa_hdr);
+		break;
+	case IMSG_CTL_SHOW_DATABASE:
+	case IMSG_CTL_SHOW_DB_EXT:
+	case IMSG_CTL_SHOW_DB_NET:
+	case IMSG_CTL_SHOW_DB_RTR:
+	case IMSG_CTL_SHOW_DB_SELF:
+	case IMSG_CTL_SHOW_DB_SUM:
+	case IMSG_CTL_SHOW_DB_ASBR:
+	case IMSG_CTL_SHOW_DB_OPAQ:
+		if (imsg_get_len(imsg) == 0) {
+			LIST_FOREACH(area, &rdeconf->area_list, entry) {
+				rde_dump_area(area, type, pid);
 			}
-			memcpy(&rr, imsg.data, sizeof(rr));
-			rde_asext_get(&rr);
-			break;
-		case IMSG_NETWORK_DEL:
-			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(rr)) {
-				log_warnx("rde_dispatch_parent: "
-				    "wrong imsg len");
+			lsa_dump(&asext_tree, type, pid);
+		} else {
+			if (imsg_get_data(imsg, &aid, sizeof(aid)) == -1) {
+				log_warnx("bad control imsg received");
 				break;
 			}
-			memcpy(&rr, imsg.data, sizeof(rr));
-			rde_asext_put(&rr);
-			break;
-		case IMSG_RECONF_CONF:
-			if ((nconf = malloc(sizeof(struct ospfd_conf))) ==
-			    NULL)
-				fatal(NULL);
-			memcpy(nconf, imsg.data, sizeof(struct ospfd_conf));
-
-			LIST_INIT(&nconf->area_list);
-			LIST_INIT(&nconf->cand_list);
-			break;
-		case IMSG_RECONF_AREA:
-			if ((narea = area_new()) == NULL)
-				fatal(NULL);
-			memcpy(narea, imsg.data, sizeof(struct area));
-
-			LIST_INIT(&narea->iface_list);
-			LIST_INIT(&narea->nbr_list);
-			RB_INIT(&narea->lsa_tree);
-			SIMPLEQ_INIT(&narea->redist_list);
-
-			LIST_INSERT_HEAD(&nconf->area_list, narea, entry);
-			break;
-		case IMSG_RECONF_REDIST:
-			if ((nred= malloc(sizeof(struct redistribute))) == NULL)
-				fatal(NULL);
-			memcpy(nred, imsg.data, sizeof(struct redistribute));
+			if ((area = area_find(rdeconf, aid)) != NULL) {
+				rde_dump_area(area, type, pid);
+				if (!area->stub)
+					lsa_dump(&asext_tree, type, pid);
+			}
+		}
+		imsg_compose(imsg_ospfe, IMSG_CTL_END, 0, pid, -1, NULL, 0);
+		break;
+	case IMSG_CTL_SHOW_RIB:
+		LIST_FOREACH(area, &rdeconf->area_list, entry) {
+			imsg_compose(imsg_ospfe, IMSG_CTL_AREA,
+			    0, pid, -1, &area->id, sizeof(area->id));
 
-			SIMPLEQ_INSERT_TAIL(&narea->redist_list, nred, entry);
-			break;
-		case IMSG_RECONF_IFACE:
-			if ((niface = malloc(sizeof(struct iface))) == NULL)
-				fatal(NULL);
-			memcpy(niface, imsg.data, sizeof(struct iface));
+			rt_dump(area->id, pid, RIB_RTR);
+			rt_dump(area->id, pid, RIB_NET);
+		}
+		aid.s_addr = 0;
+		rt_dump(aid, pid, RIB_EXT);
 
-			LIST_INIT(&niface->nbr_list);
-			TAILQ_INIT(&niface->ls_ack_list);
-			TAILQ_INIT(&niface->auth_md_list);
-			RB_INIT(&niface->lsa_tree);
+		imsg_compose(imsg_ospfe, IMSG_CTL_END, 0, pid, -1, NULL, 0);
+		break;
+	case IMSG_CTL_SHOW_SUM:
+		rde_send_summary(pid);
+		LIST_FOREACH(area, &rdeconf->area_list, entry)
+			rde_send_summary_area(area, pid);
+		imsg_compose(imsg_ospfe, IMSG_CTL_END, 0, pid, -1, NULL, 0);
+		break;
+	case IMSG_CTL_LOG_VERBOSE:
+		if (imsg_get_data(imsg, &verbose, sizeof(verbose)) ==
+		    -1)
+			log_warn("wrong imsg len");
+		else
+			log_setverbose(verbose);
+		break;
+	default:
+		log_debug("rde_dispatch_imsg: unexpected imsg %d", type);
+		break;
+	}
+}
 
-			niface->area = narea;
-			LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
+void
+rde_dispatch_parent(struct imsg *imsg, void *arg)
+{
+	static struct area	*narea;
+	struct iface		*niface;
+	struct redistribute	*nred;
+	struct kroute		 rr;
+	uint32_t		 type;
+
+	type = imsg_get_type(imsg);
+	switch (type) {
+	case IMSG_NETWORK_ADD:
+		if (imsg_get_data(imsg, &rr, sizeof(rr)) == -1)
+			fatalx("bad NETWORK_ADD imsg received");
+		rde_asext_get(&rr);
+		break;
+	case IMSG_NETWORK_DEL:
+		if (imsg_get_data(imsg, &rr, sizeof(rr)) == -1)
+			fatalx("bad NETWORK_DEL imsg received");
+		rde_asext_put(&rr);
+		break;
+	case IMSG_RECONF_CONF:
+		if ((nconf = malloc(sizeof(struct ospfd_conf))) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, nconf, sizeof(*nconf)) == -1)
+			fatalx("bad RECONF_CONF imsg received");
+
+		LIST_INIT(&nconf->area_list);
+		LIST_INIT(&nconf->cand_list);
+		break;
+	case IMSG_RECONF_AREA:
+		if ((narea = area_new()) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, narea, sizeof(*narea)) == -1)
+			fatalx("bad RECONF_AREA imsg received");
+
+		LIST_INIT(&narea->iface_list);
+		LIST_INIT(&narea->nbr_list);
+		RB_INIT(&narea->lsa_tree);
+		SIMPLEQ_INIT(&narea->redist_list);
+
+		LIST_INSERT_HEAD(&nconf->area_list, narea, entry);
+		break;
+	case IMSG_RECONF_REDIST:
+		if ((nred= malloc(sizeof(struct redistribute))) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, nred, sizeof(*nred)) == -1)
+			fatalx("bad RECONF_REDIST imsg received");
 
-			break;
-		case IMSG_RECONF_END:
-			merge_config(rdeconf, nconf);
-			nconf = NULL;
-			break;
-		default:
-			log_debug("rde_dispatch_parent: unexpected imsg %d",
-			    imsg.hdr.type);
-			break;
-		}
-		imsg_free(&imsg);
-	}
-	if (!shut)
-		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
-	else {
-		/* this pipe is dead, exit asap */
-		event_loopexit(NULL);
+		SIMPLEQ_INSERT_TAIL(&narea->redist_list, nred, entry);
+		break;
+	case IMSG_RECONF_IFACE:
+		if ((niface = malloc(sizeof(struct iface))) == NULL)
+			fatal(NULL);
+		if (imsg_get_data(imsg, niface, sizeof(*niface)) == -1)
+			fatalx("bad RECONF_IFACE imsg received");
+
+		LIST_INIT(&niface->nbr_list);
+		TAILQ_INIT(&niface->ls_ack_list);
+		TAILQ_INIT(&niface->auth_md_list);
+		RB_INIT(&niface->lsa_tree);
+
+		niface->area = narea;
+		LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
+		break;
+	case IMSG_RECONF_END:
+		merge_config(rdeconf, nconf);
+		nconf = NULL;
+		break;
+	default:
+		log_debug("rde_dispatch_parent: unexpected imsg %d", type);
+		break;
 	}
 }
 
@@ -1205,7 +1114,7 @@ rde_asext_get(struct kroute *kr)
 			/* lsa to insert is more specific, fix other lsa */
 			mask = v->lsa->data.asext.mask;
 			oan = asext_find(v->lsa->hdr.ls_id & mask,
-			   mask2prefixlen(mask));
+			    mask2prefixlen(mask));
 			if (oan == NULL)
 				fatalx("as-ext LSA DB corrupted");
 		}