Index | Thread | Search

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

Download raw body.

Thread
  • Claudio Jeker:

    ospfd: rewrite the imsg handling part 1

This is a major rework of the libevent based imsg handling in ospfd.
The goal is mostly to kill all the boilerplate around the libevent
integration of imsg handling.

This is using the new imsgbuf_set_userdata() and
imsgbuf_set_close_callback() API calls to wrap the imsg event properly
into the imsg framework.

All of this is wrapped inside imsgev.c.

With this imsg_compose_event() can be nuked and one can use the imsg API
directly without thinking about libevent. Also the setup is just one call
now :)

This diff only does the minimal bits and keeps the imsg handler (e.g.
main_dispatch_ospfe) mostly untouched. Part 2 of this will then rip out
that.

Seems to work for me but my ospfd usage is minimal.
-- 
:wq Claudio

diff --git usr.sbin/ospfd/Makefile usr.sbin/ospfd/Makefile
index 9094371611e..e03c34360df 100644
--- usr.sbin/ospfd/Makefile
+++ usr.sbin/ospfd/Makefile
@@ -1,7 +1,7 @@
 #	$OpenBSD: Makefile,v 1.9 2016/09/02 14:02:48 benno Exp $
 
 PROG=	ospfd
-SRCS=	area.c auth.c carp.c control.c database.c hello.c \
+SRCS=	area.c auth.c carp.c control.c database.c hello.c imsgev.c \
 	in_cksum.c interface.c iso_cksum.c kroute.c lsack.c \
 	lsreq.c lsupdate.c log.c logmsg.c neighbor.c ospfd.c ospfe.c packet.c \
 	parse.y printconf.c rde.c rde_lsdb.c rde_spf.c name2id.c
diff --git usr.sbin/ospfd/auth.c usr.sbin/ospfd/auth.c
index 046cddec0be..43b1ef11448 100644
--- usr.sbin/ospfd/auth.c
+++ usr.sbin/ospfd/auth.c
@@ -269,12 +269,12 @@ md_list_find(struct auth_md_head *head, u_int8_t keyid)
 }
 
 int
-md_list_send(struct auth_md_head *head, struct imsgev *to)
+md_list_send(struct auth_md_head *head, struct imsgbuf *to)
 {
 	struct auth_md	*m;
 
 	TAILQ_FOREACH(m, head, entry) {
-		if (imsg_compose_event(to, IMSG_RECONF_AUTHMD,
+		if (imsg_compose(to, IMSG_RECONF_AUTHMD,
 		    m->keyid, 0, -1, m->key, sizeof(m->key)) == -1)
 			return (-1);
 	}
diff --git usr.sbin/ospfd/control.c usr.sbin/ospfd/control.c
index cb6ca3fc8ae..396af06f422 100644
--- usr.sbin/ospfd/control.c
+++ usr.sbin/ospfd/control.c
@@ -176,17 +176,12 @@ control_accept(int listenfd, short event, void *bula)
 		return;
 	}
 
-	if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) {
+	if ((c->imsgbuf = imsgev_new(connfd, control_dispatch_imsg)) == NULL) {
 		log_warn("imsgbuf_init");
 		close(connfd);
 		free(c);
 		return;
 	}
-	c->iev.handler = control_dispatch_imsg;
-	c->iev.events = EV_READ;
-	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
-	    c->iev.handler, &c->iev);
-	event_add(&c->iev.ev, NULL);
 
 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
 }
@@ -197,7 +192,7 @@ control_connbyfd(int fd)
 	struct ctl_conn	*c;
 
 	TAILQ_FOREACH(c, &ctl_conns, entry) {
-		if (c->iev.ibuf.fd == fd)
+		if (c->imsgbuf->fd == fd)
 			break;
 	}
 
@@ -210,7 +205,7 @@ control_connbypid(pid_t pid)
 	struct ctl_conn	*c;
 
 	TAILQ_FOREACH(c, &ctl_conns, entry) {
-		if (c->iev.ibuf.pid == pid)
+		if (c->imsgbuf->pid == pid)
 			break;
 	}
 
@@ -227,11 +222,8 @@ control_close(int fd)
 		return;
 	}
 
-	imsgbuf_clear(&c->iev.ibuf);
 	TAILQ_REMOVE(&ctl_conns, c, entry);
