From: Claudio Jeker Subject: ospfd: rewrite the imsg handling part 2 To: tech@openbsd.org Date: Mon, 14 Sep 2026 15:49:24 +0200 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 #include #include @@ -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 -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"); }