summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bgpd/bgpd.c77
-rw-r--r--usr.sbin/bgpd/bgpd.h45
-rw-r--r--usr.sbin/bgpd/buffer.c43
-rw-r--r--usr.sbin/bgpd/mrt.c593
-rw-r--r--usr.sbin/bgpd/mrt.h337
-rw-r--r--usr.sbin/bgpd/parse.y63
-rw-r--r--usr.sbin/bgpd/rde.c37
-rw-r--r--usr.sbin/bgpd/session.c31
-rw-r--r--usr.sbin/bgpd/session.h4
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 */