-
-	event_del(&c->iev.ev);
-	close(c->iev.ibuf.fd);
+	imsgev_free(c->imsgbuf);
 
 	/* Some file descriptors are available again. */
 	if (evtimer_pending(&control_state.evt, NULL)) {
@@ -256,20 +248,20 @@ control_dispatch_imsg(int fd, short event, void *bula)
 	}
 
 	if (event & EV_READ) {
-		if (imsgbuf_read(&c->iev.ibuf) != 1) {
+		if (imsgbuf_read(c->imsgbuf) != 1) {
 			control_close(fd);
 			return;
 		}
 	}
 	if (event & EV_WRITE) {
-		if (imsgbuf_write(&c->iev.ibuf) == -1) {
+		if (imsgbuf_write(c->imsgbuf) == -1) {
 			control_close(fd);
 			return;
 		}
 	}
 
 	for (;;) {
-		if ((n = imsgbuf_get(&c->iev.ibuf, &imsg)) == -1) {
+		if ((n = imsgbuf_get(c->imsgbuf, &imsg)) == -1) {
 			control_close(fd);
 			return;
 		}
@@ -277,6 +269,7 @@ control_dispatch_imsg(int fd, short event, void *bula)
 		if (n == 0)
 			break;
 
+		c->imsgbuf->pid = imsg.hdr.pid;
 		switch (imsg.hdr.type) {
 		case IMSG_CTL_FIB_COUPLE:
 		case IMSG_CTL_FIB_DECOUPLE:
@@ -284,13 +277,11 @@ control_dispatch_imsg(int fd, short event, void *bula)
 			/* FALLTHROUGH */
 		case IMSG_CTL_FIB_RELOAD:
 		case IMSG_CTL_RELOAD:
-			c->iev.ibuf.pid = imsg.hdr.pid;
 			ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
 			break;
 		case IMSG_CTL_KROUTE:
 		case IMSG_CTL_KROUTE_ADDR:
 		case IMSG_CTL_IFINFO:
-			c->iev.ibuf.pid = imsg.hdr.pid;
 			ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
 			break;
@@ -299,7 +290,7 @@ control_dispatch_imsg(int fd, short event, void *bula)
 			    sizeof(ifidx)) {
 				memcpy(&ifidx, imsg.data, sizeof(ifidx));
 				ospfe_iface_ctl(c, ifidx);
-				imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
+				imsg_compose(c->imsgbuf, IMSG_CTL_END, 0,
 				    0, -1, NULL, 0);
 			}
 			break;
@@ -313,7 +304,6 @@ control_dispatch_imsg(int fd, short event, void *bula)
 		case IMSG_CTL_SHOW_DB_OPAQ:
 		case IMSG_CTL_SHOW_RIB:
 		case IMSG_CTL_SHOW_SUM:
-			c->iev.ibuf.pid = imsg.hdr.pid;
 			ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
 			break;
@@ -342,7 +332,7 @@ control_dispatch_imsg(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 
-	imsg_event_add(&c->iev);
+	imsg_event_add(c->imsgbuf, imsgbuf_get_userdata(c->imsgbuf));
 }
 
 int
@@ -353,6 +343,6 @@ control_imsg_relay(struct imsg *imsg)
 	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
 		return (0);
 
-	return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
+	return (imsg_compose(c->imsgbuf, imsg->hdr.type, 0, imsg->hdr.pid,
 	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
 }
diff --git usr.sbin/ospfd/control.h usr.sbin/ospfd/control.h
index 563a6237f25..7608b7805e2 100644
--- usr.sbin/ospfd/control.h
+++ usr.sbin/ospfd/control.h
@@ -24,8 +24,8 @@
 #include <event.h>
 
 struct ctl_conn {
-	TAILQ_ENTRY(ctl_conn)	entry;
-	struct imsgev		iev;
+	TAILQ_ENTRY(ctl_conn)	 entry;
+	struct imsgbuf		*imsgbuf;
 };
 
 int	control_check(char *);
diff --git usr.sbin/ospfd/imsgev.c usr.sbin/ospfd/imsgev.c
new file mode 100644
index 00000000000..9948006e8cb
--- /dev/null
+++ usr.sbin/ospfd/imsgev.c
@@ -0,0 +1,84 @@
+/*	$OpenBSD$ */
+
+/*
+ * Copyright (c) 2026 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <event.h>
+
+#include "imsgev.h"
+
+struct imsgev {
+	struct imsgbuf		 ibuf;
+	void			(*handler)(int, short, void *);
+	struct event		 ev;
+	short			 events;
+};
+
+void
+imsg_event_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_del(&iev->ev);
+	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler,
+	    &iev->ibuf);
+	event_add(&iev->ev, NULL);
+}
+
+struct imsgbuf *
+imsgev_new(int fd, void (*handler)(int, short, void *))
+{
+	struct imsgev *iev;
+
+	if ((iev = calloc(1, sizeof(struct imsgev))) == NULL)
+		return NULL;
+
+	if (imsgbuf_init(&iev->ibuf, fd) == -1) {
+		free(iev);
+		return NULL;
+	}
+
+	imsgbuf_set_userdata(&iev->ibuf, iev);
+	imsgbuf_set_close_callback(&iev->ibuf, imsg_event_add);
+	iev->handler = handler;
+
+	iev->events = EV_READ;
+	event_set(&iev->ev, fd, iev->events, iev->handler, &iev->ibuf);
+	event_add(&iev->ev, NULL);
+
+	return &iev->ibuf;
+}
+
+void
+imsgev_free(struct imsgbuf *imsgbuf)
+{
+	struct imsgev *iev;
+
+	iev = imsgbuf_get_userdata(imsgbuf);
+
+	close(imsgbuf->fd);
+	imsgbuf_clear(imsgbuf);
+
+	event_del(&iev->ev);
+	free(iev);
+}
diff --git usr.sbin/ospfd/imsgev.h usr.sbin/ospfd/imsgev.h
new file mode 100644
index 00000000000..75c4d1c587a
--- /dev/null
+++ usr.sbin/ospfd/imsgev.h
@@ -0,0 +1,23 @@
+/*	$OpenBSD$ */
+
+/*
+ * Copyright (c) 2026 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <imsg.h>
+
+void		 imsg_event_add(struct imsgbuf *, void *);
+struct imsgbuf	*imsgev_new(int, void (*)(int, short, void *));
+void		 imsgev_free(struct imsgbuf *);
diff --git usr.sbin/ospfd/ospfd.c usr.sbin/ospfd/ospfd.c
index 47f93716dcd..9a172415e82 100644
--- usr.sbin/ospfd/ospfd.c
+++ usr.sbin/ospfd/ospfd.c
@@ -69,8 +69,8 @@ int	pipe_ospfe2rde[2];
 
 enum ospfd_process	 ospfd_process;
 struct ospfd_conf	*ospfd_conf = NULL;
-static struct imsgev	*iev_ospfe;
-static struct imsgev	*iev_rde;
+static struct imsgbuf	*imsg_ospfe;
+static struct imsgbuf	*imsg_rde;
 char			*conffile;
 
 pid_t			 ospfe_pid = 0;
@@ -260,27 +260,12 @@ main(int argc, char *argv[])
 	close(pipe_ospfe2rde[0]);
 	close(pipe_ospfe2rde[1]);
 
-	if ((iev_ospfe = malloc(sizeof(struct imsgev))) == NULL ||
-	    (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
+	if ((imsg_ospfe = imsgev_new(pipe_parent2ospfe[0],
+	    main_dispatch_ospfe)) == NULL ||
+	    (imsg_rde = imsgev_new(pipe_parent2rde[0],
+	    main_dispatch_rde)) == NULL)
 		fatal(NULL);
-	if (imsgbuf_init(&iev_ospfe->ibuf, pipe_parent2ospfe[0]) == -1)
-		fatal(NULL);
-	imsgbuf_allow_fdpass(&iev_ospfe->ibuf);
-	iev_ospfe->handler = main_dispatch_ospfe;
-	if (imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1)
-		fatal(NULL);
-	iev_rde->handler = main_dispatch_rde;
-
-	/* setup event handler */
-	iev_ospfe->events = EV_READ;
-	event_set(&iev_ospfe->ev, iev_ospfe->ibuf.fd, iev_ospfe->events,
-	    iev_ospfe->handler, iev_ospfe);
-	event_add(&iev_ospfe->ev, NULL);
-
-	iev_rde->events = EV_READ;
-	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
-	    iev_rde->handler, iev_rde);
-	event_add(&iev_rde->ev, NULL);
+	imsgbuf_allow_fdpass(imsg_ospfe);
 
 	if ((control_fd = control_init(ospfd_conf->csock)) == -1)
 		fatalx("control socket setup failed");
@@ -316,12 +301,6 @@ ospfd_shutdown(void)
 	int			 status;
 	struct redistribute	*r;
 
-	/* close pipes */
-	imsgbuf_clear(&iev_ospfe->ibuf);
-	close(iev_ospfe->ibuf.fd);
-	imsgbuf_clear(&iev_rde->ibuf);
-	close(iev_rde->ibuf.fd);
-
 	control_cleanup();
 	while ((r = SIMPLEQ_FIRST(&ospfd_conf->redist_list)) != NULL) {
 		SIMPLEQ_REMOVE_HEAD(&ospfd_conf->redist_list, entry);
@@ -330,6 +309,9 @@ ospfd_shutdown(void)
 	kr_shutdown();
 	carp_demote_shutdown();
 
+	imsgev_free(imsg_ospfe);
+	imsgev_free(imsg_rde);
+
 	log_debug("waiting for children to terminate");
 	do {
 		pid = wait(&status);
@@ -342,8 +324,6 @@ ospfd_shutdown(void)
 			    "ospf engine", WTERMSIG(status));
 	} while (pid != -1 || (pid == -1 && errno == EINTR));
 
-	free(iev_ospfe);
-	free(iev_rde);
 	free(ospfd_conf);
 
 	log_info("terminating");
@@ -352,16 +332,13 @@ ospfd_shutdown(void)
 
 /* imsg handling */
 void
-main_dispatch_ospfe(int fd, short event, void *bula)
+main_dispatch_ospfe(int fd, short event, void *arg)
 {
-	struct imsgev		*iev = bula;
-	struct imsgbuf		*ibuf;
+	struct imsgbuf		*ibuf = arg;
 	struct imsg		 imsg;
 	struct demote_msg	 dmsg;
 	int			 n, shut = 0, verbose;
 
-	ibuf = &iev->ibuf;
-
 	if (event & EV_READ) {
 		if ((n = imsgbuf_read(ibuf)) == -1)
 			fatal("imsgbuf_read error");
@@ -432,24 +409,20 @@ main_dispatch_ospfe(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
 
 void
-main_dispatch_rde(int fd, short event, void *bula)
+main_dispatch_rde(int fd, short event, void *arg)
 {
-	struct imsgev	*iev = bula;
-	struct imsgbuf  *ibuf;
+	struct imsgbuf  *ibuf = arg;
 	struct imsg	 imsg;
 	int		 n, shut = 0;
 
-	ibuf = &iev->ibuf;
-
 	if (event & EV_READ) {
 		if ((n = imsgbuf_read(ibuf)) == -1)
 			fatal("imsgbuf_read error");
@@ -490,10 +463,9 @@ main_dispatch_rde(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
@@ -501,46 +473,22 @@ main_dispatch_rde(int fd, short event, void *bula)
 void
 main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen)
 {
-	if (iev_ospfe)
-		imsg_compose_event(iev_ospfe, type, 0, pid, -1, data, datalen);
+	if (imsg_ospfe)
+		imsg_compose(imsg_ospfe, type, 0, pid, -1, data, datalen);
 }
 
 void
 main_imsg_compose_ospfe_fd(int type, pid_t pid, int fd)
 {
-	if (iev_ospfe)
-		imsg_compose_event(iev_ospfe, type, 0, pid, fd, NULL, 0);
+	if (imsg_ospfe)
+		imsg_compose(imsg_ospfe, type, 0, pid, fd, NULL, 0);
 }
 
 void
 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
 {
-	if (iev_rde)
-		imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
-}
-
-void
-imsg_event_add(struct imsgev *iev)
-{
-	iev->events = EV_READ;
-	if (imsgbuf_queuelen(&iev->ibuf) > 0)
-		iev->events |= EV_WRITE;
-
-	event_del(&iev->ev);
-	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
-	event_add(&iev->ev, NULL);
-}
-
-int
-imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
-    pid_t pid, int fd, void *data, u_int16_t datalen)
-{
-	int	ret;
-
-	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
-	    pid, fd, data, datalen)) != -1)
-		imsg_event_add(iev);
-	return (ret);
+	if (imsg_rde)
+		imsg_compose(imsg_rde, type, 0, pid, -1, data, datalen);
 }
 
 int
@@ -764,7 +712,7 @@ ospf_reload(void)
 				return (-1);
 			if (iface->auth_type == AUTH_CRYPT)
 				if (md_list_send(&iface->auth_md_list,
-				    iev_ospfe) == -1)
+				    imsg_ospfe) == -1)
 					return (-1);
 		}
 	}
@@ -781,9 +729,9 @@ ospf_reload(void)
 int
 ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len)
 {
-	if (imsg_compose_event(iev_ospfe, type, 0, 0, -1, buf, len) == -1)
+	if (imsg_compose(imsg_ospfe, type, 0, 0, -1, buf, len) == -1)
 		return (-1);
-	if (imsg_compose_event(iev_rde, type, 0, 0, -1, buf, len) == -1)
+	if (imsg_compose(imsg_rde, type, 0, 0, -1, buf, len) == -1)
 		return (-1);
 	return (0);
 }
