diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-01-05 22:58:00 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-01-05 22:58:00 +0000 |
commit | 2c230dedefb7d8f275f3f485f8e6b38f6f5c7e60 (patch) | |
tree | 7d3257ca2d7e7a6628397b81f1c125c9c6fb6992 /usr.sbin | |
parent | 1f3050ca8dc1d2ec9e4b4a483c438741612fbdb7 (diff) |
Big overhaul of the mrt code.
Dumping of incomming bgp messages is now possible and dumping the (not yet)
filtered updates works too. Per neighbor dumps are still missing.
OK henning@
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 */ |