diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 77 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 45 | ||||
-rw-r--r-- | usr.sbin/bgpd/buffer.c | 43 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.c | 593 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.h | 337 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 63 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 37 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 31 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 4 |
9 files changed, 759 insertions, 471 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index a60a7a8c3d8..632c1cd8c63 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.56 2004/01/05 19:10:24 henning Exp $ */ +/* $OpenBSD: bgpd.c,v 1.57 2004/01/05 22:57:59 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -39,11 +39,10 @@ void sighdlr(int); void usage(void); int main(int, char *[]); int check_child(pid_t, const char *); -int reconfigure(char *, struct bgpd_config *, struct mrt_config *, +int reconfigure(char *, struct bgpd_config *, struct mrt_head *, struct peer *); -int dispatch_imsg(struct imsgbuf *, int, struct mrt_config *); +int dispatch_imsg(struct imsgbuf *, int, struct mrt_head *); -int mrtfd = -1; int rfd = -1; volatile sig_atomic_t mrtdump = 0; volatile sig_atomic_t quit = 0; @@ -67,10 +66,8 @@ sighdlr(int sig) reconfig = 1; break; case SIGALRM: - mrtdump = 1; - break; case SIGUSR1: - mrtdump = 2; + mrtdump = 1; break; } } @@ -96,13 +93,13 @@ main(int argc, char *argv[]) { struct bgpd_config conf; struct peer *peer_l, *p, *next; - struct mrt_config mrtconf; - struct mrtdump_config *mconf, *(mrt[POLL_MAX]); + struct mrt_head mrtconf; + struct mrt *(mrt[POLL_MAX]); struct pollfd pfd[POLL_MAX]; pid_t io_pid = 0, rde_pid = 0, pid; char *conffile; int debug = 0; - int ch, i, j, n, nfds, csock; + int ch, csock, i, j, n, nfds, timeout; int pipe_m2s[2]; int pipe_m2r[2]; int pipe_s2r[2]; @@ -113,7 +110,6 @@ main(int argc, char *argv[]) log_init(1); /* log to stderr until daemonized */ bzero(&conf, sizeof(conf)); - bzero(&mrtconf, sizeof(mrtconf)); LIST_INIT(&mrtconf); peer_l = NULL; @@ -203,6 +199,7 @@ main(int argc, char *argv[]) imsg_init(&ibuf_se, pipe_m2s[0]); imsg_init(&ibuf_rde, pipe_m2r[0]); + mrt_init(&ibuf_rde, &ibuf_se); if ((rfd = kroute_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1) quit = 1; @@ -223,12 +220,7 @@ main(int argc, char *argv[]) pfd[PFD_SOCK_ROUTE].fd = rfd; pfd[PFD_SOCK_ROUTE].events = POLLIN; i = PFD_MRT_START; - LIST_FOREACH(mconf, &mrtconf, list) - if (mconf->msgbuf.queued > 0) { - pfd[i].fd = mconf->msgbuf.sock; - pfd[i].events |= POLLOUT; - mrt[i++] = mconf; - } + i = mrt_select(&mrtconf, pfd, mrt, i, POLL_MAX, &timeout); if ((nfds = poll(pfd, i, INFTIM)) == -1) if (errno != EINTR) { @@ -270,9 +262,8 @@ main(int argc, char *argv[]) for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { if (pfd[j].revents & POLLOUT) { - if ((n = msgbuf_write(&mrt[i]->msgbuf)) < 0) { - log_err("pipe write error (MRT)"); - quit = 1; + if ((n = mrt_write(mrt[i])) < 0) { + log_err("mrt write error"); } } } @@ -280,8 +271,6 @@ main(int argc, char *argv[]) if (reconfig) { logit(LOG_CRIT, "rereading config"); reconfigure(conffile, &conf, &mrtconf, peer_l); - LIST_FOREACH(mconf, &mrtconf, list) - mrt_state(mconf, IMSG_NONE, &ibuf_rde); reconfig = 0; } @@ -294,10 +283,7 @@ main(int argc, char *argv[]) } if (mrtdump == 1) { - mrt_alrm(&mrtconf, &ibuf_rde); - mrtdump = 0; - } else if (mrtdump == 2) { - mrt_usr1(&mrtconf, &ibuf_rde); + mrt_handler(&mrtconf); mrtdump = 0; } } @@ -342,7 +328,7 @@ check_child(pid_t pid, const char *pname) } int -reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc, +reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrtc, struct peer *peer_l) { struct peer *p, *next; @@ -376,18 +362,12 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc, return (0); } -/* - * XXX currently messages are only buffered for mrt files. - */ int -dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) +dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_head *mrtc) { - struct imsg imsg; - struct buf *wbuf; - struct mrtdump_config *m; - ssize_t len; - int n; - in_addr_t ina; + struct imsg imsg; + int n; + in_addr_t ina; if ((n = imsg_read(ibuf)) == -1) return (-1); @@ -407,27 +387,8 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) switch (imsg.hdr.type) { case IMSG_MRT_MSG: case IMSG_MRT_END: - LIST_FOREACH(m, conf, list) { - if (m->id != imsg.hdr.peerid) - continue; - if (mrt_state(m, imsg.hdr.type, ibuf) == 0) - break; - if (m->msgbuf.sock == -1) - break; - 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); - } - break; - } + if (mrt_queue(mrtc, &imsg) == -1) + logit(LOG_CRIT, "mrt_queue failed."); 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 56583a8a33f..e72dbbd79c3 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.53 2004/01/05 16:21:14 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.54 2004/01/05 22:57:59 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -115,41 +115,6 @@ struct peer_config { enum reconf_action reconf_action; }; -#define MRT_FILE_LEN 512 -enum mrtdump_type { - MRT_NONE, - MRT_TABLE_DUMP -/* - * MRT_UPDATE_START, - * MRT_SESSION_START, - * MRT_UPDATE_STOP, - * MRT_SESSION_STOP, - */ -}; - -enum mrtdump_state { - MRT_STATE_OPEN, - MRT_STATE_RUNNING, - MRT_STATE_DONE, - MRT_STATE_CLOSE, - MRT_STATE_REOPEN -}; - -LIST_HEAD(mrt_config, mrtdump_config); - -struct mrtdump_config { - enum mrtdump_type type; - u_int32_t id; - struct msgbuf msgbuf; - char name[MRT_FILE_LEN]; /* base file name */ - char file[MRT_FILE_LEN]; /* actual file name */ - time_t ReopenTimer; - time_t ReopenTimerInterval; - enum mrtdump_state state; - LIST_ENTRY(mrtdump_config) - list; -}; - /* ipc messages */ #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) @@ -196,6 +161,9 @@ struct imsg { void *data; }; +/* needed for session.h parse prototype */ +LIST_HEAD(mrt_head, mrt); + /* error subcode for UPDATE; needed in SE and RDE */ enum suberr_update { ERR_UPD_ATTRLIST = 1, @@ -237,6 +205,8 @@ void buf_free(struct buf *); void msgbuf_init(struct msgbuf *); void msgbuf_clear(struct msgbuf *); int msgbuf_write(struct msgbuf *); +int msgbuf_writebound(struct msgbuf *); +int msgbuf_unbounded(struct msgbuf *msgbuf); /* log.c */ void log_init(int); @@ -258,9 +228,6 @@ int imsg_get(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, int, u_int32_t, void *, u_int16_t); void imsg_free(struct imsg *); -/* mrt.c */ -int mrt_mergeconfig(struct mrt_config *, struct mrt_config *); - /* kroute.c */ int kroute_init(int); int kroute_change(struct kroute *); diff --git a/usr.sbin/bgpd/buffer.c b/usr.sbin/bgpd/buffer.c index bc0223b7f50..55d898a4e4d 100644 --- a/usr.sbin/bgpd/buffer.c +++ b/usr.sbin/bgpd/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.10 2003/12/26 17:13:52 henning Exp $ */ +/* $OpenBSD: buffer.c,v 1.11 2004/01/05 22:57:59 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -98,7 +98,7 @@ buf_write(int sock, struct buf *buf) ssize_t n; if ((n = write(sock, buf->buf + buf->rpos, - buf->size-buf->rpos)) == -1) { + buf->size - buf->rpos)) == -1) { if (errno == EAGAIN) /* cannot write immediately */ return (0); else @@ -170,6 +170,45 @@ msgbuf_write(struct msgbuf *msgbuf) return (0); } +int +msgbuf_writebound(struct msgbuf *msgbuf) +{ + /* + * possible race here + * when we cannot write out data completely from a buffer, + * we MUST return and NOT try to write out stuff from later buffers - + * the socket might have become writeable again + */ + struct buf *buf; + int n; + + if (!msgbuf_unbounded(msgbuf)) + return (1); + + buf = TAILQ_FIRST(&msgbuf->bufs); + if ((n = buf_write(msgbuf->sock, buf)) < 0) + return (n); + + if (n == 1) { /* everything written out */ + buf_dequeue(msgbuf, buf); + return (1); + } else + return (0); +} + +int +msgbuf_unbounded(struct msgbuf *msgbuf) +{ + struct buf *buf; + + /* return 1 if last buffer was not completely written. */ + buf = TAILQ_FIRST(&msgbuf->bufs); + if (buf != NULL && buf->rpos != 0) + return (1); + else + return (0); +} + void buf_enqueue(struct msgbuf *msgbuf, struct buf *buf) { diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index 7da202df50f..480912f6f6a 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.14 2004/01/01 21:18:13 henning Exp $ */ +/* $OpenBSD: mrt.c,v 1.15 2004/01/05 22:57:58 claudio Exp $ */ /* * Copyright (c) 2003 Claudio Jeker <claudio@openbsd.org> @@ -38,43 +38,51 @@ * XXX imsg_create(), imsg_add(), imsg_close() ... */ -static int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, +static int mrt_dump_entry(struct mrt_config *, struct prefix *, u_int16_t, struct peer_config *); -static void mrt_dump_header(struct buf *, u_int16_t, u_int16_t, u_int32_t); -static int mrt_open(struct mrtdump_config *); +static int mrt_dump_header(struct buf *, u_int16_t, u_int16_t, u_int32_t); +static int mrt_open(struct mrt *); #define DUMP_BYTE(x, b) \ do { \ u_char t = (b); \ - if (buf_add((x), &t, sizeof(t)) == -1) \ - fatalx("buf_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + logit(LOG_ERR, "mrt_dump1: buf_add error"); \ + return (-1); \ + } \ } while (0) #define DUMP_SHORT(x, s) \ do { \ u_int16_t t; \ t = htons((s)); \ - if (buf_add((x), &t, sizeof(t)) == -1) \ - fatalx("buf_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + logit(LOG_ERR, "mrt_dump2: buf_add error"); \ + return (-1); \ + } \ } while (0) #define DUMP_LONG(x, l) \ do { \ u_int32_t t; \ t = htonl((l)); \ - if (buf_add((x), &t, sizeof(t)) == -1) \ - fatalx("buf_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + logit(LOG_ERR, "mrt_dump3: buf_add error"); \ + return (-1); \ + } \ } while (0) #define DUMP_NLONG(x, l) \ do { \ u_int32_t t = (l); \ - if (buf_add((x), &t, sizeof(t)) == -1) \ - fatalx("buf_add error"); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + logit(LOG_ERR, "mrt_dump4: buf_add error"); \ + return (-1); \ + } \ } while (0) int -mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, int type, +mrt_dump_bgp_msg(struct mrt_config *mrt, void *pkg, u_int16_t pkglen, int type, struct peer_config *peer, struct bgpd_config *bgp) { struct buf *buf; @@ -82,18 +90,26 @@ mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, int type, int i, n; u_int16_t len; - len = pkglen + MRT_BGP4MP_HEADER_SIZE + type > 0 ? MSGSIZE_HEADER : 0; + len = pkglen + MRT_BGP4MP_HEADER_SIZE + (type > 0 ? MSGSIZE_HEADER : 0); hdr.len = len + IMSG_HEADER_SIZE + MRT_HEADER_SIZE; hdr.type = IMSG_MRT_MSG; hdr.peerid = mrt->id; buf = buf_open(hdr.len); - if (buf == NULL) - fatal("mrt_dump_bgp_msg"); - if (buf_add(buf, &hdr, sizeof(hdr)) == -1) - fatalx("buf_add error"); + if (buf == NULL) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_open error"); + return (-1); + } + if (buf_add(buf, &hdr, sizeof(hdr)) == -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } - mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, len); + if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, len) == + -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } DUMP_SHORT(buf, bgp->as); DUMP_SHORT(buf, peer->remote_as); @@ -110,17 +126,69 @@ mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, int type, DUMP_BYTE(buf, type); } - if (buf_add(buf, pkg, pkglen) == -1) - fatalx("buf_add error"); + if (buf_add(buf, pkg, pkglen) == -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } + + if ((n = buf_close(mrt->msgbuf, buf)) < 0) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_close error"); + return (-1); + } + + return (n); +} + +int +mrt_dump_state(struct mrt_config *mrt, u_int16_t old_state, u_int16_t new_state, + struct peer_config *peer, struct bgpd_config *bgp) +{ + struct buf *buf; + struct imsg_hdr hdr; + int n; + u_int16_t len; + + len = 4 + MRT_BGP4MP_HEADER_SIZE; + hdr.len = len + IMSG_HEADER_SIZE + MRT_HEADER_SIZE; + hdr.type = IMSG_MRT_MSG; + hdr.peerid = mrt->id; + buf = buf_open(hdr.len); + if (buf == NULL) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_open error"); + return (-1); + } + if (buf_add(buf, &hdr, sizeof(hdr)) == -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } + + if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE, + len) == -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } + + DUMP_SHORT(buf, bgp->as); + DUMP_SHORT(buf, peer->remote_as); + DUMP_SHORT(buf, /* ifindex */ 0); + DUMP_SHORT(buf, 4); + DUMP_NLONG(buf, peer->local_addr.sin_addr.s_addr); + DUMP_NLONG(buf, peer->remote_addr.sin_addr.s_addr); + + DUMP_SHORT(buf, old_state); + DUMP_SHORT(buf, new_state); - if ((n = buf_close(mrt->msgbuf, buf)) < 0) - fatalx("buf_close error"); + if ((n = buf_close(mrt->msgbuf, buf)) < 0) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_close error"); + return (-1); + } return (n); + } static int -mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, +mrt_dump_entry(struct mrt_config *mrt, struct prefix *p, u_int16_t snum, struct peer_config *peer) { struct buf *buf; @@ -136,31 +204,44 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, hdr.type = IMSG_MRT_MSG; hdr.peerid = mrt->id; buf = buf_open(hdr.len); - if (buf == NULL) - fatal("mrt_dump_entry"); - if (buf_add(buf, &hdr, sizeof(hdr)) == -1) - fatalx("buf_add error"); + if (buf == NULL) { + logit(LOG_ERR, "mrt_dump_entry: buf_open error"); + return (-1); + } + if (buf_add(buf, &hdr, sizeof(hdr)) == -1) { + logit(LOG_ERR, "mrt_dump_entry: buf_add error"); + return (-1); + } - mrt_dump_header(buf, MSG_TABLE_DUMP, AFI_IPv4, len); + if (mrt_dump_header(buf, MSG_TABLE_DUMP, AFI_IPv4, len) == -1) { + logit(LOG_ERR, "mrt_dump_bgp_msg: buf_add error"); + return (-1); + } DUMP_SHORT(buf, 0); DUMP_SHORT(buf, snum); DUMP_NLONG(buf, p->prefix->prefix.s_addr); DUMP_BYTE(buf, p->prefix->prefixlen); - DUMP_BYTE(buf, 1); + DUMP_BYTE(buf, 1); /* state */ DUMP_LONG(buf, p->lastchange); /* originated */ DUMP_NLONG(buf, peer->remote_addr.sin_addr.s_addr); DUMP_SHORT(buf, peer->remote_as); DUMP_SHORT(buf, attr_len); - if ((bptr = buf_reserve(buf, attr_len)) == NULL) - fatalx("buf_reserve error"); + if ((bptr = buf_reserve(buf, attr_len)) == NULL) { + logit(LOG_ERR, "mrt_dump_entry: buf_reserve error"); + return (-1); + } - if (attr_dump(bptr, attr_len, &p->aspath->flags) == -1) - fatalx("attr_dump error"); + if (attr_dump(bptr, attr_len, &p->aspath->flags) == -1) { + logit(LOG_ERR, "mrt_dump_entry: attr_dump error"); + return (-1); + } - if ((n = buf_close(mrt->msgbuf, buf)) < 0) - fatalx("buf_close error"); + if ((n = buf_close(mrt->msgbuf, buf)) < 0) { + logit(LOG_ERR, "mrt_dump_entry: buf_close error"); + return (-1); + } return (n); } @@ -176,8 +257,8 @@ mrt_clear_seq(void) void mrt_dump_upcall(struct pt_entry *pt, void *ptr) { - struct mrt *mrtbuf = ptr; - struct prefix *p; + struct mrt_config *mrtbuf = ptr; + struct prefix *p; /* * dump all prefixes even the inactive ones. That is the way zebra @@ -188,226 +269,357 @@ mrt_dump_upcall(struct pt_entry *pt, void *ptr) mrt_dump_entry(mrtbuf, p, sequencenum++, &p->peer->conf); } -static void +static int mrt_dump_header(struct buf *buf, u_int16_t type, u_int16_t subtype, u_int32_t len) { - struct mrt_header mrt; time_t now; now = time(NULL); - mrt.timestamp = htonl(now); - mrt.type = ntohs(type); - mrt.subtype = ntohs(subtype); - mrt.length = htonl(len); + DUMP_LONG(buf, now); + DUMP_SHORT(buf, type); + DUMP_SHORT(buf, subtype); + DUMP_LONG(buf, len); + + return (0); +} + +static struct imsgbuf *mrt_imsgbuf[2]; - if (buf_add(buf, &mrt, sizeof(mrt)) == -1) - fatalx("buf_add error"); +void +mrt_init(struct imsgbuf *rde, struct imsgbuf *se) +{ + mrt_imsgbuf[0] = rde; + mrt_imsgbuf[1] = se; } static int -mrt_open(struct mrtdump_config *mconf) +mrt_open(struct mrt *mrt) { time_t now; now = time(NULL); - if (strftime(mconf->file, sizeof(mconf->file), mconf->name, + if (strftime(mrt->file, sizeof(mrt->file), mrt->name, localtime(&now)) == 0) { - logit(LOG_CRIT, "mrt_open strftime failed"); - mconf->msgbuf.sock = -1; - return -1; + logit(LOG_ERR, "mrt_open: strftime conversion failed"); + mrt->msgbuf.sock = -1; + return (0); } - mconf->msgbuf.sock = open(mconf->file, + mrt->msgbuf.sock = open(mrt->file, O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644); - if (mconf->msgbuf.sock == -1) - logit(LOG_CRIT, "mrt_open %s: %s", - mconf->file, strerror(errno)); + if (mrt->msgbuf.sock == -1) { + logit(LOG_ERR, "mrt_open %s: %s", + mrt->file, strerror(errno)); + return (0); + } + return (1); +} - return mconf->msgbuf.sock; +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 (mrt->msgbuf.sock == -1) { + close(mrt->msgbuf.sock); + mrt->msgbuf.sock = -1; + } + + return (1); +} + +void +mrt_abort(struct mrt *mrt) +{ + /* + * something failed horribly. Stop all dumping and go back to start + * position. Retry after MRT_MIN_RETRY or ReopenTimerInterval. Which- + * ever is bigger. + */ + 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); } int -mrt_state(struct mrtdump_config *m, enum imsg_type type, - struct imsgbuf *buf) +mrt_queue(struct mrt_head *mrtc, struct imsg *imsg) { - switch (m->state) { - case MRT_STATE_DONE: - /* no dump expected */ - return (0); - case MRT_STATE_CLOSE: - switch (type) { - case IMSG_NONE: - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_END, m->id, NULL, 0); + 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); - case IMSG_MRT_END: - /* dump no longer valid */ - close(m->msgbuf.sock); - LIST_REMOVE(m, list); - free(m); + + if (imsg->hdr.type == IMSG_MRT_END) { + if (mrt_close(m) == 0) { + m->state = MRT_STATE_CLOSE; + } else { + msgbuf_clear(&m->msgbuf); + m->state = MRT_STATE_STOPPED; + } return (0); - default: - break; } - break; - case MRT_STATE_REOPEN: - switch (type) { - case IMSG_NONE: - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_END, m->id, NULL, 0); - return (0); - case IMSG_MRT_END: - if (m->msgbuf.sock != -1) - close(m->msgbuf.sock); - m->state = MRT_STATE_OPEN; - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_REQ, m->id, NULL, 0); - return (0); - default: - break; + + 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); } - break; - case MRT_STATE_OPEN: - switch (type) { - case IMSG_NONE: - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_REQ, m->id, NULL, 0); - return (0); - case IMSG_MRT_MSG: - mrt_open(m); - m->state = MRT_STATE_RUNNING; - break; - default: - return (0); + 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; + + if (mrt->state == MRT_STATE_REOPEN || + mrt->state == MRT_STATE_CLOSE || + 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 MRT_STATE_RUNNING: - if (type == IMSG_MRT_END) { - if (m->msgbuf.sock != -1) - close(m->msgbuf.sock); - m->msgbuf.sock = -1; - m->state = MRT_STATE_DONE; + case 0: + return (0); + case -1: + logit(LOG_ERR, "mrt_write: msgbuf_write: %s", + strerror(errno)); + mrt_abort(mrt); + return (0); + case -2: + logit(LOG_ERR, "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) { + logit(LOG_ERR, "mrt_write: mrt_close failed"); + 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_CLOSE: + /* Close request: free all left buffers */ + msgbuf_clear(&mrt->msgbuf); + mrt->state = MRT_STATE_STOPPED; + 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; } break; + default: + break; } return (1); } int -mrt_usr1(struct mrt_config *mconf, struct imsgbuf *buf) +mrt_select(struct mrt_head *mc, struct pollfd *pfd, struct mrt **mrt, + int start, int size, int *timeout) { - struct mrtdump_config *m; - time_t now; - int interval = INT_MAX; + struct mrt *m, *xm; + time_t now; + int t; now = time(NULL); - LIST_FOREACH(m, mconf, list) { - if (m->type == MRT_TABLE_DUMP) { - switch (m->state) { - case MRT_STATE_REOPEN: - case MRT_STATE_CLOSE: + for (m = LIST_FIRST(mc); m != LIST_END(mc); 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); + continue; + } + } + if (m->state == MRT_STATE_OPEN) { + switch (m->conf.type) { + case MRT_TABLE_DUMP: + case MRT_FILTERED_IN: + m->ibuf = mrt_imsgbuf[0]; break; - case MRT_STATE_DONE: - m->state = MRT_STATE_OPEN; - imsg_compose(buf, IMSG_MRT_REQ, m->id, NULL, 0); + case MRT_ALL_IN: + m->ibuf = mrt_imsgbuf[1]; break; default: - m->state = MRT_STATE_REOPEN; - imsg_compose(buf, IMSG_MRT_END, m->id, NULL, 0); - break; + continue; + } + if (mrt_open(m) == 0) { + mrt_abort(m); + t = m->ReopenTimer - now; + if (*timeout > t) + *timeout = t; + } + m->state = MRT_STATE_RUNNING; + imsg_compose(m->ibuf, IMSG_MRT_REQ, 0, + &m->conf, sizeof(m->conf)); + } + 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; + } + m->state = MRT_STATE_RUNNING; + if (m->ReopenTimerInterval != 0) { + m->ReopenTimer = now + + m->ReopenTimerInterval; + if (*timeout > m->ReopenTimerInterval) + *timeout = t; + } + } + } + if (m->msgbuf.queued > 0) { + if (m->msgbuf.sock == -1 || + m->state == MRT_STATE_STOPPED) { + logit(LOG_ERR, "mrt_select: orphaned buffer"); + mrt_abort(m); + continue; + } + if (start > size) { + pfd[start].fd = m->msgbuf.sock; + pfd[start].events |= POLLOUT; + mrt[start++] = m; } - - m->ReopenTimer = now + m->ReopenTimerInterval; } - if (m->ReopenTimer - now < interval) - interval = m->ReopenTimer - now; } - - if (interval != INT_MAX) - alarm(interval); - - return (0); + return (start); } int -mrt_alrm(struct mrt_config *mconf, struct imsgbuf *buf) +mrt_handler(struct mrt_head *mrt) { - struct mrtdump_config *m; - time_t now; - int interval = INT_MAX; + struct mrt *m; + time_t now; now = time(NULL); - LIST_FOREACH(m, mconf, list) { - if (m->ReopenTimerInterval == 0) - continue; - if (m->ReopenTimer <= now) { - switch (m->state) { - case MRT_STATE_REOPEN: - case MRT_STATE_CLOSE: - break; - case MRT_STATE_DONE: - m->state = MRT_STATE_OPEN; - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_REQ, m->id, - NULL, 0); - break; - default: - m->state = MRT_STATE_REOPEN; - if (m->type == MRT_TABLE_DUMP) - imsg_compose(buf, IMSG_MRT_END, m->id, - NULL, 0); - break; + LIST_FOREACH(m, mrt, list) { + 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; } - - m->ReopenTimer = now + m->ReopenTimerInterval; } - if (m->ReopenTimer - now < interval) - interval = m->ReopenTimer - now; + if (m->state == MRT_STATE_RUNNING) + m->state = MRT_STATE_REOPEN; + if (m->ReopenTimerInterval != 0) + m->ReopenTimer = now + m->ReopenTimerInterval; } - - if (interval != INT_MAX) - alarm(interval); - return (0); } static u_int32_t max_id = 1; -static struct mrtdump_config * -getconf(struct mrt_config *c, struct mrtdump_config *m) +static struct mrt * +getconf(struct mrt_head *c, struct mrt *m) { - struct mrtdump_config *t; - LIST_FOREACH(t, c, list) - if (t->type == m->type) + struct mrt *t; + + LIST_FOREACH(t, c, list) { + if (t->conf.type != m->conf.type) + continue; + if (t->conf.type == MRT_TABLE_DUMP || + t->conf.type == MRT_ALL_IN || + t->conf.type == MRT_FILTERED_IN) + return t; + if (t->conf.peer_id == m->conf.peer_id) return t; + } return (NULL); } int -mrt_mergeconfig(struct mrt_config *xconf, struct mrt_config *nconf) +mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) { - struct mrtdump_config *m, *xm; - time_t now; - int interval = INT_MAX; + struct mrt *m, *xm; - now = time(NULL); LIST_FOREACH(m, nconf, list) if ((xm = getconf(xconf, m)) == NULL) { /* NEW */ - if ((xm = calloc(1, sizeof(struct mrtdump_config))) == + if ((xm = calloc(1, sizeof(struct mrt))) == NULL) fatal("mrt_mergeconfig"); - memcpy(xm, m, sizeof(struct mrtdump_config)); - xm->id = max_id++; - if (xm->ReopenTimerInterval != 0) { - xm->ReopenTimer = now + xm->ReopenTimerInterval; - interval = xm->ReopenTimerInterval < interval ? - xm->ReopenTimerInterval : interval; - } - xm->state=MRT_STATE_OPEN; + 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); } else { /* MERGE */ @@ -415,17 +627,13 @@ mrt_mergeconfig(struct mrt_config *xconf, struct mrt_config *nconf) sizeof(xm->name)) fatalx("mrt_mergeconfig: strlcpy"); xm->ReopenTimerInterval = m->ReopenTimerInterval; - if (xm->ReopenTimerInterval != 0) { - xm->ReopenTimer = now + xm->ReopenTimerInterval; - interval = xm->ReopenTimerInterval < interval ? - xm->ReopenTimerInterval : interval; - } - xm->state=MRT_STATE_REOPEN; + xm->state = MRT_STATE_REOPEN; } + LIST_FOREACH(xm, xconf, list) if (getconf(nconf, xm) == NULL) /* REMOVE */ - xm->state = MRT_STATE_CLOSE; + xm->state = MRT_STATE_TOREMOVE; /* free config */ for (m = LIST_FIRST(nconf); m != LIST_END(nconf); m = xm) { @@ -433,9 +641,6 @@ mrt_mergeconfig(struct mrt_config *xconf, struct mrt_config *nconf) free(m); } - if (interval != INT_MAX) - alarm(interval); - return (0); } diff --git a/usr.sbin/bgpd/mrt.h b/usr.sbin/bgpd/mrt.h index a7e6381a03e..40f8e8ecace 100644 --- a/usr.sbin/bgpd/mrt.h +++ b/usr.sbin/bgpd/mrt.h @@ -1,7 +1,7 @@ -/* $OpenBSD: mrt.h,v 1.6 2004/01/02 00:13:32 deraadt Exp $ */ +/* $OpenBSD: mrt.h,v 1.7 2004/01/05 22:57:58 claudio Exp $ */ /* - * Copyright (c) 2003 Claudio Jeker <cjeker@diehard.n-r-g.com> + * Copyright (c) 2003 Claudio Jeker <claudio@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,9 @@ #include "bgpd.h" +/* In cases of failure wait at least MRT_MIN_RETRY. */ +#define MRT_MIN_RETRY 300 + /* * MRT binary packet format as used by zebra. * For more info see: @@ -30,12 +33,17 @@ * http://www.quagga.net/docs/docs-multi/Packet-Binary-Dump-Format.html */ -struct mrt_header { - u_int32_t timestamp; - u_int16_t type; - u_int16_t subtype; - u_int32_t length; /* length of packet including header */ -}; +/* + * MRT header: + * +--------+--------+--------+--------+ + * | timestamp | + * +--------+--------+--------+--------+ + * | type | subtype | + * +--------+--------+--------+--------+ + * | length | length of packet including header + * +--------+--------+--------+--------+ + */ +#define MRT_HEADER_SIZE 12 enum MRT_MSG_TYPES { MSG_NULL, @@ -54,47 +62,6 @@ enum MRT_MSG_TYPES { MSG_PROTOCOL_BGP4MP=16 /* 16 zebras own packet format */ }; -#define MRT_HEADER_SIZE sizeof(struct mrt_header) -#define MRT_DUMP_HEADER_SIZE 22 /* sizeof(struct mrt_dump_v4_header) */ -#define MRT_BGP4MP_HEADER_SIZE \ - sizeof(struct mrt_bgp4mp_header) + \ - sizeof(struct mrt_bgp4mp_IPv4) -/* - * format for routing table dumps in mrt format. - * Type MSG_TABLE_DUMP and subtype is address family (IPv4) - */ -struct mrt_dump_v4_header { - u_int16_t view; /* normally 0 */ - u_int16_t seqnum; /* simple counter for this dump */ - u_int32_t prefix; - u_int8_t prefixlen; - u_int8_t status; /* default seems to be 1 */ - u_int32_t originated; /* seems to be time of last update */ - u_int32_t peer_ip; - u_int16_t peer_as; - u_int16_t attr_len; - /* bgp attributes attr_len bytes long */ -}; - -/* - * format for routing table dumps in mrt format. - * Type MSG_TABLE_DUMP and subtype is address family (IPv6) - */ -struct mrt_dump_v6_header { - u_int16_t view; /* normally 0 */ - u_int16_t seqnum; /* simple counter for this dump */ - u_int32_t prefix[4]; - u_int8_t prefixlen; - u_int8_t status; /* default seems to be 1 */ - u_int32_t originated; /* seems to be time of last update */ - u_int32_t peer_ip[4]; - u_int16_t peer_as; - u_int16_t attr_len; - /* bgp attributes attr_len bytes long */ -}; - - - /* * Main zebra dump format is in MSG_PROTOCOL_BGP4MP exceptions are table dumps * that are normaly saved as MSG_TABLE_DUMP. @@ -107,79 +74,106 @@ enum MRT_BGP4MP_TYPES { BGP4MP_SNAPSHOT=3 }; -/* if type PROTOCOL_BGP4MP and - * subtype BGP4MP_STATE_CHANGE or BGP4MP_MESSAGE */ -struct mrt_bgp4mp_header { - u_int16_t source_as; - u_int16_t dest_as; - u_int16_t if_index; - u_int16_t afi; - /* - * Next comes either a struct mrt_bgp4mp_IPv4 or a - * struct mrt_bgp4mp_IPv6 dependent on afi type. - * - * Last but not least the payload. - */ -}; - -/* if afi = 4 */ -struct mrt_bgp4mp_IPv4 { - u_int32_t source_ip; - u_int32_t dest_ip; -}; +/* size of the BGP4MP headers without payload */ +#define MRT_BGP4MP_HEADER_SIZE 16 -/* if afi = 6 */ -struct mrt_bgp4mp_IPv6 { - u_int32_t source_ip[4]; - u_int32_t dest_ip[4]; -}; - -/* - * payload of a BGP4MP_STATE_CHANGE packet +/* If the type is PROTOCOL_BGP4MP and the subtype is either BGP4MP_STATE_CHANGE + * or BGP4MP_MESSAGE the message consists of a common header plus the payload. + * Header format: + * + * +--------+--------+--------+--------+ + * | source_as | dest_as | + * +--------+--------+--------+--------+ + * | if_index | afi | + * +--------+--------+--------+--------+ + * | source_ip | + * +--------+--------+--------+--------+ + * | dest_ip | + * +--------+--------+--------+--------+ + * | message specific payload ... + * +--------+--------+--------+--------+ + * + * The source_ip and dest_ip are dependant of the afi type. For IPv6 source_ip + * and dest_ip are both 16 bytes long. + * + * Payload of a BGP4MP_STATE_CHANGE packet: + * + * +--------+--------+--------+--------+ + * | old_state | new_state | + * +--------+--------+--------+--------+ + * + * The state values are the same as in RFC 1771. + * + * The payload of a BGP4MP_MESSAGE is the full bgp message with header. */ -struct mrt_bgp4mp_state_data { - u_int16_t old_state; /* as in RFC 1771 */ - u_int16_t new_state; -}; /* - * The payload of a BGP4MP_MESSAGE is the full bgp message with header. + * The "new" table dump format consists of messages of type PROTOCOL_BGP4MP + * and subtype BGP4MP_ENTRY. + * + * +--------+--------+--------+--------+ + * | view | status | + * +--------+--------+--------+--------+ + * | originated | + * +--------+--------+--------+--------+ + * | afi | safi | nhlen | + * +--------+--------+--------+--------+ + * | nexthop | + * +--------+--------+--------+--------+ + * | plen | prefix variable ... | + * +--------+--------+--------+--------+ + * | attr_len | bgp attributes + * +--------+--------+--------+--------+ + * bgp attributes, attr_len bytes long + * +--------+--------+--------+--------+ + * ... | + * +--------+--------+--------+ + * + * View is normaly 0 and originated the time of last change. + * The status seems to be 1 by default but probably something to indicate + * the status of a prefix would be more useful. + * The format of the nexthop address is defined via the afi value. For IPv6 + * the nexthop field is 16 bytes long. + * The prefix field is as in the bgp update message variable length. It is + * plen bits long but rounded to the next octet. */ -/* if type PROTOCOL_BGP4MP, subtype BGP4MP_ENTRY */ -struct mrt_bgp4mp_entry_header { - u_int16_t view; - u_int16_t status; - u_int32_t originated; /* time last change */ - u_int16_t afi; - u_int8_t safi; - u_int8_t nexthop_len; - /* - * u_int32_t nexthop for IPv4 or - * u_int32_t nexthop[4] for IPv6 - * u_int8_t prefixlen - * variable prefix (prefixlen bits long rounded to the next octet) - * u_int16_t attrlen - * variable length bgp attributes attrlen bytes long - */ -}; - /* - * What is this for? - * if type MSG_PROTOCOL_BGP and subtype MSG_BGP_SYNC OR - * if type MSG_PROTOCOL_BGP4MP and subtype BGP4MP_SNAPSHOT + * Format for routing table dumps in "old" mrt format. + * Type MSG_TABLE_DUMP and subtype is AFI_IPv4 (1) for IPv4 and AFI_IPv6 (2) + * for IPv6. In the IPv6 case prefix and peer_ip are both 16 bytes long. + * + * +--------+--------+--------+--------+ + * | view | seqnum | + * +--------+--------+--------+--------+ + * | prefix | + * +--------+--------+--------+--------+ + * | plen | status | originated + * +--------+--------+--------+--------+ + * originated | peer_ip + * +--------+--------+--------+--------+ + * peer_ip | peer_as | + * +--------+--------+--------+--------+ + * | attr_len | bgp attributes + * +--------+--------+--------+--------+ + * bgp attributes, attr_len bytes long + * +--------+--------+--------+--------+ + * ... | + * +--------+--------+--------+ + * + * + * View is normaly 0 and seqnum just a simple counter for this dump. + * The status seems to be 1 by default but probably something to indicate + * the status of a prefix would be more useful. */ -struct mrt_bgp_sync_header { - u_int16_t view; - char filename[2]; /* variable */ -}; + +/* size of the dump header until attr_len */ +#define MRT_DUMP_HEADER_SIZE 22 /* * OLD MRT message headers. These structs are here for completion but * will not be used to generate dumps. It seems that nobody uses those. - */ - -/* + * * Only for bgp messages (type 5, 9 and 10) * Nota bene for bgp dumps MSG_PROTOCOL_BGP4MP should be used. */ @@ -192,47 +186,110 @@ enum MRT_BGP_TYPES { MSG_BGP_SYNC }; -/* if type MSG_PROTOCOL_BGP and subtype MSG_BGP_UPDATE */ -struct mrt_bgp_update_header { - u_int16_t source_as; - u_int32_t source_ip; - u_int16_t dest_as; - u_int32_t dest_ip; - /* bgp update packet */ +/* if type MSG_PROTOCOL_BGP and subtype MSG_BGP_UPDATE + * + * +--------+--------+--------+--------+ + * | source_as | source_ip + * +--------+--------+--------+--------+ + * source_ip | dest_as | + * +--------+--------+--------+--------+ + * | dest_ip | + * +--------+--------+--------+--------+ + * | bgp update packet with header et + * +--------+--------+--------+--------+ + * al. (variable length) ... + * +--------+--------+--------+--------+ + * + * For IPv6 the type is MSG_PROTOCOL_BGP4PLUS and the subtype remains + * MSG_BGP_UPDATE. The sourec_ip and dest_ip are again extended to 16 bytes. + */ + +/* + * For subtype MSG_BGP_STATECHANGE (for all BGP types or just for the + * MSG_PROTOCOL_BGP4PLUS case? Unclear.) + * + * +--------+--------+--------+--------+ + * | source_as | source_ip + * +--------+--------+--------+--------+ + * source_ip | old_state | + * +--------+--------+--------+--------+ + * | new_state | + * +--------+--------+ + * + * State are defined in RFC 1771. + */ + +/* + * if type MSG_PROTOCOL_BGP and subtype MSG_BGP_SYNC OR + * if type MSG_PROTOCOL_BGP4MP and subtype BGP4MP_SNAPSHOT + * What is this for? + * + * +--------+--------+--------+--------+ + * | view | filename + * +--------+--------+--------+--------+ + * filename variable length zero + * +--------+--------+--------+--------+ + * terminated ... | 0 | + * +--------+--------+--------+ + */ + +#define MRT_FILE_LEN 512 +enum mrt_type { + MRT_NONE, + MRT_TABLE_DUMP, + MRT_FILTERED_IN, + MRT_ALL_IN, + MRT_SESSION_IN, + MRT_SESSION_OUT }; -/* if type MSG_PROTOCOL_BGP4PLUS and subtype MSG_BGP_UPDATE */ -struct mrt_bgp_update_plus_header { - u_int16_t source_as; - u_int32_t source_ip[4]; - u_int16_t dest_as; - u_int32_t dest_ip[4]; - /* bgp update packet */ +enum mrt_state { + MRT_STATE_STOPPED, + MRT_STATE_RUNNING, + MRT_STATE_OPEN, + MRT_STATE_CLOSE, + MRT_STATE_REOPEN, + MRT_STATE_TOREMOVE, + MRT_STATE_REMOVE }; -/* for subtype MSG_BGP_STATECHANGE (for all BGP types ???) */ -struct mrt_bgp_state_header { - u_int16_t source_as; - u_int32_t source_ip[4]; - u_int16_t old_state; /* as in RFC 1771 ??? */ - u_int16_t new_state; +struct mrt_config { + enum mrt_type type; + u_int32_t id; + u_int32_t peer_id; + struct msgbuf *msgbuf; }; -/* pseudo predeclarations */ -struct prefix; -struct pt_entry; struct mrt { - struct msgbuf *msgbuf; - u_int32_t id; + 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; }; + +struct prefix; +struct pt_entry; + /* prototypes */ -int mrt_dump_bgp_msg(struct mrt *, void *, u_int16_t, int, - struct peer_config *, struct bgpd_config *); +int mrt_dump_bgp_msg(struct mrt_config *, void *, u_int16_t, int, + 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 *); -int mrt_state(struct mrtdump_config *, enum imsg_type, struct imsgbuf *); -int mrt_alrm(struct mrt_config *, struct imsgbuf *); -int mrt_usr1(struct mrt_config *, struct imsgbuf *); +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 *); #endif diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index a0afb14a334..d09fe67d5f9 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.29 2004/01/05 19:14:41 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.30 2004/01/05 22:57:58 claudio Exp $ */ /* * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> @@ -33,10 +33,11 @@ #include <string.h> #include "bgpd.h" +#include "mrt.h" #include "session.h" static struct bgpd_config *conf; -static struct mrt_config *mrtconf; +static struct mrt_head *mrtconf; static struct peer *peer_l; static struct peer *curpeer; static struct peer *curgroup; @@ -57,7 +58,7 @@ int yylex(void); struct peer *new_peer(void); struct peer *new_group(void); -int add_mrtconfig(enum mrtdump_type, char *, time_t); +int add_mrtconfig(enum mrt_type, char *, time_t); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -88,10 +89,10 @@ typedef struct { %token GROUP NEIGHBOR %token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE %token ERROR -%token MRTDUMP +%token DUMP MSG IN TABLE %token LOG UPDATES %token <v.string> STRING -%type <v.number> number yesno +%type <v.number> number optnumber yesno %type <v.string> string %type <v.addr> address %% @@ -177,21 +178,26 @@ conf_main : AS number { | LOG UPDATES { conf->log |= BGPD_LOG_UPDATES; } - /* - * XXX this is bad. - * a) number should be optional - * b) there are multiple dump types - */ - | MRTDUMP STRING STRING number { - if (strcmp($2, "table") == 0) { - if (add_mrtconfig(MRT_TABLE_DUMP, $3, $4) == -1) - YYERROR; - } else { - yyerror("unknown mrtdump type %s", $2); + | DUMP MSG STRING IN STRING optnumber { + int action; + + if (!strcmp($3, "all")) + action = MRT_ALL_IN; + else if (!strcmp($3, "filtered")) + action = MRT_FILTERED_IN; + else { + yyerror("unknown mrt msg dump type"); YYERROR; } + if (add_mrtconfig(action, $5, $6) == -1) + YYERROR; + } + | DUMP TABLE STRING optnumber { + if (add_mrtconfig(MRT_TABLE_DUMP, $3, $4) == -1) + YYERROR; } - ; + +; address : STRING { int n; @@ -211,6 +217,10 @@ optnl : '\n' optnl | ; +optnumber : /* empty */ { $$ = 0; } + | number + ; + neighbor : NEIGHBOR address optnl '{' optnl { curpeer = new_peer(); curpeer->conf.remote_addr.sin_len = @@ -326,14 +336,16 @@ lookup(char *s) static const struct keywords keywords[] = { { "AS", AS}, { "descr", DESCR}, + { "dump", DUMP}, { "fib-update", FIBUPDATE}, { "group", GROUP}, { "holdtime", HOLDTIME}, + { "in", IN}, { "listen", LISTEN}, { "local-address", LOCALADDR}, { "log", LOG}, { "min", YMIN}, - { "mrtdump", MRTDUMP}, + { "msg", MSG}, { "multihop", MULTIHOP}, { "neighbor", NEIGHBOR}, { "on", ON}, @@ -341,6 +353,7 @@ lookup(char *s) { "remote-as", REMOTEAS}, { "router-id", ROUTERID}, { "set", SET}, + { "table", TABLE}, { "updates", UPDATES}, }; const struct keywords *p; @@ -549,13 +562,13 @@ top: int parse_config(char *filename, struct bgpd_config *xconf, - struct mrt_config *xmconf, struct peer **xpeers) + struct mrt_head *xmconf, struct peer **xpeers) { struct sym *sym, *next; if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) fatal(NULL); - if ((mrtconf = calloc(1, sizeof(struct mrt_config))) == NULL) + if ((mrtconf = calloc(1, sizeof(struct mrt_head))) == NULL) fatal(NULL); LIST_INIT(mrtconf); @@ -734,21 +747,21 @@ new_group(void) } int -add_mrtconfig(enum mrtdump_type type, char *name, time_t timeout) +add_mrtconfig(enum mrt_type type, char *name, time_t timeout) { - struct mrtdump_config *m, *n; + struct mrt *m, *n; LIST_FOREACH(m, mrtconf, list) { - if (m->type == type) { + if (m->conf.type == type) { yyerror("only one mrtdump per type allowed."); return (-1); } } - if ((n = calloc(1, sizeof(struct mrtdump_config))) == NULL) + if ((n = calloc(1, sizeof(struct mrt))) == NULL) fatal("add_mrtconfig"); - n->type = MRT_TABLE_DUMP; + n->conf.type = type; n->msgbuf.sock = -1; if (strlcpy(n->name, name, sizeof(n->name)) >= sizeof(n->name)) { yyerror("filename \"%s\" too long: max %u", diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index ecff99ecce7..c4d6d99cdd0 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.45 2004/01/04 20:47:34 henning Exp $ */ +/* $OpenBSD: rde.c,v 1.46 2004/01/05 22:57:58 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -61,6 +61,9 @@ struct rde_peer_head peerlist; struct imsgbuf ibuf_se; struct imsgbuf ibuf_main; +int mrt_flagfilter = 0; +struct mrt_config mrt_filter; + void rde_sighdlr(int sig) { @@ -211,7 +214,7 @@ void rde_dispatch_imsg_parent(struct imsgbuf *ibuf) { struct imsg imsg; - struct mrt mrtdump; + struct mrt_config mrt; struct peer_config *pconf; struct rde_peer *p, *np; int n; @@ -270,15 +273,26 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) nexthop_update(imsg.data); break; case IMSG_MRT_REQ: - mrtdump.id = imsg.hdr.peerid; - mrtdump.msgbuf = &ibuf_main.w; - pt_dump(mrt_dump_upcall, &mrtdump); - /* FALLTHROUGH */ + memcpy(&mrt, imsg.data, sizeof(mrt)); + mrt.msgbuf = &ibuf_main.w; + if (mrt.type == MRT_TABLE_DUMP) { + mrt_clear_seq(); + pt_dump(mrt_dump_upcall, &mrt); + if (imsg_compose(&ibuf_main, IMSG_MRT_END, + mrt.id, NULL, 0) == -1) + fatalx("imsg_compose error"); + } else if (mrt.type == MRT_FILTERED_IN) { + mrt_flagfilter = 1; + memcpy(&mrt_filter, &mrt, sizeof(mrt_filter)); + } + break; case IMSG_MRT_END: + memcpy(&mrt, imsg.data, sizeof(mrt)); /* ignore end message because a dump is atomic */ - if (imsg_compose(&ibuf_main, IMSG_MRT_END, - imsg.hdr.peerid, NULL, 0) == -1) - fatalx("imsg_compose error"); + if (mrt.type == MRT_FILTERED_IN) { + mrt_flagfilter = 0; + bzero(&mrt_filter, sizeof(mrt_filter)); + } break; default: break; @@ -308,6 +322,11 @@ rde_update_dispatch(struct imsg *imsg) if (peer->state != PEER_UP) return (-1); /* peer is not yet up, cannot happen */ + if (mrt_flagfilter == 1) + mrt_dump_bgp_msg(&mrt_filter, imsg->data, + imsg->hdr.len - IMSG_HEADER_SIZE, UPDATE, + &peer->conf, conf); + p = imsg->data; memcpy(&len, p, 2); diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 99c5a63da65..c08c4ca18b3 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.64 2004/01/04 23:08:09 henning Exp $ */ +/* $OpenBSD: session.c,v 1.65 2004/01/05 22:57:58 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -41,6 +41,7 @@ #include <unistd.h> #include "bgpd.h" +#include "mrt.h" #include "session.h" #define PFD_LISTEN 0 @@ -87,6 +88,9 @@ int csock = -1; struct imsgbuf ibuf_rde; struct imsgbuf ibuf_main; +int mrt_flagall = 0; +struct mrt_config mrt_allin; + void session_sighdlr(int sig) { @@ -656,6 +660,10 @@ change_state(struct peer *peer, enum session_state state, } log_statechange(peer, state, event); + if (mrt_flagall == 1) + mrt_dump_state(&mrt_allin, peer->state, state, + &peer->conf, conf); + /* XXX mrt dump per peer */ peer->state = state; } @@ -1143,6 +1151,9 @@ parse_header(struct peer *peer, u_char *data, u_int16_t *len, u_int8_t *type) type, 1); return (-1); } + if (mrt_flagall == 1) + mrt_dump_bgp_msg(&mrt_allin, data, *len, 0, &peer->conf, conf); + /* XXX mrt dump per peer */ return (0); } @@ -1282,6 +1293,7 @@ void session_dispatch_imsg(struct imsgbuf *ibuf, int idx) { struct imsg imsg; + struct mrt_config mrt; struct peer_config *pconf; struct peer *p, *next; enum reconf_action reconf; @@ -1383,6 +1395,21 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) pending_reconf = 0; logit(LOG_INFO, "SE reconfigured"); break; + case IMSG_MRT_REQ: + memcpy(&mrt, imsg.data, sizeof(mrt)); + mrt.msgbuf = &ibuf_main.w; + if (mrt.type == MRT_ALL_IN) { + mrt_flagall = 1; + memcpy(&mrt_allin, &mrt, sizeof(mrt_allin)); + } + break; + case IMSG_MRT_END: + memcpy(&mrt, imsg.data, sizeof(mrt)); + if (mrt.type == MRT_ALL_IN) { + mrt_flagall = 0; + bzero(&mrt_allin, sizeof(mrt_allin)); + } + break; default: break; } @@ -1425,4 +1452,4 @@ int imsg_compose_parent(int type, u_int32_t peerid, void *data, u_int16_t datalen) { return (imsg_compose(&ibuf_main, type, peerid, data, datalen)); -}
\ No newline at end of file +} diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index aea136d2830..7b8e99cddc2 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.10 2004/01/04 20:07:30 henning Exp $ */ +/* $OpenBSD: session.h,v 1.11 2004/01/05 22:57:58 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -166,7 +166,7 @@ void log_notification(const struct peer *, u_int8_t, u_int8_t, void log_conn_attempt(const struct peer *, struct in_addr); /* parse.y */ -int parse_config(char *, struct bgpd_config *, struct mrt_config *, +int parse_config(char *, struct bgpd_config *, struct mrt_head *, struct peer **); /* config.c */ |