diff --git usr.sbin/ospfd/ospfd.h usr.sbin/ospfd/ospfd.h
index 5cf8c28f838..7e8a9955e5b 100644
--- usr.sbin/ospfd/ospfd.h
+++ usr.sbin/ospfd/ospfd.h
@@ -29,7 +29,7 @@
 #include <netinet/in.h>
 #include <event.h>
 
-#include <imsg.h>
+#include "imsgev.h"
 #include "ospf.h"
 #include "log.h"
 
@@ -67,14 +67,6 @@ static const char * const log_procnames[] = {
 	"rde"
 };
 
-struct imsgev {
-	struct imsgbuf		 ibuf;
-	void			(*handler)(int, short, void *);
-	struct event		 ev;
-	void			*data;
-	short			 events;
-};
-
 enum imsg_type {
 	IMSG_NONE,
 	IMSG_CTL_RELOAD,
@@ -619,9 +611,6 @@ void	main_imsg_compose_ospfe_fd(int, pid_t, int);
 void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
 int	ospf_redistribute(struct kroute *, u_int32_t *);
 void	merge_config(struct ospfd_conf *, struct ospfd_conf *);
-void	imsg_event_add(struct imsgev *);
-int	imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
-	    pid_t, int, void *, u_int16_t);
 int	ifstate_is_up(struct kif *kif);
 struct iface
 	*iface_txsan(const struct iface *);
