diff options
-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: |