diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-07-03 17:20:00 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-07-03 17:20:00 +0000 |
commit | 87cfe6e1e9ac329627ea8a97d6f5756ca6acb079 (patch) | |
tree | 2f284e8ba9618c7cf05143b38d6876c5aef8e362 /usr.sbin | |
parent | f67a7215fd9cb58925ec5da43a2f29466f8ac6a0 (diff) |
Switch mrt dumping to fd passing. This gives some speed up when extensive
dumping is done. Acctually mrt dumps were broken because of the fd passing.
The nice side effect is a much cleaner code, especially in the parent process.
OK henning@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 45 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 9 | ||||
-rw-r--r-- | usr.sbin/bgpd/buffer.c | 3 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.c | 506 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.h | 70 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 34 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 17 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 85 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 157 |
9 files changed, 435 insertions, 491 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index b66996e6ce7..01ff6cd1a42 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.97 2004/06/20 18:35:11 henning Exp $ */ +/* $OpenBSD: bgpd.c,v 1.98 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -83,11 +83,11 @@ usage(void) exit(1); } -#define POLL_MAX 8 #define PFD_PIPE_SESSION 0 #define PFD_PIPE_ROUTE 1 #define PFD_SOCK_ROUTE 2 -#define PFD_MRT_START 3 +#define POLL_MAX 3 +#define MAX_TIMEOUT 3600 int main(int argc, char *argv[]) @@ -99,13 +99,13 @@ main(int argc, char *argv[]) struct filter_head *rules_l; struct network *net; struct filter_rule *r; - struct mrt *(mrt[POLL_MAX]), *m; + struct mrt *m; struct listen_addr *la; struct pollfd pfd[POLL_MAX]; pid_t io_pid = 0, rde_pid = 0, pid; char *conffile; int debug = 0; - int ch, i, j, nfds, timeout; + int ch, nfds, timeout; int pipe_m2s[2]; int pipe_m2r[2]; int pipe_s2r[2]; @@ -236,6 +236,8 @@ main(int argc, char *argv[]) free(la); } + mrt_reconfigure(&mrt_l); + while (quit == 0) { pfd[PFD_PIPE_SESSION].fd = ibuf_se.fd; pfd[PFD_PIPE_SESSION].events = POLLIN; @@ -247,10 +249,12 @@ main(int argc, char *argv[]) pfd[PFD_PIPE_ROUTE].events |= POLLOUT; pfd[PFD_SOCK_ROUTE].fd = rfd; pfd[PFD_SOCK_ROUTE].events = POLLIN; - i = PFD_MRT_START; - i = mrt_select(&mrt_l, pfd, mrt, i, POLL_MAX, &timeout); - if ((nfds = poll(pfd, i, INFTIM)) == -1) + timeout = mrt_timeout(&mrt_l); + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + if ((nfds = poll(pfd, POLL_MAX, timeout * 1000)) == -1) if (errno != EINTR) { log_warn("poll error"); quit = 1; @@ -288,14 +292,6 @@ main(int argc, char *argv[]) quit = 1; } - for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { - if (pfd[j].revents & POLLOUT) { - if (mrt_write(mrt[j]) < 0) { - log_warn("mrt write error"); - } - } - } - if (reconfig) { log_info("rereading config"); reconfigure(conffile, &conf, &mrt_l, &peer_l, rules_l); @@ -329,7 +325,7 @@ main(int argc, char *argv[]) free(p); } while ((m = LIST_FIRST(&mrt_l)) != NULL) { - LIST_REMOVE(m, list); + LIST_REMOVE(m, entry); free(m); } @@ -424,6 +420,8 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) return (-1); + /* mrt changes can be sent out of bound */ + mrt_reconfigure(mrt_l); return (0); } @@ -431,6 +429,7 @@ int dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_head *mrt_l) { struct imsg imsg; + struct mrt mrt; int n; if ((n = imsg_read(ibuf)) == -1) @@ -449,10 +448,14 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_head *mrt_l) break; switch (imsg.hdr.type) { - case IMSG_MRT_MSG: - case IMSG_MRT_END: - if (mrt_queue(mrt_l, &imsg) == -1) - log_warnx("mrt_queue failed."); + case IMSG_MRT_CLOSE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct mrt)) { + log_warnx("wrong imsg len"); + break; + } + memcpy(&mrt, imsg.data, sizeof(struct mrt)); + mrt_close(mrt_get(mrt_l, &mrt)); break; case IMSG_KROUTE_CHANGE: if (idx != PFD_PIPE_ROUTE) diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 0823e88199d..8b7f35a3a02 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.132 2004/06/25 20:08:46 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.133 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -264,9 +264,9 @@ enum imsg_type { IMSG_UPDATE_ERR, IMSG_SESSION_UP, IMSG_SESSION_DOWN, - IMSG_MRT_REQ, - IMSG_MRT_MSG, - IMSG_MRT_END, + IMSG_MRT_OPEN, + IMSG_MRT_REOPEN, + IMSG_MRT_CLOSE, IMSG_KROUTE_CHANGE, IMSG_KROUTE_DELETE, IMSG_NEXTHOP_ADD, @@ -551,6 +551,7 @@ struct buf *buf_open(ssize_t); int buf_add(struct buf *, void *, ssize_t); void *buf_reserve(struct buf *, ssize_t); int buf_close(struct msgbuf *, struct buf *); +int buf_write(int, struct buf *); void buf_free(struct buf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); diff --git a/usr.sbin/bgpd/buffer.c b/usr.sbin/bgpd/buffer.c index a47ced7b15d..6887b793a59 100644 --- a/usr.sbin/bgpd/buffer.c +++ b/usr.sbin/bgpd/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.21 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: buffer.c,v 1.22 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -29,7 +29,6 @@ #include "bgpd.h" -int buf_write(int, struct buf *); void buf_enqueue(struct msgbuf *, struct buf *); void buf_dequeue(struct msgbuf *, struct buf *); diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index 121800b6eef..e68fccc95d8 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.32 2004/06/22 20:28:58 claudio Exp $ */ +/* $OpenBSD: mrt.c,v 1.33 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -34,17 +34,17 @@ static u_int16_t mrt_attr_length(struct attr_flags *); static int mrt_attr_dump(void *, u_int16_t, struct attr_flags *); -static int mrt_dump_entry(struct mrt_config *, struct prefix *, +static int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct peer_config *); static int mrt_dump_header(struct buf *, u_int16_t, u_int16_t, u_int32_t); -static int mrt_open(struct mrt *); +static int mrt_open(struct mrt *, time_t); #define DUMP_BYTE(x, b) \ do { \ u_char t = (b); \ - if (imsg_add((x), &t, sizeof(t)) == -1) { \ - log_warnx("mrt_dump1: imsg_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump1: buf_add error"); \ return (-1); \ } \ } while (0) @@ -53,8 +53,8 @@ static int mrt_open(struct mrt *); do { \ u_int16_t t; \ t = htons((s)); \ - if (imsg_add((x), &t, sizeof(t)) == -1) { \ - log_warnx("mrt_dump2: imsg_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump2: buf_add error"); \ return (-1); \ } \ } while (0) @@ -63,8 +63,8 @@ static int mrt_open(struct mrt *); do { \ u_int32_t t; \ t = htonl((l)); \ - if (imsg_add((x), &t, sizeof(t)) == -1) { \ - log_warnx("mrt_dump3: imsg_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump3: buf_add error"); \ return (-1); \ } \ } while (0) @@ -72,14 +72,14 @@ static int mrt_open(struct mrt *); #define DUMP_NLONG(x, l) \ do { \ u_int32_t t = (l); \ - if (imsg_add((x), &t, sizeof(t)) == -1) { \ - log_warnx("mrt_dump4: imsg_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump4: buf_add error"); \ return (-1); \ } \ } while (0) int -mrt_dump_bgp_msg(struct mrt_config *mrt, void *pkg, u_int16_t pkglen, +mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, struct peer_config *peer, struct bgpd_config *bgp) { struct buf *buf; @@ -87,15 +87,14 @@ mrt_dump_bgp_msg(struct mrt_config *mrt, void *pkg, u_int16_t pkglen, len = pkglen + MRT_BGP4MP_HEADER_SIZE; - if ((buf = imsg_create(mrt->ibuf, IMSG_MRT_MSG, mrt->id, - len + MRT_HEADER_SIZE)) == NULL) { - log_warnx("mrt_dump_bgp_msg: imsg_open error"); + if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { + log_warnx("mrt_dump_bgp_msg: buf_open error"); return (-1); } if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, len) == -1) { - log_warnx("mrt_dump_bgp_msg: imsg_add error"); + log_warnx("mrt_dump_bgp_msg: buf_add error"); return (-1); } @@ -106,21 +105,19 @@ mrt_dump_bgp_msg(struct mrt_config *mrt, void *pkg, u_int16_t pkglen, DUMP_NLONG(buf, peer->local_addr.v4.s_addr); DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); - if (imsg_add(buf, pkg, pkglen) == -1) { - log_warnx("mrt_dump_bgp_msg: imsg_add error"); + if (buf_add(buf, pkg, pkglen) == -1) { + log_warnx("mrt_dump_bgp_msg: buf_add error"); return (-1); } - if ((imsg_close(mrt->ibuf, buf)) == -1) { - log_warnx("mrt_dump_bgp_msg: imsg_close error"); - return (-1); - } + TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); + mrt->queued++; return (len + MRT_HEADER_SIZE); } int -mrt_dump_state(struct mrt_config *mrt, u_int16_t old_state, u_int16_t new_state, +mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, struct peer_config *peer, struct bgpd_config *bgp) { struct buf *buf; @@ -128,15 +125,14 @@ mrt_dump_state(struct mrt_config *mrt, u_int16_t old_state, u_int16_t new_state, len = 4 + MRT_BGP4MP_HEADER_SIZE; - if ((buf = imsg_create(mrt->ibuf, IMSG_MRT_MSG, mrt->id, - len + MRT_HEADER_SIZE)) == NULL) { - log_warnx("mrt_dump_bgp_state: imsg_open error"); + if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { + log_warnx("mrt_dump_bgp_state: buf_open error"); return (-1); } if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE, len) == -1) { - log_warnx("mrt_dump_bgp_state: imsg_add error"); + log_warnx("mrt_dump_bgp_state: buf_add error"); return (-1); } @@ -150,10 +146,8 @@ mrt_dump_state(struct mrt_config *mrt, u_int16_t old_state, u_int16_t new_state, DUMP_SHORT(buf, old_state); DUMP_SHORT(buf, new_state); - if ((imsg_close(mrt->ibuf, buf)) == -1) { - log_warnx("mrt_dump_bgp_state: imsg_close error"); - return (-1); - } + TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); + mrt->queued++; return (len + MRT_HEADER_SIZE); } @@ -232,7 +226,7 @@ mrt_attr_dump(void *p, u_int16_t len, struct attr_flags *a) } static int -mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, +mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, struct peer_config *peer) { struct buf *buf; @@ -244,9 +238,8 @@ mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, len = MRT_DUMP_HEADER_SIZE + attr_len; pt_getaddr(p->prefix, &addr); - if ((buf = imsg_create(mrt->ibuf, IMSG_MRT_MSG, mrt->id, - len + MRT_HEADER_SIZE)) == NULL) { - log_warnx("mrt_dump_entry: imsg_open error"); + if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { + log_warnx("mrt_dump_entry: buf_open error"); return (-1); } @@ -277,10 +270,8 @@ mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, return (-1); } - if ((imsg_close(mrt->ibuf, buf)) == -1) { - log_warnx("mrt_dump_bgp_state: imsg_close error"); - return (-1); - } + TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); + mrt->queued++; return (len + MRT_HEADER_SIZE); } @@ -296,7 +287,7 @@ mrt_clear_seq(void) void mrt_dump_upcall(struct pt_entry *pt, void *ptr) { - struct mrt_config *mrtbuf = ptr; + struct mrt *mrtbuf = ptr; struct prefix *p; /* @@ -325,6 +316,39 @@ mrt_dump_header(struct buf *buf, u_int16_t type, u_int16_t subtype, return (0); } +int +mrt_write(struct mrt *mrt) +{ + struct buf *b; + int r = 0; + + while ((b = TAILQ_FIRST(&mrt->bufs)) && + (r = buf_write(mrt->fd, b)) == 1) { + TAILQ_REMOVE(&mrt->bufs, b, entry); + mrt->queued--; + buf_free(b); + } + if (r == -1) { + log_warn("mrt dump write"); + mrt_clean(mrt); + return (-1); + } + return (0); +} + +void +mrt_clean(struct mrt *mrt) +{ + struct buf *b; + + close(mrt->fd); + while ((b = TAILQ_FIRST(&mrt->bufs))) { + TAILQ_REMOVE(&mrt->bufs, b, entry); + buf_free(b); + } + mrt->queued = 0; +} + static struct imsgbuf *mrt_imsgbuf[2]; void @@ -334,339 +358,147 @@ mrt_init(struct imsgbuf *rde, struct imsgbuf *se) mrt_imsgbuf[1] = se; } -static int -mrt_open(struct mrt *mrt) +int +mrt_open(struct mrt *mrt, time_t now) { - time_t now; + enum imsg_type type; + int i; - now = time(NULL); - if (strftime(mrt->file, sizeof(mrt->file), mrt->name, - localtime(&now)) == 0) { + mrt_close(mrt); + if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), + MRT2MC(mrt)->name, localtime(&now)) == 0) { log_warnx("mrt_open: strftime conversion failed"); - mrt->msgbuf.fd = -1; - return (0); + mrt->fd = -1; + return (-1); } - mrt->msgbuf.fd = open(mrt->file, + mrt->fd = open(MRT2MC(mrt)->file, O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644); - if (mrt->msgbuf.fd == -1) { - log_warnx("mrt_open %s: %s", - mrt->file, strerror(errno)); - return (0); + if (mrt->fd == -1) { + log_warn("mrt_open %s", MRT2MC(mrt)->file); + return (1); } - return (1); -} -static int -mrt_close(struct mrt *mrt) -{ - /* - * close the mrt filedescriptor but first ensure that the last - * mrt message was written correctly. If not mrt_write needs to do - * that the next time called. - * To ensure this we need to fiddle around with internal msgbuf stuff. - */ - if (msgbuf_unbounded(&mrt->msgbuf)) - return (0); + if (MRT2MC(mrt)->state == MRT_STATE_OPEN) + type = IMSG_MRT_OPEN; + else + type = IMSG_MRT_REOPEN; - if (mrt->msgbuf.fd != -1) { - close(mrt->msgbuf.fd); - mrt->msgbuf.fd = -1; - } + i = mrt->type == MRT_TABLE_DUMP ? 0 : 1; + + if (imsg_compose_fdpass(mrt_imsgbuf[i], type, mrt->fd, + mrt, sizeof(struct mrt)) == -1) + log_warn("mrt_close"); return (1); } void -mrt_abort(struct mrt *mrt) +mrt_close(struct mrt *mrt) { + if (mrt == NULL) + return; /* - * something failed horribly. Stop all dumping and go back to start - * position. Retry after MRT_MIN_RETRY or ReopenTimerInterval. Which- - * ever is bigger. + * this function is normaly called twice. First because of a imsg + * form the child to inform the parent to close the fd. The second time + * it is called after reconfigure when the mrt file gets removed. + * In that case the parent must inform the child to close and remove + * this mrt dump descriptor. */ - msgbuf_clear(&mrt->msgbuf); - mrt_close(mrt); - mrt->state = MRT_STATE_STOPPED; - - if (MRT_MIN_RETRY > mrt->ReopenTimerInterval) - mrt->ReopenTimer = MRT_MIN_RETRY + time(NULL); - else - mrt->ReopenTimer = mrt->ReopenTimerInterval + time(NULL); + if (MRT2MC(mrt)->state == MRT_STATE_REMOVE) + if (imsg_compose( + mrt_imsgbuf[mrt->type == MRT_TABLE_DUMP ? 0 : 1], + IMSG_MRT_CLOSE, 0, mrt, sizeof(struct mrt)) == -1) + log_warn("mrt_close"); + + if (mrt->fd == -1) + return; + close(mrt->fd); + mrt->fd = -1; } int -mrt_queue(struct mrt_head *mrtc, struct imsg *imsg) +mrt_timeout(struct mrt_head *mrt) { - struct buf *wbuf; struct mrt *m; - ssize_t len; - int n; - - if (imsg->hdr.type != IMSG_MRT_MSG && imsg->hdr.type != IMSG_MRT_END) - return (-1); - - LIST_FOREACH(m, mrtc, list) { - if (m->conf.id != imsg->hdr.peerid) - continue; - if (m->state != MRT_STATE_RUNNING && - m->state != MRT_STATE_REOPEN) - return (0); - - if (imsg->hdr.type == IMSG_MRT_END) { - m->state = MRT_STATE_CLOSE; - return (0); - } - - len = imsg->hdr.len - IMSG_HEADER_SIZE; - wbuf = buf_open(len); - if (wbuf == NULL) - return (-1); - if (buf_add(wbuf, imsg->data, len) == -1) { - buf_free(wbuf); - return (-1); - } - if ((n = buf_close(&m->msgbuf, wbuf)) < 0) { - buf_free(wbuf); - return (-1); - } - return (n); - } - return (0); -} - -int -mrt_write(struct mrt *mrt) -{ - int r; + time_t now; + int timeout = MRT_MAX_TIMEOUT; - if (mrt->state == MRT_STATE_REOPEN || - mrt->state == MRT_STATE_REMOVE) - r = msgbuf_writebound(&mrt->msgbuf); - else - r = msgbuf_write(&mrt->msgbuf); - - switch (r) { - case 1: - /* only msgbuf_writebound returns 1 */ - break; - case 0: - if (mrt->state == MRT_STATE_CLOSE && mrt->msgbuf.queued == 0) { - if (mrt_close(mrt) != 1) { - log_warnx("mrt_write: mrt_close failed"); - mrt_abort(mrt); - return (0); + now = time(NULL); + LIST_FOREACH(m, mrt, entry) { + if (MRT2MC(m)->state == MRT_STATE_RUNNING && + MRT2MC(m)->ReopenTimerInterval != 0) { + if (MRT2MC(m)->ReopenTimer <= now) { + mrt_open(m, now); + MRT2MC(m)->ReopenTimer = + now + MRT2MC(m)->ReopenTimerInterval; } - mrt->state = MRT_STATE_STOPPED; - } - return (0); - case -1: - log_warnx("mrt_write: msgbuf_write: %s", - strerror(errno)); - mrt_abort(mrt); - return (0); - case -2: - log_warnx("mrt_write: msgbuf_write: %s", - "connection closed"); - mrt_abort(mrt); - return (0); - default: - fatalx("mrt_write: unexpected retval from msgbuf_write"); - } - - if (mrt_close(mrt) != 1) { - log_warnx("mrt_write: mrt_close failed"); - mrt_abort(mrt); - return (0); - } - - switch (mrt->state) { - case MRT_STATE_REMOVE: - /* - * Remove request: free all left buffers and - * remove the descriptor. - */ - msgbuf_clear(&mrt->msgbuf); - LIST_REMOVE(mrt, list); - free(mrt); - return (0); - case MRT_STATE_REOPEN: - if (mrt_open(mrt) == 0) { - mrt_abort(mrt); - return (0); - } else { - if (mrt->ReopenTimerInterval != 0) - mrt->ReopenTimer = time(NULL) + - mrt->ReopenTimerInterval; - mrt->state = MRT_STATE_RUNNING; + if (MRT2MC(m)->ReopenTimer - now < timeout) + timeout = MRT2MC(m)->ReopenTimer - now; } - break; - default: - break; } - return (1); + return (timeout > 0 ? timeout : 0); } -int -mrt_select(struct mrt_head *mc, struct pollfd *pfd, struct mrt **mrt, - int start, int size, int *timeout) +void +mrt_reconfigure(struct mrt_head *mrt) { struct mrt *m, *xm; time_t now; - int t; now = time(NULL); - for (m = LIST_FIRST(mc); m != NULL; m = xm) { - xm = LIST_NEXT(m, list); - if (m->state == MRT_STATE_TOREMOVE) { - imsg_compose(m->ibuf, IMSG_MRT_END, 0, - &m->conf, sizeof(m->conf)); - if (mrt_close(m) == 0) { - m->state = MRT_STATE_REMOVE; - m->ReopenTimer = 0; - } else { - msgbuf_clear(&m->msgbuf); - LIST_REMOVE(m, list); - free(m); + for (m = LIST_FIRST(mrt); m != NULL; m = xm) { + xm = LIST_NEXT(m, entry); + if (MRT2MC(m)->state == MRT_STATE_OPEN || + MRT2MC(m)->state == MRT_STATE_REOPEN) { + if (mrt_open(m, now) == -1) continue; - } - } - if (m->state == MRT_STATE_OPEN) { - switch (m->conf.type) { - case MRT_TABLE_DUMP: - m->ibuf = mrt_imsgbuf[0]; - break; - case MRT_ALL_IN: - case MRT_ALL_OUT: - case MRT_UPDATE_IN: - case MRT_UPDATE_OUT: - m->ibuf = mrt_imsgbuf[1]; - break; - default: - continue; - } - if (mrt_open(m) == 0) { - mrt_abort(m); - t = m->ReopenTimer - now; - if (*timeout > t) - *timeout = t; - continue; - } - if (m->ReopenTimerInterval != 0) - m->ReopenTimer = now + m->ReopenTimerInterval; - m->state = MRT_STATE_RUNNING; - imsg_compose(m->ibuf, IMSG_MRT_REQ, 0, - &m->conf, sizeof(m->conf)); - } - if (m->state == MRT_STATE_REOPEN) { - if (mrt_close(m) == 0) { - m->state = MRT_STATE_REOPEN; - continue; - } - if (mrt_open(m) == 0) { - mrt_abort(m); - t = m->ReopenTimer - now; - if (*timeout > t) - *timeout = t; - continue; - } - if (m->ReopenTimerInterval != 0) - m->ReopenTimer = now + m->ReopenTimerInterval; - m->state = MRT_STATE_RUNNING; - } - if (m->ReopenTimer != 0) { - t = m->ReopenTimer - now; - if (t <= 0 && (m->state == MRT_STATE_RUNNING || - m->state == MRT_STATE_STOPPED)) { - if (m->state == MRT_STATE_RUNNING) { - /* reopen file */ - if (mrt_close(m) == 0) { - m->state = MRT_STATE_REOPEN; - continue; - } - } - if (mrt_open(m) == 0) { - mrt_abort(m); - t = m->ReopenTimer - now; - if (*timeout > t) - *timeout = t; - continue; - } - if (m->conf.type == MRT_TABLE_DUMP && - m->state == MRT_STATE_STOPPED) { - imsg_compose(mrt_imsgbuf[0], - IMSG_MRT_REQ, 0, - &m->conf, sizeof(m->conf)); - } - - m->state = MRT_STATE_RUNNING; - if (m->ReopenTimerInterval != 0) { - m->ReopenTimer = now + - m->ReopenTimerInterval; - if (*timeout > m->ReopenTimerInterval) - *timeout = t; - } - } + if (MRT2MC(m)->ReopenTimerInterval != 0) + MRT2MC(m)->ReopenTimer = + now + MRT2MC(m)->ReopenTimerInterval; + MRT2MC(m)->state = MRT_STATE_RUNNING; } - if (m->msgbuf.queued > 0) { - if (m->msgbuf.fd == -1 || - m->state == MRT_STATE_STOPPED) { - log_warnx("mrt_select: orphaned buffer"); - mrt_abort(m); - continue; - } - if (start < size) { - pfd[start].fd = m->msgbuf.fd; - pfd[start].events = POLLOUT; - mrt[start++] = m; - } + if (MRT2MC(m)->state == MRT_STATE_REMOVE) { + mrt_close(m); + LIST_REMOVE(m, entry); + free(m); + continue; } } - return (start); } -int +void mrt_handler(struct mrt_head *mrt) { struct mrt *m; time_t now; now = time(NULL); - LIST_FOREACH(m, mrt, list) { - if (m->state == MRT_STATE_RUNNING) - m->state = MRT_STATE_REOPEN; - if (m->conf.type == MRT_TABLE_DUMP) { - if (m->state == MRT_STATE_STOPPED) { - if (mrt_open(m) == 0) { - mrt_abort(m); - break; - } - imsg_compose(mrt_imsgbuf[0], IMSG_MRT_REQ, 0, - &m->conf, sizeof(m->conf)); - m->state = MRT_STATE_RUNNING; - } + LIST_FOREACH(m, mrt, entry) { + if (MRT2MC(m)->state == MRT_STATE_RUNNING && + (MRT2MC(m)->ReopenTimerInterval != 0 || + m->type == MRT_TABLE_DUMP)) { + if (mrt_open(m, now) == -1) + continue; + MRT2MC(m)->ReopenTimer = + now + MRT2MC(m)->ReopenTimerInterval; } - if (m->ReopenTimerInterval != 0) - m->ReopenTimer = now + m->ReopenTimerInterval; } - return (0); } -static u_int32_t max_id = 1; - -static struct mrt * -getconf(struct mrt_head *c, struct mrt *m) +struct mrt * +mrt_get(struct mrt_head *c, struct mrt *m) { struct mrt *t; - LIST_FOREACH(t, c, list) { - if (t->conf.type != m->conf.type) + LIST_FOREACH(t, c, entry) { + if (t->type != m->type) continue; - if (t->conf.type == MRT_TABLE_DUMP) - return t; - if (t->conf.peer_id == m->conf.peer_id && - t->conf.group_id == m->conf.group_id) - return t; + if (t->type == MRT_TABLE_DUMP) + return (t); + if (t->peer_id == m->peer_id && + t->group_id == m->group_id) + return (t); } return (NULL); } @@ -676,33 +508,35 @@ mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) { struct mrt *m, *xm; - LIST_FOREACH(m, nconf, list) - if ((xm = getconf(xconf, m)) == NULL) { + LIST_FOREACH(m, nconf, entry) { + if ((xm = mrt_get(xconf, m)) == NULL) { /* NEW */ - if ((xm = calloc(1, sizeof(struct mrt))) == NULL) + if ((xm = calloc(1, sizeof(struct mrt_config))) == NULL) fatal("mrt_mergeconfig"); - memcpy(xm, m, sizeof(struct mrt)); - msgbuf_init(&xm->msgbuf); - xm->conf.id = max_id++; - xm->state = MRT_STATE_OPEN; - LIST_INSERT_HEAD(xconf, xm, list); + memcpy(xm, m, sizeof(struct mrt_config)); + xm->fd = -1; + MRT2MC(xm)->state = MRT_STATE_OPEN; + LIST_INSERT_HEAD(xconf, xm, entry); } else { /* MERGE */ - if (strlcpy(xm->name, m->name, sizeof(xm->name)) >= - sizeof(xm->name)) + if (strlcpy(MRT2MC(xm)->name, MRT2MC(xm)->name, + sizeof(MRT2MC(xm)->name)) >= + sizeof(MRT2MC(xm)->name)) fatalx("mrt_mergeconfig: strlcpy"); - xm->ReopenTimerInterval = m->ReopenTimerInterval; - xm->state = MRT_STATE_REOPEN; + MRT2MC(xm)->ReopenTimerInterval = + MRT2MC(m)->ReopenTimerInterval; + MRT2MC(xm)->state = MRT_STATE_REOPEN; } + } - LIST_FOREACH(xm, xconf, list) - if (getconf(nconf, xm) == NULL) + LIST_FOREACH(xm, xconf, entry) + if (mrt_get(nconf, xm) == NULL) /* REMOVE */ - xm->state = MRT_STATE_TOREMOVE; + MRT2MC(xm)->state = MRT_STATE_REMOVE; /* free config */ while ((m = LIST_FIRST(nconf)) != NULL) { - LIST_REMOVE(m, list); + LIST_REMOVE(m, entry); free(m); } diff --git a/usr.sbin/bgpd/mrt.h b/usr.sbin/bgpd/mrt.h index 8e281461a59..19c457f0edf 100644 --- a/usr.sbin/bgpd/mrt.h +++ b/usr.sbin/bgpd/mrt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.h,v 1.10 2004/02/25 19:48:18 claudio Exp $ */ +/* $OpenBSD: mrt.h,v 1.11 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -244,56 +244,52 @@ enum mrt_type { }; enum mrt_state { - MRT_STATE_STOPPED, MRT_STATE_RUNNING, MRT_STATE_OPEN, - MRT_STATE_CLOSE, MRT_STATE_REOPEN, - MRT_STATE_TOREMOVE, MRT_STATE_REMOVE }; -LIST_HEAD(mrt_config_head, mrt_config); - -struct mrt_config { - enum mrt_type type; - u_int32_t id; - u_int32_t peer_id; - u_int32_t group_id; - struct imsgbuf *ibuf; - LIST_ENTRY(mrt_config) list; /* used in the SE */ +struct mrt { + enum mrt_type type; + u_int32_t peer_id; + u_int32_t group_id; + u_int32_t queued; + int fd; + TAILQ_HEAD(, buf) bufs; + LIST_ENTRY(mrt) entry; }; -struct mrt { - struct mrt_config conf; - time_t ReopenTimer; - time_t ReopenTimerInterval; - enum mrt_state state; - struct msgbuf msgbuf; - struct imsgbuf *ibuf; - char name[MRT_FILE_LEN]; /* base file name */ - char file[MRT_FILE_LEN]; /* actual file name */ - LIST_ENTRY(mrt) list; /* used in the parent */ +struct mrt_config { + struct mrt conf; + time_t ReopenTimer; + time_t ReopenTimerInterval; + enum mrt_state state; + char name[MRT_FILE_LEN]; /* base file name */ + char file[MRT_FILE_LEN]; /* actual file name */ }; +#define MRT2MC(x) ((struct mrt_config *)(x)) +#define MRT_MAX_TIMEOUT 7200 struct prefix; struct pt_entry; /* prototypes */ -int mrt_dump_bgp_msg(struct mrt_config *, void *, u_int16_t, - struct peer_config *, struct bgpd_config *); -int mrt_dump_state(struct mrt_config *, u_int16_t, u_int16_t, - struct peer_config *, struct bgpd_config *); -void mrt_clear_seq(void); -void mrt_dump_upcall(struct pt_entry *, void *); -void mrt_init(struct imsgbuf *, struct imsgbuf *); -void mrt_abort(struct mrt *); -int mrt_queue(struct mrt_head *, struct imsg *); -int mrt_write(struct mrt *); -int mrt_select(struct mrt_head *, struct pollfd *, struct mrt **, - int, int, int *); -int mrt_handler(struct mrt_head *); -int mrt_mergeconfig(struct mrt_head *, struct mrt_head *); +int mrt_dump_bgp_msg(struct mrt *, void *, u_int16_t, + struct peer_config *, struct bgpd_config *); +int mrt_dump_state(struct mrt *, u_int16_t, u_int16_t, + struct peer_config *, struct bgpd_config *); +void mrt_clear_seq(void); +void mrt_dump_upcall(struct pt_entry *, void *); +int mrt_write(struct mrt *); +void mrt_clean(struct mrt *); +void mrt_init(struct imsgbuf *, struct imsgbuf *); +void mrt_close(struct mrt *); +int mrt_timeout(struct mrt_head *); +void mrt_reconfigure(struct mrt_head *); +void mrt_handler(struct mrt_head *); +struct mrt *mrt_get(struct mrt_head *, struct mrt *); +int mrt_mergeconfig(struct mrt_head *, struct mrt_head *); #endif diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index a37537c017f..d970903d46c 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.116 2004/06/23 00:11:27 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.117 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -1573,44 +1573,44 @@ add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p) { struct mrt *m, *n; - LIST_FOREACH(m, mrtconf, list) { + LIST_FOREACH(m, mrtconf, entry) { if (p == NULL) { - if (m->conf.peer_id != 0 || m->conf.group_id != 0) + if (m->peer_id != 0 || m->group_id != 0) continue; } else { - if (m->conf.peer_id != p->conf.id || - m->conf.group_id != p->conf.groupid) + if (m->peer_id != p->conf.id || + m->group_id != p->conf.groupid) continue; } - if (m->conf.type == type) { + if (m->type == type) { yyerror("only one mrtdump per type allowed."); return (-1); } } - if ((n = calloc(1, sizeof(struct mrt))) == NULL) + if ((n = calloc(1, sizeof(struct mrt_config))) == NULL) fatal("add_mrtconfig"); - n->conf.type = type; - n->msgbuf.fd = -1; - if (strlcpy(n->name, name, sizeof(n->name)) >= sizeof(n->name)) { + n->type = type; + if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >= + sizeof(MRT2MC(n)->name)) { yyerror("filename \"%s\" too long: max %u", - name, sizeof(n->name) - 1); + name, sizeof(MRT2MC(n)->name) - 1); free(n); return (-1); } - n->ReopenTimerInterval = timeout; + MRT2MC(n)->ReopenTimerInterval = timeout; if (p != NULL) { if (curgroup == p) { - n->conf.peer_id = 0; - n->conf.group_id = p->conf.id; + n->peer_id = 0; + n->group_id = p->conf.id; } else { - n->conf.peer_id = p->conf.id; - n->conf.group_id = 0; + n->peer_id = p->conf.id; + n->group_id = 0; } } - LIST_INSERT_HEAD(mrtconf, n, list); + LIST_INSERT_HEAD(mrtconf, n, entry); return (0); } diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 95871b3b8c6..8f592d246b3 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.22 2004/06/20 18:35:12 henning Exp $ */ +/* $OpenBSD: printconf.c,v 1.23 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -353,16 +353,17 @@ print_mrt(u_int32_t pid, u_int32_t gid, const char *prep) if (xmrt_l == NULL) return; - LIST_FOREACH(m, xmrt_l, list) - if ((gid != 0 && m->conf.group_id == gid) || - (m->conf.peer_id == pid && m->conf.group_id == gid)) { - if (m->ReopenTimerInterval == 0) + LIST_FOREACH(m, xmrt_l, entry) + if ((gid != 0 && m->group_id == gid) || + (m->peer_id == pid && m->group_id == gid)) { + if (MRT2MC(m)->ReopenTimerInterval == 0) printf("%sdump %s %s\n", prep, - mrt_type(m->conf.type), m->name); + mrt_type(m->type), MRT2MC(m)->name); else printf("%sdump %s %s %d\n", prep, - mrt_type(m->conf.type), - m->name, m->ReopenTimerInterval); + mrt_type(m->type), + MRT2MC(m)->name, + MRT2MC(m)->ReopenTimerInterval); } } diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 1bc3ee8895c..0a0abd969a1 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.121 2004/06/24 23:15:58 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.122 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -35,6 +35,7 @@ #define PFD_PIPE_MAIN 0 #define PFD_PIPE_SESSION 1 +#define PFD_MRT_FILE 2 void rde_sighdlr(int); void rde_dispatch_imsg_session(struct imsgbuf *); @@ -84,6 +85,7 @@ struct rde_peer peerdynamic; struct filter_head *rules_l, *newrules; struct imsgbuf ibuf_se; struct imsgbuf ibuf_main; +struct mrt *mrt; void rde_sighdlr(int sig) @@ -107,10 +109,9 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, { pid_t pid; struct passwd *pw; - struct mrt *m; struct listen_addr *la; - struct pollfd pfd[2]; - int nfds; + struct pollfd pfd[3]; + int nfds, i; switch (pid = fork()) { case -1: @@ -153,10 +154,12 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, imsg_init(&ibuf_main, pipe_m2r[1]); /* main mrt list and listener list are not used in the SE */ - while ((m = LIST_FIRST(mrt_l)) != NULL) { - LIST_REMOVE(m, list); - free(m); + while ((mrt = LIST_FIRST(mrt_l)) != NULL) { + LIST_REMOVE(mrt, entry); + free(mrt); } + mrt = NULL; + while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) { TAILQ_REMOVE(config->listen_addrs, la, entry); free(la); @@ -184,7 +187,14 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, if (ibuf_se.w.queued > 0) pfd[PFD_PIPE_SESSION].events |= POLLOUT; - if ((nfds = poll(pfd, 2, INFTIM)) == -1) + i = 2; + if (mrt && mrt->queued) { + pfd[PFD_MRT_FILE].fd = mrt->fd; + pfd[PFD_MRT_FILE].events = POLLOUT; + i++; + } + + if ((nfds = poll(pfd, i, INFTIM)) == -1) if (errno != EINTR) fatal("poll error"); @@ -207,6 +217,15 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, nfds--; rde_dispatch_imsg_session(&ibuf_se); } + + if (nfds > 0 && pfd[PFD_MRT_FILE].revents & POLLOUT) { + if (mrt_write(mrt) == -1) { + free(mrt); + mrt = NULL; + } else if (mrt->queued == 0) + close(mrt->fd); + } + rde_update_queue_runner(); } @@ -334,8 +353,8 @@ void rde_dispatch_imsg_parent(struct imsgbuf *ibuf) { struct imsg imsg; - struct mrt_config mrt; struct filter_rule *r; + struct mrt *xmrt; int n; if ((n = imsg_read(ibuf)) == -1) @@ -400,18 +419,44 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) case IMSG_NEXTHOP_UPDATE: nexthop_update(imsg.data); break; - case IMSG_MRT_REQ: - memcpy(&mrt, imsg.data, sizeof(mrt)); - mrt.ibuf = &ibuf_main; - if (mrt.type == MRT_TABLE_DUMP) { - mrt_clear_seq(); - pt_dump(mrt_dump_upcall, &mrt, AF_UNSPEC); - if (imsg_compose(&ibuf_main, IMSG_MRT_END, - mrt.id, NULL, 0) == -1) - fatalx("imsg_compose error"); + case IMSG_MRT_OPEN: + case IMSG_MRT_REOPEN: + if (imsg.hdr.len > IMSG_HEADER_SIZE + + sizeof(struct mrt)) { + log_warnx("wrong imsg len"); + break; + } + + xmrt = calloc(1, sizeof(struct mrt)); + if (xmrt == NULL) + fatal("rde_dispatch_imsg_parent"); + memcpy(xmrt, imsg.data, sizeof(struct mrt)); + TAILQ_INIT(&xmrt->bufs); + + if ((xmrt->fd = imsg_get_fd(ibuf)) == -1) + log_warnx("expected to receive fd for mrt dump " + "but didn't receive any"); + + /* tell parent to close fd */ + if (imsg_compose(&ibuf_main, IMSG_MRT_CLOSE, 0, + xmrt, sizeof(struct mrt)) == -1) + log_warn("rde_dispatch_imsg_parent: mrt close"); + + if (xmrt->type == MRT_TABLE_DUMP) { + /* do not dump if a other is still running */ + if (mrt == NULL || mrt->queued == 0) { + free(mrt); + mrt = xmrt; + mrt_clear_seq(); + pt_dump(mrt_dump_upcall, mrt, + AF_UNSPEC); + break; + } } + close(xmrt->fd); + free(xmrt); break; - case IMSG_MRT_END: + case IMSG_MRT_CLOSE: /* ignore end message because a dump is atomic */ break; default: @@ -850,7 +895,7 @@ rde_update_log(const char *message, if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1) p = NULL; - log_debug("neighbor %s (AS%u) %s %s/%u %s", + log_info("neighbor %s (AS%u) %s %s/%u %s", log_addr(&peer->conf.remote_addr), peer->conf.remote_as, message, p ? p : "out of memory", nexthop ? nexthop : ""); diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 00063c8aab8..91fa899164b 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.180 2004/06/22 07:58:19 alexander Exp $ */ +/* $OpenBSD: session.c,v 1.181 2004/07/03 17:19:59 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -94,7 +94,7 @@ int csock = -1; struct imsgbuf ibuf_rde; struct imsgbuf ibuf_main; -struct mrt_config_head mrt_l; +struct mrt_head mrthead; void session_sighdlr(int sig) @@ -160,16 +160,17 @@ session_main(struct bgpd_config *config, struct peer *cpeers, struct network_head *net_l, struct filter_head *rules, struct mrt_head *m_l, int pipe_m2s[2], int pipe_s2r[2]) { - int nfds, i, j, timeout, idx_peers, idx_listeners; + int nfds, i, j, timeout; + int idx_peers, idx_listeners, idx_mrts; pid_t pid; time_t nextaction; - u_int pfd_elms = 0, peer_l_elms = 0, new_cnt; - u_int listener_cnt, peer_cnt, ctl_cnt; + u_int pfd_elms = 0, peer_l_elms = 0, mrt_l_elms = 0; + u_int listener_cnt, peer_cnt, ctl_cnt, mrt_cnt; + u_int new_cnt; struct passwd *pw; struct peer *p, **peer_l = NULL, *last, *next; struct network *net; - struct mrt *m; - struct mrt_config *mrt; + struct mrt *m, **mrt_l = NULL; struct filter_rule *r; struct pollfd *pfd = NULL; struct ctl_conn *ctl_conn; @@ -228,7 +229,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers, imsg_init(&ibuf_main, pipe_m2s[1]); TAILQ_INIT(&ctl_conns); csock = control_listen(); - LIST_INIT(&mrt_l); + LIST_INIT(&mrthead); peer_cnt = 0; ctl_cnt = 0; @@ -247,7 +248,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers, /* main mrt list is not used in the SE */ while ((m = LIST_FIRST(m_l)) != NULL) { - LIST_REMOVE(m, list); + LIST_REMOVE(m, entry); free(m); } @@ -300,8 +301,28 @@ session_main(struct bgpd_config *config, struct peer *cpeers, peer_l_elms = peer_cnt + PEER_L_RESERVE; } - new_cnt = - PFD_LISTENERS_START + listener_cnt + peer_cnt + ctl_cnt; + mrt_cnt = 0; + LIST_FOREACH(m, &mrthead, entry) { + if (m->queued) + mrt_cnt++; + } + + if (mrt_cnt > mrt_l_elms || + mrt_cnt + 2 * PEER_L_RESERVE < mrt_l_elms) { + if ((newp = realloc(mrt_l, sizeof(struct mrt *) * + (mrt_cnt + PEER_L_RESERVE))) == NULL) { + /* panic for now */ + log_warn("could not resize mrt_l from %u -> %u" + " entries", mrt_l_elms, + mrt_cnt + PEER_L_RESERVE); + fatalx("exiting"); + } + mrt_l = newp; + mrt_l_elms = mrt_cnt + PEER_L_RESERVE; + } + + new_cnt = PFD_LISTENERS_START + listener_cnt + peer_cnt + + ctl_cnt + mrt_cnt; if (new_cnt > pfd_elms || (new_cnt + 2) * PFD_RESERVE < pfd_elms) { if ((newp = realloc(pfd, sizeof(struct pollfd) * @@ -391,6 +412,16 @@ session_main(struct bgpd_config *config, struct peer *cpeers, idx_peers = i; + LIST_FOREACH(m, &mrthead, entry) + if (m->queued) { + pfd[i].fd = m->fd; + pfd[i].events = POLLOUT; + mrt_l[i - idx_peers] = m; + i++; + } + + idx_mrts = i; + TAILQ_FOREACH(ctl_conn, &ctl_conns, entry) { pfd[i].fd = ctl_conn->ibuf.fd; pfd[i].events = POLLIN; @@ -442,6 +473,12 @@ session_main(struct bgpd_config *config, struct peer *cpeers, nfds -= session_dispatch_msg(&pfd[j], peer_l[j - idx_listeners]); + for (; nfds > 0 && j < idx_mrts; j++) + if (pfd[j].revents & POLLOUT) { + nfds--; + mrt_write(mrt_l[j - idx_peers]); + } + for (; nfds > 0 && j < i; j++) nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt); } @@ -453,9 +490,10 @@ session_main(struct bgpd_config *config, struct peer *cpeers, free(p); } - while ((mrt = LIST_FIRST(&mrt_l)) != NULL) { - LIST_REMOVE(mrt, list); - free(mrt); + while ((m = LIST_FIRST(&mrthead)) != NULL) { + mrt_clean(m); + LIST_REMOVE(m, entry); + free(m); } while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { @@ -760,7 +798,7 @@ void change_state(struct peer *peer, enum session_state state, enum session_events event) { - struct mrt_config *mrt; + struct mrt *mrt; switch (state) { case STATE_IDLE: @@ -818,7 +856,7 @@ change_state(struct peer *peer, enum session_state state, } log_statechange(peer, state, event); - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_IN && mrt->type != MRT_ALL_OUT) continue; if ((mrt->peer_id == 0 && mrt->group_id == 0) || @@ -1074,7 +1112,7 @@ session_open(struct peer *p) { struct msg_open msg; struct buf *buf; - struct mrt_config *mrt; + struct mrt *mrt; u_int16_t len; int errs = 0; u_int8_t op_type, op_len = 0, optparamlen = 0; @@ -1154,7 +1192,7 @@ session_open(struct peer *p) } if (errs == 0) { - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_OUT) continue; if ((mrt->peer_id == 0 && mrt->group_id == 0) || @@ -1184,7 +1222,7 @@ session_keepalive(struct peer *peer) { struct msg_header msg; struct buf *buf; - struct mrt_config *mrt; + struct mrt *mrt; ssize_t len; int errs = 0; @@ -1208,7 +1246,7 @@ session_keepalive(struct peer *peer) return; } - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_OUT) continue; if ((mrt->peer_id == 0 && mrt->group_id == 0) || @@ -1234,7 +1272,7 @@ session_update(u_int32_t peerid, void *data, size_t datalen) struct peer *p; struct msg_header msg; struct buf *buf; - struct mrt_config *mrt; + struct mrt *mrt; ssize_t len; int errs = 0; @@ -1267,7 +1305,7 @@ session_update(u_int32_t peerid, void *data, size_t datalen) return; } - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_OUT && mrt->type != MRT_UPDATE_OUT) continue; if ((mrt->peer_id == 0 && mrt->group_id == 0) || @@ -1293,7 +1331,7 @@ session_notification(struct peer *peer, u_int8_t errcode, u_int8_t subcode, { struct msg_header msg; struct buf *buf; - struct mrt_config *mrt; + struct mrt *mrt; ssize_t len; int errs = 0; @@ -1322,7 +1360,7 @@ session_notification(struct peer *peer, u_int8_t errcode, u_int8_t subcode, return; } - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_OUT) continue; if ((mrt->peer_id == 0 && mrt->group_id == 0) || @@ -1481,7 +1519,7 @@ session_dispatch_msg(struct pollfd *pfd, struct peer *p) int parse_header(struct peer *peer, u_char *data, u_int16_t *len, u_int8_t *type) { - struct mrt_config *mrt; + struct mrt *mrt; u_char *p; u_char one = 0xff; int i; @@ -1566,7 +1604,7 @@ parse_header(struct peer *peer, u_char *data, u_int16_t *len, u_int8_t *type) type, 1); return (-1); } - LIST_FOREACH(mrt, &mrt_l, list) { + LIST_FOREACH(mrt, &mrthead, entry) { if (mrt->type != MRT_ALL_IN && (mrt->type != MRT_UPDATE_IN || *type != UPDATE)) continue; @@ -1971,8 +2009,8 @@ void session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) { struct imsg imsg; - struct mrt_config xmrt; - struct mrt_config *mrt; + struct mrt xmrt; + struct mrt *mrt; struct peer_config *pconf; struct peer *p, *next; struct listen_addr *la, *nla; @@ -2118,25 +2156,52 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) pending_reconf = 0; log_info("SE reconfigured"); break; - case IMSG_MRT_REQ: - if ((mrt = calloc(1, sizeof(struct mrt_config))) == - NULL) - fatal("session_dispatch_imsg"); - memcpy(mrt, imsg.data, sizeof(struct mrt_config)); - mrt->ibuf = &ibuf_main; - LIST_INSERT_HEAD(&mrt_l, mrt, list); + case IMSG_MRT_OPEN: + case IMSG_MRT_REOPEN: + if (imsg.hdr.len > IMSG_HEADER_SIZE + + sizeof(struct mrt)) { + log_warnx("wrong imsg len"); + break; + } + + memcpy(&xmrt, imsg.data, sizeof(struct mrt)); + if ((xmrt.fd = imsg_get_fd(ibuf)) == -1) + log_warnx("expected to receive fd for mrt dump " + "but didn't receive any"); + + mrt = mrt_get(&mrthead, &xmrt); + if (mrt == NULL) { + /* new dump */ + mrt = calloc(1, sizeof(struct mrt)); + if (mrt == NULL) + fatal("session_dispatch_imsg"); + memcpy(mrt, &xmrt, sizeof(struct mrt)); + TAILQ_INIT(&mrt->bufs); + LIST_INSERT_HEAD(&mrthead, mrt, entry); + } else { + /* old dump reopened */ + close(mrt->fd); + mrt->fd = xmrt.fd; + } + + /* tell parent to close fd */ + if (imsg_compose(&ibuf_main, IMSG_MRT_CLOSE, 0, + &xmrt, sizeof(struct mrt)) == -1) + log_warn("session_dispatch_imsg: mrt close"); break; - case IMSG_MRT_END: - memcpy(&xmrt, imsg.data, sizeof(struct mrt_config)); - LIST_FOREACH(mrt, &mrt_l, list) { - if (mrt->type != xmrt.type) - continue; - if (mrt->peer_id == xmrt.peer_id && - mrt->group_id == xmrt.group_id) { - LIST_REMOVE(mrt, list); - free(mrt); - break; - } + case IMSG_MRT_CLOSE: + if (imsg.hdr.len > IMSG_HEADER_SIZE + + sizeof(struct mrt)) { + log_warnx("wrong imsg len"); + break; + } + + memcpy(&xmrt, imsg.data, sizeof(struct mrt)); + mrt = mrt_get(&mrthead, &xmrt); + if (mrt != NULL) { + mrt_clean(mrt); + LIST_REMOVE(mrt, entry); + free(mrt); } break; case IMSG_CTL_KROUTE: |