diff --git usr.sbin/ospfd/ospfe.c usr.sbin/ospfd/ospfe.c
index 31ad7a07e7e..47c48cf0318 100644
--- usr.sbin/ospfd/ospfe.c
+++ usr.sbin/ospfd/ospfe.c
@@ -48,8 +48,8 @@ void		 orig_rtr_lsa_all(struct area *);
 struct iface	*find_vlink(struct abr_rtr *);
 
 struct ospfd_conf	*oeconf = NULL, *noeconf;
-static struct imsgev	*iev_main;
-static struct imsgev	*iev_rde;
+static struct imsgbuf	*imsg_main;
+static struct imsgbuf	*imsg_rde;
 int			 oe_nofib;
 
 void
@@ -152,27 +152,12 @@ ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2],
 	close(pipe_parent2rde[0]);
 	close(pipe_parent2rde[1]);
 
-	if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL ||
-	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
+	if ((imsg_rde = imsgev_new(pipe_ospfe2rde[0],
+	    ospfe_dispatch_rde)) == NULL ||
+	    (imsg_main = imsgev_new(pipe_parent2ospfe[1],
+	    ospfe_dispatch_main)) == NULL)
 		fatal(NULL);
-	if (imsgbuf_init(&iev_rde->ibuf, pipe_ospfe2rde[0]) == -1)
-		fatal(NULL);
-	iev_rde->handler = ospfe_dispatch_rde;
-	if (imsgbuf_init(&iev_main->ibuf, pipe_parent2ospfe[1]) == -1)
-		fatal(NULL);
-	imsgbuf_allow_fdpass(&iev_main->ibuf);
-	iev_main->handler = ospfe_dispatch_main;
-
-	/* setup event handler */
-	iev_rde->events = EV_READ;
-	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
-	    iev_rde->handler, iev_rde);
-	event_add(&iev_rde->ev, NULL);
-
-	iev_main->events = EV_READ;
-	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
-	    iev_main->handler, iev_main);
-	event_add(&iev_main->ev, NULL);
+	imsgbuf_allow_fdpass(imsg_main);
 
 	event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST,
 	    recv_packet, oeconf);
@@ -227,17 +212,13 @@ ospfe_shutdown(void)
 	nbr_del(nbr_find_peerid(NBR_IDSELF));
 	close(oeconf->ospf_socket);
 
-	/* close pipes */
-	imsgbuf_write(&iev_rde->ibuf);
-	imsgbuf_clear(&iev_rde->ibuf);
-	close(iev_rde->ibuf.fd);
-	imsgbuf_write(&iev_main->ibuf);
-	imsgbuf_clear(&iev_main->ibuf);
-	close(iev_main->ibuf.fd);
+	/* flush and close imsg pipes */
+	imsgbuf_write(imsg_rde);
+	imsgev_free(imsg_rde);
+	imsgbuf_write(imsg_main);
+	imsgev_free(imsg_main);
 
 	/* clean up */
-	free(iev_rde);
-	free(iev_main);
 	free(oeconf);
 
 	log_info("ospf engine exiting");
@@ -248,26 +229,24 @@ ospfe_shutdown(void)
 int
 ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
 {
-	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
+	return (imsg_compose(imsg_main, type, 0, pid, -1, data, datalen));
 }
 
 int
 ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
     void *data, u_int16_t datalen)
 {
-	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
-	    data, datalen));
+	return (imsg_compose(imsg_rde, type, peerid, pid, -1, data, datalen));
 }
 
 void
-ospfe_dispatch_main(int fd, short event, void *bula)
+ospfe_dispatch_main(int fd, short event, void *arg)
 {
 	static struct area	*narea;
 	static struct iface	*niface;
 	struct ifaddrchange	*ifc;
 	struct imsg	 imsg;
-	struct imsgev	*iev = bula;
-	struct imsgbuf	*ibuf = &iev->ibuf;
+	struct imsgbuf	*ibuf = arg;
 	struct area	*area = NULL;
 	struct iface	*iface = NULL;
 	struct kif	*kif;
@@ -478,21 +457,19 @@ ospfe_dispatch_main(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
 
 void
-ospfe_dispatch_rde(int fd, short event, void *bula)
+ospfe_dispatch_rde(int fd, short event, void *arg)
 {
 	struct ibuf		 buf;
 	struct lsa_hdr		 lsa_hdr;
-	struct imsgev		*iev = bula;
-	struct imsgbuf		*ibuf = &iev->ibuf;
+	struct imsgbuf		*ibuf = arg;
 	struct nbr		*nbr;
 	struct lsa_hdr		*lhp;
 	struct lsa_ref		*ref;
@@ -784,10 +761,9 @@ ospfe_dispatch_rde(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
@@ -1110,7 +1086,7 @@ orig_rtr_lsa(struct area *area)
 		fatal("orig_rtr_lsa: ibuf_set_n16 failed");
 
 	if (self && num_links)
-		imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0,
+		imsg_compose(imsg_rde, IMSG_LS_UPD, self->peerid, 0,
 		    -1, ibuf_data(buf), ibuf_size(buf));
 	else
 		log_warnx("orig_rtr_lsa: empty area %s",
@@ -1175,7 +1151,7 @@ orig_net_lsa(struct iface *iface)
 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
 		fatal("orig_net_lsa: ibuf_set_n16 failed");
 
-	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
+	imsg_compose(imsg_rde, IMSG_LS_UPD, iface->self->peerid, 0,
 	    -1, ibuf_data(buf), ibuf_size(buf));
 
 	ibuf_free(buf);
@@ -1211,7 +1187,7 @@ ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
 		LIST_FOREACH(iface, &area->iface_list, entry)
 			if (idx == 0 || idx == iface->ifindex) {
 				ictl = if_to_ctl(iface);
-				imsg_compose_event(&c->iev,
+				imsg_compose(c->imsgbuf,
 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
 				    ictl, sizeof(struct ctl_iface));
 			}
@@ -1230,13 +1206,13 @@ ospfe_nbr_ctl(struct ctl_conn *c)
 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
 				if (iface->self != nbr) {
 					nctl = nbr_to_ctl(nbr);
-					imsg_compose_event(&c->iev,
+					imsg_compose(c->imsgbuf,
 					    IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
 					    sizeof(struct ctl_nbr));
 				}
 			}
 
-	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
+	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 b16f0dfc50d..8483cbef069 100644
--- usr.sbin/ospfd/ospfe.h
+++ usr.sbin/ospfd/ospfe.h
@@ -102,7 +102,7 @@ int		 auth_gen(struct ibuf *, struct iface *);
 void		 md_list_add(struct auth_md_head *, u_int8_t, char *);
 void		 md_list_copy(struct auth_md_head *, struct auth_md_head *);
 void		 md_list_clr(struct auth_md_head *);
-int		 md_list_send(struct auth_md_head *, struct imsgev *);
+int		 md_list_send(struct auth_md_head *, struct imsgbuf *);
 
 /* database.c */
 int	 send_db_description(struct nbr *);
diff --git usr.sbin/ospfd/rde.c usr.sbin/ospfd/rde.c
index 57fbd33c3cd..4aad371b473 100644
--- usr.sbin/ospfd/rde.c
+++ usr.sbin/ospfd/rde.c
@@ -65,8 +65,8 @@ struct lsa	*orig_asext_lsa(struct kroute *, u_int32_t, u_int16_t);
 struct lsa	*orig_sum_lsa(struct rt_node *, struct area *, u_int8_t, int);
 
 struct ospfd_conf	*rdeconf = NULL, *nconf = NULL;
-static struct imsgev	*iev_ospfe;
-static struct imsgev	*iev_main;
+static struct imsgbuf	*imsg_ospfe;
+static struct imsgbuf	*imsg_main;
 struct rde_nbr		*nbrself;
 struct lsa_tree		 asext_tree;
 
@@ -158,26 +158,11 @@ rde(struct ospfd_conf *xconf, int pipe_parent2rde[2], int pipe_ospfe2rde[2],
 	close(pipe_parent2ospfe[0]);
 	close(pipe_parent2ospfe[1]);
 
-	if ((iev_ospfe = malloc(sizeof(struct imsgev))) == NULL ||
-	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
+	if ((imsg_ospfe = imsgev_new(pipe_ospfe2rde[1],
+	    rde_dispatch_imsg)) == NULL ||
+	    (imsg_main = imsgev_new(pipe_parent2rde[1],
+	    rde_dispatch_parent)) == NULL)
 		fatal(NULL);
-	if (imsgbuf_init(&iev_ospfe->ibuf, pipe_ospfe2rde[1]) == -1)
-		fatal(NULL);
-	iev_ospfe->handler = rde_dispatch_imsg;
-	if (imsgbuf_init(&iev_main->ibuf, pipe_parent2rde[1]) == -1)
-		fatal(NULL);
-	iev_main->handler = rde_dispatch_parent;
-
-	/* setup event handler */
-	iev_ospfe->events = EV_READ;
-	event_set(&iev_ospfe->ev, iev_ospfe->ibuf.fd, iev_ospfe->events,
-	    iev_ospfe->handler, iev_ospfe);
-	event_add(&iev_ospfe->ev, NULL);
-
-	iev_main->events = EV_READ;
-	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
-	    iev_main->handler, iev_main);
-	event_add(&iev_main->ev, NULL);
 
 	evtimer_set(&rdeconf->ev, spf_timer, rdeconf);
 	cand_list_init();
@@ -207,11 +192,6 @@ rde_shutdown(void)
 	struct area	*a;
 	struct vertex	*v, *nv;
 
-	/* close pipes */
-	imsgbuf_clear(&iev_ospfe->ibuf);
-	close(iev_ospfe->ibuf.fd);
-	imsgbuf_clear(&iev_main->ibuf);
-	close(iev_main->ibuf.fd);
 
 	stop_spf_timer(rdeconf);
 	cand_list_clr();
@@ -228,8 +208,8 @@ rde_shutdown(void)
 	rde_asext_free();
 	rde_nbr_free();
 
-	free(iev_ospfe);
-	free(iev_main);
+	imsgev_free(imsg_ospfe);
+	imsgev_free(imsg_main);
 	free(rdeconf);
 
 	log_info("route decision engine exiting");
@@ -240,15 +220,13 @@ int
 rde_imsg_compose_ospfe(int type, u_int32_t peerid, pid_t pid, void *data,
     u_int16_t datalen)
 {
-	return (imsg_compose_event(iev_ospfe, type, peerid, pid, -1,
-	    data, datalen));
+	return (imsg_compose(imsg_ospfe, type, peerid, pid, -1, data, datalen));
 }
 
 void
-rde_dispatch_imsg(int fd, short event, void *bula)
+rde_dispatch_imsg(int fd, short event, void *arg)
 {
-	struct imsgev		*iev = bula;
-	struct imsgbuf		*ibuf;
+	struct imsgbuf		*ibuf = arg;
 	struct imsg		 imsg;
 	struct in_addr		 aid;
 	struct ls_req_hdr	 req_hdr;
@@ -264,8 +242,6 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 	int			 n, r, state, self, error, shut = 0, verbose;
 	u_int16_t		 l;
 
-	ibuf = &iev->ibuf;
-
 	if (event & EV_READ) {
 		if ((n = imsgbuf_read(ibuf)) == -1)
 			fatal("imsgbuf_read error");
@@ -355,8 +331,8 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 
 			lsa_snap(nbr);
 
-			imsg_compose_event(iev_ospfe, IMSG_DB_END, imsg.hdr.peerid,
-			    0, -1, NULL, 0);
+			imsg_compose(imsg_ospfe, IMSG_DB_END,
+			    imsg.hdr.peerid, 0, -1, NULL, 0);
 			break;
 		case IMSG_DD:
 			nbr = rde_nbr_find(imsg.hdr.peerid);
@@ -388,7 +364,7 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 					 * newer or missing
 					 */
 					rde_req_list_add(nbr, &lsa_hdr);
-					imsg_compose_event(iev_ospfe, IMSG_DD,
+					imsg_compose(imsg_ospfe, IMSG_DD,
 					    imsg.hdr.peerid, 0, -1, &lsa_hdr,
 					    sizeof(lsa_hdr));
 				}
@@ -399,10 +375,10 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 				    "packet", imsg.hdr.peerid);
 
 			if (!error)
-				imsg_compose_event(iev_ospfe, IMSG_DD_END,
+				imsg_compose(imsg_ospfe, IMSG_DD_END,
 				    imsg.hdr.peerid, 0, -1, NULL, 0);
 			else
-				imsg_compose_event(iev_ospfe, IMSG_DD_BADLSA,
+				imsg_compose(imsg_ospfe, IMSG_DD_BADLSA,
 				    imsg.hdr.peerid, 0, -1, NULL, 0);
 			break;
 		case IMSG_LS_REQ:
@@ -421,12 +397,12 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 				    req_hdr.adv_rtr)) == NULL) {
 					log_debug("rde_dispatch_imsg: "
 					    "requested LSA not found");
-					imsg_compose_event(iev_ospfe,
+					imsg_compose(imsg_ospfe,
 					    IMSG_LS_BADREQ, imsg.hdr.peerid,
 					    0, -1, NULL, 0);
 					continue;
 				}
-				imsg_compose_event(iev_ospfe, IMSG_LS_UPD,
+				imsg_compose(imsg_ospfe, IMSG_LS_UPD,
 				    imsg.hdr.peerid, 0, -1, v->lsa,
 				    ntohs(v->lsa->hdr.len));
 			}
@@ -481,13 +457,13 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 						break;
 
 				/* flood and perhaps ack LSA */
-				imsg_compose_event(iev_ospfe, IMSG_LS_FLOOD,
+				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_event(iev_ospfe,
+					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 */
@@ -503,7 +479,7 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 				 * in the table we should reset the session.
 				 */
 				if (rde_req_list_exists(nbr, &lsa->hdr)) {
-					imsg_compose_event(iev_ospfe,
+					imsg_compose(imsg_ospfe,
 					    IMSG_LS_BADREQ, imsg.hdr.peerid,
 					    0, -1, NULL, 0);
 					free(lsa);
@@ -523,12 +499,12 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 					break;
 
 				/* directly send current LSA, no ack */
-				imsg_compose_event(iev_ospfe, IMSG_LS_UPD,
+				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_event(iev_ospfe, IMSG_LS_ACK,
+				imsg_compose(imsg_ospfe, IMSG_LS_ACK,
 				    imsg.hdr.peerid, 0, -1, &lsa->hdr,
 				    sizeof(lsa->hdr));
 				free(lsa);
@@ -591,12 +567,12 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 						    imsg.hdr.pid);
 				}
 			}
-			imsg_compose_event(iev_ospfe, IMSG_CTL_END, 0,
+			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_event(iev_ospfe, IMSG_CTL_AREA,
+				imsg_compose(imsg_ospfe, IMSG_CTL_AREA,
 				    0, imsg.hdr.pid, -1,
 				    &area->id, sizeof(area->id));
 
@@ -606,14 +582,14 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 			aid.s_addr = 0;
 			rt_dump(aid, imsg.hdr.pid, RIB_EXT);
 
-			imsg_compose_event(iev_ospfe, IMSG_CTL_END, 0,
+			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_event(iev_ospfe, IMSG_CTL_END, 0,
+			imsg_compose(imsg_ospfe, IMSG_CTL_END, 0,
 			    imsg.hdr.pid, -1, NULL, 0);
 			break;
 		case IMSG_CTL_LOG_VERBOSE:
@@ -631,28 +607,24 @@ rde_dispatch_imsg(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
 
 void
-rde_dispatch_parent(int fd, short event, void *bula)
+rde_dispatch_parent(int fd, short event, void *arg)
 {
 	static struct area	*narea;
 	struct iface		*niface;
 	struct imsg		 imsg;
 	struct kroute		 rr;
-	struct imsgev		*iev = bula;
-	struct imsgbuf		*ibuf;
+	struct imsgbuf		*ibuf = arg;
 	struct redistribute	*nred;
 	int			 n, shut = 0;
 
-	ibuf = &iev->ibuf;
-
 	if (event & EV_READ) {
 		if ((n = imsgbuf_read(ibuf)) == -1)
 			fatal("imsgbuf_read error");
@@ -747,10 +719,9 @@ rde_dispatch_parent(int fd, short event, void *bula)
 		imsg_free(&imsg);
 	}
 	if (!shut)
-		imsg_event_add(iev);
+		imsg_event_add(ibuf, imsgbuf_get_userdata(ibuf));
 	else {
-		/* this pipe is dead, so remove the event handler */
-		event_del(&iev->ev);
+		/* this pipe is dead, exit asap */
 		event_loopexit(NULL);
 	}
 }
@@ -760,12 +731,12 @@ rde_dump_area(struct area *area, int imsg_type, pid_t pid)
 {
 	struct iface	*iface;
 
-	imsg_compose_event(iev_ospfe, IMSG_CTL_AREA, 0, pid, -1, &area->id,
+	imsg_compose(imsg_ospfe, IMSG_CTL_AREA, 0, pid, -1, &area->id,
 	    sizeof(area->id));
 
 	/* dump link local lsa */
 	LIST_FOREACH(iface, &area->iface_list, entry) {
-		imsg_compose_event(iev_ospfe, IMSG_CTL_IFACE,
+		imsg_compose(imsg_ospfe, IMSG_CTL_IFACE,
 		    0, pid, -1, iface->name, sizeof(iface->name));
 		lsa_dump(&iface->lsa_tree, imsg_type, pid);
 	}
@@ -798,7 +769,7 @@ rde_send_change_kroute(struct rt_node *r)
 	struct rt_nexthop	*rn;
 	struct ibuf		*wbuf;
 
-	if ((wbuf = imsg_create(&iev_main->ibuf, IMSG_KROUTE_CHANGE, 0, 0,
+	if ((wbuf = imsg_create(imsg_main, IMSG_KROUTE_CHANGE, 0, 0,
 	    sizeof(kr))) == NULL) {
 		return;
 	}
@@ -824,8 +795,7 @@ rde_send_change_kroute(struct rt_node *r)
 		rde_send_delete_kroute(r);
 		return;
 	}
-	imsg_close(&iev_main->ibuf, wbuf);
-	imsg_event_add(iev_main);
+	imsg_close(imsg_main, wbuf);
 }
 
 void
@@ -837,7 +807,7 @@ rde_send_delete_kroute(struct rt_node *r)
 	kr.prefix.s_addr = r->prefix.s_addr;
 	kr.prefixlen = r->prefixlen;
 
-	imsg_compose_event(iev_main, IMSG_KROUTE_DELETE, 0, 0, -1,
+	imsg_compose(imsg_main, IMSG_KROUTE_DELETE, 0, 0, -1,
 	    &kr, sizeof(kr));
 }