From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lunar@debian.org>
Date: Sat, 23 Jul 2011 17:37:22 +0200
Subject: [PATCH] Import FreeBSD port patches (4.9.20110612)
---
Makefile | 5 +
Makefile.inc | 5 +
bgpctl/Makefile | 7 +-
bgpctl/bgpctl.8 | 49 +-
bgpctl/bgpctl.c | 423 ++++++-----
bgpctl/irr_parser.c | 8 +-
bgpctl/irr_prefix.c | 92 ++-
bgpctl/irrfilter.c | 3 +
bgpctl/irrfilter.h | 14 +-
bgpctl/parser.c | 100 ++-
bgpctl/parser.h | 10 +-
bgpctl/whois.c | 5 +-
bgpd/Makefile | 18 +-
bgpd/bgpd.8 | 73 +-
bgpd/bgpd.c | 373 +++++-----
bgpd/bgpd.conf.5 | 374 ++++++++--
bgpd/bgpd.h | 380 +++++++---
bgpd/buffer.c | 305 -------
bgpd/carp.c | 13 +-
bgpd/config.c | 51 +-
bgpd/control.c | 61 +-
bgpd/imsg.c | 268 ------
bgpd/imsg.h | 108 ---
bgpd/kroute.c | 1716 ++++++++++++++++++++++++++++-----------
bgpd/log.c | 39 +-
bgpd/mrt.c | 228 ++++--
bgpd/mrt.h | 15 +-
bgpd/parse.y | 926 ++++++++++++++++-----
bgpd/pfkey.c | 104 ++--
bgpd/pftable.c | 4 +-
bgpd/printconf.c | 230 ++++--
bgpd/rde.c | 1389 ++++++++++++++++++++++----------
bgpd/rde.h | 82 ++-
bgpd/rde_attr.c | 344 ++++++++-
bgpd/rde_decide.c | 14 +-
bgpd/rde_filter.c | 118 ++-
bgpd/rde_prefix.c | 179 ++--
bgpd/rde_rib.c | 173 +++--
bgpd/rde_update.c | 315 +++++--
bgpd/session.c | 726 +++++++++--------
bgpd/session.h | 37 +-
bgpd/timer.c | 4 +-
bgpd/util.c | 248 ++++++-
openbsd-compat/fmt_scaled.c | 268 ++++++
openbsd-compat/hash.h | 127 +++
openbsd-compat/if_media.h | 612 ++++++++++++++
openbsd-compat/imsg-buffer.c | 303 +++++++
openbsd-compat/imsg.c | 271 ++++++
openbsd-compat/imsg.h | 112 +++
openbsd-compat/openbsd-compat.h | 87 ++
openbsd-compat/pfkey_compat.c | 32 +
openbsd-compat/util.h | 119 +++
52 files changed, 8147 insertions(+), 3420 deletions(-)
create mode 100644 Makefile
create mode 100644 Makefile.inc
delete mode 100644 bgpd/buffer.c
delete mode 100644 bgpd/imsg.c
delete mode 100644 bgpd/imsg.h
create mode 100644 openbsd-compat/fmt_scaled.c
create mode 100644 openbsd-compat/hash.h
create mode 100644 openbsd-compat/if_media.h
create mode 100644 openbsd-compat/imsg-buffer.c
create mode 100644 openbsd-compat/imsg.c
create mode 100644 openbsd-compat/imsg.h
create mode 100644 openbsd-compat/openbsd-compat.h
create mode 100644 openbsd-compat/pfkey_compat.c
create mode 100644 openbsd-compat/util.h
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..520c1df
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+# $hrs: openbgpd/Makefile,v 1.2 2009/06/30 07:07:55 hrs Exp $
+
+SUBDIR= bgpd bgpctl
+
+.include <bsd.subdir.mk>
diff --git a/Makefile.inc b/Makefile.inc
new file mode 100644
index 0000000..efde290
--- /dev/null
+++ b/Makefile.inc
@@ -0,0 +1,5 @@
+# $hrs: openbgpd/Makefile.inc,v 1.2 2009/06/30 07:19:13 hrs Exp $
+
+PREFIX?= /usr/local
+BINDIR?= ${PREFIX}/sbin
+MANDIR?= ${PREFIX}/man/man
diff --git a/bgpctl/Makefile b/bgpctl/Makefile
index 575a423..c6d3ec5 100644
--- a/bgpctl/Makefile
+++ b/bgpctl/Makefile
@@ -1,17 +1,18 @@
# $OpenBSD: Makefile,v 1.10 2007/12/20 17:08:48 henning Exp $
-.PATH: ${.CURDIR}/../bgpd
+.PATH: ${.CURDIR}/../bgpd ${.CURDIR}/../openbsd-compat
PROG= bgpctl
-SRCS= bgpctl.c parser.c buffer.c imsg.c util.c timer.c
+SRCS= bgpctl.c parser.c util.c timer.c
SRCS+= irrfilter.c whois.c irr_asset.c irr_prefix.c irr_output.c
SRCS+= irr_parser.c
+SRCS+= fmt_scaled.c imsg.c imsg-buffer.c
CFLAGS+= -Wall
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare
-CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../bgpd
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../bgpd -I${.CURDIR}/../openbsd-compat
MAN= bgpctl.8
LDADD= -lutil
DPADD+= ${LIBUTIL}
diff --git a/bgpctl/bgpctl.8 b/bgpctl/bgpctl.8
index 73fb8ea..26e55a1 100644
--- a/bgpctl/bgpctl.8
+++ b/bgpctl/bgpctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpctl.8,v 1.49 2009/06/06 06:11:17 claudio Exp $
+.\" $OpenBSD: bgpctl.8,v 1.52 2009/11/03 08:09:15 jmc Exp $
.\"
.\" Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 6 2009 $
+.Dd $Mdocdate: May 3 2010 $
.Dt BGPCTL 8
.Os
.Sh NAME
@@ -32,8 +32,7 @@ The
program controls the
.Xr bgpd 8
daemon.
-Commands to switch between displays may be abbreviated to the
-minimum unambiguous prefix; for example,
+Commands may be abbreviated to the minimum unambiguous prefix; for example,
.Cm s s
for
.Cm show summary .
@@ -53,11 +52,19 @@ to communicate with
.Pp
The commands are as follows:
.Bl -tag -width xxxxxx
-.It Cm fib couple
-Insert the learned routes into the Forwarding Information Base
+.It Xo
+.Cm fib
+.Op Cm table Ar number
+.Cm couple
+.Xc
+Insert the learned routes into the specified Forwarding Information Base
a.k.a. the kernel routing table.
-.It Cm fib decouple
-Remove the learned routes from the Forwarding Information Base
+.It Xo
+.Cm fib
+.Op Cm table Ar number
+.Cm decouple
+.Xc
+Remove the learned routes from the specified Forwarding Information Base
a.k.a. the kernel routing table.
.It Xo
.Cm irrfilter
@@ -79,7 +86,15 @@ The options are as follows:
Use
.Ar directory
to write the filter files to.
+.It Fl 4
+Fetch only IPv4 prefixes from the registry.
+.It Fl 6
+Fetch only IPv6 prefixes from the registry.
.El
+.It Cm log brief
+Disable verbose debug logging.
+.It Cm log verbose
+Enable verbose debug logging.
.It Cm neighbor Ar peer Cm up
Take the BGP session to the specified neighbor up.
.Ar peer
@@ -98,8 +113,10 @@ Note that the neighbor is not obliged to re-send all routes, or any routes at
all, even if it announced the route refresh capability.
.Ar peer
may be the neighbor's address or description.
-.It Cm network add Ar prefix
+.It Cm network add Ar prefix Op Ar arguments
Add the specified prefix to the list of announced networks.
+It is possible to set various path attributes with additional
+.Ar arguments .
.It Cm network delete Ar prefix
Remove the specified prefix from the list of announced networks.
.It Cm network flush
@@ -122,7 +139,7 @@ view of the Forwarding Information Base.
can be an IP address, in which case the route to this address is shown,
or a flag:
.Pp
-.Bl -tag -width connected -compact
+.Bl -tag -width tableXnumber -compact
.It Cm connected
Show only connected routes.
.It Cm static
@@ -133,6 +150,14 @@ Show only routes originating from
itself.
.It Cm nexthop
Show only routes required to reach a BGP nexthop.
+.It Cm inet
+Show only IPv4 routes.
+.It Cm inet6
+Show only IPv6 routes.
+.It Cm table Ar number
+Show the routing table with ID
+.Ar number
+instead of the default routing table with ID 0.
.El
.It Cm show interfaces
Show the interface states.
@@ -243,10 +268,12 @@ and message counters.
.It Cm show summary terse
Show a list of all neighbors, including information about the session state,
in a terse format.
+.It Cm show tables
+Show a list of all currently loaded fib routing tables.
.El
.Sh FILES
.Bl -tag -width "/var/run/bgpd.sockXXX" -compact
-.It Pa /etc/bgpd.conf
+.It Pa %%PREFIX%%/etc/bgpd.conf
default
.Xr bgpd 8
configuration file
diff --git a/bgpctl/bgpctl.c b/bgpctl/bgpctl.c
index b11a072..c684295 100644
--- a/bgpctl/bgpctl.c
+++ b/bgpctl/bgpctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpctl.c,v 1.142 2009/06/06 06:33:15 eric Exp $ */
+/* $OpenBSD: bgpctl.c,v 1.157 2010/03/08 17:02:19 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
@@ -16,11 +16,19 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if defined(__FreeBSD__) /* compat */
+#include "openbsd-compat.h"
+#endif /* defined(__FreeBSD__) */
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
+#if defined(__FreeBSD__) /* net/if_media.h */
+#include "if_media.h"
+#else
#include <net/if_media.h>
+#endif /* defined(__FreeBSD__) */
#include <net/if_types.h>
#include <err.h>
@@ -29,7 +37,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#if defined(__FreeBSD__) /* util.h */
+#include "util.h"
+#else
#include <util.h>
+#endif /* defined(__FreeBSD__) */
#include "bgpd.h"
#include "session.h"
@@ -38,6 +50,10 @@
#include "parser.h"
#include "irrfilter.h"
+#if defined(__FreeBSD__) /* FreeBSD has no LINK_STATE_IS_UP macro. */
+#define LINK_STATE_IS_UP(_s) ((_s) >= LINK_STATE_UP)
+#endif /* defined(__FreeBSD__) */
+
enum neighbor_views {
NV_DEFAULT,
NV_TIMERS
@@ -50,12 +66,13 @@ int show_summary_msg(struct imsg *, int);
int show_summary_terse_msg(struct imsg *, int);
int show_neighbor_terse(struct imsg *);
int show_neighbor_msg(struct imsg *, enum neighbor_views);
-void print_neighbor_capa_mp_safi(u_int8_t);
+void print_neighbor_capa_mp(struct peer *);
void print_neighbor_msgstats(struct peer *);
void print_timer(const char *, time_t);
static char *fmt_timeframe(time_t t);
static char *fmt_timeframe_core(time_t t);
void show_fib_head(void);
+void show_fib_tables_head(void);
void show_network_head(void);
void show_fib_flags(u_int16_t);
int show_fib_msg(struct imsg *);
@@ -65,7 +82,7 @@ void show_interface_head(void);
int ift2ifm(int);
const char * get_media_descr(int);
const char * get_linkstate(int, int);
-void print_baudrate(u_int64_t);
+const char * get_baudrate(u_int64_t, char *);
int show_interface_msg(struct imsg *);
void show_rib_summary_head(void);
void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
@@ -74,7 +91,6 @@ void print_flags(u_int8_t, int);
int show_rib_summary_msg(struct imsg *);
int show_rib_detail_msg(struct imsg *, int);
void show_community(u_char *, u_int16_t);
-const char *get_ext_subtype(u_int8_t);
void show_ext_community(u_char *, u_int16_t);
char *fmt_mem(int64_t);
int show_rib_memory_msg(struct imsg *);
@@ -98,7 +114,7 @@ int
main(int argc, char *argv[])
{
struct sockaddr_un sun;
- int fd, n, done, ch, nodescr = 0;
+ int fd, n, done, ch, nodescr = 0, verbose = 0;
struct imsg imsg;
struct network_config net;
struct parse_result *res;
@@ -128,8 +144,11 @@ main(int argc, char *argv[])
if ((res = parse(argc, argv)) == NULL)
exit(1);
- if (res->action == IRRFILTER)
+ if (res->action == IRRFILTER) {
+ if (!(res->flags & (F_IPV4|F_IPV6)))
+ res->flags |= (F_IPV4|F_IPV6);
irr_main(res->as.as, res->flags, res->irr_outdir);
+ }
memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
@@ -164,24 +183,32 @@ main(int argc, char *argv[])
imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
break;
case SHOW_FIB:
- if (!res->addr.af) {
- struct buf *msg;
-
- if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 0, 0,
- sizeof(res->flags) + sizeof(res->af))) == NULL)
+ if (!res->addr.aid) {
+ struct ibuf *msg;
+ sa_family_t af;
+
+ af = aid2af(res->aid);
+ if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE,
+ res->rtableid, 0, sizeof(res->flags) +
+ sizeof(af))) == NULL)
errx(1, "imsg_create failure");
if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
-1 ||
- imsg_add(msg, &res->af, sizeof(res->af)) == -1)
+ imsg_add(msg, &af, sizeof(af)) == -1)
errx(1, "imsg_add failure");
imsg_close(ibuf, msg);
} else
- imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
- &res->addr, sizeof(res->addr));
+ imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid,
+ 0, -1, &res->addr, sizeof(res->addr));
show_fib_head();
break;
+ case SHOW_FIB_TABLES:
+ imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0);
+ show_fib_tables_head();
+ break;
case SHOW_NEXTHOP:
- imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, 0, 0, -1, NULL, 0);
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1,
+ NULL, 0);
show_nexthop_head();
break;
case SHOW_INTERFACE:
@@ -192,7 +219,7 @@ main(int argc, char *argv[])
case SHOW_NEIGHBOR_TIMERS:
case SHOW_NEIGHBOR_TERSE:
neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
- if (res->peeraddr.af || res->peerdesc[0])
+ if (res->peeraddr.aid || res->peerdesc[0])
imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
&neighbor, sizeof(neighbor));
else
@@ -206,7 +233,7 @@ main(int argc, char *argv[])
memcpy(&ribreq.as, &res->as, sizeof(res->as));
type = IMSG_CTL_SHOW_RIB_AS;
}
- if (res->addr.af) {
+ if (res->addr.aid) {
memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
ribreq.prefixlen = res->prefixlen;
type = IMSG_CTL_SHOW_RIB_PREFIX;
@@ -220,7 +247,7 @@ main(int argc, char *argv[])
memcpy(&ribreq.neighbor, &neighbor,
sizeof(ribreq.neighbor));
strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
- ribreq.af = res->af;
+ ribreq.aid = res->aid;
ribreq.flags = res->flags;
imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
if (!(res->flags & F_CTL_DETAIL))
@@ -237,12 +264,14 @@ main(int argc, char *argv[])
errx(1, "action==FIB");
break;
case FIB_COUPLE:
- imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
+ imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
+ NULL, 0);
printf("couple request sent.\n");
done = 1;
break;
case FIB_DECOUPLE:
- imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
+ imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1,
+ NULL, 0);
printf("decouple request sent.\n");
done = 1;
break;
@@ -290,12 +319,21 @@ main(int argc, char *argv[])
break;
case NETWORK_SHOW:
bzero(&ribreq, sizeof(ribreq));
- ribreq.af = res->af;
+ ribreq.aid = res->aid;
strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
&ribreq, sizeof(ribreq));
show_network_head();
break;
+ case LOG_VERBOSE:
+ verbose = 1;
+ /* FALLTHROUGH */
+ case LOG_BRIEF:
+ imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
+ &verbose, sizeof(verbose));
+ printf("logging request sent.\n");
+ done = 1;
+ break;
}
while (ibuf->w.queued)
@@ -304,13 +342,13 @@ main(int argc, char *argv[])
while (!done) {
if ((n = imsg_read(ibuf)) == -1)
- errx(1, "imsg_read error");
+ err(1, "imsg_read error");
if (n == 0)
errx(1, "pipe closed");
while (!done) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
- errx(1, "imsg_get error");
+ err(1, "imsg_get error");
if (n == 0)
break;
@@ -329,6 +367,8 @@ main(int argc, char *argv[])
done = show_summary_terse_msg(&imsg, nodescr);
break;
case SHOW_FIB:
+ case SHOW_FIB_TABLES:
+ case NETWORK_SHOW:
done = show_fib_msg(&imsg);
break;
case SHOW_NEXTHOP:
@@ -356,9 +396,6 @@ main(int argc, char *argv[])
case SHOW_RIB_MEM:
done = show_rib_memory_msg(&imsg);
break;
- case NETWORK_SHOW:
- done = show_fib_msg(&imsg);
- break;
case NEIGHBOR:
case NEIGHBOR_UP:
case NEIGHBOR_DOWN:
@@ -373,6 +410,8 @@ main(int argc, char *argv[])
case NETWORK_REMOVE:
case NETWORK_FLUSH:
case IRRFILTER:
+ case LOG_VERBOSE:
+ case LOG_BRIEF:
break;
}
imsg_free(&imsg);
@@ -398,8 +437,8 @@ fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
}
ip = log_addr(remote_addr);
- if (masklen != -1 && ((remote_addr->af == AF_INET && masklen != 32) ||
- (remote_addr->af == AF_INET6 && masklen != 128))) {
+ if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
+ (remote_addr->aid == AID_INET6 && masklen != 128))) {
if (asprintf(&p, "%s/%u", ip, masklen) == -1)
err(1, NULL);
} else {
@@ -521,13 +560,15 @@ show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
struct ctl_timer *t;
struct in_addr ina;
char buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
+ int hascapamp = 0;
+ u_int8_t i;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NEIGHBOR:
p = imsg->data;
- if ((p->conf.remote_addr.af == AF_INET &&
+ if ((p->conf.remote_addr.aid == AID_INET &&
p->conf.remote_masklen != 32) ||
- (p->conf.remote_addr.af == AF_INET6 &&
+ (p->conf.remote_addr.aid == AID_INET6 &&
p->conf.remote_masklen != 128)) {
if (asprintf(&s, "%s/%u",
log_addr(&p->conf.remote_addr),
@@ -549,6 +590,10 @@ show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
printf(", Template");
if (p->conf.cloned)
printf(", Cloned");
+ if (p->conf.passive)
+ printf(", Passive");
+ if (p->conf.ebgp && p->conf.distance > 1)
+ printf(", Multihop (%u)", (int)p->conf.distance);
printf("\n");
if (p->conf.descr[0])
printf(" Description: %s\n", p->conf.descr);
@@ -563,17 +608,16 @@ show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
printf(" Last read %s, holdtime %us, keepalive interval %us\n",
fmt_timeframe(p->stats.last_read),
p->holdtime, p->holdtime/3);
- if (p->capa.peer.mp_v4 || p->capa.peer.mp_v6 ||
- p->capa.peer.refresh || p->capa.peer.restart ||
- p->capa.peer.as4byte) {
+ for (i = 0; i < AID_MAX; i++)
+ if (p->capa.peer.mp[i])
+ hascapamp = 1;
+ if (hascapamp || p->capa.peer.refresh ||
+ p->capa.peer.restart || p->capa.peer.as4byte) {
printf(" Neighbor capabilities:\n");
- if (p->capa.peer.mp_v4) {
- printf(" Multiprotocol extensions: IPv4");
- print_neighbor_capa_mp_safi(p->capa.peer.mp_v4);
- }
- if (p->capa.peer.mp_v6) {
- printf(" Multiprotocol extensions: IPv6");
- print_neighbor_capa_mp_safi(p->capa.peer.mp_v6);
+ if (hascapamp) {
+ printf(" Multiprotocol extensions: ");
+ print_neighbor_capa_mp(p);
+ printf("\n");
}
if (p->capa.peer.refresh)
printf(" Route Refresh\n");
@@ -633,20 +677,16 @@ show_neighbor_msg(struct imsg *imsg, enum neighbor_views nv)
}
void
-print_neighbor_capa_mp_safi(u_int8_t safi)
+print_neighbor_capa_mp(struct peer *p)
{
- switch (safi) {
- case SAFI_UNICAST:
- printf(" Unicast");
- break;
- case SAFI_MULTICAST:
- printf(" Multicast");
- break;
- default:
- printf(" unknown (%u)", safi);
- break;
- }
- printf("\n");
+ int comma;
+ u_int8_t i;
+
+ for (i = 0, comma = 0; i < AID_MAX; i++)
+ if (p->capa.peer.mp[i]) {
+ printf("%s%s", comma ? ", " : "", aid2str(i));
+ comma = 1;
+ }
}
void
@@ -680,7 +720,7 @@ print_neighbor_msgstats(struct peer *p)
}
void
-print_timer(const char *name, timer_t d)
+print_timer(const char *name, time_t d)
{
printf(" %-20s ", name);
@@ -745,6 +785,12 @@ show_fib_head(void)
}
void
+show_fib_tables_head(void)
+{
+ printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
+}
+
+void
show_network_head(void)
{
printf("flags: S = Static\n");
@@ -788,56 +834,44 @@ show_fib_flags(u_int16_t flags)
int
show_fib_msg(struct imsg *imsg)
{
- struct kroute *k;
- struct kroute6 *k6;
+ struct kroute_full *kf;
+ struct ktable *kt;
char *p;
switch (imsg->hdr.type) {
case IMSG_CTL_KROUTE:
case IMSG_CTL_SHOW_NETWORK:
- if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
errx(1, "wrong imsg len");
- k = imsg->data;
+ kf = imsg->data;
- show_fib_flags(k->flags);
+ show_fib_flags(kf->flags);
- if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) ==
- -1)
+ if (asprintf(&p, "%s/%u", log_addr(&kf->prefix),
+ kf->prefixlen) == -1)
err(1, NULL);
- printf("%4i %-20s ", k->priority, p);
+ printf("%4i %-20s ", kf->priority, p);
free(p);
- if (k->nexthop.s_addr)
- printf("%s", inet_ntoa(k->nexthop));
- else if (k->flags & F_CONNECTED)
- printf("link#%u", k->ifindex);
+ if (kf->flags & F_CONNECTED)
+ printf("link#%u", kf->ifindex);
+ else
+ printf("%s", log_addr(&kf->nexthop));
printf("\n");
break;
- case IMSG_CTL_KROUTE6:
- case IMSG_CTL_SHOW_NETWORK6:
- if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute6))
+ case IMSG_CTL_SHOW_FIB_TABLES:
+ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
errx(1, "wrong imsg len");
- k6 = imsg->data;
+ kt = imsg->data;
- show_fib_flags(k6->flags);
-
- if (asprintf(&p, "%s/%u", log_in6addr(&k6->prefix),
- k6->prefixlen) == -1)
- err(1, NULL);
- printf("%4i %-20s ", k6->priority, p);
- free(p);
-
- if (!IN6_IS_ADDR_UNSPECIFIED(&k6->nexthop))
- printf("%s", log_in6addr(&k6->nexthop));
- else if (k6->flags & F_CONNECTED)
- printf("link#%u", k6->ifindex);
- printf("\n");
+ printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
+ kt->fib_sync ? "coupled" : "decoupled",
+ kt->fib_sync != kt->fib_conf ? "*" : "");
break;
case IMSG_CTL_END:
return (1);
- break;
default:
break;
}
@@ -848,35 +882,70 @@ show_fib_msg(struct imsg *imsg)
void
show_nexthop_head(void)
{
- printf("%-20s %-10s\n", "Nexthop", "State");
+ printf("Flags: * = nexthop valid\n");
+ printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
+ "Prio", "Gateway", "Iface");
}
int
show_nexthop_msg(struct imsg *imsg)
{
struct ctl_show_nexthop *p;
- int ifms_type;
+ struct kroute *k;
+ struct kroute6 *k6;
+ char *s;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NEXTHOP:
p = imsg->data;
- printf("%-20s %-10s", log_addr(&p->addr),
- p->valid ? "valid" : "invalid");
+ printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr));
+ if (!p->krvalid) {
+ printf("\n");
+ return (0);
+ }
+ switch (p->addr.aid) {
+ case AID_INET:
+ k = &p->kr.kr4;
+ if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix),
+ k->prefixlen) == -1)
+ err(1, NULL);
+ printf("%-20s", s);
+ free(s);
+ printf("%3i %-15s ", k->priority,
+ k->flags & F_CONNECTED ? "connected" :
+ inet_ntoa(k->nexthop));
+ break;
+ case AID_INET6:
+ k6 = &p->kr.kr6;
+ if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix),
+ k6->prefixlen) == -1)
+ err(1, NULL);
+ printf("%-20s", s);
+ free(s);
+ printf("%3i %-15s ", k6->priority,
+ k6->flags & F_CONNECTED ? "connected" :
+ log_in6addr(&k6->nexthop));
+ break;
+ default:
+ printf("unknown address family\n");
+ return (0);
+ }
if (p->kif.ifname[0]) {
- printf("%-8s", p->kif.ifname);
- if (p->kif.flags & IFF_UP) {
- printf("UP");
- ifms_type = ift2ifm(p->kif.media_type);
- if (ifms_type != 0)
- printf(", %s, %s",
- get_media_descr(ifms_type),
- get_linkstate(ifms_type,
- p->kif.link_state));
- if (p->kif.baudrate) {
- printf(", ");
- print_baudrate(p->kif.baudrate);
- }
- }
+ char *s1;
+ if (p->kif.baudrate) {
+ if (asprintf(&s1, ", %s",
+ get_baudrate(p->kif.baudrate,
+ "bps")) == -1)
+ err(1, NULL);
+ } else if (asprintf(&s1, ", %s", get_linkstate(
+ p->kif.media_type, p->kif.link_state)) == -1)
+ err(1, NULL);
+ if (asprintf(&s, "%s (%s%s)", p->kif.ifname,
+ p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1)
+ err(1, NULL);
+ printf("%-15s", s);
+ free(s1);
+ free(s);
}
printf("\n");
break;
@@ -898,9 +967,8 @@ show_interface_head(void)
"Link state");
}
-const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
-const struct ifmedia_status_description
- ifm_status_descriptions[] = IFM_STATUS_DESCRIPTIONS;
+const struct if_status_description
+ if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
const struct ifmedia_description
ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
@@ -936,36 +1004,36 @@ get_media_descr(int media_type)
const char *
get_linkstate(int media_type, int link_state)
{
- const struct ifmedia_status_description *p;
- int i;
-
- if (link_state == LINK_STATE_UNKNOWN)
- return ("unknown");
-
- for (i = 0; ifm_status_valid_list[i] != 0; i++)
- for (p = ifm_status_descriptions; p->ifms_valid != 0; p++) {
- if (p->ifms_type != media_type ||
- p->ifms_valid != ifm_status_valid_list[i])
- continue;
- if (LINK_STATE_IS_UP(link_state))
- return (p->ifms_string[1]);
- return (p->ifms_string[0]);
- }
+ const struct if_status_description *p;
+ static char buf[8];
- return ("unknown link state");
+ for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
+ if (LINK_STATE_DESC_MATCH(p, media_type, link_state))
+ return (p->ifs_string);
+ }
+ snprintf(buf, sizeof(buf), "[#%d]", link_state);
+ return (buf);
}
-void
-print_baudrate(u_int64_t baudrate)
+const char *
+get_baudrate(u_int64_t baudrate, char *unit)
{
+ static char bbuf[16];
+
if (baudrate > IF_Gbps(1))
- printf("%llu GBit/s", baudrate / IF_Gbps(1));
+ snprintf(bbuf, sizeof(bbuf), "%llu G%s",
+ baudrate / IF_Gbps(1), unit);
else if (baudrate > IF_Mbps(1))
- printf("%llu MBit/s", baudrate / IF_Mbps(1));
+ snprintf(bbuf, sizeof(bbuf), "%llu M%s",
+ baudrate / IF_Mbps(1), unit);
else if (baudrate > IF_Kbps(1))
- printf("%llu KBit/s", baudrate / IF_Kbps(1));
+ snprintf(bbuf, sizeof(bbuf), "%llu K%s",
+ baudrate / IF_Kbps(1), unit);
else
- printf("%llu Bit/s", baudrate);
+ snprintf(bbuf, sizeof(bbuf), "%llu %s",
+ baudrate, unit);
+
+ return (bbuf);
}
int
@@ -982,17 +1050,12 @@ show_interface_msg(struct imsg *imsg)
printf("%-15s", k->flags & IFF_UP ? "UP" : "");
if ((ifms_type = ift2ifm(k->media_type)) != 0)
- printf("%s, %s", get_media_descr(ifms_type),
- get_linkstate(ifms_type, k->link_state));
- else if (k->link_state == LINK_STATE_UNKNOWN)
- printf("unknown");
- else
- printf("link state %u", k->link_state);
+ printf("%s, ", get_media_descr(ifms_type));
- if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
- printf(", ");
- print_baudrate(k->baudrate);
- }
+ printf("%s", get_linkstate(k->media_type, k->link_state));
+
+ if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0)
+ printf(", %s", get_baudrate(k->baudrate, "Bit/s"));
printf("\n");
break;
case IMSG_CTL_END:
@@ -1011,7 +1074,7 @@ show_rib_summary_head(void)
printf(
"flags: * = Valid, > = Selected, I = via IBGP, A = Announced\n");
printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
- printf("%-5s %-20s%-15s %5s %5s %s\n", "flags", "destination",
+ printf("%-5s %-20s %-15s %5s %5s %s\n", "flags", "destination",
"gateway", "lpref", "med", "aspath origin");
}
@@ -1049,26 +1112,26 @@ print_flags(u_int8_t flags, int sum)
char *p = flagstr;
if (sum) {
- if (flags & F_RIB_ANNOUNCE)
+ if (flags & F_PREF_ANNOUNCE)
*p++ = 'A';
- if (flags & F_RIB_INTERNAL)
+ if (flags & F_PREF_INTERNAL)
*p++ = 'I';
- if (flags & F_RIB_ELIGIBLE)
+ if (flags & F_PREF_ELIGIBLE)
*p++ = '*';
- if (flags & F_RIB_ACTIVE)
+ if (flags & F_PREF_ACTIVE)
*p++ = '>';
*p = '\0';
printf("%-5s ", flagstr);
} else {
- if (flags & F_RIB_INTERNAL)
+ if (flags & F_PREF_INTERNAL)
printf("internal");
else
printf("external");
- if (flags & F_RIB_ELIGIBLE)
+ if (flags & F_PREF_ELIGIBLE)
printf(", valid");
- if (flags & F_RIB_ACTIVE)
+ if (flags & F_PREF_ACTIVE)
printf(", best");
- if (flags & F_RIB_ANNOUNCE)
+ if (flags & F_PREF_ANNOUNCE)
printf(", announced");
}
}
@@ -1085,7 +1148,7 @@ show_rib_summary_msg(struct imsg *imsg)
memcpy(&rib, imsg->data, sizeof(rib));
print_prefix(&rib.prefix, rib.prefixlen, rib.flags);
- printf("%-15s ", log_addr(&rib.exit_nexthop));
+ printf(" %-15s ", log_addr(&rib.exit_nexthop));
printf(" %5u %5u ", rib.local_pref, rib.med);
@@ -1189,8 +1252,8 @@ show_rib_detail_msg(struct imsg *imsg, int nodescr)
case ATTR_AGGREGATOR:
memcpy(&as, data, sizeof(as));
memcpy(&id, data + sizeof(as), sizeof(id));
- printf(" Aggregator: %s [%s]\n",
- log_as(htonl(as)), inet_ntoa(id));
+ printf(" Aggregator: %s [%s]\n",
+ log_as(ntohl(as)), inet_ntoa(id));
break;
case ATTR_ORIGINATOR_ID:
memcpy(&id, data, sizeof(id));
@@ -1236,22 +1299,27 @@ fmt_mem(int64_t num)
return (buf);
}
+size_t pt_sizes[AID_MAX] = AID_PTSIZE;
+
int
show_rib_memory_msg(struct imsg *imsg)
{
struct rde_memstats stats;
+ size_t pts = 0;
+ int i;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_RIB_MEM:
memcpy(&stats, imsg->data, sizeof(stats));
printf("RDE memory statistics\n");
- printf("%10lld IPv4 network entries using %s of memory\n",
- (long long)stats.pt4_cnt, fmt_mem(stats.pt4_cnt *
- sizeof(struct pt_entry4)));
- if (stats.pt6_cnt != 0)
- printf("%10lld IPv6 network entries using "
- "%s of memory\n", (long long)stats.pt6_cnt,
- fmt_mem(stats.pt6_cnt * sizeof(struct pt_entry6)));
+ for (i = 0; i < AID_MAX; i++) {
+ if (stats.pt_cnt[i] == 0)
+ continue;
+ pts += stats.pt_cnt[i] * pt_sizes[i];
+ printf("%10lld %s network entries using %s of memory\n",
+ (long long)stats.pt_cnt[i], aid_vals[i].name,
+ fmt_mem(stats.pt_cnt[i] * pt_sizes[i]));
+ }
printf("%10lld rib entries using %s of memory\n",
(long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
sizeof(struct rib_entry)));
@@ -1272,9 +1340,7 @@ show_rib_memory_msg(struct imsg *imsg)
(long long)stats.attr_refs);
printf("%10lld BGP attributes using %s of memory\n",
(long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
- printf("RIB using %s of memory\n", fmt_mem(
- stats.pt4_cnt * sizeof(struct pt_entry4) +
- stats.pt6_cnt * sizeof(struct pt_entry6) +
+ printf("RIB using %s of memory\n", fmt_mem(pts +
stats.prefix_cnt * sizeof(struct prefix) +
stats.rib_cnt * sizeof(struct rib_entry) +
stats.path_cnt * sizeof(struct rde_aspath) +
@@ -1328,30 +1394,6 @@ show_community(u_char *data, u_int16_t len)
}
}
-const char *
-get_ext_subtype(u_int8_t type)
-{
- static char etype[6];
-
- switch (type) {
- case EXT_COMMUNITY_ROUTE_TGT:
- return "rt"; /* route target */
- case EXT_CUMMUNITY_ROUTE_ORIG:
- return "soo"; /* source of origin */
- case EXT_COMMUNITY_OSPF_DOM_ID:
- return "odi"; /* ospf domain id */
- case EXT_COMMUNITY_OSPF_RTR_TYPE:
- return "ort"; /* ospf route type */
- case EXT_COMMUNITY_OSPF_RTR_ID:
- return "ori"; /* ospf router id */
- case EXT_COMMUNITY_BGP_COLLECT:
- return "bdc"; /* bgp data collection */
- default:
- snprintf(etype, sizeof(etype), "[%i]", (int)type);
- return etype;
- }
-}
-
void
show_ext_community(u_char *data, u_int16_t len)
{
@@ -1372,28 +1414,29 @@ show_ext_community(u_char *data, u_int16_t len)
case EXT_COMMUNITY_TWO_AS:
memcpy(&as2, data + i + 2, sizeof(as2));
memcpy(&u32, data + i + 4, sizeof(u32));
- printf("%s %hu:%u", get_ext_subtype(subtype), as2, u32);
+ printf("%s %s:%u", log_ext_subtype(subtype),
+ log_as(ntohs(as2)), ntohl(u32));
break;
case EXT_COMMUNITY_IPV4:
memcpy(&ip, data + i + 2, sizeof(ip));
memcpy(&u16, data + i + 6, sizeof(u16));
- printf("%s %s:%hu", get_ext_subtype(subtype),
- inet_ntoa(ip), u16);
+ printf("%s %s:%hu", log_ext_subtype(subtype),
+ inet_ntoa(ip), ntohs(u16));
break;
case EXT_COMMUNITY_FOUR_AS:
memcpy(&as4, data + i + 2, sizeof(as4));
memcpy(&u16, data + i + 6, sizeof(u16));
- printf("%s %s:%hu", get_ext_subtype(subtype),
- log_as(as4), u16);
+ printf("%s %s:%hu", log_ext_subtype(subtype),
+ log_as(ntohl(as4)), ntohs(u16));
break;
case EXT_COMMUNITY_OPAQUE:
memcpy(&ext, data + i, sizeof(ext));
ext = betoh64(ext) & 0xffffffffffffLL;
- printf("%s 0x%llx", get_ext_subtype(subtype), ext);
+ printf("%s 0x%llx", log_ext_subtype(subtype), ext);
break;
default:
memcpy(&ext, data + i, sizeof(ext));
- printf("0x%llx", betoh64(ext));
+ printf("0x%llx", betoh64(ext));
}
if (i + 8 < len)
printf(", ");
diff --git a/bgpctl/irr_parser.c b/bgpctl/irr_parser.c
index 063faba..33e51e8 100644
--- a/bgpctl/irr_parser.c
+++ b/bgpctl/irr_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: irr_parser.c,v 1.8 2007/03/05 22:34:08 henning Exp $ */
+/* $OpenBSD: irr_parser.c,v 1.9 2009/09/08 15:40:25 claudio Exp $ */
/*
* Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
@@ -81,6 +81,7 @@ parse_response(FILE *f, enum qtype qtype)
return (-1);
break;
case QTYPE_ROUTE:
+ case QTYPE_ROUTE6:
if ((n = parse_route(key, val)) == -1)
return (-1);
break;
@@ -281,7 +282,7 @@ parse_policy(char *key, char *val)
!isdigit(tok[2]))
errx(1, "peering spec \"%s\": format "
"error, AS expected", tok);
- pi->peer_as = strtonum(tok + 2, 1, USHRT_MAX,
+ pi->peer_as = strtonum(tok + 2, 1, UINT_MAX,
&errstr);
if (errstr)
errx(1, "peering spec \"%s\": format "
@@ -407,7 +408,8 @@ parse_asset(char *key, char *val)
int
parse_route(char *key, char *val)
{
- if (strcmp(key, "route")) /* ignore everything else */
+ if (strcmp(key, "route") && strcmp(key, "route6"))
+ /* ignore everything else */
return (0);
/* route is single-value, but seen trailing , in the wild */
diff --git a/bgpctl/irr_prefix.c b/bgpctl/irr_prefix.c
index 8bc0d74..df85a6b 100644
--- a/bgpctl/irr_prefix.c
+++ b/bgpctl/irr_prefix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: irr_prefix.c,v 1.15 2007/05/27 18:54:25 henning Exp $ */
+/* $OpenBSD: irr_prefix.c,v 1.18 2010/05/10 02:00:50 krw Exp $ */
/*
* Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
@@ -29,6 +29,7 @@
#include <arpa/inet.h>
#include "irrfilter.h"
+#include "bgpd.h"
void prefixset_aggregate(struct prefix_set *);
int prefix_aggregate(struct irr_prefix *, const struct irr_prefix *);
@@ -63,7 +64,11 @@ prefixset_get(char *as)
fflush(stdout);
}
curpfxs = pfxs;
- if (whois(as, QTYPE_ROUTE) == -1)
+ if ((irrflags & F_IPV4) && whois(as, QTYPE_ROUTE) == -1)
+ errx(1, "whois error, prefixset_get %s", as);
+ if ((irrflags & F_IPV6) && whois(as, QTYPE_ROUTE6) == -1)
+ errx(1, "whois error, prefixset_get %s", as);
+ if (whois(as, QTYPE_ROUTE6) == -1)
errx(1, "whois error, prefixset_get %s", as);
curpfxs = NULL;
if (irrverbose >= 3)
@@ -80,9 +85,11 @@ prefixset_addmember(char *s)
void *p;
u_int i;
struct irr_prefix *pfx;
- int len;
+ int len, ret;
+ char *slash;
+ const char *errstr;
- if (strchr(s, '/') == NULL) {
+ if ((slash = strchr(s, '/')) == NULL) {
fprintf(stderr, "%s: prefix %s does not have the len "
"specified, ignoring\n", curpfxs->as, s);
return (0);
@@ -92,17 +99,26 @@ prefixset_addmember(char *s)
err(1, "prefixset_addmember calloc");
if ((len = inet_net_pton(AF_INET, s, &pfx->addr.in,
- sizeof(pfx->addr.in))) == -1) {
- if (errno == ENOENT) {
- fprintf(stderr, "%s: prefix \"%s\": parse error\n",
+ sizeof(pfx->addr.in))) != -1) {
+ pfx->af = AF_INET;
+ } else {
+ len = strtonum(slash + 1, 0, 128, &errstr);
+ if (errstr)
+ errx(1, "prefixset_addmember %s prefix %s: prefixlen "
+ "is %s", curpfxs->as, s, errstr);
+ *slash = '\0';
+
+ if ((ret = inet_pton(AF_INET6, s, &pfx->addr.in6)) == -1)
+ err(1, "prefixset_addmember %s prefix \"%s\"",
curpfxs->as, s);
+ else if (ret == 0) {
+ fprintf(stderr, "prefixset_addmember %s prefix \"%s\": "
+ "No matching address family found", curpfxs->as, s);
+ free(pfx);
return (0);
- } else
- err(1, "prefixset_addmember %s inet_net_pton \"%s\"",
- curpfxs->as, s);
+ }
+ pfx->af = AF_INET6;
}
-
- pfx->af = AF_INET;
pfx->len = pfx->maxlen = len;
/* yes, there are dupes... e. g. from multiple sources */
@@ -175,24 +191,47 @@ prefixset_aggregate(struct prefix_set *pfxs)
int
prefix_aggregate(struct irr_prefix *a, const struct irr_prefix *b)
{
- in_addr_t mask;
+ in_addr_t mask;
+ struct in6_addr ma;
+ struct in6_addr mb;
if (a->len == 0)
return (1);
- mask = htonl(0xffffffff << (32 - a->len));
+ if (a->af != b->af)
+ /* We cannot aggregate addresses of different families. */
+ return (0);
- if ((a->addr.in.s_addr & mask) == (b->addr.in.s_addr & mask))
- return (1);
+ if (a->af == AF_INET) {
+ mask = htonl(prefixlen2mask(a->len));
+ if ((a->addr.in.s_addr & mask) == (b->addr.in.s_addr & mask))
+ return (1);
+ } else if (a->af == AF_INET6) {
+ inet6applymask(&ma, &a->addr.in6, a->len);
+ inet6applymask(&mb, &b->addr.in6, a->len);
+ if (IN6_ARE_ADDR_EQUAL(&ma, &mb))
+ return (1);
+ }
- /* see wether we can fold them in one */
+ /* see whether we can fold them in one */
if (a->len == b->len && a->len > 1) {
- mask = htonl(0xffffffff << (32 - (a->len - 1)));
- if ((a->addr.in.s_addr & mask) ==
- (b->addr.in.s_addr & mask)) {
- a->len--;
- a->addr.in.s_addr &= mask;
- return (1);
+ if (a->af == AF_INET) {
+ mask = htonl(prefixlen2mask(a->len - 1));
+ if ((a->addr.in.s_addr & mask) ==
+ (b->addr.in.s_addr & mask)) {
+ a->len--;
+ a->addr.in.s_addr &= mask;
+ return (1);
+ }
+ } else if (a->af == AF_INET6) {
+ inet6applymask(&ma, &a->addr.in6, a->len - 1);
+ inet6applymask(&mb, &b->addr.in6, a->len - 1);
+
+ if (IN6_ARE_ADDR_EQUAL(&ma, &mb)) {
+ a->len--;
+ memcpy(&a->addr.in6, &ma, sizeof(ma));
+ return (1);
+ }
}
}
@@ -219,6 +258,13 @@ irr_prefix_cmp(const void *a, const void *b)
if (ntohl(pa->addr.in.s_addr) >
ntohl(pb->addr.in.s_addr))
return (1);
+ } else if (pa->af == AF_INET6) {
+ for (r = 0; r < 16; r++) {
+ if (pa->addr.in6.s6_addr[r] < pb->addr.in6.s6_addr[r])
+ return (-1);
+ if (pa->addr.in6.s6_addr[r] > pb->addr.in6.s6_addr[r])
+ return (1);
+ }
} else
errx(1, "irr_prefix_cmp unknown af %u", pa->af);
diff --git a/bgpctl/irrfilter.c b/bgpctl/irrfilter.c
index fb5b4f0..e731554 100644
--- a/bgpctl/irrfilter.c
+++ b/bgpctl/irrfilter.c
@@ -15,6 +15,9 @@
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if defined(__FreeBSD__) /* compat */
+#include "openbsd-compat.h"
+#endif /* defined(__FreeBSD__) */
#include <sys/types.h>
#include <sys/param.h>
diff --git a/bgpctl/irrfilter.h b/bgpctl/irrfilter.h
index 5059240..9def255 100644
--- a/bgpctl/irrfilter.h
+++ b/bgpctl/irrfilter.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: irrfilter.h,v 1.7 2007/03/06 16:45:34 henning Exp $ */
+/* $OpenBSD: irrfilter.h,v 1.9 2009/09/08 16:11:36 sthen Exp $ */
/*
* Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
@@ -16,11 +16,17 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if defined(__FreeBSD__) /* compat */
+#include "openbsd-compat.h"
+#endif /* defined(__FreeBSD__) */
+
#include <sys/queue.h>
#include <sys/tree.h>
#include <netinet/in.h>
#define F_IMPORTONLY 0x01 /* skip export: items */
+#define F_IPV4 0x02 /* use IPv4 items */
+#define F_IPV6 0x04 /* use IPv6 items */
int irrflags;
int irrverbose;
@@ -37,7 +43,7 @@ struct policy_item {
char *action;
char *filter;
enum pdir dir;
- u_int16_t peer_as;
+ u_int32_t peer_as;
};
TAILQ_HEAD(policy_head, policy_item);
@@ -55,7 +61,8 @@ enum qtype {
QTYPE_NONE,
QTYPE_OWNAS,
QTYPE_ASSET,
- QTYPE_ROUTE
+ QTYPE_ROUTE,
+ QTYPE_ROUTE6
};
struct as_set {
@@ -72,6 +79,7 @@ struct as_set {
struct irr_prefix {
union {
struct in_addr in;
+ struct in6_addr in6;
} addr;
sa_family_t af;
u_int8_t len;
diff --git a/bgpctl/parser.c b/bgpctl/parser.c
index bc6d078..4416f71 100644
--- a/bgpctl/parser.c
+++ b/bgpctl/parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.c,v 1.54 2009/06/12 16:44:02 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.61 2010/03/08 17:02:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,6 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if defined(__FreeBSD__) /* compat */
+#include "openbsd-compat.h"
+#endif /* defined(__FreeBSD__) */
+
#include <sys/types.h>
#include <sys/socket.h>
@@ -52,7 +56,8 @@ enum token_type {
PREPSELF,
WEIGHT,
FAMILY,
- GETOPT
+ GETOPT,
+ RTABLE
};
enum getopts {
@@ -97,6 +102,9 @@ static const struct token t_prepself[];
static const struct token t_weight[];
static const struct token t_irrfilter[];
static const struct token t_irrfilter_opts[];
+static const struct token t_log[];
+static const struct token t_fib_table[];
+static const struct token t_show_fib_table[];
static const struct token t_main[] = {
{ KEYWORD, "reload", RELOAD, NULL},
@@ -105,6 +113,7 @@ static const struct token t_main[] = {
{ KEYWORD, "neighbor", NEIGHBOR, t_neighbor},
{ KEYWORD, "network", NONE, t_network},
{ KEYWORD, "irrfilter", IRRFILTER, t_irrfilter},
+ { KEYWORD, "log", NONE, t_log},
{ ENDTOKEN, "", NONE, NULL}
};
@@ -116,6 +125,7 @@ static const struct token t_show[] = {
{ KEYWORD, "network", NETWORK_SHOW, t_network_show},
{ KEYWORD, "nexthop", SHOW_NEXTHOP, NULL},
{ KEYWORD, "rib", SHOW_RIB, t_show_rib},
+ { KEYWORD, "tables", SHOW_FIB_TABLES, NULL},
{ KEYWORD, "ip", NONE, t_show_ip},
{ KEYWORD, "summary", SHOW_SUMMARY, t_show_summary},
{ ENDTOKEN, "", NONE, NULL}
@@ -128,14 +138,15 @@ static const struct token t_show_summary[] = {
};
static const struct token t_show_fib[] = {
- { NOTOKEN, "", NONE, NULL},
- { FLAG, "connected", F_CONNECTED, t_show_fib},
- { FLAG, "static", F_STATIC, t_show_fib},
- { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib},
- { FLAG, "nexthop", F_NEXTHOP, t_show_fib},
- { FAMILY, "", NONE, t_show_fib},
- { ADDRESS, "", NONE, NULL},
- { ENDTOKEN, "", NONE, NULL}
+ { NOTOKEN, "", NONE, NULL},
+ { FLAG, "connected", F_CONNECTED, t_show_fib},
+ { FLAG, "static", F_STATIC, t_show_fib},
+ { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib},
+ { FLAG, "nexthop", F_NEXTHOP, t_show_fib},
+ { KEYWORD, "table", NONE, t_show_fib_table},
+ { FAMILY, "", NONE, t_show_fib},
+ { ADDRESS, "", NONE, NULL},
+ { ENDTOKEN, "", NONE, NULL}
};
static const struct token t_show_rib[] = {
@@ -187,6 +198,7 @@ static const struct token t_show_neighbor_modifiers[] = {
static const struct token t_fib[] = {
{ KEYWORD, "couple", FIB_COUPLE, NULL},
{ KEYWORD, "decouple", FIB_DECOUPLE, NULL},
+ { KEYWORD, "table", NONE, t_fib_table},
{ ENDTOKEN, "", NONE, NULL}
};
@@ -311,6 +323,22 @@ static const struct token t_irrfilter_opts[] = {
{ ENDTOKEN, "", NONE, NULL}
};
+static const struct token t_log[] = {
+ { KEYWORD, "verbose", LOG_VERBOSE, NULL},
+ { KEYWORD, "brief", LOG_BRIEF, NULL},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_fib_table[] = {
+ { RTABLE, "", NONE, t_fib},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_fib_table[] = {
+ { RTABLE, "", NONE, t_show_fib},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
static struct parse_result res;
const struct token *match_token(int *argc, char **argv[],
@@ -404,15 +432,22 @@ match_token(int *argc, char **argv[], const struct token table[])
case FAMILY:
if (word == NULL)
break;
- if (!strcmp(word, "inet") || !strcmp(word, "IPv4")) {
+ if (!strcmp(word, "inet") ||
+ !strcasecmp(word, "IPv4")) {
+ match++;
+ t = &table[i];
+ res.aid = AID_INET;
+ }
+ if (!strcmp(word, "inet6") ||
+ !strcasecmp(word, "IPv6")) {
match++;
t = &table[i];
- res.af = AF_INET;
+ res.aid = AID_INET6;
}
- if (!strcmp(word, "inet6") || !strcmp(word, "IPv6")) {
+ if (!strcasecmp(word, "VPNv4")) {
match++;
t = &table[i];
- res.af = AF_INET6;
+ res.aid = AID_VPN_IPv4;
}
break;
case ADDRESS:
@@ -485,6 +520,7 @@ match_token(int *argc, char **argv[], const struct token table[])
case PREPNBR:
case PREPSELF:
case WEIGHT:
+ case RTABLE:
if (word != NULL && strlen(word) > 0 &&
parse_number(word, &res, table[i].type)) {
match++;
@@ -577,6 +613,9 @@ show_valid_args(const struct token table[])
case WEIGHT:
fprintf(stderr, " <number>\n");
break;
+ case RTABLE:
+ fprintf(stderr, " <rtableid>\n");
+ break;
case NEXTHOP:
fprintf(stderr, " <address>\n");
break;
@@ -584,7 +623,7 @@ show_valid_args(const struct token table[])
fprintf(stderr, " <pftable>\n");
break;
case FAMILY:
- fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n");
+ fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 | VPNv4 ]\n");
break;
case GETOPT:
fprintf(stderr, " <options>\n");
@@ -608,7 +647,7 @@ parse_addr(const char *word, struct bgpd_addr *addr)
bzero(&ina, sizeof(ina));
if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
- addr->af = AF_INET;
+ addr->aid = AID_INET;
addr->v4 = ina;
return (1);
}
@@ -618,13 +657,7 @@ parse_addr(const char *word, struct bgpd_addr *addr)
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(word, "0", &hints, &r) == 0) {
- addr->af = AF_INET6;
- memcpy(&addr->v6,
- &((struct sockaddr_in6 *)r->ai_addr)->sin6_addr,
- sizeof(addr->v6));
- addr->scope_id =
- ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id;
-
+ sa2addr(r->ai_addr, addr);
freeaddrinfo(r);
return (1);
}
@@ -663,15 +696,15 @@ parse_prefix(const char *word, struct bgpd_addr *addr, u_int8_t *prefixlen)
if (parse_addr(word, addr) == 0)
return (0);
- switch (addr->af) {
- case AF_INET:
+ switch (addr->aid) {
+ case AID_INET:
if (mask == -1)
mask = 32;
if (mask > 32)
errx(1, "invalid netmask: too large");
addr->v4.s_addr = addr->v4.s_addr & htonl(prefixlen2mask(mask));
break;
- case AF_INET6:
+ case AID_INET6:
if (mask == -1)
mask = 128;
inet6applymask(&addr->v6, &addr->v6, mask);
@@ -706,7 +739,7 @@ parse_asnum(const char *word, u_int32_t *asnum)
if (errstr)
errx(1, "AS number is %s: %s", errstr, word);
} else {
- uval = strtonum(word, 0, ASNUM_MAX - 1, &errstr);
+ uval = strtonum(word, 0, UINT_MAX, &errstr);
if (errstr)
errx(1, "AS number is %s: %s", errstr, word);
}
@@ -730,6 +763,11 @@ parse_number(const char *word, struct parse_result *r, enum token_type type)
errx(1, "number is %s: %s", errstr, word);
/* number was parseable */
+ if (type == RTABLE) {
+ r->rtableid = uval;
+ return (1);
+ }
+
if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
err(1, NULL);
switch (type) {
@@ -882,8 +920,14 @@ bgpctl_getopt(int *argc, char **argv[], int type)
int ch;
optind = optreset = 1;
- while ((ch = getopt((*argc) + 1, (*argv) - 1, "o:")) != -1) {
+ while ((ch = getopt((*argc) + 1, (*argv) - 1, "46o:")) != -1) {
switch (ch) {
+ case '4':
+ res.flags = (res.flags | F_IPV4) & ~F_IPV6;
+ break;
+ case '6':
+ res.flags = (res.flags | F_IPV6) & ~F_IPV4;
+ break;
case 'o':
res.irr_outdir = optarg;
break;
diff --git a/bgpctl/parser.h b/bgpctl/parser.h
index 8adb5b5..3b6ce75 100644
--- a/bgpctl/parser.h
+++ b/bgpctl/parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.h,v 1.19 2009/06/06 06:05:41 claudio Exp $ */
+/* $OpenBSD: parser.h,v 1.22 2010/05/03 13:11:41 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -29,6 +29,7 @@ enum actions {
SHOW_NEIGHBOR_TIMERS,
SHOW_NEIGHBOR_TERSE,
SHOW_FIB,
+ SHOW_FIB_TABLES,
SHOW_RIB,
SHOW_RIB_MEM,
SHOW_NEXTHOP,
@@ -37,6 +38,8 @@ enum actions {
FIB,
FIB_COUPLE,
FIB_DECOUPLE,
+ LOG_VERBOSE,
+ LOG_BRIEF,
NEIGHBOR,
NEIGHBOR_UP,
NEIGHBOR_DOWN,
@@ -59,9 +62,10 @@ struct parse_result {
char rib[PEER_DESCR_LEN];
char *irr_outdir;
int flags;
- enum actions action;
+ u_int rtableid;
+ enum actions action;
u_int8_t prefixlen;
- sa_family_t af;
+ u_int8_t aid;
};
__dead void usage(void);
diff --git a/bgpctl/whois.c b/bgpctl/whois.c
index 839dcbb..f14d07d 100644
--- a/bgpctl/whois.c
+++ b/bgpctl/whois.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: whois.c,v 1.3 2007/03/05 16:43:24 henning Exp $ */
+/* $OpenBSD: whois.c,v 1.4 2009/09/08 15:40:25 claudio Exp $ */
/*
* Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
@@ -68,7 +68,8 @@ char *qtype_opts[] = {
"",
"-T aut-num",
"-K -T as-set",
- "-K -T route -i origin"
+ "-K -T route -i origin",
+ "-K -T route6 -i origin"
};
char *server = "whois.radb.net";
diff --git a/bgpd/Makefile b/bgpd/Makefile
index 739f5e2..adda69b 100644
--- a/bgpd/Makefile
+++ b/bgpd/Makefile
@@ -1,15 +1,25 @@
-# $OpenBSD: Makefile,v 1.28 2009/06/25 14:14:54 deraadt Exp $
+# $OpenBSD: Makefile,v 1.29 2010/05/26 16:44:32 nicm Exp $
+
+.PATH: ${.CURDIR}/.. ${.CURDIR}/../openbsd-compat
+
+CONFFILE?= ${PREFIX}/etc/bgpd.conf
PROG= bgpd
-SRCS= bgpd.c buffer.c session.c log.c parse.y config.c imsg.c \
+SRCS= bgpd.c session.c log.c parse.y config.c \
rde.c rde_rib.c rde_decide.c rde_prefix.c mrt.c kroute.c \
- control.c pfkey.c rde_update.c rde_attr.c printconf.c \
- rde_filter.c pftable.c name2id.c util.c carp.c timer.c
+ control.c pfkey_compat.c rde_update.c rde_attr.c printconf.c \
+ rde_filter.c pftable.c name2id.c util.c carp.c timer.c \
+ imsg.c imsg-buffer.c
CFLAGS+= -Wall -I${.CURDIR}
+CFLAGS+= -I${.CURDIR}/../openbsd-compat
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare
+CFLAGS+= -DCONFFILE=\"${CONFFILE}\"
+.if defined(IPV6_LINKLOCAL_PEER)
+CFLAGS+= -DIPV6_LINKLOCAL_PEER
+.endif
YFLAGS=
MAN= bgpd.8 bgpd.conf.5
diff --git a/bgpd/bgpd.8 b/bgpd/bgpd.8
index 295e2f9..e547db4 100644
--- a/bgpd/bgpd.8
+++ b/bgpd/bgpd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.8,v 1.28 2009/01/13 23:01:36 sthen Exp $
+.\" $OpenBSD: bgpd.8,v 1.33 2009/12/16 15:40:55 claudio Exp $
.\"
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: January 13 2009 $
+.Dd $Mdocdate: June 27 2010 $
.Dt BGPD 8
.Os
.Sh NAME
@@ -24,12 +24,8 @@
.Nm bgpd
.Bk -words
.Op Fl cdnv
-.Oo Xo
-.Fl D Ar macro Ns = Ns Ar value Oc
-.Xc
+.Op Fl D Ar macro Ns = Ns Ar value
.Op Fl f Ar file
-.Op Fl r Ar path
-.Op Fl s Ar path
.Ek
.Sh DESCRIPTION
.Nm
@@ -42,15 +38,15 @@ concerning
with other BGP systems.
.Nm
uses the Border Gateway Protocol, Version 4,
-as described in RFC 1771.
+as described in RFC 4271.
Please refer to that document for more information about BGP.
.Pp
.Nm
is usually started at boot time, and can be enabled by
setting the following in
-.Pa /etc/rc.conf.local :
+.Pa /etc/rc.conf :
.Pp
-.Dl bgpd_flags=\&"\&"
+.Dl openbgpd_enable=\&"YES\&"
.Pp
See
.Xr rc 8
@@ -117,25 +113,16 @@ Use
.Ar file
as the configuration file,
instead of the default
-.Pa /etc/bgpd.conf .
+.Pa %%PREFIX%%/etc/bgpd.conf .
.It Fl n
Configtest mode.
Only check the configuration file for validity.
-.It Fl r Ar path
-Open a second, restricted, control socket that
-.Xr bgpctl 8
-can use.
-Only
-.Em show
-requests are allowed on this socket.
-.It Fl s Ar path
-Use an alternate location for the default control socket.
.It Fl v
Produce more verbose output.
.El
.Sh FILES
.Bl -tag -width "/var/run/bgpd.sockXXX" -compact
-.It Pa /etc/bgpd.conf
+.It Pa %%PREFIX%%/etc/bgpd.conf
default
.Nm
configuration file
@@ -150,9 +137,9 @@ control socket
.Xr bgplg 8 ,
.Xr bgplgsh 8
.Rs
-.%R RFC 1771
+.%R RFC 4271
.%T "A Border Gateway Protocol 4 (BGP-4)"
-.%D March 1995
+.%D January 2006
.Re
.Rs
.%R RFC 1997
@@ -165,6 +152,11 @@ control socket
.%D August 1998
.Re
.Rs
+.%R RFC 2545
+.%T "Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing"
+.%D March 1999
+.Re
+.Rs
.%R RFC 2796
.%T "BGP Route Reflection - An Alternative to Full Mesh IBGP"
.%D April 2000
@@ -175,11 +167,6 @@ control socket
.%D September 2000
.Re
.Rs
-.%R RFC 3392
-.%T "Capabilities Advertisement with BGP-4"
-.%D January 1999
-.Re
-.Rs
.%R RFC 3682
.%T "The Generalized TTL Security Mechanism (GTSM)"
.%D February 2004
@@ -190,6 +177,21 @@ control socket
.%D April 2004
.Re
.Rs
+.%R RFC 4360
+.%T "BGP Extended Communities Attribute"
+.%D February 2006
+.Re
+.Rs
+.%R RFC 4364
+.%T "BGP/MPLS IP Virtual Private Networks (VPNs)"
+.%D February 2006
+.Re
+.Rs
+.%R RFC 4486
+.%T "BGP Cease Notification Message Subcodes"
+.%D April 2006
+.Re
+.Rs
.%R RFC 4760
.%T "Multiprotocol Extensions for BGP-4"
.%D January 2007
@@ -199,6 +201,21 @@ control socket
.%T "BGP Support for Four-octet AS Number Space"
.%D May 2007
.Re
+.Rs
+.%R RFC 5492
+.%T "Capabilities Advertisement with BGP-4"
+.%D February 2009
+.Re
+.Rs
+.%R draft-ietf-idr-optional-transitive-00
+.%T "Error Handling for Optional Transitive BGP Attributes"
+.%D April 2009
+.Re
+.Rs
+.%R draft-ietf-idr-fsm-subcode-00
+.%T "Subcodes for BGP Finite State Machine Error"
+.%D September 2010
+.Re
.Sh HISTORY
The
.Nm
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 43e284b..7a177fa 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.c,v 1.148 2009/06/07 00:30:23 claudio Exp $ */
+/* $OpenBSD: bgpd.c,v 1.167 2011/05/01 10:42:28 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -32,8 +32,8 @@
#include <string.h>
#include <unistd.h>
-#include "mrt.h"
#include "bgpd.h"
+#include "mrt.h"
#include "session.h"
void sighdlr(int);
@@ -42,23 +42,22 @@ int main(int, char *[]);
int check_child(pid_t, const char *);
int send_filterset(struct imsgbuf *, struct filter_set_head *);
int reconfigure(char *, struct bgpd_config *, struct mrt_head *,
- struct peer **, struct filter_head *);
+ struct peer **);
int dispatch_imsg(struct imsgbuf *, int);
+int control_setup(struct bgpd_config *);
int rfd = -1;
-int cflags = 0;
-struct filter_set_head *connectset;
-struct filter_set_head *connectset6;
-struct filter_set_head *staticset;
-struct filter_set_head *staticset6;
-volatile sig_atomic_t mrtdump = 0;
-volatile sig_atomic_t quit = 0;
-volatile sig_atomic_t sigchld = 0;
-volatile sig_atomic_t reconfig = 0;
-pid_t reconfpid = 0;
+int cflags;
+volatile sig_atomic_t mrtdump;
+volatile sig_atomic_t quit;
+volatile sig_atomic_t sigchld;
+volatile sig_atomic_t reconfig;
+pid_t reconfpid;
struct imsgbuf *ibuf_se;
struct imsgbuf *ibuf_rde;
struct rib_names ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames);
+char *cname;
+char *rcname;
void
sighdlr(int sig)
@@ -86,8 +85,8 @@ usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-cdnv] ", __progname);
- fprintf(stderr, "[-D macro=value] [-f file] [-r path] [-s path]\n");
+ fprintf(stderr, "usage: %s [-cdnv] [-D macro=value] [-f file]\n",
+ __progname);
exit(1);
}
@@ -101,15 +100,10 @@ int
main(int argc, char *argv[])
{
struct bgpd_config conf;
- struct peer *peer_l, *p;
struct mrt_head mrt_l;
- struct network_head net_l;
- struct filter_head *rules_l;
- struct network *net;
- struct filter_rule *r;
+ struct peer *peer_l, *p;
struct mrt *m;
struct listen_addr *la;
- struct rde_rib *rr;
struct pollfd pfd[POLL_MAX];
pid_t io_pid = 0, rde_pid = 0, pid;
char *conffile;
@@ -125,17 +119,11 @@ main(int argc, char *argv[])
log_init(1); /* log to stderr until daemonized */
- if ((rules_l = calloc(1, sizeof(struct filter_head))) == NULL)
- err(1, NULL);
-
bzero(&conf, sizeof(conf));
LIST_INIT(&mrt_l);
- TAILQ_INIT(&net_l);
- TAILQ_INIT(rules_l);
peer_l = NULL;
- conf.csock = SOCKET_NAME;
- while ((ch = getopt(argc, argv, "cdD:f:nr:s:v")) != -1) {
+ while ((ch = getopt(argc, argv, "cdD:f:nv")) != -1) {
switch (ch) {
case 'c':
conf.opts |= BGPD_OPT_FORCE_DEMOTE;
@@ -158,12 +146,7 @@ main(int argc, char *argv[])
if (conf.opts & BGPD_OPT_VERBOSE)
conf.opts |= BGPD_OPT_VERBOSE2;
conf.opts |= BGPD_OPT_VERBOSE;
- break;
- case 'r':
- conf.rcsock = optarg;
- break;
- case 's':
- conf.csock = optarg;
+ log_verbose(1);
break;
default:
usage();
@@ -176,24 +159,22 @@ main(int argc, char *argv[])
if (argc > 0)
usage();
- if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l, rules_l)) {
- free(rules_l);
- exit(1);
- }
-
if (conf.opts & BGPD_OPT_NOACTION) {
+ struct network_head net_l;
+ struct rdomain_head rdom_l;
+ struct filter_head rules_l;
+
+ if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l,
+ &rules_l, &rdom_l))
+ exit(1);
+
if (conf.opts & BGPD_OPT_VERBOSE)
- print_config(&conf, &ribnames, &net_l, peer_l, rules_l,
- &mrt_l);
+ print_config(&conf, &ribnames, &net_l, peer_l, &rules_l,
+ &mrt_l, &rdom_l);
else
fprintf(stderr, "configuration OK\n");
exit(0);
}
- cflags = conf.flags;
- connectset = &conf.connectset;
- staticset = &conf.staticset;
- connectset6 = &conf.connectset6;
- staticset6 = &conf.staticset6;
if (geteuid())
errx(1, "need root privileges");
@@ -225,13 +206,9 @@ main(int argc, char *argv[])
session_socket_blockmode(pipe_s2r_c[0], BM_NONBLOCK);
session_socket_blockmode(pipe_s2r_c[1], BM_NONBLOCK);
- prepare_listeners(&conf);
-
/* fork children */
- rde_pid = rde_main(&conf, peer_l, &net_l, rules_l, &mrt_l, &ribnames,
- pipe_m2r, pipe_s2r, pipe_m2s, pipe_s2r_c, debug);
- io_pid = session_main(&conf, peer_l, &net_l, rules_l, &mrt_l, &ribnames,
- pipe_m2s, pipe_s2r, pipe_m2r, pipe_s2r_c);
+ rde_pid = rde_main(pipe_m2r, pipe_s2r, pipe_m2s, pipe_s2r_c, debug);
+ io_pid = session_main(pipe_m2s, pipe_s2r, pipe_m2r, pipe_s2r_c);
setproctitle("parent");
@@ -254,33 +231,12 @@ 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 = kr_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE),
- conf.rtableid)) == -1)
+ if ((rfd = kr_init()) == -1)
quit = 1;
+ quit = reconfigure(conffile, &conf, &mrt_l, &peer_l);
if (pftable_clear_all() != 0)
quit = 1;
- while ((net = TAILQ_FIRST(&net_l)) != NULL) {
- TAILQ_REMOVE(&net_l, net, entry);
- filterset_free(&net->net.attrset);
- free(net);
- }
-
- while ((r = TAILQ_FIRST(rules_l)) != NULL) {
- TAILQ_REMOVE(rules_l, r, entry);
- free(r);
- }
- TAILQ_FOREACH(la, conf.listen_addrs, entry) {
- close(la->fd);
- la->fd = -1;
- }
- while ((rr = SIMPLEQ_FIRST(&ribnames))) {
- SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
- free(rr);
- }
-
- mrt_reconfigure(&mrt_l);
-
while (quit == 0) {
bzero(pfd, sizeof(pfd));
pfd[PFD_PIPE_SESSION].fd = ibuf_se->fd;
@@ -336,8 +292,7 @@ main(int argc, char *argv[])
reconfig = 0;
log_info("rereading config");
- switch (reconfigure(conffile, &conf, &mrt_l, &peer_l,
- rules_l)) {
+ switch (reconfigure(conffile, &conf, &mrt_l, &peer_l)) {
case -1: /* fatal error */
quit = 1;
break;
@@ -389,13 +344,13 @@ main(int argc, char *argv[])
LIST_REMOVE(m, entry);
free(m);
}
- while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) {
- TAILQ_REMOVE(conf.listen_addrs, la, entry);
- close(la->fd);
- free(la);
- }
+ if (conf.listen_addrs)
+ while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) {
+ TAILQ_REMOVE(conf.listen_addrs, la, entry);
+ close(la->fd);
+ free(la);
+ }
- free(rules_l);
control_cleanup(conf.csock);
control_cleanup(conf.rcsock);
carp_demote_shutdown();
@@ -413,6 +368,8 @@ main(int argc, char *argv[])
free(ibuf_se);
msgbuf_clear(&ibuf_rde->w);
free(ibuf_rde);
+ free(rcname);
+ free(cname);
log_info("Terminating");
return (0);
@@ -452,27 +409,25 @@ send_filterset(struct imsgbuf *i, struct filter_set_head *set)
int
reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
- struct peer **peer_l, struct filter_head *rules_l)
+ struct peer **peer_l)
{
struct network_head net_l;
- struct network *n;
+ struct rdomain_head rdom_l;
+ struct filter_head rules_l;
struct peer *p;
struct filter_rule *r;
struct listen_addr *la;
struct rde_rib *rr;
+ struct rdomain *rd;
- if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, rules_l)) {
+ if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, &rules_l,
+ &rdom_l)) {
log_warnx("config file %s has errors, not reloading",
conffile);
return (1);
}
cflags = conf->flags;
- connectset = &conf->connectset;
- staticset = &conf->staticset;
- connectset6 = &conf->connectset6;
- staticset6 = &conf->staticset6;
-
prepare_listeners(conf);
/* start reconfiguration */
@@ -483,12 +438,6 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
conf, sizeof(struct bgpd_config)) == -1)
return (-1);
- /* send peer list and listeners to the SE */
- for (p = *peer_l; p != NULL; p = p->next)
- if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1,
- &p->conf, sizeof(struct peer_config)) == -1)
- return (-1);
-
TAILQ_FOREACH(la, conf->listen_addrs, entry) {
if (imsg_compose(ibuf_se, IMSG_RECONF_LISTENER, 0, 0, la->fd,
la, sizeof(struct listen_addr)) == -1)
@@ -496,51 +445,104 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
la->fd = -1;
}
+ if (control_setup(conf) == -1)
+ return (-1);
+
+ /* adjust fib syncing on reload */
+ ktable_preload();
+
/* RIBs for the RDE */
while ((rr = SIMPLEQ_FIRST(&ribnames))) {
SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
+ if (ktable_update(rr->rtableid, rr->name, NULL,
+ rr->flags) == -1) {
+ log_warnx("failed to load rdomain %d",
+ rr->rtableid);
+ return (-1);
+ }
if (imsg_compose(ibuf_rde, IMSG_RECONF_RIB, 0, 0, -1,
rr, sizeof(struct rde_rib)) == -1)
return (-1);
free(rr);
}
- /* networks for the RDE */
- while ((n = TAILQ_FIRST(&net_l)) != NULL) {
- if (imsg_compose(ibuf_rde, IMSG_NETWORK_ADD, 0, 0, -1,
- &n->net, sizeof(struct network_config)) == -1)
- return (-1);
- if (send_filterset(ibuf_rde, &n->net.attrset) == -1)
+ /* send peer list and listeners to the SE and RDE */
+ for (p = *peer_l; p != NULL; p = p->next) {
+ if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1,
+ &p->conf, sizeof(struct peer_config)) == -1)
return (-1);
- if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1,
- NULL, 0) == -1)
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 0, -1,
+ &p->conf, sizeof(struct peer_config)) == -1)
return (-1);
- TAILQ_REMOVE(&net_l, n, entry);
- filterset_free(&n->net.attrset);
- free(n);
}
- /* redistribute list needs to be reloaded too */
- if (kr_reload() == -1)
+ /* networks go via kroute to the RDE */
+ if (kr_net_reload(0, &net_l))
return (-1);
/* filters for the RDE */
- while ((r = TAILQ_FIRST(rules_l)) != NULL) {
+ while ((r = TAILQ_FIRST(&rules_l)) != NULL) {
+ TAILQ_REMOVE(&rules_l, r, entry);
if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1,
r, sizeof(struct filter_rule)) == -1)
return (-1);
if (send_filterset(ibuf_rde, &r->set) == -1)
return (-1);
- TAILQ_REMOVE(rules_l, r, entry);
filterset_free(&r->set);
free(r);
}
+ while ((rd = SIMPLEQ_FIRST(&rdom_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&rdom_l, entry);
+ if (ktable_update(rd->rtableid, rd->descr, rd->ifmpe,
+ rd->flags) == -1) {
+ log_warnx("failed to load rdomain %d",
+ rd->rtableid);
+ return (-1);
+ }
+ /* networks go via kroute to the RDE */
+ if (kr_net_reload(rd->rtableid, &rd->net_l))
+ return (-1);
+
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN, 0, 0, -1,
+ rd, sizeof(*rd)) == -1)
+ return (-1);
+
+ /* export targets */
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_EXPORT, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+ if (send_filterset(ibuf_rde, &rd->export) == -1)
+ return (-1);
+ filterset_free(&rd->export);
+
+ /* import targets */
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_IMPORT, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+ if (send_filterset(ibuf_rde, &rd->import) == -1)
+ return (-1);
+ filterset_free(&rd->import);
+
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_DONE, 0, 0,
+ -1, NULL, 0) == -1)
+ return (-1);
+
+ free(rd);
+ }
+
/* signal both childs to replace their config */
if (imsg_compose(ibuf_se, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1 ||
imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1)
return (-1);
+ /* fix kroute information */
+ ktable_postload();
+
+ /* redistribute list needs to be reloaded too */
+ if (kr_reload() == -1)
+ return (-1);
+
/* mrt changes can be sent out of bound */
mrt_reconfigure(mrt_l);
return (0);
@@ -550,8 +552,8 @@ int
dispatch_imsg(struct imsgbuf *ibuf, int idx)
{
struct imsg imsg;
- int n;
- int rv;
+ ssize_t n;
+ int rv, verbose;
if ((n = imsg_read(ibuf)) == -1)
return (-1);
@@ -573,46 +575,39 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx)
case IMSG_KROUTE_CHANGE:
if (idx != PFD_PIPE_ROUTE)
log_warnx("route request not from RDE");
- else if (kr_change(imsg.data))
+ else if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct kroute_full))
+ log_warnx("wrong imsg len");
+ else if (kr_change(imsg.hdr.peerid, imsg.data))
rv = -1;
break;
case IMSG_KROUTE_DELETE:
if (idx != PFD_PIPE_ROUTE)
log_warnx("route request not from RDE");
- else if (kr_delete(imsg.data))
- rv = -1;
- break;
- case IMSG_KROUTE6_CHANGE:
- if (idx != PFD_PIPE_ROUTE)
- log_warnx("route request not from RDE");
- else if (kr6_change(imsg.data))
- rv = -1;
- break;
- case IMSG_KROUTE6_DELETE:
- if (idx != PFD_PIPE_ROUTE)
- log_warnx("route request not from RDE");
- else if (kr6_delete(imsg.data))
+ else if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct kroute_full))
+ log_warnx("wrong imsg len");
+ else if (kr_delete(imsg.hdr.peerid, imsg.data))
rv = -1;
break;
case IMSG_NEXTHOP_ADD:
if (idx != PFD_PIPE_ROUTE)
log_warnx("nexthop request not from RDE");
- else
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct bgpd_addr))
- log_warnx("wrong imsg len");
- else if (kr_nexthop_add(imsg.data) == -1)
- rv = -1;
+ else if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct bgpd_addr))
+ log_warnx("wrong imsg len");
+ else if (kr_nexthop_add(imsg.hdr.peerid, imsg.data) ==
+ -1)
+ rv = -1;
break;
case IMSG_NEXTHOP_REMOVE:
if (idx != PFD_PIPE_ROUTE)
log_warnx("nexthop request not from RDE");
+ else if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct bgpd_addr))
+ log_warnx("wrong imsg len");
else
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct bgpd_addr))
- log_warnx("wrong imsg len");
- else
- kr_nexthop_delete(imsg.data);
+ kr_nexthop_delete(imsg.hdr.peerid, imsg.data);
break;
case IMSG_PFTABLE_ADD:
if (idx != PFD_PIPE_ROUTE)
@@ -654,18 +649,19 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx)
if (idx != PFD_PIPE_SESSION)
log_warnx("couple request not from SE");
else
- kr_fib_couple();
+ kr_fib_couple(imsg.hdr.peerid);
break;
case IMSG_CTL_FIB_DECOUPLE:
if (idx != PFD_PIPE_SESSION)
log_warnx("decouple request not from SE");
else
- kr_fib_decouple();
+ kr_fib_decouple(imsg.hdr.peerid);
break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_SHOW_NEXTHOP:
case IMSG_CTL_SHOW_INTERFACE:
+ case IMSG_CTL_SHOW_FIB_TABLES:
if (idx != PFD_PIPE_SESSION)
log_warnx("kroute request not from SE");
else
@@ -692,6 +688,11 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx)
carp_demote_set(msg->demote_group, msg->level);
}
break;
+ case IMSG_CTL_LOG_VERBOSE:
+ /* already checked by SE */
+ memcpy(&verbose, imsg.data, sizeof(verbose));
+ log_verbose(verbose);
+ break;
default:
break;
}
@@ -707,7 +708,7 @@ send_nexthop_update(struct kroute_nexthop *msg)
{
char *gw = NULL;
- if (msg->gateway.af)
+ if (msg->gateway.aid)
if (asprintf(&gw, ": via %s",
log_addr(&msg->gateway)) == -1) {
log_warn("send_nexthop_update");
@@ -717,7 +718,7 @@ send_nexthop_update(struct kroute_nexthop *msg)
log_info("nexthop %s now %s%s%s", log_addr(&msg->nexthop),
msg->valid ? "valid" : "invalid",
msg->connected ? ": directly connected" : "",
- msg->gateway.af ? gw : "");
+ msg->gateway.aid ? gw : "");
free(gw);
@@ -733,56 +734,20 @@ send_imsg_session(int type, pid_t pid, void *data, u_int16_t datalen)
}
int
-bgpd_redistribute(int type, struct kroute *kr, struct kroute6 *kr6)
+send_network(int type, struct network_config *net, struct filter_set_head *h)
{
- struct network_config net;
- struct filter_set_head *h;
-
- if ((cflags & BGPD_FLAG_REDIST_CONNECTED) && kr &&
- (kr->flags & F_CONNECTED))
- h = connectset;
- else if ((cflags & BGPD_FLAG_REDIST_STATIC) && kr &&
- (kr->flags & F_STATIC))
- h = staticset;
- else if ((cflags & BGPD_FLAG_REDIST6_CONNECTED) && kr6 &&
- (kr6->flags & F_CONNECTED))
- h = connectset6;
- else if ((cflags & BGPD_FLAG_REDIST6_STATIC) && kr6 &&
- (kr6->flags & F_STATIC))
- h = staticset6;
- else
- return (0);
-
- bzero(&net, sizeof(net));
- if (kr && kr6)
- fatalx("bgpd_redistribute: unable to redistribute v4 and v6"
- "together");
- if (kr != NULL) {
- net.prefix.af = AF_INET;
- net.prefix.v4.s_addr = kr->prefix.s_addr;
- net.prefixlen = kr->prefixlen;
- }
- if (kr6 != NULL) {
- net.prefix.af = AF_INET6;
- memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
- net.prefixlen = kr6->prefixlen;
- }
-
-
- if (imsg_compose(ibuf_rde, type, 0, 0, -1, &net,
+ if (imsg_compose(ibuf_rde, type, 0, 0, -1, net,
sizeof(struct network_config)) == -1)
return (-1);
-
/* networks that get deleted don't need to send the filter set */
if (type == IMSG_NETWORK_REMOVE)
- return (1);
-
+ return (0);
if (send_filterset(ibuf_rde, h) == -1)
return (-1);
if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0) == -1)
return (-1);
- return (1);
+ return (0);
}
int
@@ -810,3 +775,45 @@ bgpd_filternexthop(struct kroute *kr, struct kroute6 *kr6)
return (1);
}
+
+int
+control_setup(struct bgpd_config *conf)
+{
+ int fd, restricted;
+
+ /* control socket is outside chroot */
+ if (!cname || strcmp(cname, conf->csock)) {
+ if (cname) {
+ control_cleanup(cname);
+ free(cname);
+ }
+ if ((cname = strdup(conf->csock)) == NULL)
+ fatal("strdup");
+ if ((fd = control_init(0, cname)) == -1)
+ fatalx("control socket setup failed");
+ restricted = 0;
+ if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd,
+ &restricted, sizeof(restricted)) == -1)
+ return (-1);
+ }
+ if (!conf->rcsock) {
+ /* remove restricted socket */
+ control_cleanup(rcname);
+ free(rcname);
+ rcname = NULL;
+ } else if (!rcname || strcmp(rcname, conf->rcsock)) {
+ if (rcname) {
+ control_cleanup(rcname);
+ free(rcname);
+ }
+ if ((rcname = strdup(conf->rcsock)) == NULL)
+ fatal("strdup");
+ if ((fd = control_init(1, rcname)) == -1)
+ fatalx("control socket setup failed");
+ restricted = 1;
+ if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd,
+ &restricted, sizeof(restricted)) == -1)
+ return (-1);
+ }
+ return (0);
+}
diff --git a/bgpd/bgpd.conf.5 b/bgpd/bgpd.conf.5
index 484e041..f9df578 100644
--- a/bgpd/bgpd.conf.5
+++ b/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.94 2009/06/07 00:31:22 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.104 2010/03/05 15:25:00 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 7 2009 $
+.Dd $Mdocdate: October 23 2010 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -26,7 +26,7 @@
The
.Xr bgpd 8
daemon implements the Border Gateway Protocol version 4 as described
-in RFC 1771.
+in RFC 4271.
.Sh SECTIONS
The
.Nm
@@ -38,6 +38,8 @@ configuration file.
.It Sy Global Configuration
Global settings for
.Xr bgpd 8 .
+.It Sy Routing Domain Configuration
+The definition and properties for BGP MPLS VPNs are set in this section.
.It Sy Neighbors and Groups
.Xr bgpd 8
establishes sessions with
@@ -93,7 +95,7 @@ Set the local
.Em autonomous system
number to
.Ar as-number .
-If the first AS number is a 4-byte AS it is possible to specifiy a secondary
+If the first AS number is a 4-byte AS it is possible to specify a secondary
2-byte AS number which is used for neighbors which do not support 4-byte AS
numbers.
The default for the secondary AS is 23456.
@@ -143,13 +145,13 @@ The default is 120 seconds.
.It Xo
.Ic dump
.Op Ic rib Ar name
-.Pq Ic table Ns \&| Ns Ic table-mp
+.Pq Ic table Ns | Ns Ic table-mp
.Ar file Op Ar timeout
.Xc
.It Xo
.Ic dump
-.Pq Ic all Ns \&| Ns Ic updates
-.Pq Ic in Ns \&| Ns Ic out
+.Pq Ic all Ns | Ns Ic updates
+.Pq Ic in Ns | Ns Ic out
.Ar file Op Ar timeout
.Xc
Dump the RIB, a.k.a. the
@@ -195,7 +197,7 @@ dump updates out "/tmp/updates-out-%H%M" 300
.Pp
.It Xo
.Ic fib-update
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic no ,
@@ -242,12 +244,12 @@ Log received and sent updates.
.Xc
.It Xo
.Ic network
-.Pq Ic inet Ns \&| Ns Ic inet6
+.Pq Ic inet Ns | Ns Ic inet6
.Ic static Op Ic set ...\&
.Xc
.It Xo
.Ic network
-.Pq Ic inet Ns \&| Ns Ic inet6
+.Pq Ic inet Ns | Ns Ic inet6
.Ic connected Op Ic set ...\&
.Xc
Announce the specified network as belonging to our AS.
@@ -278,7 +280,7 @@ section.
.Ic nexthop
.Ic qualify
.Ic via
-.Pq Ic bgp Ns \&| Ns Ic default
+.Pq Ic bgp Ns | Ns Ic default
.Xc
If set to
.Ic bgp ,
@@ -295,7 +297,7 @@ daemons like
.Ic rde
.Ic med
.Ic compare
-.Pq Ic always Ns \&| Ns Ic strict
+.Pq Ic always Ns | Ns Ic strict
.Xc
If set to
.Ic always ,
@@ -313,20 +315,31 @@ is only compared between peers belonging to the same AS.
.Ic rib Ar name
.Op Ic no Ic evaluate
.Xc
-Creat an additional RIB named
+.It Xo
+.Ic rde
+.Ic rib Ar name
+.Op Ic rtable Ar number
+.Xc
+Create an additional RIB named
.Ar name .
It is possible to disable the decision process per RIB with the
.Ic no Ic evaluate
flag.
+If a
+.Ic rtable
+is specified, routes will be exported to the given kernel routing table.
+Currently the routing table must belong to the default routing domain and
+nexthop verification happens on table 0.
+Routes in the specified table will not be considered for nexthop verification.
.Ic Adj-RIB-In
and
.Ic Loc-RIB
-are created automaticaly and used as default.
+are created automatically and used as default.
.Pp
.It Xo
.Ic rde
.Ic route-age
-.Pq Ic ignore Ns \&| Ns Ic evaluate
+.Pq Ic ignore Ns | Ns Ic evaluate
.Xc
If set to
.Ic evaluate ,
@@ -339,7 +352,7 @@ The default is
.Pp
.It Xo
.Ic route-collector
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic yes ,
@@ -361,13 +374,24 @@ to the local machine.
Work with the given kernel routing table
instead of the default table,
.Ar 0 .
-Note that this table is used for nexthop verification as well.
-Directly connected networks are always taken into account, even though
-their routes live in table 0.
+Note that table 0 is used for nexthop verification.
+Routes in the specified table will not be considered for nexthop verification.
+This is the same as using the following syntax:
+.Bd -literal -offset indent
+rde rib Loc-RIB rtable number
+.Ed
+.Pp
+.It Ic socket Qo Ar path Qc Op Ic restricted
+Set the control socket location to
+.Ar path .
+If
+.Ic restricted
+is specified a restricted control socket will be created.
+By default /var/run/bgpd.sock is used and no restricted socket is created.
.Pp
.It Xo
.Ic transparent-as
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic yes ,
@@ -376,6 +400,111 @@ to EBGP neighbors are not prepended with their own AS.
The default is
.Ic no .
.El
+.Sh ROUTING DOMAIN CONFIGURATION
+.Xr bgpd 8
+supports the setup and distribution of Virtual Private Networks.
+It is possible to import and export prefixes between routing domains.
+Each routing domain is specified by an
+.Ic rdomain
+section, which allows properties to be set specifically for that rdomain:
+.Bd -literal -offset indent
+rdomain 1 {
+ descr "a rdomain"
+ rd 65002:1
+ import-target rt 65002:42
+ export-target rt 65002:42
+ network 192.168.1/24
+ depend on mpe0
+}
+.Ed
+.Pp
+There are several routing domain properties:
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic depend on Ar interface
+Routes added to the rdomain will use this interface as the outgoing interface.
+Normally this will be an MPLS Provider Edge,
+.Xr mpe 4 ,
+interface that is part of the rdomain.
+Local networks will be announced with the MPLS label specified on the interface.
+.Pp
+.It Ic descr Ar description
+Add a description.
+The description is used when logging but has no further meaning to
+.Xr bgpd 8 .
+.Pp
+.It Ic export-target Ar subtype Ar as-number Ns Li : Ns Ar local
+.It Ic export-target Ar subtype Ar IP Ns Li : Ns Ar local
+Specify an extended community which will be attached to announced networks.
+More than one
+.Ic export-target
+can be specified.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding.
+The
+.Ar subtype
+should be set to
+.Ar rt
+for best compatibility with other implementations.
+.Pp
+.It Xo
+.Ic fib-update
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic no ,
+do not update the Forwarding Information Base, a.k.a. the kernel
+routing table.
+The default is
+.Ic yes .
+.Pp
+.It Ic import-target Ar subtype Ar as-number Ns Li : Ns Ar local
+.It Ic import-target Ar subtype Ar IP Ns Li : Ns Ar local
+Only prefixes matching one of the specified
+.Ic import-targets
+will be imported into the rdomain.
+More than one
+.Ic import-target
+can be specified.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding of extended communities.
+The
+.Ar subtype
+should be set to
+.Ar rt
+for best compatibility with other implementations.
+.Pp
+.It Ic network Ar arguments ...
+Define which networks should be exported into this VPN.
+See also the
+.Ic nexthop
+section in
+.Sx GLOBAL CONFIGURATION
+for further information about the arguments.
+.Pp
+.It Ic rd Ar as-number Ns Li : Ns Ar local
+.It Ic rd Ar IP Ns Li : Ns Ar local
+The Route Distinguishers uniquely identifies a set of VPN prefixes.
+Only prefixes matching the
+.Ic rd
+will be imported into the routing domain.
+The purpose of the
+.Ic rd
+is solely to allow one to create distinct routes to a common address prefix.
+The
+.Ar as-number
+or
+.Ar IP
+of a
+.Ic rd
+should be set to a number or IP that was assigned by an appropriate authority.
+Whereas
+.Ar local
+can be chosen by the local operator.
+.Pp
+.El
.Sh NEIGHBORS AND GROUPS
.Xr bgpd 8
establishes TCP connections to other BGP speakers called
@@ -470,21 +599,35 @@ The default for IBGP peers is
.Pp
.It Xo
.Ic announce
-.Pq Ic IPv4 Ns \&| Ns Ic IPv6
-.Pq Ic none Ns \&| Ns Ic unicast
+.Pq Ic IPv4 Ns | Ns Ic IPv6
+.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn
.Xc
For the given address family, control which subsequent address families
(at the moment, only
.Em none ,
-which disables the announcement of that address family, and
-.Em unicast
-are supported) are announced during the capabilities negotiation.
+which disables the announcement of that address family,
+.Em unicast ,
+and
+.Em vpn ,
+which allows the distribution of BGP MPLS VPNs, are supported) are announced
+during the capabilities negotiation.
Only routes for that address family and subsequent address family will be
announced and processed.
.Pp
.It Xo
+.Ic announce as-4byte
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic no ,
+the 4-byte AS capability is not announced and so native 4-byte AS support is
+disabled.
+The default is
+.Ic yes .
+.Pp
+.It Xo
.Ic announce capabilities
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic no ,
@@ -493,6 +636,29 @@ This can be helpful to connect to old or broken BGP implementations.
The default is
.Ic yes .
.Pp
+.It Xo
+.Ic announce refresh
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic no ,
+the route refresh capability is not announced.
+The default is
+.Ic yes .
+.Pp
+.It Xo
+.Ic announce restart
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic yes ,
+the graceful restart capability is announced.
+Currently only the End-of-RIB marker is supported and announced by the
+.Ic restart
+capability.
+The default is
+.Ic no .
+.Pp
.It Ic demote Ar group
Increase the
.Xr carp 4
@@ -504,7 +670,7 @@ The demotion counter will be increased as soon as
.Xr bgpd 8
starts and decreased
60 seconds after the session went to state
-.Em ESTABLISHED.
+.Em ESTABLISHED .
For neighbors added at runtime, the demotion counter is only increased after
the session has been
.Em ESTABLISHED
@@ -548,8 +714,8 @@ Do not start the session when bgpd comes up but stay in
.Pp
.It Xo
.Ic dump
-.Pq Ic all Ns \&| Ns Ic updates
-.Pq Ic in Ns \&| Ns Ic out
+.Pq Ic all Ns | Ns Ic updates
+.Pq Ic in Ns | Ns Ic out
.Ar file Op Ar timeout
.Xc
Do a peer specific MRT dump.
@@ -564,7 +730,7 @@ section in
.Pp
.It Xo
.Ic enforce neighbor-as
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic yes ,
@@ -589,10 +755,16 @@ Inherited from the global configuration if not given.
Set the minimal acceptable holdtime.
Inherited from the global configuration if not given.
.Pp
+.It Ic interface Ar interface
+Set an interface used for a nexthop with a link-local IPv6 address.
+Note that if this is not specified and a link-local IPv6 address is
+received as nexthop of the peer, it will be marked as invalid and
+ignored.
+.Pp
.It Xo
.Ic ipsec
-.Pq Ic ah Ns \&| Ns Ic esp
-.Pq Ic in Ns \&| Ns Ic out
+.Pq Ic ah Ns | Ns Ic esp
+.Pq Ic in Ns | Ns Ic out
.Ic spi Ar spi-number authspec Op Ar encspec
.Xc
Enable IPsec with static keying.
@@ -627,7 +799,7 @@ Keys must be given in hexadecimal format.
.Pp
.It Xo
.Ic ipsec
-.Pq Ic ah Ns \&| Ns Ic esp
+.Pq Ic ah Ns | Ns Ic esp
.Ic ike
.Xc
Enable IPsec with dynamic keying.
@@ -639,11 +811,11 @@ is responsible for managing the session keys.
With
.Xr isakmpd 8 ,
it is sufficient to copy the peer's public key, found in
-.Pa /etc/isakmpd/local.pub ,
+.Pa %%PREFIX%%/etc/isakmpd/private/local.pub ,
to the local machine.
It must be stored in a file
named after the peer's IP address and must be stored in
-.Pa /etc/isakmpd/pubkeys/ipv4/ .
+.Pa %%PREFIX%%/etc/isakmpd/pubkeys/ipv4/ .
The local public key must be copied to the peer in the same way.
As
.Xr bgpd 8
@@ -698,7 +870,7 @@ Do not attempt to actively open a TCP connection to the neighbor system.
.It Ic remote-as Ar as-number
Set the AS number of the remote system.
.Pp
-.It rib .Ar name
+.It Ic rib Ar name
Bind the neighbor to the specified RIB.
.Pp
.It Ic route-reflector Op Ar address
@@ -732,8 +904,8 @@ These sets are rewritten into filter rules and can be viewed with
.Pp
.It Xo
.Ic softreconfig
-.Pq Ic in Ns \&| Ns Ic out
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic in Ns | Ns Ic out
+.Pq Ic yes Ns | Ns Ic no
.Xc
Turn soft reconfiguration on or off for the specified direction.
If soft reconfiguration is turned on, filter changes will be applied on
@@ -760,7 +932,7 @@ tcp md5sig key deadbeef
.Pp
.It Xo
.Ic transparent-as
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
If set to
.Ic yes ,
@@ -772,7 +944,7 @@ setting.
.Pp
.It Xo
.Ic ttl-security
-.Pq Ic yes Ns \&| Ns Ic no
+.Pq Ic yes Ns | Ns Ic no
.Xc
Enable or disable ttl-security.
When enabled,
@@ -849,6 +1021,10 @@ is matched against a part of the
.Em AS path
specified by the
.Ar as-type .
+.Ar as-number
+may be set to
+.Ic neighbor-as ,
+which is expanded to the current neighbor remote AS number.
.Ar as-type
is one of the following operators:
.Pp
@@ -917,7 +1093,32 @@ may be set to
which is expanded to the current neighbor remote AS number.
.Pp
.It Xo
-.Pq Ic from Ns \&| Ns Ic to
+.Ic ext-community
+.Ar subtype Ar as-number Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community
+.Ar subtype Ar IP Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community
+.Ar subtype Ar numvalue
+.Xc
+This rule applies only to
+.Em UPDATES
+where the
+.Em extended community
+path attribute is present and matches.
+Extended Communities are specified by a
+.Ar subtype
+and normally two values, a globally unique part (e.g. the AS number) and a
+local part.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding.
+.Pp
+.It Xo
+.Pq Ic from Ns | Ns Ic to
.Ar peer
.Xc
This rule applies only to
@@ -945,7 +1146,7 @@ if enclosed in curly brackets:
deny from { 128.251.16.1, 251.128.16.2, group hojo }
.Ed
.Pp
-.It Pq Ic inet Ns \&| Ns Ic inet6
+.It Pq Ic inet Ns | Ns Ic inet6
This rule applies only to routes matching the stated address family.
The address family needs to be set only in rules that use
.Ic prefixlen
@@ -953,6 +1154,24 @@ without specifying a
.Ic prefix
beforehand.
.Pp
+.It Ic max-as-len Ar len
+This rule applies only to
+.Em UPDATES
+where the
+.Em AS path
+has more than
+.Ar len
+elements.
+.Pp
+.It Ic max-as-seq Ar len
+This rule applies only to
+.Em UPDATES
+where a single
+.Em AS number
+is repeated more than
+.Ar len
+times.
+.Pp
.It Xo
.Ic prefix
.Ar address Ns Li / Ns Ar len
@@ -1028,6 +1247,12 @@ matches a rule which has the
option set, this rule is considered the last matching rule, and evaluation
of subsequent rules is skipped.
.Pp
+.It Ic rib Ar name
+Apply rule only to the specified RIB.
+This only applies for received updates, so not for rules using the
+.Ar to peer
+parameter.
+.Pp
.It Ic set Ar attribute ...
All matching rules can set the
.Em AS path attributes
@@ -1079,6 +1304,48 @@ Alternately, well-known communities may be specified by name:
or
.Ic NO_PEER .
.Pp
+.It Xo
+.Ic ext-community Op Ar delete
+.Ar subtype Ar as-number Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community Op Ar delete
+.Ar subtype Ar IP Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community Op Ar delete
+.Ar subtype Ar numvalue
+.Xc
+Set or delete the
+.Em Extended Community
+AS path attribute.
+Extended Communities are specified by a
+.Ar subtype
+and normally two values, a globally unique part (e.g. the AS number) and a
+local part.
+The type is selected depending on the encoding of the global part.
+Two-octet AS Specific Extended Communities and Four-octet AS Specific Extended
+Communities are encoded as
+.Ar as-number Ns Li : Ns Ar local .
+Four-octet encoding is used if the
+.Ar as-number
+is bigger then 65535 or if the AS_DOT encoding is used.
+IPv4 Address Specific Extended Communities are encoded as
+.Ar IP Ns Li : Ns Ar local .
+Opaque Extended Communities are encoded with a single numeric value.
+Currently the following subtypes are supported:
+.Bd -literal -offset indent
+rt Route Target
+soo Source of Origin
+odi OSPF Domain Identifier
+ort OSPF Route Type
+ori OSPF Router ID
+bdc BGP Data Collection
+.Ed
+.Pp
+Not all type and subtype value pairs are allowed by IANA and the parser
+will ensure that no invalid combination is created.
+.Pp
.It Ic localpref Ar number
Set the
.Em LOCAL_PREF
@@ -1108,6 +1375,20 @@ otherwise it will be set to
.Ar number .
.Pp
.It Xo
+.Ic origin
+.Sm off
+.Po Ic igp \*(Ba
+.Ic egp \*(Ba
+.Ic incomplete Pc
+.Sm on
+.Xc
+Set the
+.Em ORIGIN
+AS path attribute to mark the source of this
+route as being injected from an igp protocol, an egp protocol
+or being an aggregated route.
+.Pp
+.It Xo
.Ic nexthop
.Sm off
.Po Ar address \*(Ba
@@ -1157,9 +1438,8 @@ times to the
.Em AS path .
.Pp
.It Ic rtlabel Ar label
-Add the prefix with the specified
-.Ar label
-to the kernel routing table.
+Add the prefix to the kernel routing table with the specified
+.Ar label .
.Pp
.It Ic weight Ar number
The
@@ -1181,8 +1461,8 @@ For prefixes with equally long paths, the prefix with the larger weight
is selected.
.El
.Sh FILES
-.Bl -tag -width "/etc/bgpd.conf" -compact
-.It Pa /etc/bgpd.conf
+.Bl -tag -width "%%PREFIX%%/etc/bgpd.conf" -compact
+.It Pa %%PREFIX%%/etc/bgpd.conf
.Xr bgpd 8
configuration file
.El
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a8dbaa4..c0a3841 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.241 2009/06/12 16:42:53 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.255 2010/04/06 13:25:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
+#include <sys/tree.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -30,11 +31,16 @@
#include <poll.h>
#include <stdarg.h>
-#include <imsg.h>
+#if defined(__FreeBSD__) /* compat */
+#include "openbsd-compat.h"
+#endif /* defined(__FreeBSD__) */
+#include "imsg.h"
#define BGP_VERSION 4
#define BGP_PORT 179
+#ifndef CONFFILE
#define CONFFILE "/etc/bgpd.conf"
+#endif /* !CONFFILE */
#define BGPD_USER "_bgpd"
#define PEER_DESCR_LEN 32
#define PFTABLE_LEN 16
@@ -42,8 +48,6 @@
#define IPSEC_ENC_KEY_LEN 32
#define IPSEC_AUTH_KEY_LEN 20
-#define ASNUM_MAX 0xffffffff
-
#define MAX_PKTSIZE 4096
#define MIN_HOLDTIME 3
#define READ_BUF_SIZE 65535
@@ -55,13 +59,8 @@
#define BGPD_OPT_NOACTION 0x0004
#define BGPD_OPT_FORCE_DEMOTE 0x0008
-#define BGPD_FLAG_NO_FIB_UPDATE 0x0001
#define BGPD_FLAG_NO_EVALUATE 0x0002
#define BGPD_FLAG_REFLECTOR 0x0004
-#define BGPD_FLAG_REDIST_STATIC 0x0008
-#define BGPD_FLAG_REDIST_CONNECTED 0x0010
-#define BGPD_FLAG_REDIST6_STATIC 0x0020
-#define BGPD_FLAG_REDIST6_CONNECTED 0x0040
#define BGPD_FLAG_NEXTHOP_BGP 0x0080
#define BGPD_FLAG_NEXTHOP_DEFAULT 0x1000
#define BGPD_FLAG_DECISION_MASK 0x0f00
@@ -83,6 +82,8 @@
#define F_REJECT 0x0080
#define F_BLACKHOLE 0x0100
#define F_LONGER 0x0200
+#define F_MPLS 0x0400
+#define F_REDISTRIBUTED 0x0800
#define F_CTL_DETAIL 0x1000 /* only used by bgpctl */
#define F_CTL_ADJ_IN 0x2000
#define F_CTL_ADJ_OUT 0x4000
@@ -109,18 +110,74 @@ enum reconf_action {
RECONF_DELETE
};
+/* Address Family Numbers as per RFC 1700 */
+#define AFI_UNSPEC 0
+#define AFI_IPv4 1
+#define AFI_IPv6 2
+
+/* Subsequent Address Family Identifier as per RFC 4760 */
+#define SAFI_NONE 0
+#define SAFI_UNICAST 1
+#define SAFI_MULTICAST 2
+#define SAFI_MPLS 4
+#define SAFI_MPLSVPN 128
+
+struct aid {
+ u_int16_t afi;
+ sa_family_t af;
+ u_int8_t safi;
+ char *name;
+};
+
+extern const struct aid aid_vals[];
+
+#define AID_UNSPEC 0
+#define AID_INET 1
+#define AID_INET6 2
+#define AID_VPN_IPv4 3
+#define AID_MAX 4
+
+#define AID_VALS { \
+ /* afi, af, safii, name */ \
+ { AFI_UNSPEC, AF_UNSPEC, SAFI_NONE, "unspec"}, \
+ { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" }, \
+ { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" }, \
+ { AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" } \
+}
+
+#define AID_PTSIZE { \
+ 0, \
+ sizeof(struct pt_entry4), \
+ sizeof(struct pt_entry6), \
+ sizeof(struct pt_entry_vpn4) \
+}
+
+struct vpn4_addr {
+ u_int64_t rd;
+ struct in_addr addr;
+ u_int8_t labelstack[21]; /* max that makes sense */
+ u_int8_t labellen;
+ u_int8_t pad1;
+ u_int8_t pad2;
+};
+
+#define BGP_MPLS_BOS 0x01
+
struct bgpd_addr {
- sa_family_t af;
union {
struct in_addr v4;
struct in6_addr v6;
- u_int8_t addr8[16];
- u_int16_t addr16[8];
- u_int32_t addr32[4];
+ struct vpn4_addr vpn4;
+ /* maximum size for a prefix is 256 bits */
+ u_int8_t addr8[32];
+ u_int16_t addr16[16];
+ u_int32_t addr32[8];
} ba; /* 128-bit address */
u_int32_t scope_id; /* iface scope id for v6 */
+ u_int8_t aid;
#define v4 ba.v4
#define v6 ba.v6
+#define vpn4 ba.vpn4
#define addr8 ba.addr8
#define addr16 ba.addr16
#define addr32 ba.addr32
@@ -141,17 +198,12 @@ TAILQ_HEAD(listen_addrs, listen_addr);
TAILQ_HEAD(filter_set_head, filter_set);
struct bgpd_config {
- struct filter_set_head connectset;
- struct filter_set_head connectset6;
- struct filter_set_head staticset;
- struct filter_set_head staticset6;
struct listen_addrs *listen_addrs;
char *csock;
char *rcsock;
int opts;
int flags;
int log;
- u_int rtableid;
u_int32_t bgpid;
u_int32_t clusterid;
u_int32_t as;
@@ -205,11 +257,10 @@ struct peer_auth {
};
struct capabilities {
- u_int8_t mp_v4; /* multiprotocol extensions, RFC 4760 */
- u_int8_t mp_v6;
- u_int8_t refresh; /* route refresh, RFC 2918 */
- u_int8_t restart; /* graceful restart, RFC 4724 */
- u_int8_t as4byte; /* draft-ietf-idr-as4bytes-13 */
+ int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */
+ int8_t refresh; /* route refresh, RFC 2918 */
+ int8_t restart; /* graceful restart, RFC 4724 */
+ int8_t as4byte; /* draft-ietf-idr-as4bytes-13 */
};
struct peer_config {
@@ -248,21 +299,31 @@ struct peer_config {
u_int8_t ttlsec; /* TTL security hack */
u_int8_t flags;
u_int8_t pad[3];
+ char lliface[IFNAMSIZ];
};
#define PEERFLAG_TRANS_AS 0x01
+enum network_type {
+ NETWORK_DEFAULT,
+ NETWORK_STATIC,
+ NETWORK_CONNECTED
+};
+
struct network_config {
struct bgpd_addr prefix;
struct filter_set_head attrset;
+ u_int rtableid;
+ enum network_type type;
u_int8_t prefixlen;
+ u_int8_t old; /* used for reloading */
};
TAILQ_HEAD(network_head, network);
struct network {
- struct network_config net;
- TAILQ_ENTRY(network) entry;
+ struct network_config net;
+ TAILQ_ENTRY(network) entry;
};
enum imsg_type {
@@ -276,7 +337,6 @@ enum imsg_type {
IMSG_CTL_NEIGHBOR_CLEAR,
IMSG_CTL_NEIGHBOR_RREFRESH,
IMSG_CTL_KROUTE,
- IMSG_CTL_KROUTE6,
IMSG_CTL_KROUTE_ADDR,
IMSG_CTL_RESULT,
IMSG_CTL_SHOW_NEIGHBOR,
@@ -288,10 +348,11 @@ enum imsg_type {
IMSG_CTL_SHOW_RIB_ATTR,
IMSG_CTL_SHOW_RIB_COMMUNITY,
IMSG_CTL_SHOW_NETWORK,
- IMSG_CTL_SHOW_NETWORK6,
IMSG_CTL_SHOW_RIB_MEM,
IMSG_CTL_SHOW_TERSE,
IMSG_CTL_SHOW_TIMER,
+ IMSG_CTL_LOG_VERBOSE,
+ IMSG_CTL_SHOW_FIB_TABLES,
IMSG_NETWORK_ADD,
IMSG_NETWORK_REMOVE,
IMSG_NETWORK_FLUSH,
@@ -302,6 +363,11 @@ enum imsg_type {
IMSG_RECONF_PEER,
IMSG_RECONF_FILTER,
IMSG_RECONF_LISTENER,
+ IMSG_RECONF_CTRL,
+ IMSG_RECONF_RDOMAIN,
+ IMSG_RECONF_RDOMAIN_EXPORT,
+ IMSG_RECONF_RDOMAIN_IMPORT,
+ IMSG_RECONF_RDOMAIN_DONE,
IMSG_RECONF_DONE,
IMSG_UPDATE,
IMSG_UPDATE_ERR,
@@ -313,8 +379,6 @@ enum imsg_type {
IMSG_MRT_CLOSE,
IMSG_KROUTE_CHANGE,
IMSG_KROUTE_DELETE,
- IMSG_KROUTE6_CHANGE,
- IMSG_KROUTE6_DELETE,
IMSG_NEXTHOP_ADD,
IMSG_NEXTHOP_REMOVE,
IMSG_NEXTHOP_UPDATE,
@@ -379,9 +443,43 @@ enum suberr_cease {
ERR_CEASE_RSRC_EXHAUST
};
+struct kroute_node;
+struct kroute6_node;
+struct knexthop_node;
+RB_HEAD(kroute_tree, kroute_node);
+RB_HEAD(kroute6_tree, kroute6_node);
+RB_HEAD(knexthop_tree, knexthop_node);
+
+struct ktable {
+ char descr[PEER_DESCR_LEN];
+ char ifmpe[IFNAMSIZ];
+ struct kroute_tree krt;
+ struct kroute6_tree krt6;
+ struct knexthop_tree knt;
+ struct network_head krn;
+ u_int rtableid;
+ u_int nhtableid; /* rdomain id for nexthop lookup */
+ u_int ifindex; /* ifindex of ifmpe */
+ int nhrefcnt; /* refcnt for nexthop table */
+ enum reconf_action state;
+ u_int8_t fib_conf; /* configured FIB sync flag */
+ u_int8_t fib_sync; /* is FIB synced with kernel? */
+};
+
+struct kroute_full {
+ struct bgpd_addr prefix;
+ struct bgpd_addr nexthop;
+ char label[RTLABEL_LEN];
+ u_int16_t flags;
+ u_short ifindex;
+ u_int8_t prefixlen;
+ u_int8_t priority;
+};
+
struct kroute {
struct in_addr prefix;
struct in_addr nexthop;
+ u_int32_t mplslabel;
u_int16_t flags;
u_int16_t labelid;
u_short ifindex;
@@ -400,14 +498,12 @@ struct kroute6 {
};
struct kroute_nexthop {
- union {
- struct kroute kr4;
- struct kroute6 kr6;
- } kr;
struct bgpd_addr nexthop;
struct bgpd_addr gateway;
+ struct bgpd_addr net;
u_int8_t valid;
u_int8_t connected;
+ u_int8_t netlen;
};
struct kif {
@@ -423,8 +519,7 @@ struct kif {
struct session_up {
struct bgpd_addr local_addr;
struct bgpd_addr remote_addr;
- struct capabilities capa_announced;
- struct capabilities capa_received;
+ struct capabilities capa;
u_int32_t remote_bgpid;
u_int16_t short_as;
};
@@ -437,8 +532,13 @@ struct pftable_msg {
struct ctl_show_nexthop {
struct bgpd_addr addr;
- u_int8_t valid;
struct kif kif;
+ union {
+ struct kroute kr4;
+ struct kroute6 kr6;
+ } kr;
+ u_int8_t valid;
+ u_int8_t krvalid;
};
struct ctl_neighbor {
@@ -447,20 +547,10 @@ struct ctl_neighbor {
int show_timers;
};
-struct kroute_label {
- struct kroute kr;
- char label[RTLABEL_LEN];
-};
-
-struct kroute6_label {
- struct kroute6 kr;
- char label[RTLABEL_LEN];
-};
-
-#define F_RIB_ELIGIBLE 0x01
-#define F_RIB_ACTIVE 0x02
-#define F_RIB_INTERNAL 0x04
-#define F_RIB_ANNOUNCE 0x08
+#define F_PREF_ELIGIBLE 0x01
+#define F_PREF_ACTIVE 0x02
+#define F_PREF_INTERNAL 0x04
+#define F_PREF_ANNOUNCE 0x08
struct ctl_show_rib {
struct bgpd_addr true_nexthop;
@@ -498,16 +588,52 @@ enum as_spec {
AS_EMPTY
};
+enum aslen_spec {
+ ASLEN_NONE,
+ ASLEN_MAX,
+ ASLEN_SEQ
+};
+
struct filter_as {
- enum as_spec type;
u_int32_t as;
+ u_int16_t flags;
+ enum as_spec type;
+};
+
+struct filter_aslen {
+ u_int aslen;
+ enum aslen_spec type;
};
+#define AS_FLAG_NEIGHBORAS 0x01
+
struct filter_community {
- int as;
- int type;
+ int as;
+ int type;
+};
+
+struct filter_extcommunity {
+ u_int16_t flags;
+ u_int8_t type;
+ u_int8_t subtype; /* if extended type */
+ union {
+ struct ext_as {
+ u_int16_t as;
+ u_int32_t val;
+ } ext_as;
+ struct ext_as4 {
+ u_int32_t as4;
+ u_int16_t val;
+ } ext_as4;
+ struct ext_ip {
+ struct in_addr addr;
+ u_int16_t val;
+ } ext_ip;
+ u_int64_t ext_opaq; /* only 48 bits */
+ } data;
};
+
struct ctl_show_rib_request {
char rib[PEER_DESCR_LEN];
struct ctl_neighbor neighbor;
@@ -518,8 +644,8 @@ struct ctl_show_rib_request {
pid_t pid;
u_int16_t flags;
enum imsg_type type;
- sa_family_t af;
u_int8_t prefixlen;
+ u_int8_t aid;
};
enum filter_actions {
@@ -585,6 +711,28 @@ struct filter_peers {
#define EXT_COMMUNITY_OSPF_RTR_TYPE 6 /* RFC 4577 */
#define EXT_COMMUNITY_OSPF_RTR_ID 7 /* RFC 4577 */
#define EXT_COMMUNITY_BGP_COLLECT 8 /* RFC 4384 */
+/* other handy defines */
+#define EXT_COMMUNITY_OPAQUE_MAX 0xffffffffffffULL
+#define EXT_COMMUNITY_FLAG_VALID 0x01
+
+struct ext_comm_pairs {
+ u_int8_t type;
+ u_int8_t subtype;
+ u_int8_t transitive; /* transitive bit needs to be set */
+};
+
+#define IANA_EXT_COMMUNITIES { \
+ { EXT_COMMUNITY_TWO_AS, EXT_COMMUNITY_ROUTE_TGT, 0 }, \
+ { EXT_COMMUNITY_TWO_AS, EXT_CUMMUNITY_ROUTE_ORIG, 0 }, \
+ { EXT_COMMUNITY_TWO_AS, EXT_COMMUNITY_OSPF_DOM_ID, 0 }, \
+ { EXT_COMMUNITY_TWO_AS, EXT_COMMUNITY_BGP_COLLECT, 0 }, \
+ { EXT_COMMUNITY_FOUR_AS, EXT_COMMUNITY_ROUTE_TGT, 0 }, \
+ { EXT_COMMUNITY_FOUR_AS, EXT_CUMMUNITY_ROUTE_ORIG, 0 }, \
+ { EXT_COMMUNITY_IPV4, EXT_COMMUNITY_ROUTE_TGT, 0 }, \
+ { EXT_COMMUNITY_IPV4, EXT_CUMMUNITY_ROUTE_ORIG, 0 }, \
+ { EXT_COMMUNITY_IPV4, EXT_COMMUNITY_OSPF_RTR_ID, 0 }, \
+ { EXT_COMMUNITY_OPAQUE, EXT_COMMUNITY_OSPF_RTR_TYPE, 0 } \
+}
struct filter_prefix {
@@ -594,16 +742,18 @@ struct filter_prefix {
struct filter_prefixlen {
enum comp_ops op;
- sa_family_t af;
+ u_int8_t aid;
u_int8_t len_min;
u_int8_t len_max;
};
struct filter_match {
- struct filter_prefix prefix;
- struct filter_prefixlen prefixlen;
- struct filter_as as;
- struct filter_community community;
+ struct filter_prefix prefix;
+ struct filter_prefixlen prefixlen;
+ struct filter_as as;
+ struct filter_aslen aslen;
+ struct filter_community community;
+ struct filter_extcommunity ext_community;
};
TAILQ_HEAD(filter_head, filter_rule);
@@ -635,10 +785,13 @@ enum action_types {
ACTION_SET_NEXTHOP_SELF,
ACTION_SET_COMMUNITY,
ACTION_DEL_COMMUNITY,
+ ACTION_SET_EXT_COMMUNITY,
+ ACTION_DEL_EXT_COMMUNITY,
ACTION_PFTABLE,
ACTION_PFTABLE_ID,
ACTION_RTLABEL,
- ACTION_RTLABEL_ID
+ ACTION_RTLABEL_ID,
+ ACTION_SET_ORIGIN
};
struct filter_set {
@@ -650,23 +803,53 @@ struct filter_set {
int32_t relative;
struct bgpd_addr nexthop;
struct filter_community community;
+ struct filter_extcommunity ext_community;
char pftable[PFTABLE_LEN];
char rtlabel[RTLABEL_LEN];
+ u_int8_t origin;
} action;
enum action_types type;
};
-struct rrefresh {
- u_int16_t afi;
- u_int8_t safi;
+struct rdomain {
+ SIMPLEQ_ENTRY(rdomain) entry;
+ char descr[PEER_DESCR_LEN];
+ char ifmpe[IFNAMSIZ];
+ struct filter_set_head import;
+ struct filter_set_head export;
+ struct network_head net_l;
+ u_int64_t rd;
+ u_int rtableid;
+ u_int label;
+ int flags;
};
+SIMPLEQ_HEAD(rdomain_head, rdomain);
+
+struct rde_rib {
+ SIMPLEQ_ENTRY(rde_rib) entry;
+ char name[PEER_DESCR_LEN];
+ u_int rtableid;
+ u_int16_t id;
+ u_int16_t flags;
+};
+SIMPLEQ_HEAD(rib_names, rde_rib);
+extern struct rib_names ribnames;
+
+/* rde_rib flags */
+#define F_RIB_ENTRYLOCK 0x0001
+#define F_RIB_NOEVALUATE 0x0002
+#define F_RIB_NOFIB 0x0004
+#define F_RIB_NOFIBSYNC 0x0008
+#define F_RIB_HASNOFIB (F_RIB_NOFIB | F_RIB_NOEVALUATE)
+
+/* 4-byte magic AS number */
+#define AS_TRANS 23456
struct rde_memstats {
int64_t path_cnt;
int64_t prefix_cnt;
int64_t rib_cnt;
- int64_t pt4_cnt;
- int64_t pt6_cnt;
+ int64_t pt_cnt[AID_MAX];
int64_t nexthop_cnt;
int64_t aspath_cnt;
int64_t aspath_size;
@@ -677,38 +860,29 @@ struct rde_memstats {
int64_t attr_dcnt;
};
-struct rde_rib {
- SIMPLEQ_ENTRY(rde_rib) entry;
- char name[PEER_DESCR_LEN];
- u_int16_t id;
- u_int16_t flags;
-};
-SIMPLEQ_HEAD(rib_names, rde_rib);
-extern struct rib_names ribnames;
-
-/* Address Family Numbers as per RFC 1700 */
-#define AFI_IPv4 1
-#define AFI_IPv6 2
-#define AFI_ALL 0xffff
+/* macros for IPv6 link-local address */
+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER)
+#define IN6_LINKLOCAL_IFINDEX(addr) \
+ ((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
-/* Subsequent Address Family Identifier as per RFC 4760 */
-#define SAFI_NONE 0x00
-#define SAFI_UNICAST 0x01
-#define SAFI_MULTICAST 0x02
-#define SAFI_ALL 0xff
-
-/* 4-byte magic AS number */
-#define AS_TRANS 23456
+#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
+ do { \
+ (addr).s6_addr[2] = ((index) >> 8) & 0xff; \
+ (addr).s6_addr[3] = (index) & 0xff; \
+ } while (0)
+#endif
/* prototypes */
/* bgpd.c */
void send_nexthop_update(struct kroute_nexthop *);
void send_imsg_session(int, pid_t, void *, u_int16_t);
-int bgpd_redistribute(int, struct kroute *, struct kroute6 *);
+int send_network(int, struct network_config *,
+ struct filter_set_head *);
int bgpd_filternexthop(struct kroute *, struct kroute6 *);
/* log.c */
void log_init(int);
+void log_verbose(int);
void vlog(int, const char *, va_list);
void log_peer_warn(const struct peer_config *, const char *, ...);
void log_peer_warnx(const struct peer_config *, const char *, ...);
@@ -726,19 +900,22 @@ int cmdline_symset(char *);
int host(const char *, struct bgpd_addr *, u_int8_t *);
/* kroute.c */
-int kr_init(int, u_int);
-int kr_change(struct kroute_label *);
-int kr_delete(struct kroute_label *);
-int kr6_change(struct kroute6_label *);
-int kr6_delete(struct kroute6_label *);
+int kr_init(void);
+int ktable_update(u_int, char *, char *, int);
+void ktable_preload(void);
+void ktable_postload(void);
+int ktable_exists(u_int, u_int *);
+int kr_change(u_int, struct kroute_full *);
+int kr_delete(u_int, struct kroute_full *);
void kr_shutdown(void);
-void kr_fib_couple(void);
-void kr_fib_decouple(void);
+void kr_fib_couple(u_int);
+void kr_fib_decouple(u_int);
int kr_dispatch_msg(void);
-int kr_nexthop_add(struct bgpd_addr *);
-void kr_nexthop_delete(struct bgpd_addr *);
+int kr_nexthop_add(u_int32_t, struct bgpd_addr *);
+void kr_nexthop_delete(u_int32_t, struct bgpd_addr *);
void kr_show_route(struct imsg *);
void kr_ifinfo(char *);
+int kr_net_reload(u_int, struct network_head *);
int kr_reload(void);
struct in6_addr *prefixlen2mask6(u_int8_t prefixlen);
@@ -772,6 +949,8 @@ void pftable_ref(u_int16_t);
/* rde_filter.c */
void filterset_free(struct filter_set_head *);
int filterset_cmp(struct filter_set *, struct filter_set *);
+void filterset_move(struct filter_set_head *,
+ struct filter_set_head *);
const char *filterset_name(enum action_types);
/* util.c */
@@ -779,11 +958,20 @@ const char *log_addr(const struct bgpd_addr *);
const char *log_in6addr(const struct in6_addr *);
const char *log_sockaddr(struct sockaddr *);
const char *log_as(u_int32_t);
+const char *log_rd(u_int64_t);
+const char *log_ext_subtype(u_int8_t);
int aspath_snprint(char *, size_t, void *, u_int16_t);
int aspath_asprint(char **, void *, u_int16_t);
size_t aspath_strlen(void *, u_int16_t);
in_addr_t prefixlen2mask(u_int8_t);
void inet6applymask(struct in6_addr *, const struct in6_addr *,
int);
+const char *aid2str(u_int8_t);
+int aid2afi(u_int8_t, u_int16_t *, u_int8_t *);
+int afi2aid(u_int16_t, u_int8_t, u_int8_t *);
+sa_family_t aid2af(u_int8_t);
+int af2aid(sa_family_t, u_int8_t, u_int8_t *);
+struct sockaddr *addr2sa(struct bgpd_addr *, u_int16_t);
+void sa2addr(struct sockaddr *, struct bgpd_addr *);
#endif /* __BGPD_H__ */
diff --git a/bgpd/buffer.c b/bgpd/buffer.c
deleted file mode 100644
index a4b9e9d..0000000
--- a/bgpd/buffer.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/* $OpenBSD: buffer.c,v 1.43 2009/06/06 06:33:15 eric Exp $ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "imsg.h"
-
-int buf_realloc(struct buf *, size_t);
-void buf_enqueue(struct msgbuf *, struct buf *);
-void buf_dequeue(struct msgbuf *, struct buf *);
-
-struct buf *
-buf_open(size_t len)
-{
- struct buf *buf;
-
- if ((buf = calloc(1, sizeof(struct buf))) == NULL)
- return (NULL);
- if ((buf->buf = malloc(len)) == NULL) {
- free(buf);
- return (NULL);
- }
- buf->size = buf->max = len;
- buf->fd = -1;
-
- return (buf);
-}
-
-struct buf *
-buf_dynamic(size_t len, size_t max)
-{
- struct buf *buf;
-
- if (max < len)
- return (NULL);
-
- if ((buf = buf_open(len)) == NULL)
- return (NULL);
-
- if (max > 0)
- buf->max = max;
-
- return (buf);
-}
-
-int
-buf_realloc(struct buf *buf, size_t len)
-{
- u_char *b;
-
- /* on static buffers max is eq size and so the following fails */
- if (buf->wpos + len > buf->max) {
- errno = ENOMEM;
- return (-1);
- }
-
- b = realloc(buf->buf, buf->wpos + len);
- if (b == NULL)
- return (-1);
- buf->buf = b;
- buf->size = buf->wpos + len;
-
- return (0);
-}
-
-int
-buf_add(struct buf *buf, const void *data, size_t len)
-{
- if (buf->wpos + len > buf->size)
- if (buf_realloc(buf, len) == -1)
- return (-1);
-
- memcpy(buf->buf + buf->wpos, data, len);
- buf->wpos += len;
- return (0);
-}
-
-void *
-buf_reserve(struct buf *buf, size_t len)
-{
- void *b;
-
- if (buf->wpos + len > buf->size)
- if (buf_realloc(buf, len) == -1)
- return (NULL);
-
- b = buf->buf + buf->wpos;
- buf->wpos += len;
- return (b);
-}
-
-void *
-buf_seek(struct buf *buf, size_t pos, size_t len)
-{
- /* only allowed to seek in already written parts */
- if (pos + len > buf->wpos)
- return (NULL);
-
- return (buf->buf + pos);
-}
-
-size_t
-buf_size(struct buf *buf)
-{
- return (buf->wpos);
-}
-
-size_t
-buf_left(struct buf *buf)
-{
- return (buf->max - buf->wpos);
-}
-
-void
-buf_close(struct msgbuf *msgbuf, struct buf *buf)
-{
- buf_enqueue(msgbuf, buf);
-}
-
-int
-buf_write(struct msgbuf *msgbuf)
-{
- struct iovec iov[IOV_MAX];
- struct buf *buf, *next;
- unsigned int i = 0;
- ssize_t n;
-
- bzero(&iov, sizeof(iov));
- TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
- if (i >= IOV_MAX)
- break;
- iov[i].iov_base = buf->buf + buf->rpos;
- iov[i].iov_len = buf->size - buf->rpos;
- i++;
- }
-
- if ((n = writev(msgbuf->fd, iov, i)) == -1) {
- if (errno == EAGAIN || errno == ENOBUFS ||
- errno == EINTR) /* try later */
- return (0);
- else
- return (-1);
- }
-
- if (n == 0) { /* connection closed */
- errno = 0;
- return (-2);
- }
-
- for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
- buf = next) {
- next = TAILQ_NEXT(buf, entry);
- if (buf->rpos + n >= buf->size) {
- n -= buf->size - buf->rpos;
- buf_dequeue(msgbuf, buf);
- } else {
- buf->rpos += n;
- n = 0;
- }
- }
-
- return (0);
-}
-
-void
-buf_free(struct buf *buf)
-{
- free(buf->buf);
- free(buf);
-}
-
-void
-msgbuf_init(struct msgbuf *msgbuf)
-{
- msgbuf->queued = 0;
- msgbuf->fd = -1;
- TAILQ_INIT(&msgbuf->bufs);
-}
-
-void
-msgbuf_clear(struct msgbuf *msgbuf)
-{
- struct buf *buf;
-
- while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
- buf_dequeue(msgbuf, buf);
-}
-
-int
-msgbuf_write(struct msgbuf *msgbuf)
-{
- struct iovec iov[IOV_MAX];
- struct buf *buf, *next;
- unsigned int i = 0;
- ssize_t n;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- union {
- struct cmsghdr hdr;
- char buf[CMSG_SPACE(sizeof(int))];
- } cmsgbuf;
-
- bzero(&iov, sizeof(iov));
- bzero(&msg, sizeof(msg));
- TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
- if (i >= IOV_MAX)
- break;
- iov[i].iov_base = buf->buf + buf->rpos;
- iov[i].iov_len = buf->wpos - buf->rpos;
- i++;
- if (buf->fd != -1)
- break;
- }
-
- msg.msg_iov = iov;
- msg.msg_iovlen = i;
-
- if (buf != NULL && buf->fd != -1) {
- msg.msg_control = (caddr_t)&cmsgbuf.buf;
- msg.msg_controllen = sizeof(cmsgbuf.buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- *(int *)CMSG_DATA(cmsg) = buf->fd;
- }
-
- if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
- if (errno == EAGAIN || errno == ENOBUFS ||
- errno == EINTR) /* try later */
- return (0);
- else
- return (-1);
- }
-
- if (n == 0) { /* connection closed */
- errno = 0;
- return (-2);
- }
-
- /*
- * assumption: fd got sent if sendmsg sent anything
- * this works because fds are passed one at a time
- */
- if (buf != NULL && buf->fd != -1) {
- close(buf->fd);
- buf->fd = -1;
- }
-
- for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
- buf = next) {
- next = TAILQ_NEXT(buf, entry);
- if (buf->rpos + n >= buf->wpos) {
- n -= buf->wpos - buf->rpos;
- buf_dequeue(msgbuf, buf);
- } else {
- buf->rpos += n;
- n = 0;
- }
- }
-
- return (0);
-}
-
-void
-buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
-{
- TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
- msgbuf->queued++;
-}
-
-void
-buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
-{
- TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
-
- if (buf->fd != -1)
- close(buf->fd);
-
- msgbuf->queued--;
- buf_free(buf);
-}
diff --git a/bgpd/carp.c b/bgpd/carp.c
index 655a30d..aa25e46 100644
--- a/bgpd/carp.c
+++ b/bgpd/carp.c
@@ -93,9 +93,8 @@ carp_demote_shutdown(void)
while ((c = TAILQ_FIRST(&carpgroups)) != NULL) {
TAILQ_REMOVE(&carpgroups, c, entry);
- for (; c->changed_by > 0; c->changed_by--)
- if (c->do_demote)
- carp_demote_ioctl(c->group, -1);
+ if (c->do_demote && c->changed_by > 0)
+ carp_demote_ioctl(c->group, -c->changed_by);
free(c->group);
free(c);
@@ -105,6 +104,9 @@ carp_demote_shutdown(void)
int
carp_demote_get(char *group)
{
+#if defined(__FreeBSD__) /* FreeBSD does not have support for CARP */
+ return (-1);
+#else
int s;
struct ifgroupreq ifgr;
@@ -127,6 +129,7 @@ carp_demote_get(char *group)
close(s);
return ((int)ifgr.ifgr_attrib.ifg_carp_demoted);
+#endif /* defined(__FreeBSD__) */
}
int
@@ -159,6 +162,9 @@ carp_demote_set(char *group, int demote)
int
carp_demote_ioctl(char *group, int demote)
{
+#if defined(__FreeBSD__) /* FreeBSD does not have support for CARP */
+ return (-1);
+#else
int s, res;
struct ifgroupreq ifgr;
@@ -181,4 +187,5 @@ carp_demote_ioctl(char *group, int demote)
close(s);
return (res);
+#endif /* defined(__FreeBSD__) */
}
diff --git a/bgpd/config.c b/bgpd/config.c
index e7c7d1f..51e3096 100644
--- a/bgpd/config.c
+++ b/bgpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.51 2009/01/26 23:10:02 claudio Exp $ */
+/* $OpenBSD: config.c,v 1.56 2010/10/24 17:20:08 deraadt Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -20,6 +20,11 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */
+#include <netmpls/mpls.h>
+#endif
#include <errno.h>
#include <ifaddrs.h>
@@ -47,8 +52,6 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
/* preserve cmd line opts */
conf->opts = xconf->opts;
- conf->csock = xconf->csock;
- conf->rcsock = xconf->rcsock;
if (!conf->as) {
log_warnx("configuration error: AS not given");
@@ -64,6 +67,9 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
conf->clusterid = conf->bgpid;
+ free(xconf->csock);
+ free(xconf->rcsock);
+
conf->listen_addrs = xconf->listen_addrs;
memcpy(xconf, conf, sizeof(struct bgpd_config));
@@ -74,7 +80,7 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
nla->reconf = RECONF_REINIT;
} else {
- /*
+ /*
* merge new listeners:
* -flag all existing ones as to be deleted
* -those that are in both new and old: flag to keep
@@ -208,7 +214,7 @@ host_v4(const char *s, struct bgpd_addr *h, u_int8_t *len)
return (0);
}
- h->af = AF_INET;
+ h->aid = AID_INET;
h->v4.s_addr = ina.s_addr;
*len = bits;
@@ -225,13 +231,7 @@ host_v6(const char *s, struct bgpd_addr *h)
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(s, "0", &hints, &res) == 0) {
- h->af = AF_INET6;
- memcpy(&h->v6,
- &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
- sizeof(h->v6));
- h->scope_id =
- ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
-
+ sa2addr(res->ai_addr, h);
freeaddrinfo(res);
return (1);
}
@@ -317,3 +317,30 @@ prepare_listeners(struct bgpd_config *conf)
}
}
}
+
+int
+get_mpe_label(struct rdomain *r)
+{
+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */
+ struct ifreq ifr;
+ struct shim_hdr shim;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return (-1);
+
+ bzero(&shim, sizeof(shim));
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t)&shim;
+
+ if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
+ close(s);
+ return (-1);
+ }
+ close(s);
+ r->label = shim.shim_label;
+#endif
+ return (0);
+}
diff --git a/bgpd/control.c b/bgpd/control.c
index e8097dd..8ee3f50 100644
--- a/bgpd/control.c
+++ b/bgpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.61 2009/05/05 20:09:19 sthen Exp $ */
+/* $OpenBSD: control.c,v 1.70 2010/10/29 12:51:53 henning Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -53,7 +53,7 @@ control_init(int restricted, char *path)
if (unlink(path) == -1)
if (errno != ENOENT) {
- log_warn("unlink %s", path);
+ log_warn("control_init: unlink %s", path);
close(fd);
return (-1);
}
@@ -123,14 +123,14 @@ control_accept(int listenfd, int restricted)
if ((connfd = accept(listenfd,
(struct sockaddr *)&sun, &len)) == -1) {
if (errno != EWOULDBLOCK && errno != EINTR)
- log_warn("session_control_accept");
+ log_warn("control_accept: accept");
return (0);
}
session_socket_blockmode(connfd, BM_NONBLOCK);
- if ((ctl_conn = malloc(sizeof(struct ctl_conn))) == NULL) {
- log_warn("session_control_accept");
+ if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) {
+ log_warn("control_accept");
close(connfd);
return (0);
}
@@ -191,7 +191,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
{
struct imsg imsg;
struct ctl_conn *c;
- int n;
+ ssize_t n;
+ int verbose;
struct peer *p;
struct ctl_neighbor *neighbor;
struct ctl_show_rib_request *ribreq;
@@ -305,7 +306,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
break;
case IMSG_CTL_FIB_COUPLE:
case IMSG_CTL_FIB_DECOUPLE:
- imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
+ imsg_compose_parent(imsg.hdr.type, imsg.hdr.peerid,
+ 0, NULL, 0);
break;
case IMSG_CTL_NEIGHBOR_UP:
case IMSG_CTL_NEIGHBOR_DOWN:
@@ -328,13 +330,19 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
control_result(c, CTL_RES_OK);
break;
case IMSG_CTL_NEIGHBOR_DOWN:
- bgp_fsm(p, EVNT_STOP);
+ session_stop(p, ERR_CEASE_ADMIN_DOWN);
control_result(c, CTL_RES_OK);
break;
case IMSG_CTL_NEIGHBOR_CLEAR:
- bgp_fsm(p, EVNT_STOP);
- timer_set(p, Timer_IdleHold,
- SESSION_CLEAR_DELAY);
+ if (!p->conf.down) {
+ session_stop(p,
+ ERR_CEASE_ADMIN_RESET);
+ timer_set(p, Timer_IdleHold,
+ SESSION_CLEAR_DELAY);
+ } else {
+ session_stop(p,
+ ERR_CEASE_ADMIN_DOWN);
+ }
control_result(c, CTL_RES_OK);
break;
case IMSG_CTL_NEIGHBOR_RREFRESH:
@@ -352,13 +360,19 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
"wrong length");
break;
case IMSG_CTL_RELOAD:
+ case IMSG_CTL_SHOW_INTERFACE:
+ case IMSG_CTL_SHOW_FIB_TABLES:
+ c->ibuf.pid = imsg.hdr.pid;
+ imsg_compose_parent(imsg.hdr.type, 0, imsg.hdr.pid,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_SHOW_NEXTHOP:
- case IMSG_CTL_SHOW_INTERFACE:
c->ibuf.pid = imsg.hdr.pid;
- imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
- imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ imsg_compose_parent(imsg.hdr.type, imsg.hdr.peerid,
+ imsg.hdr.pid, imsg.data, imsg.hdr.len -
+ IMSG_HEADER_SIZE);
break;
case IMSG_CTL_SHOW_RIB:
case IMSG_CTL_SHOW_RIB_AS:
@@ -370,7 +384,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
neighbor->descr[PEER_DESCR_LEN - 1] = 0;
ribreq->peerid = 0;
p = NULL;
- if (neighbor->addr.af) {
+ if (neighbor->addr.aid) {
p = getpeerbyaddr(&neighbor->addr);
if (p == NULL) {
control_result(c,
@@ -397,8 +411,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
break;
}
if ((imsg.hdr.type == IMSG_CTL_SHOW_RIB_PREFIX)
- && (ribreq->prefix.af != AF_INET)
- && (ribreq->prefix.af != AF_INET6)) {
+ && (ribreq->prefix.aid == AID_UNSPEC)) {
/* malformed request, must specify af */
control_result(c, CTL_RES_PARSE_ERROR);
break;
@@ -425,6 +438,20 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
imsg_compose_rde(imsg.hdr.type, 0,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
break;
+ case IMSG_CTL_LOG_VERBOSE:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(verbose))
+ break;
+
+ /* forward to other processes */
+ imsg_compose_parent(imsg.hdr.type, 0, imsg.hdr.pid,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+ imsg_compose_rde(imsg.hdr.type, 0,
+ imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
+
+ memcpy(&verbose, imsg.data, sizeof(verbose));
+ log_verbose(verbose);
+ break;
default:
break;
}
diff --git a/bgpd/imsg.c b/bgpd/imsg.c
deleted file mode 100644
index 3ba224e..0000000
--- a/bgpd/imsg.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* $OpenBSD: imsg.c,v 1.47 2009/06/08 08:30:06 dlg Exp $ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "imsg.h"
-
-int imsg_get_fd(struct imsgbuf *);
-
-void
-imsg_init(struct imsgbuf *ibuf, int fd)
-{
- msgbuf_init(&ibuf->w);
- bzero(&ibuf->r, sizeof(ibuf->r));
- ibuf->fd = fd;
- ibuf->w.fd = fd;
- ibuf->pid = getpid();
- TAILQ_INIT(&ibuf->fds);
-}
-
-ssize_t
-imsg_read(struct imsgbuf *ibuf)
-{
- struct msghdr msg;
- struct cmsghdr *cmsg;
- union {
- struct cmsghdr hdr;
- char buf[CMSG_SPACE(sizeof(int) * 16)];
- } cmsgbuf;
- struct iovec iov;
- ssize_t n;
- int fd;
- struct imsg_fd *ifd;
-
- bzero(&msg, sizeof(msg));
-
- iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
- iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &cmsgbuf.buf;
- msg.msg_controllen = sizeof(cmsgbuf.buf);
-
- if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
- if (errno != EINTR && errno != EAGAIN) {
- return (-1);
- }
- return (-2);
- }
-
- ibuf->r.wpos += n;
-
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- fd = (*(int *)CMSG_DATA(cmsg));
- if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
- /* XXX: this return can leak */
- return (-1);
- }
- ifd->fd = fd;
- TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry);
- }
- /* we do not handle other ctl data level */
- }
-
- return (n);
-}
-
-ssize_t
-imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
-{
- size_t av, left, datalen;
-
- av = ibuf->r.wpos;
-
- if (IMSG_HEADER_SIZE > av)
- return (0);
-
- memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
- if (imsg->hdr.len < IMSG_HEADER_SIZE ||
- imsg->hdr.len > MAX_IMSGSIZE) {
- errno = ERANGE;
- return (-1);
- }
- if (imsg->hdr.len > av)
- return (0);
- datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
- ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
- if ((imsg->data = malloc(datalen)) == NULL)
- return (-1);
-
- if (imsg->hdr.flags & IMSGF_HASFD)
- imsg->fd = imsg_get_fd(ibuf);
- else
- imsg->fd = -1;
-
- memcpy(imsg->data, ibuf->r.rptr, datalen);
-
- if (imsg->hdr.len < av) {
- left = av - imsg->hdr.len;
- memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
- ibuf->r.wpos = left;
- } else
- ibuf->r.wpos = 0;
-
- return (datalen + IMSG_HEADER_SIZE);
-}
-
-int
-imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
- pid_t pid, int fd, void *data, u_int16_t datalen)
-{
- struct buf *wbuf;
-
- if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
- return (-1);
-
- if (imsg_add(wbuf, data, datalen) == -1)
- return (-1);
-
- wbuf->fd = fd;
-
- imsg_close(ibuf, wbuf);
-
- return (1);
-}
-
-int
-imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
- pid_t pid, int fd, const struct iovec *iov, int iovcnt)
-{
- struct buf *wbuf;
- int i, datalen = 0;
-
- for (i = 0; i < iovcnt; i++)
- datalen += iov[i].iov_len;
-
- if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
- return (-1);
-
- for (i = 0; i < iovcnt; i++)
- if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
- return (-1);
-
- wbuf->fd = fd;
-
- imsg_close(ibuf, wbuf);
-
- return (1);
-}
-
-/* ARGSUSED */
-struct buf *
-imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
- pid_t pid, u_int16_t datalen)
-{
- struct buf *wbuf;
- struct imsg_hdr hdr;
-
- datalen += IMSG_HEADER_SIZE;
- if (datalen > MAX_IMSGSIZE) {
- errno = ERANGE;
- return (NULL);
- }
-
- hdr.type = type;
- hdr.flags = 0;
- hdr.peerid = peerid;
- if ((hdr.pid = pid) == 0)
- hdr.pid = ibuf->pid;
- if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
- return (NULL);
- }
- if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
- return (NULL);
-
- return (wbuf);
-}
-
-int
-imsg_add(struct buf *msg, void *data, u_int16_t datalen)
-{
- if (datalen)
- if (buf_add(msg, data, datalen) == -1) {
- buf_free(msg);
- return (-1);
- }
- return (datalen);
-}
-
-void
-imsg_close(struct imsgbuf *ibuf, struct buf *msg)
-{
- struct imsg_hdr *hdr;
-
- hdr = (struct imsg_hdr *)msg->buf;
-
- hdr->flags &= ~IMSGF_HASFD;
- if (msg->fd != -1)
- hdr->flags |= IMSGF_HASFD;
-
- hdr->len = (u_int16_t)msg->wpos;
-
- buf_close(&ibuf->w, msg);
-}
-
-void
-imsg_free(struct imsg *imsg)
-{
- free(imsg->data);
-}
-
-int
-imsg_get_fd(struct imsgbuf *ibuf)
-{
- int fd;
- struct imsg_fd *ifd;
-
- if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
- return (-1);
-
- fd = ifd->fd;
- TAILQ_REMOVE(&ibuf->fds, ifd, entry);
- free(ifd);
-
- return (fd);
-}
-
-int
-imsg_flush(struct imsgbuf *ibuf)
-{
- while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) < 0)
- return (-1);
- return (0);
-}
-
-void
-imsg_clear(struct imsgbuf *ibuf)
-{
- while (ibuf->w.queued)
- msgbuf_clear(&ibuf->w);
-}
diff --git a/bgpd/imsg.h b/bgpd/imsg.h
deleted file mode 100644
index 8fa2e4f..0000000
--- a/bgpd/imsg.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $OpenBSD: imsg.h,v 1.3 2009/06/07 05:56:24 eric Exp $ */
-
-/*
- * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
- * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2003, 2004 Henning Brauer <henning@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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/tree.h>
-
-#define READ_BUF_SIZE 65535
-#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
-#define MAX_IMSGSIZE 16384
-
-struct buf {
- TAILQ_ENTRY(buf) entry;
- u_char *buf;
- size_t size;
- size_t max;
- size_t wpos;
- size_t rpos;
- int fd;
-};
-
-struct msgbuf {
- TAILQ_HEAD(, buf) bufs;
- u_int32_t queued;
- int fd;
-};
-
-struct buf_read {
- u_char buf[READ_BUF_SIZE];
- u_char *rptr;
- size_t wpos;
-};
-
-struct imsg_fd {
- TAILQ_ENTRY(imsg_fd) entry;
- int fd;
-};
-
-struct imsgbuf {
- TAILQ_HEAD(, imsg_fd) fds;
- struct buf_read r;
- struct msgbuf w;
- int fd;
- pid_t pid;
-};
-
-#define IMSGF_HASFD 1
-
-struct imsg_hdr {
- u_int32_t type;
- u_int16_t len;
- u_int16_t flags;
- u_int32_t peerid;
- u_int32_t pid;
-};
-
-struct imsg {
- struct imsg_hdr hdr;
- int fd;
- void *data;
-};
-
-
-/* buffer.c */
-struct buf *buf_open(size_t);
-struct buf *buf_dynamic(size_t, size_t);
-int buf_add(struct buf *, const void *, size_t);
-void *buf_reserve(struct buf *, size_t);
-void *buf_seek(struct buf *, size_t, size_t);
-size_t buf_size(struct buf *);
-size_t buf_left(struct buf *);
-void buf_close(struct msgbuf *, struct buf *);
-int buf_write(struct msgbuf *);
-void buf_free(struct buf *);
-void msgbuf_init(struct msgbuf *);
-void msgbuf_clear(struct msgbuf *);
-int msgbuf_write(struct msgbuf *);
-
-/* imsg.c */
-void imsg_init(struct imsgbuf *, int);
-ssize_t imsg_read(struct imsgbuf *);
-ssize_t imsg_get(struct imsgbuf *, struct imsg *);
-int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
- int, void *, u_int16_t);
-int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
- int, const struct iovec *, int);
-struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
- u_int16_t);
-int imsg_add(struct buf *, void *, u_int16_t);
-void imsg_close(struct imsgbuf *, struct buf *);
-void imsg_free(struct imsg *);
-int imsg_flush(struct imsgbuf *);
-void imsg_clear(struct imsgbuf *);
diff --git a/bgpd/kroute.c b/bgpd/kroute.c
index d16cf3b..db8c8d4 100644
--- a/bgpd/kroute.c
+++ b/bgpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.169 2009/06/25 15:54:22 claudio Exp $ */
+/* $OpenBSD: kroute.c,v 1.176 2010/04/06 13:25:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -27,6 +27,9 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */
+#include <netmpls/mpls.h>
+#endif
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -37,11 +40,12 @@
#include "bgpd.h"
+struct ktable **krt;
+u_int krt_size;
+
struct {
u_int32_t rtseq;
pid_t pid;
- u_int rtableid;
- int fib_sync;
int fd;
} kr_state;
@@ -83,32 +87,52 @@ struct kif_node {
struct kif_kr6_head kroute6_l;
};
-int kr_redistribute(int, struct kroute *);
-int kr_redistribute6(int, struct kroute6 *);
+int ktable_new(u_int, u_int, char *, char *, int);
+void ktable_free(u_int);
+void ktable_destroy(struct ktable *);
+struct ktable *ktable_get(u_int);
+
+int kr4_change(struct ktable *, struct kroute_full *);
+int kr6_change(struct ktable *, struct kroute_full *);
+int krVPN4_change(struct ktable *, struct kroute_full *);
+int kr4_delete(struct ktable *, struct kroute_full *);
+int kr6_delete(struct ktable *, struct kroute_full *);
+int krVPN4_delete(struct ktable *, struct kroute_full *);
+void kr_net_delete(struct network *);
+struct network *kr_net_match(struct ktable *, struct kroute *);
+struct network *kr_net_match6(struct ktable *, struct kroute6 *);
+struct network *kr_net_find(struct ktable *, struct network *);
+int kr_redistribute(int, struct ktable *, struct kroute *);
+int kr_redistribute6(int, struct ktable *, struct kroute6 *);
+struct kroute_full *kr_tofull(struct kroute *);
+struct kroute_full *kr6_tofull(struct kroute6 *);
int kroute_compare(struct kroute_node *, struct kroute_node *);
int kroute6_compare(struct kroute6_node *, struct kroute6_node *);
int knexthop_compare(struct knexthop_node *, struct knexthop_node *);
int kif_compare(struct kif_node *, struct kif_node *);
-struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t);
+struct kroute_node *kroute_find(struct ktable *, in_addr_t, u_int8_t,
+ u_int8_t);
struct kroute_node *kroute_matchgw(struct kroute_node *,
struct sockaddr_in *);
-int kroute_insert(struct kroute_node *);
-int kroute_remove(struct kroute_node *);
-void kroute_clear(void);
+int kroute_insert(struct ktable *, struct kroute_node *);
+int kroute_remove(struct ktable *, struct kroute_node *);
+void kroute_clear(struct ktable *);
-struct kroute6_node *kroute6_find(const struct in6_addr *, u_int8_t,
- u_int8_t);
+struct kroute6_node *kroute6_find(struct ktable *, const struct in6_addr *,
+ u_int8_t, u_int8_t);
struct kroute6_node *kroute6_matchgw(struct kroute6_node *,
struct sockaddr_in6 *);
-int kroute6_insert(struct kroute6_node *);
-int kroute6_remove(struct kroute6_node *);
-void kroute6_clear(void);
+int kroute6_insert(struct ktable *, struct kroute6_node *);
+int kroute6_remove(struct ktable *, struct kroute6_node *);
+void kroute6_clear(struct ktable *);
-struct knexthop_node *knexthop_find(struct bgpd_addr *);
-int knexthop_insert(struct knexthop_node *);
-int knexthop_remove(struct knexthop_node *);
-void knexthop_clear(void);
+struct knexthop_node *knexthop_find(struct ktable *, struct bgpd_addr *);
+int knexthop_insert(struct ktable *,
+ struct knexthop_node *);
+int knexthop_remove(struct ktable *,
+ struct knexthop_node *);
+void knexthop_clear(struct ktable *);
struct kif_node *kif_find(int);
int kif_insert(struct kif_node *);
@@ -124,13 +148,15 @@ int kif_kr6_remove(struct kroute6_node *);
int kif_validate(struct kif *);
int kroute_validate(struct kroute *);
int kroute6_validate(struct kroute6 *);
-void knexthop_validate(struct knexthop_node *);
-void knexthop_track(void *);
-struct kroute_node *kroute_match(in_addr_t, int);
-struct kroute6_node *kroute6_match(struct in6_addr *, int);
-void kroute_detach_nexthop(struct knexthop_node *);
-
-int protect_lo(void);
+void knexthop_validate(struct ktable *,
+ struct knexthop_node *);
+void knexthop_track(struct ktable *, void *);
+struct kroute_node *kroute_match(struct ktable *, in_addr_t, int);
+struct kroute6_node *kroute6_match(struct ktable *, struct in6_addr *, int);
+void kroute_detach_nexthop(struct ktable *,
+ struct knexthop_node *);
+
+int protect_lo(struct ktable *);
u_int8_t prefixlen_classful(in_addr_t);
u_int8_t mask2prefixlen(in_addr_t);
u_int8_t mask2prefixlen6(struct sockaddr_in6 *);
@@ -138,23 +164,20 @@ void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
void if_change(u_short, int, struct if_data *);
void if_announce(void *);
-int send_rtmsg(int, int, struct kroute *);
-int send_rt6msg(int, int, struct kroute6 *);
+int send_rtmsg(int, int, struct ktable *, struct kroute *);
+int send_rt6msg(int, int, struct ktable *, struct kroute6 *);
int dispatch_rtmsg(void);
-int fetchtable(u_int, int);
+int fetchtable(struct ktable *);
int fetchifs(int);
int dispatch_rtmsg_addr(struct rt_msghdr *,
- struct sockaddr *[RTAX_MAX], int);
+ struct sockaddr *[RTAX_MAX], struct ktable *);
-RB_HEAD(kroute_tree, kroute_node) krt;
RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
-RB_HEAD(kroute6_tree, kroute6_node) krt6;
RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare)
RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare)
-RB_HEAD(knexthop_tree, knexthop_node) knt;
RB_PROTOTYPE(knexthop_tree, knexthop_node, entry, knexthop_compare)
RB_GENERATE(knexthop_tree, knexthop_node, entry, knexthop_compare)
@@ -162,19 +185,21 @@ RB_HEAD(kif_tree, kif_node) kit;
RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
+#define KT2KNT(x) (&(ktable_get((x)->nhtableid)->knt))
+
/*
* exported functions
*/
int
-kr_init(int fs, u_int rtableid)
+kr_init(void)
{
int opt = 0, rcvbuf, default_rcvbuf;
+#if !defined(__FreeBSD__) /* FreeBSD does not have ROUTE_TABLEFILTER. */
+ unsigned int tid = RTABLE_ANY;
+#endif
socklen_t optlen;
- kr_state.rtableid = rtableid;
- kr_state.fib_sync = fs;
-
if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
log_warn("kr_init: socket");
return (-1);
@@ -198,194 +223,533 @@ kr_init(int fs, u_int rtableid)
rcvbuf /= 2)
; /* nothing */
+#if !defined(__FreeBSD__) /* FreeBSD does not have ROUTE_TABLEFILTER. */
+ if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
+ sizeof(tid)) == -1) {
+ log_warn("kr_init: setsockopt AF_ROUTE ROUTE_TABLEFILTER");
+ return (-1);
+ }
+#endif
+
kr_state.pid = getpid();
kr_state.rtseq = 1;
- RB_INIT(&krt);
- RB_INIT(&krt6);
- RB_INIT(&knt);
RB_INIT(&kit);
if (fetchifs(0) == -1)
return (-1);
- if (fetchtable(kr_state.rtableid, 0) == -1)
- return (-1);
- if (kr_state.rtableid != 0)
- if (fetchtable(0, 1) == -1)
+ return (kr_state.fd);
+}
+
+int
+ktable_new(u_int rtableid, u_int rdomid, char *name, char *ifname, int fs)
+{
+ struct ktable **xkrt;
+ struct ktable *kt;
+ size_t newsize, oldsize;
+
+ /* resize index table if needed */
+ if (rtableid >= krt_size) {
+ oldsize = sizeof(struct ktable *) * krt_size;
+ newsize = sizeof(struct ktable *) * (rtableid + 1);
+ if ((xkrt = realloc(krt, newsize)) == NULL) {
+ log_warn("ktable_new");
return (-1);
+ }
+ krt = xkrt;
+ krt_size = rtableid + 1;
+ bzero((char *)krt + oldsize, newsize - oldsize);
+ }
+
+ if (krt[rtableid])
+ fatalx("ktable_new: table already exists.");
- if (protect_lo() == -1)
+ /* allocate new element */
+ kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
+ if (kt == NULL) {
+ log_warn("ktable_new");
return (-1);
+ }
- return (kr_state.fd);
+ /* initialize structure ... */
+ strlcpy(kt->descr, name, sizeof(kt->descr));
+ RB_INIT(&kt->krt);
+ RB_INIT(&kt->krt6);
+ RB_INIT(&kt->knt);
+ TAILQ_INIT(&kt->krn);
+ kt->fib_conf = kt->fib_sync = fs;
+ kt->rtableid = rtableid;
+ kt->nhtableid = rdomid;
+ /* bump refcount of rdomain table for the nexthop lookups */
+ ktable_get(kt->nhtableid)->nhrefcnt++;
+ if (ifname) {
+ strlcpy(kt->ifmpe, ifname, IFNAMSIZ);
+ kt->ifindex = if_nametoindex(ifname);
+ }
+
+ /* ... and load it */
+ if (fetchtable(kt) == -1)
+ return (-1);
+ if (protect_lo(kt) == -1)
+ return (-1);
+
+ /* everything is up and running */
+ kt->state = RECONF_REINIT;
+ log_debug("new ktable %s for rtableid %d", name, rtableid);
+ return (0);
+}
+
+void
+ktable_free(u_int rtableid)
+{
+ struct ktable *kt, *nkt;
+
+ if ((kt = ktable_get(rtableid)) == NULL)
+ return;
+
+ /* decouple from kernel, no new routes will be entered from here */
+ kr_fib_decouple(kt->rtableid);
+
+ /* first unhook from the nexthop table */
+ nkt = ktable_get(kt->nhtableid);
+ nkt->nhrefcnt--;
+
+ /*
+ * Evil little details:
+ * If kt->nhrefcnt > 0 then kt == nkt and nothing needs to be done.
+ * If kt != nkt then kt->nhrefcnt must be 0 and kt must be killed.
+ * If nkt is no longer referenced it must be killed (possible double
+ * free so check that kt != nkt).
+ */
+ if (kt != nkt && nkt->nhrefcnt <= 0)
+ ktable_destroy(nkt);
+ if (kt->nhrefcnt <= 0)
+ ktable_destroy(kt);
+}
+
+void
+ktable_destroy(struct ktable *kt)
+{
+ /* decouple just to be sure, does not hurt */
+ kr_fib_decouple(kt->rtableid);
+
+ log_debug("freeing ktable %s rtableid %u", kt->descr, kt->rtableid);
+ knexthop_clear(kt);
+ kroute_clear(kt);
+ kroute6_clear(kt);
+
+ krt[kt->rtableid] = NULL;
+ free(kt);
+}
+
+struct ktable *
+ktable_get(u_int rtableid)
+{
+ if (rtableid >= krt_size)
+ return (NULL);
+ return (krt[rtableid]);
}
int
-kr_change(struct kroute_label *kl)
+ktable_update(u_int rtableid, char *name, char *ifname, int flags)
+{
+ struct ktable *kt, *rkt;
+ u_int rdomid;
+
+ if (!ktable_exists(rtableid, &rdomid))
+ fatalx("King Bula lost a table"); /* may not happen */
+
+ if (rdomid != rtableid || flags & F_RIB_NOFIB) {
+ rkt = ktable_get(rdomid);
+ if (rkt == NULL) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "rdomain_%d", rdomid);
+ if (ktable_new(rdomid, rdomid, buf, NULL, 0))
+ return (-1);
+ } else {
+ /* there is no need for full fib synchronisation if
+ * the table is only used for nexthop lookups.
+ */
+ if (rkt->state == RECONF_DELETE) {
+ rkt->fib_conf = 0;
+ rkt->state = RECONF_KEEP;
+ }
+ }
+ }
+
+ if (flags & (F_RIB_NOEVALUATE | F_RIB_NOFIB))
+ /* only rdomain table must exist */
+ return (0);
+
+ kt = ktable_get(rtableid);
+ if (kt == NULL) {
+ if (ktable_new(rtableid, rdomid, name, ifname,
+ !(flags & F_RIB_NOFIBSYNC)))
+ return (-1);
+ } else {
+ /* fib sync has higher preference then no sync */
+ if (kt->state == RECONF_DELETE) {
+ kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
+ kt->state = RECONF_KEEP;
+ } else if (!kt->fib_conf)
+ kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
+
+ strlcpy(kt->descr, name, sizeof(kt->descr));
+ }
+ return (0);
+}
+
+void
+ktable_preload(void)
+{
+ struct ktable *kt;
+ u_int i;
+
+ for (i = 0; i < krt_size; i++) {
+ if ((kt = ktable_get(i)) == NULL)
+ continue;
+ kt->state = RECONF_DELETE;
+ }
+}
+
+void
+ktable_postload(void)
+{
+ struct ktable *kt;
+ u_int i;
+
+ for (i = krt_size; i > 0; i--) {
+ if ((kt = ktable_get(i - 1)) == NULL)
+ continue;
+ if (kt->state == RECONF_DELETE)
+ ktable_free(i - 1);
+ else if (kt->state == RECONF_REINIT)
+ kt->fib_sync = kt->fib_conf;
+ }
+}
+
+int
+ktable_exists(u_int rtableid, u_int *rdomid)
+{
+#if !defined(__FreeBSD__) /* FreeBSD does not have NET_RT_TABLE. */
+ size_t len;
+ struct rt_tableinfo info;
+ int mib[6];
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_TABLE;
+ mib[5] = rtableid;
+
+ len = sizeof(info);
+ if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
+ if (errno == ENOENT)
+ /* table nonexistent */
+ return (0);
+ log_warn("sysctl");
+ /* must return 0 so that the table is considered non-existent */
+ return (0);
+ }
+ if (rdomid)
+ *rdomid = info.rti_domainid;
+#else
+ *rdomid = 0;
+#endif
+ return (1);
+}
+
+int
+kr_change(u_int rtableid, struct kroute_full *kl)
+{
+ struct ktable *kt;
+
+ if ((kt = ktable_get(rtableid)) == NULL)
+ /* too noisy during reloads, just ignore */
+ return (0);
+ switch (kl->prefix.aid) {
+ case AID_INET:
+ return (kr4_change(kt, kl));
+ case AID_INET6:
+ return (kr6_change(kt, kl));
+ case AID_VPN_IPv4:
+ return (krVPN4_change(kt, kl));
+ }
+ log_warnx("kr_change: not handled AID");
+ return (-1);
+}
+
+int
+kr4_change(struct ktable *kt, struct kroute_full *kl)
{
struct kroute_node *kr;
int action = RTM_ADD;
+ u_int16_t labelid;
- if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP))
- != NULL)
+ if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
+ RTP_BGP)) != NULL)
action = RTM_CHANGE;
/* nexthop within 127/8 -> ignore silently */
- if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) ==
+ if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) ==
htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
return (0);
- if (kr)
- rtlabel_unref(kr->r.labelid);
- kl->kr.labelid = rtlabel_name2id(kl->label);
+ labelid = rtlabel_name2id(kl->label);
/* for blackhole and reject routes nexthop needs to be 127.0.0.1 */
- if (kl->kr.flags & (F_BLACKHOLE|F_REJECT))
- kl->kr.nexthop.s_addr = htonl(INADDR_LOOPBACK);
-
- if (send_rtmsg(kr_state.fd, action, &kl->kr) == -1)
- return (-1);
+ if (kl->flags & (F_BLACKHOLE|F_REJECT))
+ kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
if (action == RTM_ADD) {
if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
log_warn("kr_change");
return (-1);
}
- kr->r.prefix.s_addr = kl->kr.prefix.s_addr;
- kr->r.prefixlen = kl->kr.prefixlen;
- kr->r.nexthop.s_addr = kl->kr.nexthop.s_addr;
- kr->r.flags = kl->kr.flags | F_BGPD_INSERTED;
+ kr->r.prefix.s_addr = kl->prefix.v4.s_addr;
+ kr->r.prefixlen = kl->prefixlen;
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ kr->r.flags = kl->flags | F_BGPD_INSERTED;
kr->r.priority = RTP_BGP;
- kr->r.labelid = kl->kr.labelid;
+ kr->r.labelid = labelid;
- if (kroute_insert(kr) == -1)
+ if (kroute_insert(kt, kr) == -1)
free(kr);
} else {
- kr->r.nexthop.s_addr = kl->kr.nexthop.s_addr;
- kr->r.labelid = kl->kr.labelid;
- if (kl->kr.flags & F_BLACKHOLE)
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ rtlabel_unref(kr->r.labelid);
+ kr->r.labelid = labelid;
+ if (kl->flags & F_BLACKHOLE)
kr->r.flags |= F_BLACKHOLE;
else
kr->r.flags &= ~F_BLACKHOLE;
- if (kl->kr.flags & F_REJECT)
+ if (kl->flags & F_REJECT)
kr->r.flags |= F_REJECT;
else
kr->r.flags &= ~F_REJECT;
}
+ if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1)
+ return (-1);
+
return (0);
}
int
-kr_delete(struct kroute_label *kl)
+kr6_change(struct ktable *kt, struct kroute_full *kl)
{
- struct kroute_node *kr;
+ struct kroute6_node *kr6;
+ struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
+ int action = RTM_ADD;
+ u_int16_t labelid;
- if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP))
- == NULL)
- return (0);
+ if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) !=
+ NULL)
+ action = RTM_CHANGE;
- if (!(kr->r.flags & F_BGPD_INSERTED))
+ /* nexthop to loopback -> ignore silently */
+ if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6))
return (0);
- /* nexthop within 127/8 -> ignore silently */
- if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) ==
- htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
- return (0);
+ labelid = rtlabel_name2id(kl->label);
- if (send_rtmsg(kr_state.fd, RTM_DELETE, &kl->kr) == -1)
- return (-1);
+ /* for blackhole and reject routes nexthop needs to be ::1 */
+ if (kl->flags & (F_BLACKHOLE|F_REJECT))
+ bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6));
+
+ if (action == RTM_ADD) {
+ if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
+ log_warn("kr_change");
+ return (-1);
+ }
+ memcpy(&kr6->r.prefix, &kl->prefix.v6, sizeof(struct in6_addr));
+ kr6->r.prefixlen = kl->prefixlen;
+ memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
+ sizeof(struct in6_addr));
+ kr6->r.flags = kl->flags | F_BGPD_INSERTED;
+ kr6->r.priority = RTP_BGP;
+ kr6->r.labelid = labelid;
- rtlabel_unref(kl->kr.labelid);
+ if (kroute6_insert(kt, kr6) == -1)
+ free(kr6);
+ } else {
+ memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
+ sizeof(struct in6_addr));
+ rtlabel_unref(kr6->r.labelid);
+ kr6->r.labelid = labelid;
+ if (kl->flags & F_BLACKHOLE)
+ kr6->r.flags |= F_BLACKHOLE;
+ else
+ kr6->r.flags &= ~F_BLACKHOLE;
+ if (kl->flags & F_REJECT)
+ kr6->r.flags |= F_REJECT;
+ else
+ kr6->r.flags &= ~F_REJECT;
+ }
- if (kroute_remove(kr) == -1)
+ if (send_rt6msg(kr_state.fd, action, kt, &kr6->r) == -1)
return (-1);
return (0);
}
int
-kr6_change(struct kroute6_label *kl)
+krVPN4_change(struct ktable *kt, struct kroute_full *kl)
{
- struct kroute6_node *kr6;
+ struct kroute_node *kr;
int action = RTM_ADD;
- struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
+ u_int32_t mplslabel = 0;
+ u_int16_t labelid;
- if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP))
- != NULL)
+ if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen,
+ RTP_BGP)) != NULL)
action = RTM_CHANGE;
- /* nexthop to loopback -> ignore silently */
- if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop))
+ /* nexthop within 127/8 -> ignore silently */
+ if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) ==
+ htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
return (0);
- if (kr6)
- rtlabel_unref(kr6->r.labelid);
- kl->kr.labelid = rtlabel_name2id(kl->label);
+ /* only single MPLS label are supported for now */
+ if (kl->prefix.vpn4.labellen != 3) {
+ log_warnx("krVPN4_change: %s/%u has not a single label",
+ log_addr(&kl->prefix), kl->prefixlen);
+ return (0);
+ }
+ mplslabel = (kl->prefix.vpn4.labelstack[0] << 24) |
+ (kl->prefix.vpn4.labelstack[1] << 16) |
+ (kl->prefix.vpn4.labelstack[2] << 8);
+ mplslabel = htonl(mplslabel);
- /* for blackhole and reject routes nexthop needs to be ::1 */
- if (kl->kr.flags & (F_BLACKHOLE|F_REJECT))
- bcopy(&lo6, &kl->kr.nexthop, sizeof(kl->kr.nexthop));
+ labelid = rtlabel_name2id(kl->label);
- if (send_rt6msg(kr_state.fd, action, &kl->kr) == -1)
- return (-1);
+ /* for blackhole and reject routes nexthop needs to be 127.0.0.1 */
+ if (kl->flags & (F_BLACKHOLE|F_REJECT))
+ kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
if (action == RTM_ADD) {
- if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
+ if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
log_warn("kr_change");
return (-1);
}
- memcpy(&kr6->r.prefix, &kl->kr.prefix,
- sizeof(struct in6_addr));
- kr6->r.prefixlen = kl->kr.prefixlen;
- memcpy(&kr6->r.nexthop, &kl->kr.nexthop,
- sizeof(struct in6_addr));
- kr6->r.flags = kl->kr.flags | F_BGPD_INSERTED;
- kr6->r.priority = RTP_BGP;
- kr6->r.labelid = kl->kr.labelid;
+ kr->r.prefix.s_addr = kl->prefix.vpn4.addr.s_addr;
+ kr->r.prefixlen = kl->prefixlen;
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ kr->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
+ kr->r.priority = RTP_BGP;
+ kr->r.labelid = labelid;
+ kr->r.mplslabel = mplslabel;
- if (kroute6_insert(kr6) == -1)
- free(kr6);
+ if (kroute_insert(kt, kr) == -1)
+ free(kr);
} else {
- memcpy(&kr6->r.nexthop, &kl->kr.nexthop,
- sizeof(struct in6_addr));
- kr6->r.labelid = kl->kr.labelid;
- if (kl->kr.flags & F_BLACKHOLE)
- kr6->r.flags |= F_BLACKHOLE;
+ kr->r.mplslabel = mplslabel;
+ kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
+ rtlabel_unref(kr->r.labelid);
+ kr->r.labelid = labelid;
+ if (kl->flags & F_BLACKHOLE)
+ kr->r.flags |= F_BLACKHOLE;
else
- kr6->r.flags &= ~F_BLACKHOLE;
- if (kl->kr.flags & F_REJECT)
- kr6->r.flags |= F_REJECT;
+ kr->r.flags &= ~F_BLACKHOLE;
+ if (kl->flags & F_REJECT)
+ kr->r.flags |= F_REJECT;
else
- kr6->r.flags &= ~F_REJECT;
+ kr->r.flags &= ~F_REJECT;
}
+ if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1)
+ return (-1);
+
return (0);
}
int
-kr6_delete(struct kroute6_label *kl)
+kr_delete(u_int rtableid, struct kroute_full *kl)
+{
+ struct ktable *kt;
+
+ if ((kt = ktable_get(rtableid)) == NULL)
+ /* too noisy during reloads, just ignore */
+ return (0);
+
+ switch (kl->prefix.aid) {
+ case AID_INET:
+ return (kr4_delete(kt, kl));
+ case AID_INET6:
+ return (kr6_delete(kt, kl));
+ case AID_VPN_IPv4:
+ return (krVPN4_delete(kt, kl));
+ }
+ log_warnx("kr_change: not handled AID");
+ return (-1);
+}
+
+int
+kr4_delete(struct ktable *kt, struct kroute_full *kl)
+{
+ struct kroute_node *kr;
+
+ if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
+ RTP_BGP)) == NULL)
+ return (0);
+
+ if (!(kr->r.flags & F_BGPD_INSERTED))
+ return (0);
+
+ if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r) == -1)
+ return (-1);
+
+ rtlabel_unref(kr->r.labelid);
+
+ if (kroute_remove(kt, kr) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+kr6_delete(struct ktable *kt, struct kroute_full *kl)
{
struct kroute6_node *kr6;
- if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP))
- == NULL)
+ if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) ==
+ NULL)
return (0);
if (!(kr6->r.flags & F_BGPD_INSERTED))
return (0);
- /* nexthop to loopback -> ignore silently */
- if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop))
+ if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r) == -1)
+ return (-1);
+
+ rtlabel_unref(kr6->r.labelid);
+
+ if (kroute6_remove(kt, kr6) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+krVPN4_delete(struct ktable *kt, struct kroute_full *kl)
+{
+ struct kroute_node *kr;
+
+ if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen,
+ RTP_BGP)) == NULL)
return (0);
- if (send_rt6msg(kr_state.fd, RTM_DELETE, &kl->kr) == -1)
+ if (!(kr->r.flags & F_BGPD_INSERTED))
+ return (0);
+
+ if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r) == -1)
return (-1);
- rtlabel_unref(kl->kr.labelid);
+ rtlabel_unref(kr->r.labelid);
- if (kroute6_remove(kr6) == -1)
+ if (kroute_remove(kt, kr) == -1)
return (-1);
return (0);
@@ -394,53 +758,63 @@ kr6_delete(struct kroute6_label *kl)
void
kr_shutdown(void)
{
- kr_fib_decouple();
- knexthop_clear();
- kroute_clear();
- kroute6_clear();
+ u_int i;
+
+ for (i = krt_size; i > 0; i--)
+ ktable_free(i - 1);
kif_clear();
}
void
-kr_fib_couple(void)
+kr_fib_couple(u_int rtableid)
{
+ struct ktable *kt;
struct kroute_node *kr;
struct kroute6_node *kr6;
- if (kr_state.fib_sync == 1) /* already coupled */
+ if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */
return;
- kr_state.fib_sync = 1;
+ if (kt->fib_sync) /* already coupled */
+ return;
- RB_FOREACH(kr, kroute_tree, &krt)
+ kt->fib_sync = 1;
+
+ RB_FOREACH(kr, kroute_tree, &kt->krt)
if ((kr->r.flags & F_BGPD_INSERTED))
- send_rtmsg(kr_state.fd, RTM_ADD, &kr->r);
- RB_FOREACH(kr6, kroute6_tree, &krt6)
+ send_rtmsg(kr_state.fd, RTM_ADD, kt, &kr->r);
+ RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
if ((kr6->r.flags & F_BGPD_INSERTED))
- send_rt6msg(kr_state.fd, RTM_ADD, &kr6->r);
+ send_rt6msg(kr_state.fd, RTM_ADD, kt, &kr6->r);
- log_info("kernel routing table coupled");
+ log_info("kernel routing table %u (%s) coupled", kt->rtableid,
+ kt->descr);
}
void
-kr_fib_decouple(void)
+kr_fib_decouple(u_int rtableid)
{
+ struct ktable *kt;
struct kroute_node *kr;
struct kroute6_node *kr6;
- if (kr_state.fib_sync == 0) /* already decoupled */
+ if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */
+ return;
+
+ if (!kt->fib_sync) /* already decoupled */
return;
- RB_FOREACH(kr, kroute_tree, &krt)
+ RB_FOREACH(kr, kroute_tree, &kt->krt)
if ((kr->r.flags & F_BGPD_INSERTED))
- send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
- RB_FOREACH(kr6, kroute6_tree, &krt6)
+ send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r);
+ RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
if ((kr6->r.flags & F_BGPD_INSERTED))
- send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r);
+ send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r);
- kr_state.fib_sync = 0;
+ kt->fib_sync = 0;
- log_info("kernel routing table decoupled");
+ log_info("kernel routing table %u (%s) decoupled", kt->rtableid,
+ kt->descr);
}
int
@@ -450,11 +824,16 @@ kr_dispatch_msg(void)
}
int
-kr_nexthop_add(struct bgpd_addr *addr)
+kr_nexthop_add(u_int rtableid, struct bgpd_addr *addr)
{
+ struct ktable *kt;
struct knexthop_node *h;
- if ((h = knexthop_find(addr)) != NULL) {
+ if ((kt = ktable_get(rtableid)) == NULL) {
+ log_warnx("kr_nexthop_add: non-existent rtableid %d", rtableid);
+ return (0);
+ }
+ if ((h = knexthop_find(kt, addr)) != NULL) {
/* should not happen... this is actually an error path */
struct kroute_nexthop nh;
struct kroute_node *k;
@@ -463,25 +842,30 @@ kr_nexthop_add(struct bgpd_addr *addr)
bzero(&nh, sizeof(nh));
memcpy(&nh.nexthop, addr, sizeof(nh.nexthop));
nh.valid = 1;
- if (h->kroute != NULL && addr->af == AF_INET) {
+ if (h->kroute != NULL && addr->aid == AID_INET) {
k = h->kroute;
nh.connected = k->r.flags & F_CONNECTED;
if (k->r.nexthop.s_addr != 0) {
- nh.gateway.af = AF_INET;
+ nh.gateway.aid = AID_INET;
nh.gateway.v4.s_addr =
k->r.nexthop.s_addr;
}
- memcpy(&nh.kr.kr4, &k->r, sizeof(nh.kr.kr4));
- } else if (h->kroute != NULL && addr->af == AF_INET6) {
+ nh.net.aid = AID_INET;
+ nh.net.v4.s_addr = k->r.prefix.s_addr;
+ nh.netlen = k->r.prefixlen;
+ } else if (h->kroute != NULL && addr->aid == AID_INET6) {
k6 = h->kroute;
nh.connected = k6->r.flags & F_CONNECTED;
if (memcmp(&k6->r.nexthop, &in6addr_any,
sizeof(struct in6_addr)) != 0) {
- nh.gateway.af = AF_INET6;
+ nh.gateway.aid = AID_INET6;
memcpy(&nh.gateway.v6, &k6->r.nexthop,
sizeof(struct in6_addr));
}
- memcpy(&nh.kr.kr6, &k6->r, sizeof(nh.kr.kr6));
+ nh.net.aid = AID_INET6;
+ memcpy(&nh.net.v6, &k6->r.nexthop,
+ sizeof(struct in6_addr));
+ nh.netlen = k6->r.prefixlen;
}
send_nexthop_update(&nh);
@@ -492,7 +876,7 @@ kr_nexthop_add(struct bgpd_addr *addr)
}
memcpy(&h->nexthop, addr, sizeof(h->nexthop));
- if (knexthop_insert(h) == -1)
+ if (knexthop_insert(kt, h) == -1)
return (-1);
}
@@ -500,19 +884,25 @@ kr_nexthop_add(struct bgpd_addr *addr)
}
void
-kr_nexthop_delete(struct bgpd_addr *addr)
+kr_nexthop_delete(u_int rtableid, struct bgpd_addr *addr)
{
+ struct ktable *kt;
struct knexthop_node *kn;
- if ((kn = knexthop_find(addr)) == NULL)
+ if ((kt = ktable_get(rtableid)) == NULL) {
+ log_warnx("kr_nexthop_add: non-existent rtableid %d", rtableid);
+ return;
+ }
+ if ((kn = knexthop_find(kt, addr)) == NULL)
return;
- knexthop_remove(kn);
+ knexthop_remove(kt, kn);
}
void
kr_show_route(struct imsg *imsg)
{
+ struct ktable *kt;
struct kroute_node *kr, *kn;
struct kroute6_node *kr6, *kn6;
struct bgpd_addr *addr;
@@ -521,6 +911,7 @@ kr_show_route(struct imsg *imsg)
struct ctl_show_nexthop snh;
struct knexthop_node *h;
struct kif_node *kif;
+ u_int i;
u_short ifindex = 0;
switch (imsg->hdr.type) {
@@ -528,70 +919,96 @@ kr_show_route(struct imsg *imsg)
if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags) +
sizeof(af)) {
log_warnx("kr_show_route: wrong imsg len");
- return;
+ break;
+ }
+ kt = ktable_get(imsg->hdr.peerid);
+ if (kt == NULL) {
+ log_warnx("kr_show_route: table %u does not exist",
+ imsg->hdr.peerid);
+ break;
}
memcpy(&flags, imsg->data, sizeof(flags));
memcpy(&af, (char *)imsg->data + sizeof(flags), sizeof(af));
if (!af || af == AF_INET)
- RB_FOREACH(kr, kroute_tree, &krt)
- if (!flags || kr->r.flags & flags) {
- kn = kr;
- do {
- send_imsg_session(
- IMSG_CTL_KROUTE,
- imsg->hdr.pid, &kn->r,
- sizeof(kn->r));
- } while ((kn = kn->next) != NULL);
- }
+ RB_FOREACH(kr, kroute_tree, &kt->krt) {
+ if (flags && (kr->r.flags & flags) == 0)
+ continue;
+ kn = kr;
+ do {
+ send_imsg_session(IMSG_CTL_KROUTE,
+ imsg->hdr.pid, kr_tofull(&kn->r),
+ sizeof(struct kroute_full));
+ } while ((kn = kn->next) != NULL);
+ }
if (!af || af == AF_INET6)
- RB_FOREACH(kr6, kroute6_tree, &krt6)
- if (!flags || kr6->r.flags & flags) {
- kn6 = kr6;
- do {
- send_imsg_session(
- IMSG_CTL_KROUTE6,
- imsg->hdr.pid, &kn6->r,
- sizeof(kn6->r));
- } while ((kn6 = kn6->next) != NULL);
- }
+ RB_FOREACH(kr6, kroute6_tree, &kt->krt6) {
+ if (flags && (kr6->r.flags & flags) == 0)
+ continue;
+ kn6 = kr6;
+ do {
+ send_imsg_session(IMSG_CTL_KROUTE,
+ imsg->hdr.pid, kr6_tofull(&kn6->r),
+ sizeof(struct kroute_full));
+ } while ((kn6 = kn6->next) != NULL);
+ }
break;
case IMSG_CTL_KROUTE_ADDR:
if (imsg->hdr.len != IMSG_HEADER_SIZE +
sizeof(struct bgpd_addr)) {
log_warnx("kr_show_route: wrong imsg len");
- return;
+ break;
+ }
+ kt = ktable_get(imsg->hdr.peerid);
+ if (kt == NULL) {
+ log_warnx("kr_show_route: table %u does not exist",
+ imsg->hdr.peerid);
+ break;
}
addr = imsg->data;
kr = NULL;
- switch (addr->af) {
- case AF_INET:
- kr = kroute_match(addr->v4.s_addr, 1);
+ switch (addr->aid) {
+ case AID_INET:
+ kr = kroute_match(kt, addr->v4.s_addr, 1);
if (kr != NULL)
send_imsg_session(IMSG_CTL_KROUTE,
- imsg->hdr.pid, &kr->r, sizeof(kr->r));
+ imsg->hdr.pid, kr_tofull(&kr->r),
+ sizeof(struct kroute_full));
break;
- case AF_INET6:
- kr6 = kroute6_match(&addr->v6, 1);
+ case AID_INET6:
+ kr6 = kroute6_match(kt, &addr->v6, 1);
if (kr6 != NULL)
- send_imsg_session(IMSG_CTL_KROUTE6,
- imsg->hdr.pid, &kr6->r, sizeof(kr6->r));
+ send_imsg_session(IMSG_CTL_KROUTE,
+ imsg->hdr.pid, kr6_tofull(&kr6->r),
+ sizeof(struct kroute_full));
break;
}
break;
case IMSG_CTL_SHOW_NEXTHOP:
- RB_FOREACH(h, knexthop_tree, &knt) {
+ kt = ktable_get(imsg->hdr.peerid);
+ if (kt == NULL) {
+ log_warnx("kr_show_route: table %u does not exist",
+ imsg->hdr.peerid);
+ break;
+ }
+ RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) {
bzero(&snh, sizeof(snh));
memcpy(&snh.addr, &h->nexthop, sizeof(snh.addr));
if (h->kroute != NULL) {
- switch (h->nexthop.af) {
- case AF_INET:
+ switch (h->nexthop.aid) {
+ case AID_INET:
kr = h->kroute;
snh.valid = kroute_validate(&kr->r);
+ snh.krvalid = 1;
+ memcpy(&snh.kr.kr4, &kr->r,
+ sizeof(snh.kr.kr4));
ifindex = kr->r.ifindex;
break;
- case AF_INET6:
+ case AID_INET6:
kr6 = h->kroute;
snh.valid = kroute6_validate(&kr6->r);
+ snh.krvalid = 1;
+ memcpy(&snh.kr.kr6, &kr6->r,
+ sizeof(snh.kr.kr6));
ifindex = kr6->r.ifindex;
break;
}
@@ -608,6 +1025,24 @@ kr_show_route(struct imsg *imsg)
send_imsg_session(IMSG_CTL_SHOW_INTERFACE,
imsg->hdr.pid, &kif->k, sizeof(kif->k));
break;
+ case IMSG_CTL_SHOW_FIB_TABLES:
+ for (i = 0; i < krt_size; i++) {
+ struct ktable ktab;
+
+ if ((kt = ktable_get(i)) == NULL)
+ continue;
+
+ ktab = *kt;
+ /* do not leak internal information */
+ RB_INIT(&ktab.krt);
+ RB_INIT(&ktab.krt6);
+ RB_INIT(&ktab.knt);
+ TAILQ_INIT(&ktab.krn);
+
+ send_imsg_session(IMSG_CTL_SHOW_FIB_TABLES,
+ imsg->hdr.pid, &ktab, sizeof(ktab));
+ }
+ break;
default: /* nada */
break;
}
@@ -628,21 +1063,146 @@ kr_ifinfo(char *ifname)
}
}
-struct redist_node {
- LIST_ENTRY(redist_node) entry;
- struct kroute *kr;
- struct kroute6 *kr6;
-};
+void
+kr_net_delete(struct network *n)
+{
+ filterset_free(&n->net.attrset);
+ free(n);
+}
+
+struct network *
+kr_net_match(struct ktable *kt, struct kroute *kr)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (xn->net.prefix.aid != AID_INET)
+ continue;
+ switch (xn->net.type) {
+ case NETWORK_DEFAULT:
+ if (xn->net.prefixlen == kr->prefixlen &&
+ xn->net.prefix.v4.s_addr == kr->prefix.s_addr)
+ /* static match already redistributed */
+ return (NULL);
+ break;
+ case NETWORK_STATIC:
+ if (kr->flags & F_STATIC)
+ return (xn);
+ break;
+ case NETWORK_CONNECTED:
+ if (kr->flags & F_CONNECTED)
+ return (xn);
+ break;
+ }
+ }
+ return (NULL);
+}
+struct network *
+kr_net_match6(struct ktable *kt, struct kroute6 *kr6)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (xn->net.prefix.aid != AID_INET6)
+ continue;
+ switch (xn->net.type) {
+ case NETWORK_DEFAULT:
+ if (xn->net.prefixlen == kr6->prefixlen &&
+ memcmp(&xn->net.prefix.v6, &kr6->prefix,
+ sizeof(struct in6_addr)) == 0)
+ /* static match already redistributed */
+ return (NULL);
+ break;
+ case NETWORK_STATIC:
+ if (kr6->flags & F_STATIC)
+ return (xn);
+ break;
+ case NETWORK_CONNECTED:
+ if (kr6->flags & F_CONNECTED)
+ return (xn);
+ break;
+ }
+ }
+ return (NULL);
+}
-LIST_HEAD(, redist_node) redistlist;
+struct network *
+kr_net_find(struct ktable *kt, struct network *n)
+{
+ struct network *xn;
+
+ TAILQ_FOREACH(xn, &kt->krn, entry) {
+ if (n->net.type != xn->net.type ||
+ n->net.prefixlen != xn->net.prefixlen ||
+ n->net.rtableid != xn->net.rtableid)
+ continue;
+ if (memcmp(&n->net.prefix, &xn->net.prefix,
+ sizeof(n->net.prefix)) == 0)
+ return (xn);
+ }
+ return (NULL);
+}
+
+int
+kr_net_reload(u_int rtableid, struct network_head *nh)
+{
+ struct network *n, *xn;
+ struct ktable *kt;
+
+ if ((kt = ktable_get(rtableid)) == NULL) {
+ log_warnx("kr_net_reload: non-existent rtableid %d", rtableid);
+ return (-1);
+ }
+
+ TAILQ_FOREACH(n, &kt->krn, entry)
+ n->net.old = 1;
+
+ while ((n = TAILQ_FIRST(nh)) != NULL) {
+ TAILQ_REMOVE(nh, n, entry);
+ n->net.old = 0;
+ n->net.rtableid = rtableid;
+ xn = kr_net_find(kt, n);
+ if (xn) {
+ xn->net.old = 0;
+ filterset_free(&xn->net.attrset);
+ filterset_move(&n->net.attrset, &xn->net.attrset);
+ kr_net_delete(n);
+ } else
+ TAILQ_INSERT_TAIL(&kt->krn, n, entry);
+ }
+
+ for (n = TAILQ_FIRST(&kt->krn); n != NULL; n = xn) {
+ xn = TAILQ_NEXT(n, entry);
+ if (n->net.old) {
+ if (n->net.type == NETWORK_DEFAULT)
+ if (send_network(IMSG_NETWORK_REMOVE, &n->net,
+ NULL))
+ return (-1);
+ TAILQ_REMOVE(&kt->krn, n, entry);
+ kr_net_delete(n);
+ }
+ }
+
+ return (0);
+}
int
-kr_redistribute(int type, struct kroute *kr)
+kr_redistribute(int type, struct ktable *kt, struct kroute *kr)
{
- struct redist_node *rn;
+ struct network *match;
+ struct network_config net;
u_int32_t a;
+ /* shortcut for removals */
+ if (type == IMSG_NETWORK_REMOVE) {
+ if (!(kr->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ kr->flags &= ~F_REDISTRIBUTED;
+ match = NULL;
+ goto sendit;
+ }
+
if (!(kr->flags & F_KERNEL))
return (0);
@@ -670,41 +1230,40 @@ kr_redistribute(int type, struct kroute *kr)
if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0)
return (0);
- /* Add or delete kr from list ... */
- LIST_FOREACH(rn, &redistlist, entry)
- if (rn->kr == kr)
- break;
+ match = kr_net_match(kt, kr);
+ if (match == NULL) {
+ if (!(kr->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ /* route no longer matches but is redistributed, so remove */
+ kr->flags &= ~F_REDISTRIBUTED;
+ type = IMSG_NETWORK_REMOVE;
+ } else
+ kr->flags |= F_REDISTRIBUTED;
- switch (type) {
- case IMSG_NETWORK_ADD:
- if (rn == NULL) {
- if ((rn = calloc(1, sizeof(struct redist_node))) ==
- NULL) {
- log_warn("kr_redistribute");
- return (-1);
- }
- rn->kr = kr;
- LIST_INSERT_HEAD(&redistlist, rn, entry);
- }
- break;
- case IMSG_NETWORK_REMOVE:
- if (rn != NULL) {
- LIST_REMOVE(rn, entry);
- free(rn);
- }
- break;
- default:
- errno = EINVAL;
- return (-1);
- }
+sendit:
+ bzero(&net, sizeof(net));
+ net.prefix.aid = AID_INET;
+ net.prefix.v4.s_addr = kr->prefix.s_addr;
+ net.prefixlen = kr->prefixlen;
+ net.rtableid = kt->rtableid;
- return (bgpd_redistribute(type, kr, NULL));
+ return (send_network(type, &net, match ? &match->net.attrset : NULL));
}
int
-kr_redistribute6(int type, struct kroute6 *kr6)
+kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6)
{
- struct redist_node *rn;
+ struct network *match;
+ struct network_config net;
+
+ /* shortcut for removals */
+ if (type == IMSG_NETWORK_REMOVE) {
+ if (!(kr6->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ kr6->flags &= ~F_REDISTRIBUTED;
+ match = NULL;
+ goto sendit;
+ }
if (!(kr6->flags & F_KERNEL))
return (0);
@@ -736,60 +1295,107 @@ kr_redistribute6(int type, struct kroute6 *kr6)
* never allow ::/0 the default route can only be redistributed
* with announce default.
*/
- if (memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0 &&
- kr6->prefixlen == 0)
+ if (kr6->prefixlen == 0 &&
+ memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0)
return (0);
- /* Add or delete kr from list ...
- * using a linear list to store the redistributed networks will hurt
- * as soon as redistribute ospf comes but until then keep it simple.
- */
- LIST_FOREACH(rn, &redistlist, entry)
- if (rn->kr6 == kr6)
- break;
-
- switch (type) {
- case IMSG_NETWORK_ADD:
- if (rn == NULL) {
- if ((rn = calloc(1, sizeof(struct redist_node))) ==
- NULL) {
- log_warn("kr_redistribute");
- return (-1);
- }
- rn->kr6 = kr6;
- LIST_INSERT_HEAD(&redistlist, rn, entry);
- }
- break;
- case IMSG_NETWORK_REMOVE:
- if (rn != NULL) {
- LIST_REMOVE(rn, entry);
- free(rn);
- }
- break;
- default:
- errno = EINVAL;
- return (-1);
- }
-
- return (bgpd_redistribute(type, NULL, kr6));
+ match = kr_net_match6(kt, kr6);
+ if (match == NULL) {
+ if (!(kr6->flags & F_REDISTRIBUTED))
+ return (0); /* no match, don't redistribute */
+ /* route no longer matches but is redistributed, so remove */
+ kr6->flags &= ~F_REDISTRIBUTED;
+ type = IMSG_NETWORK_REMOVE;
+ } else
+ kr6->flags |= F_REDISTRIBUTED;
+sendit:
+ bzero(&net, sizeof(net));
+ net.prefix.aid = AID_INET6;
+ memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
+ net.prefixlen = kr6->prefixlen;
+ net.rtableid = kt->rtableid;
+
+ return (send_network(type, &net, match ? &match->net.attrset : NULL));
}
int
kr_reload(void)
{
- struct redist_node *rn;
+ struct ktable *kt;
+ struct kroute_node *kr;
+ struct kroute6_node *kr6;
struct knexthop_node *nh;
+ struct network *n;
+ u_int rid;
+ int hasdyn = 0;
- LIST_FOREACH(rn, &redistlist, entry)
- if (bgpd_redistribute(IMSG_NETWORK_ADD, rn->kr, rn->kr6) == -1)
- return (-1);
+ for (rid = 0; rid < krt_size; rid++) {
+ if ((kt = ktable_get(rid)) == NULL)
+ continue;
- RB_FOREACH(nh, knexthop_tree, &knt)
- knexthop_validate(nh);
+ RB_FOREACH(nh, knexthop_tree, KT2KNT(kt))
+ knexthop_validate(kt, nh);
+
+ TAILQ_FOREACH(n, &kt->krn, entry)
+ if (n->net.type == NETWORK_DEFAULT) {
+ if (send_network(IMSG_NETWORK_ADD, &n->net,
+ &n->net.attrset))
+ return (-1);
+ } else
+ hasdyn = 1;
+
+ if (hasdyn) {
+ /* only evaluate the full tree if we need */
+ RB_FOREACH(kr, kroute_tree, &kt->krt)
+ kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r);
+ RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
+ kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr6->r);
+ }
+ }
return (0);
}
+struct kroute_full *
+kr_tofull(struct kroute *kr)
+{
+ static struct kroute_full kf;
+
+ bzero(&kf, sizeof(kf));
+
+ kf.prefix.aid = AID_INET;
+ kf.prefix.v4.s_addr = kr->prefix.s_addr;
+ kf.nexthop.aid = AID_INET;
+ kf.nexthop.v4.s_addr = kr->nexthop.s_addr;
+ strlcpy(kf.label, rtlabel_id2name(kr->labelid), sizeof(kf.label));
+ kf.flags = kr->flags;
+ kf.ifindex = kr->ifindex;
+ kf.prefixlen = kr->prefixlen;
+ kf.priority = kr->priority;
+
+ return (&kf);
+}
+
+struct kroute_full *
+kr6_tofull(struct kroute6 *kr6)
+{
+ static struct kroute_full kf;
+
+ bzero(&kf, sizeof(kf));
+
+ kf.prefix.aid = AID_INET6;
+ memcpy(&kf.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
+ kf.nexthop.aid = AID_INET6;
+ memcpy(&kf.nexthop.v6, &kr6->nexthop, sizeof(struct in6_addr));
+ strlcpy(kf.label, rtlabel_id2name(kr6->labelid), sizeof(kf.label));
+ kf.flags = kr6->flags;
+ kf.ifindex = kr6->ifindex;
+ kf.prefixlen = kr6->prefixlen;
+ kf.priority = kr6->priority;
+
+ return (&kf);
+}
+
/*
* RB-tree compare functions
*/
@@ -846,26 +1452,28 @@ kroute6_compare(struct kroute6_node *a, struct kroute6_node *b)
int
knexthop_compare(struct knexthop_node *a, struct knexthop_node *b)
{
- u_int32_t r;
+ int i;
- if (a->nexthop.af != b->nexthop.af)
- return (b->nexthop.af - a->nexthop.af);
+ if (a->nexthop.aid != b->nexthop.aid)
+ return (b->nexthop.aid - a->nexthop.aid);
- switch (a->nexthop.af) {
- case AF_INET:
- if ((r = b->nexthop.addr32[0] - a->nexthop.addr32[0]) != 0)
- return (r);
+ switch (a->nexthop.aid) {
+ case AID_INET:
+ if (ntohl(a->nexthop.v4.s_addr) < ntohl(b->nexthop.v4.s_addr))
+ return (-1);
+ if (ntohl(a->nexthop.v4.s_addr) > ntohl(b->nexthop.v4.s_addr))
+ return (1);
break;
- case AF_INET6:
- if ((r = b->nexthop.addr32[3] - a->nexthop.addr32[3]) != 0)
- return (r);
- if ((r = b->nexthop.addr32[2] - a->nexthop.addr32[2]) != 0)
- return (r);
- if ((r = b->nexthop.addr32[1] - a->nexthop.addr32[1]) != 0)
- return (r);
- if ((r = b->nexthop.addr32[0] - a->nexthop.addr32[0]) != 0)
- return (r);
+ case AID_INET6:
+ for (i = 0; i < 16; i++) {
+ if (a->nexthop.v6.s6_addr[i] < b->nexthop.v6.s6_addr[i])
+ return (-1);
+ if (a->nexthop.v6.s6_addr[i] > b->nexthop.v6.s6_addr[i])
+ return (1);
+ }
break;
+ default:
+ fatalx("knexthop_compare: unknown AF");
}
return (0);
@@ -883,7 +1491,8 @@ kif_compare(struct kif_node *a, struct kif_node *b)
*/
struct kroute_node *
-kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
+kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen,
+ u_int8_t prio)
{
struct kroute_node s;
struct kroute_node *kn, *tmp;
@@ -892,15 +1501,15 @@ kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
s.r.prefixlen = prefixlen;
s.r.priority = prio;
- kn = RB_FIND(kroute_tree, &krt, &s);
+ kn = RB_FIND(kroute_tree, &kt->krt, &s);
if (kn && prio == RTP_ANY) {
- tmp = RB_PREV(kroute_tree, &krt, kn);
+ tmp = RB_PREV(kroute_tree, &kt->krt, kn);
while (tmp) {
if (kroute_compare(&s, tmp) == 0)
kn = tmp;
else
break;
- tmp = RB_PREV(kroute_tree, &krt, kn);
+ tmp = RB_PREV(kroute_tree, &kt->krt, kn);
}
}
return (kn);
@@ -927,13 +1536,13 @@ kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
}
int
-kroute_insert(struct kroute_node *kr)
+kroute_insert(struct ktable *kt, struct kroute_node *kr)
{
struct kroute_node *krm;
struct knexthop_node *h;
in_addr_t mask, ina;
- if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
+ if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) {
/* multipath route, add at end of list */
while (krm->next != NULL)
krm = krm->next;
@@ -944,10 +1553,10 @@ kroute_insert(struct kroute_node *kr)
if (kr->r.flags & F_KERNEL) {
mask = prefixlen2mask(kr->r.prefixlen);
ina = ntohl(kr->r.prefix.s_addr);
- RB_FOREACH(h, knexthop_tree, &knt)
- if (h->nexthop.af == AF_INET &&
+ RB_FOREACH(h, knexthop_tree, KT2KNT(kt))
+ if (h->nexthop.aid == AID_INET &&
(ntohl(h->nexthop.v4.s_addr) & mask) == ina)
- knexthop_validate(h);
+ knexthop_validate(kt, h);
if (kr->r.flags & F_CONNECTED)
if (kif_kr_insert(kr) == -1)
@@ -955,19 +1564,19 @@ kroute_insert(struct kroute_node *kr)
if (krm == NULL)
/* redistribute multipath routes only once */
- kr_redistribute(IMSG_NETWORK_ADD, &kr->r);
+ kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r);
}
return (0);
}
int
-kroute_remove(struct kroute_node *kr)
+kroute_remove(struct ktable *kt, struct kroute_node *kr)
{
struct kroute_node *krm;
struct knexthop_node *s;
- if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) {
+ if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) {
log_warnx("kroute_remove failed to find %s/%u",
inet_ntoa(kr->r.prefix), kr->r.prefixlen);
return (-1);
@@ -975,13 +1584,14 @@ kroute_remove(struct kroute_node *kr)
if (krm == kr) {
/* head element */
- if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) {
+ if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) {
log_warnx("kroute_remove failed for %s/%u",
inet_ntoa(kr->r.prefix), kr->r.prefixlen);
return (-1);
}
if (kr->next != NULL) {
- if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) {
+ if (RB_INSERT(kroute_tree, &kt->krt, kr->next) !=
+ NULL) {
log_warnx("kroute_remove failed to add %s/%u",
inet_ntoa(kr->r.prefix), kr->r.prefixlen);
return (-1);
@@ -1002,13 +1612,13 @@ kroute_remove(struct kroute_node *kr)
/* check whether a nexthop depends on this kroute */
if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP))
- RB_FOREACH(s, knexthop_tree, &knt)
+ RB_FOREACH(s, knexthop_tree, KT2KNT(kt))
if (s->kroute == kr)
- knexthop_validate(s);
+ knexthop_validate(kt, s);
if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL)
/* again remove only once */
- kr_redistribute(IMSG_NETWORK_REMOVE, &kr->r);
+ kr_redistribute(IMSG_NETWORK_REMOVE, kt, &kr->r);
if (kr->r.flags & F_CONNECTED)
if (kif_kr_remove(kr) == -1) {
@@ -1021,16 +1631,17 @@ kroute_remove(struct kroute_node *kr)
}
void
-kroute_clear(void)
+kroute_clear(struct ktable *kt)
{
struct kroute_node *kr;
- while ((kr = RB_MIN(kroute_tree, &krt)) != NULL)
- kroute_remove(kr);
+ while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL)
+ kroute_remove(kt, kr);
}
struct kroute6_node *
-kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio)
+kroute6_find(struct ktable *kt, const struct in6_addr *prefix,
+ u_int8_t prefixlen, u_int8_t prio)
{
struct kroute6_node s;
struct kroute6_node *kn6, *tmp;
@@ -1039,15 +1650,15 @@ kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio)
s.r.prefixlen = prefixlen;
s.r.priority = prio;
- kn6 = RB_FIND(kroute6_tree, &krt6, &s);
+ kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s);
if (kn6 && prio == RTP_ANY) {
- tmp = RB_PREV(kroute6_tree, &krt6, kn6);
+ tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
while (tmp) {
if (kroute6_compare(&s, tmp) == 0)
kn6 = tmp;
- else
+ else
break;
- tmp = RB_PREV(kroute6_tree, &krt6, kn6);
+ tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
}
}
return (kn6);
@@ -1065,7 +1676,7 @@ kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
while (kr) {
- if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == NULL)
+ if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
return (kr);
kr = kr->next;
}
@@ -1074,13 +1685,13 @@ kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
}
int
-kroute6_insert(struct kroute6_node *kr)
+kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
{
struct kroute6_node *krm;
struct knexthop_node *h;
struct in6_addr ina, inb;
- if ((krm = RB_INSERT(kroute6_tree, &krt6, kr)) != NULL) {
+ if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) {
/* multipath route, add at end of list */
while (krm->next != NULL)
krm = krm->next;
@@ -1090,12 +1701,12 @@ kroute6_insert(struct kroute6_node *kr)
if (kr->r.flags & F_KERNEL) {
inet6applymask(&ina, &kr->r.prefix, kr->r.prefixlen);
- RB_FOREACH(h, knexthop_tree, &knt)
- if (h->nexthop.af == AF_INET6) {
+ RB_FOREACH(h, knexthop_tree, KT2KNT(kt))
+ if (h->nexthop.aid == AID_INET6) {
inet6applymask(&inb, &h->nexthop.v6,
kr->r.prefixlen);
if (memcmp(&ina, &inb, sizeof(ina)) == 0)
- knexthop_validate(h);
+ knexthop_validate(kt, h);
}
if (kr->r.flags & F_CONNECTED)
@@ -1104,19 +1715,19 @@ kroute6_insert(struct kroute6_node *kr)
if (krm == NULL)
/* redistribute multipath routes only once */
- kr_redistribute6(IMSG_NETWORK_ADD, &kr->r);
+ kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr->r);
}
return (0);
}
int
-kroute6_remove(struct kroute6_node *kr)
+kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
{
struct kroute6_node *krm;
struct knexthop_node *s;
- if ((krm = RB_FIND(kroute6_tree, &krt6, kr)) == NULL) {
+ if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) {
log_warnx("kroute6_remove failed for %s/%u",
log_in6addr(&kr->r.prefix), kr->r.prefixlen);
return (-1);
@@ -1124,13 +1735,14 @@ kroute6_remove(struct kroute6_node *kr)
if (krm == kr) {
/* head element */
- if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) {
+ if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) {
log_warnx("kroute6_remove failed for %s/%u",
log_in6addr(&kr->r.prefix), kr->r.prefixlen);
return (-1);
}
if (kr->next != NULL) {
- if (RB_INSERT(kroute6_tree, &krt6, kr->next) != NULL) {
+ if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) !=
+ NULL) {
log_warnx("kroute6_remove failed to add %s/%u",
log_in6addr(&kr->r.prefix),
kr->r.prefixlen);
@@ -1152,13 +1764,13 @@ kroute6_remove(struct kroute6_node *kr)
/* check whether a nexthop depends on this kroute */
if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP))
- RB_FOREACH(s, knexthop_tree, &knt)
+ RB_FOREACH(s, knexthop_tree, KT2KNT(kt))
if (s->kroute == kr)
- knexthop_validate(s);
+ knexthop_validate(kt, s);
if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL)
/* again remove only once */
- kr_redistribute6(IMSG_NETWORK_REMOVE, &kr->r);
+ kr_redistribute6(IMSG_NETWORK_REMOVE, kt, &kr->r);
if (kr->r.flags & F_CONNECTED)
if (kif_kr6_remove(kr) == -1) {
@@ -1171,45 +1783,46 @@ kroute6_remove(struct kroute6_node *kr)
}
void
-kroute6_clear(void)
+kroute6_clear(struct ktable *kt)
{
struct kroute6_node *kr;
- while ((kr = RB_MIN(kroute6_tree, &krt6)) != NULL)
- kroute6_remove(kr);
+ while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL)
+ kroute6_remove(kt, kr);
}
struct knexthop_node *
-knexthop_find(struct bgpd_addr *addr)
+knexthop_find(struct ktable *kt, struct bgpd_addr *addr)
{
struct knexthop_node s;
+ bzero(&s, sizeof(s));
memcpy(&s.nexthop, addr, sizeof(s.nexthop));
- return (RB_FIND(knexthop_tree, &knt, &s));
+ return (RB_FIND(knexthop_tree, KT2KNT(kt), &s));
}
int
-knexthop_insert(struct knexthop_node *kn)
+knexthop_insert(struct ktable *kt, struct knexthop_node *kn)
{
- if (RB_INSERT(knexthop_tree, &knt, kn) != NULL) {
+ if (RB_INSERT(knexthop_tree, KT2KNT(kt), kn) != NULL) {
log_warnx("knexthop_tree insert failed for %s",
log_addr(&kn->nexthop));
free(kn);
return (-1);
}
- knexthop_validate(kn);
+ knexthop_validate(kt, kn);
return (0);
}
int
-knexthop_remove(struct knexthop_node *kn)
+knexthop_remove(struct ktable *kt, struct knexthop_node *kn)
{
- kroute_detach_nexthop(kn);
+ kroute_detach_nexthop(kt, kn);
- if (RB_REMOVE(knexthop_tree, &knt, kn) == NULL) {
+ if (RB_REMOVE(knexthop_tree, KT2KNT(kt), kn) == NULL) {
log_warnx("knexthop_remove failed for %s",
log_addr(&kn->nexthop));
return (-1);
@@ -1220,12 +1833,12 @@ knexthop_remove(struct knexthop_node *kn)
}
void
-knexthop_clear(void)
+knexthop_clear(struct ktable *kt)
{
struct knexthop_node *kn;
- while ((kn = RB_MIN(knexthop_tree, &knt)) != NULL)
- knexthop_remove(kn);
+ while ((kn = RB_MIN(knexthop_tree, KT2KNT(kt))) != NULL)
+ knexthop_remove(kt, kn);
}
struct kif_node *
@@ -1257,6 +1870,7 @@ kif_insert(struct kif_node *kif)
int
kif_remove(struct kif_node *kif)
{
+ struct ktable *kt;
struct kif_kr *kkr;
struct kif_kr6 *kkr6;
@@ -1265,20 +1879,23 @@ kif_remove(struct kif_node *kif)
return (-1);
}
+ if ((kt = ktable_get(/* XXX */ 0)) == NULL)
+ goto done;
+
while ((kkr = LIST_FIRST(&kif->kroute_l)) != NULL) {
LIST_REMOVE(kkr, entry);
kkr->kr->r.flags &= ~F_NEXTHOP;
- kroute_remove(kkr->kr);
+ kroute_remove(kt, kkr->kr);
free(kkr);
}
while ((kkr6 = LIST_FIRST(&kif->kroute6_l)) != NULL) {
LIST_REMOVE(kkr6, entry);
kkr6->kr->r.flags &= ~F_NEXTHOP;
- kroute6_remove(kkr6->kr);
+ kroute6_remove(kt, kkr6->kr);
free(kkr6);
}
-
+done:
free(kif);
return (0);
}
@@ -1473,25 +2090,25 @@ kroute6_validate(struct kroute6 *kr)
}
void
-knexthop_validate(struct knexthop_node *kn)
+knexthop_validate(struct ktable *kt, struct knexthop_node *kn)
{
struct kroute_node *kr;
struct kroute6_node *kr6;
struct kroute_nexthop n;
int was_valid = 0;
- if (kn->nexthop.af == AF_INET && (kr = kn->kroute) != NULL)
+ if (kn->nexthop.aid == AID_INET && (kr = kn->kroute) != NULL)
was_valid = kroute_validate(&kr->r);
- if (kn->nexthop.af == AF_INET6 && (kr6 = kn->kroute) != NULL)
+ if (kn->nexthop.aid == AID_INET6 && (kr6 = kn->kroute) != NULL)
was_valid = kroute6_validate(&kr6->r);
bzero(&n, sizeof(n));
memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop));
- kroute_detach_nexthop(kn);
+ kroute_detach_nexthop(kt, kn);
- switch (kn->nexthop.af) {
- case AF_INET:
- if ((kr = kroute_match(kn->nexthop.v4.s_addr, 0)) == NULL) {
+ switch (kn->nexthop.aid) {
+ case AID_INET:
+ if ((kr = kroute_match(kt, kn->nexthop.v4.s_addr, 0)) == NULL) {
if (was_valid)
send_nexthop_update(&n);
} else { /* match */
@@ -1500,8 +2117,10 @@ knexthop_validate(struct knexthop_node *kn)
n.connected = kr->r.flags & F_CONNECTED;
if ((n.gateway.v4.s_addr =
kr->r.nexthop.s_addr) != 0)
- n.gateway.af = AF_INET;
- memcpy(&n.kr.kr4, &kr->r, sizeof(n.kr.kr4));
+ n.gateway.aid = AID_INET;
+ n.net.aid = AID_INET;
+ n.net.v4.s_addr = kr->r.prefix.s_addr;
+ n.netlen = kr->r.prefixlen;
send_nexthop_update(&n);
} else /* down */
if (was_valid)
@@ -1511,8 +2130,8 @@ knexthop_validate(struct knexthop_node *kn)
kr->r.flags |= F_NEXTHOP;
}
break;
- case AF_INET6:
- if ((kr6 = kroute6_match(&kn->nexthop.v6, 0)) == NULL) {
+ case AID_INET6:
+ if ((kr6 = kroute6_match(kt, &kn->nexthop.v6, 0)) == NULL) {
if (was_valid)
send_nexthop_update(&n);
} else { /* match */
@@ -1521,11 +2140,14 @@ knexthop_validate(struct knexthop_node *kn)
n.connected = kr6->r.flags & F_CONNECTED;
if (memcmp(&kr6->r.nexthop, &in6addr_any,
sizeof(struct in6_addr)) != 0) {
- n.gateway.af = AF_INET6;
+ n.gateway.aid = AID_INET6;
memcpy(&n.gateway.v6, &kr6->r.nexthop,
sizeof(struct in6_addr));
}
- memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6));
+ n.net.aid = AID_INET6;
+ memcpy(&n.net.v6, &kr6->r.nexthop,
+ sizeof(struct in6_addr));
+ n.netlen = kr6->r.prefixlen;
send_nexthop_update(&n);
} else /* down */
if (was_valid)
@@ -1539,39 +2161,44 @@ knexthop_validate(struct knexthop_node *kn)
}
void
-knexthop_track(void *krn)
+knexthop_track(struct ktable *kt, void *krp)
{
struct knexthop_node *kn;
struct kroute_node *kr;
struct kroute6_node *kr6;
struct kroute_nexthop n;
- RB_FOREACH(kn, knexthop_tree, &knt)
- if (kn->kroute == krn) {
+ RB_FOREACH(kn, knexthop_tree, KT2KNT(kt))
+ if (kn->kroute == krp) {
bzero(&n, sizeof(n));
memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop));
- switch (kn->nexthop.af) {
- case AF_INET:
- kr = krn;
+ switch (kn->nexthop.aid) {
+ case AID_INET:
+ kr = krp;
n.valid = 1;
n.connected = kr->r.flags & F_CONNECTED;
if ((n.gateway.v4.s_addr =
kr->r.nexthop.s_addr) != 0)
- n.gateway.af = AF_INET;
- memcpy(&n.kr.kr4, &kr->r, sizeof(n.kr.kr4));
+ n.gateway.aid = AID_INET;
+ n.net.aid = AID_INET;
+ n.net.v4.s_addr = kr->r.prefix.s_addr;
+ n.netlen = kr->r.prefixlen;
break;
- case AF_INET6:
- kr6 = krn;
+ case AID_INET6:
+ kr6 = krp;
n.valid = 1;
n.connected = kr6->r.flags & F_CONNECTED;
if (memcmp(&kr6->r.nexthop, &in6addr_any,
sizeof(struct in6_addr)) != 0) {
- n.gateway.af = AF_INET6;
+ n.gateway.aid = AID_INET6;
memcpy(&n.gateway.v6, &kr6->r.nexthop,
sizeof(struct in6_addr));
}
- memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6));
+ n.net.aid = AID_INET6;
+ memcpy(&n.net.v6, &kr6->r.nexthop,
+ sizeof(struct in6_addr));
+ n.netlen = kr6->r.prefixlen;
break;
}
send_nexthop_update(&n);
@@ -1579,7 +2206,7 @@ knexthop_track(void *krn)
}
struct kroute_node *
-kroute_match(in_addr_t key, int matchall)
+kroute_match(struct ktable *kt, in_addr_t key, int matchall)
{
int i;
struct kroute_node *kr;
@@ -1589,13 +2216,13 @@ kroute_match(in_addr_t key, int matchall)
/* we will never match the default route */
for (i = 32; i > 0; i--)
- if ((kr = kroute_find(htonl(ina & prefixlen2mask(i)), i,
+ if ((kr = kroute_find(kt, htonl(ina & prefixlen2mask(i)), i,
RTP_ANY)) != NULL)
if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0)
return (kr);
/* if we don't have a match yet, try to find a default route */
- if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL)
+ if ((kr = kroute_find(kt, 0, 0, RTP_ANY)) != NULL)
if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0)
return (kr);
@@ -1603,7 +2230,7 @@ kroute_match(in_addr_t key, int matchall)
}
struct kroute6_node *
-kroute6_match(struct in6_addr *key, int matchall)
+kroute6_match(struct ktable *kt, struct in6_addr *key, int matchall)
{
int i;
struct kroute6_node *kr6;
@@ -1612,13 +2239,13 @@ kroute6_match(struct in6_addr *key, int matchall)
/* we will never match the default route */
for (i = 128; i > 0; i--) {
inet6applymask(&ina, key, i);
- if ((kr6 = kroute6_find(&ina, i, RTP_ANY)) != NULL)
+ if ((kr6 = kroute6_find(kt, &ina, i, RTP_ANY)) != NULL)
if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0)
return (kr6);
}
/* if we don't have a match yet, try to find a default route */
- if ((kr6 = kroute6_find(&in6addr_any, 0, RTP_ANY)) != NULL)
+ if ((kr6 = kroute6_find(kt, &in6addr_any, 0, RTP_ANY)) != NULL)
if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0)
return (kr6);
@@ -1626,7 +2253,7 @@ kroute6_match(struct in6_addr *key, int matchall)
}
void
-kroute_detach_nexthop(struct knexthop_node *kn)
+kroute_detach_nexthop(struct ktable *kt, struct knexthop_node *kn)
{
struct knexthop_node *s;
struct kroute_node *k;
@@ -1640,17 +2267,17 @@ kroute_detach_nexthop(struct knexthop_node *kn)
if (kn->kroute == NULL)
return;
- for (s = RB_MIN(knexthop_tree, &knt); s != NULL &&
- s->kroute != kn->kroute; s = RB_NEXT(knexthop_tree, &knt, s))
+ for (s = RB_MIN(knexthop_tree, KT2KNT(kt)); s != NULL &&
+ s->kroute != kn->kroute; s = RB_NEXT(knexthop_tree, KT2KNT(kt), s))
; /* nothing */
if (s == NULL) {
- switch (kn->nexthop.af) {
- case AF_INET:
+ switch (kn->nexthop.aid) {
+ case AID_INET:
k = kn->kroute;
k->r.flags &= ~F_NEXTHOP;
break;
- case AF_INET6:
+ case AID_INET6:
k6 = kn->kroute;
k6->r.flags &= ~F_NEXTHOP;
break;
@@ -1665,7 +2292,7 @@ kroute_detach_nexthop(struct knexthop_node *kn)
*/
int
-protect_lo(void)
+protect_lo(struct ktable *kt)
{
struct kroute_node *kr;
struct kroute6_node *kr6;
@@ -1675,11 +2302,11 @@ protect_lo(void)
log_warn("protect_lo");
return (-1);
}
- kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK);
+ kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
kr->r.prefixlen = 8;
kr->r.flags = F_KERNEL|F_CONNECTED;
- if (RB_INSERT(kroute_tree, &krt, kr) != NULL)
+ if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL)
free(kr); /* kernel route already there, no problem */
/* special protection for loopback */
@@ -1689,9 +2316,9 @@ protect_lo(void)
}
memcpy(&kr6->r.prefix, &in6addr_loopback, sizeof(kr6->r.prefix));
kr6->r.prefixlen = 128;
- kr->r.flags = F_KERNEL|F_CONNECTED;
+ kr6->r.flags = F_KERNEL|F_CONNECTED;
- if (RB_INSERT(kroute6_tree, &krt6, kr6) != NULL)
+ if (RB_INSERT(kroute6_tree, &kt->krt6, kr6) != NULL)
free(kr6); /* kernel route already there, no problem */
return (0);
@@ -1726,17 +2353,17 @@ mask2prefixlen(in_addr_t ina)
u_int8_t
mask2prefixlen6(struct sockaddr_in6 *sa_in6)
{
- u_int8_t l = 0, i, len;
+ u_int8_t l = 0, *ap, *ep;
/*
* sin6_len is the size of the sockaddr so substract the offset of
* the possibly truncated sin6_addr struct.
*/
- len = sa_in6->sin6_len -
- (u_int8_t)(&((struct sockaddr_in6 *)NULL)->sin6_addr);
- for (i = 0; i < len; i++) {
+ ap = (u_int8_t *)&sa_in6->sin6_addr;
+ ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
+ for (; ap < ep; ap++) {
/* this "beauty" is adopted from sbin/route/show.c ... */
- switch (sa_in6->sin6_addr.s6_addr[i]) {
+ switch (*ap) {
case 0xff:
l += 8;
break;
@@ -1764,7 +2391,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6)
case 0x00:
return (l);
default:
- fatalx("non continguous inet6 netmask");
+ fatalx("non contiguous inet6 netmask");
}
}
@@ -1788,7 +2415,7 @@ prefixlen2mask6(u_int8_t prefixlen)
}
#define ROUNDUP(a) \
- (((a) & ((sizeof(long)) - 1)) ? (1 + ((a) | ((sizeof(long)) - 1))) : (a))
+ (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
@@ -1808,6 +2435,7 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
void
if_change(u_short ifindex, int flags, struct if_data *ifd)
{
+ struct ktable *kt;
struct kif_node *kif;
struct kif_kr *kkr;
struct kif_kr6 *kkr6;
@@ -1833,13 +2461,18 @@ if_change(u_short ifindex, int flags, struct if_data *ifd)
kif->k.nh_reachable = reachable;
+ kt = ktable_get(/* XXX */ 0);
+
LIST_FOREACH(kkr, &kif->kroute_l, entry) {
if (reachable)
kkr->kr->r.flags &= ~F_DOWN;
else
kkr->kr->r.flags |= F_DOWN;
- RB_FOREACH(n, knexthop_tree, &knt)
+ if (kt == NULL)
+ continue;
+
+ RB_FOREACH(n, knexthop_tree, KT2KNT(kt))
if (n->kroute == kkr->kr) {
bzero(&nh, sizeof(nh));
memcpy(&nh.nexthop, &n->nexthop,
@@ -1849,10 +2482,11 @@ if_change(u_short ifindex, int flags, struct if_data *ifd)
nh.connected = 1;
if ((nh.gateway.v4.s_addr =
kkr->kr->r.nexthop.s_addr) != 0)
- nh.gateway.af = AF_INET;
+ nh.gateway.aid = AID_INET;
}
- memcpy(&nh.kr.kr4, &kkr->kr->r,
- sizeof(nh.kr.kr4));
+ nh.net.aid = AID_INET;
+ nh.net.v4.s_addr = kkr->kr->r.prefix.s_addr;
+ nh.netlen = kkr->kr->r.prefixlen;
send_nexthop_update(&nh);
}
}
@@ -1862,7 +2496,9 @@ if_change(u_short ifindex, int flags, struct if_data *ifd)
else
kkr6->kr->r.flags |= F_DOWN;
- RB_FOREACH(n, knexthop_tree, &knt)
+ if (kt == NULL)
+ continue;
+ RB_FOREACH(n, knexthop_tree, KT2KNT(kt))
if (n->kroute == kkr6->kr) {
bzero(&nh, sizeof(nh));
memcpy(&nh.nexthop, &n->nexthop,
@@ -1873,14 +2509,16 @@ if_change(u_short ifindex, int flags, struct if_data *ifd)
if (memcmp(&kkr6->kr->r.nexthop,
&in6addr_any, sizeof(struct
in6_addr))) {
- nh.gateway.af = AF_INET6;
+ nh.gateway.aid = AID_INET6;
memcpy(&nh.gateway.v6,
&kkr6->kr->r.nexthop,
sizeof(struct in6_addr));
}
}
- memcpy(&nh.kr.kr6, &kkr6->kr->r,
- sizeof(nh.kr.kr6));
+ nh.net.aid = AID_INET6;
+ memcpy(&nh.net.v6, &kkr6->kr->r.nexthop,
+ sizeof(struct in6_addr));
+ nh.netlen = kkr6->kr->r.prefixlen;
send_nexthop_update(&nh);
}
}
@@ -1917,25 +2555,38 @@ if_announce(void *msg)
*/
int
-send_rtmsg(int fd, int action, struct kroute *kroute)
+send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute)
{
- struct iovec iov[5];
+ struct iovec iov[7];
struct rt_msghdr hdr;
struct sockaddr_in prefix;
struct sockaddr_in nexthop;
struct sockaddr_in mask;
+ struct {
+ struct sockaddr_dl dl;
+ char pad[sizeof(long)];
+ } ifp;
+#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */
+ struct sockaddr_mpls mpls;
struct sockaddr_rtlabel label;
+#endif /* !defined(__FreeBSD__) */
int iovcnt = 0;
- if (kr_state.fib_sync == 0)
+ if (!kt->fib_sync)
return (0);
/* initialize header */
bzero(&hdr, sizeof(hdr));
hdr.rtm_version = RTM_VERSION;
hdr.rtm_type = action;
- hdr.rtm_tableid = kr_state.rtableid;
+#if !defined(__FreeBSD__) /* XXX: FreeBSD has no multiple routing tables */
+ hdr.rtm_tableid = kt->rtableid;
+#endif /* !defined(__FreeBSD__) */
+#if !defined(__FreeBSD__) /* XXX: FreeBSD has no rtm_priority */
hdr.rtm_priority = RTP_BGP;
+#else
+ hdr.rtm_flags = RTF_PROTO1;
+#endif /* !defined(__FreeBSD__) */
if (kroute->flags & F_BLACKHOLE)
hdr.rtm_flags |= RTF_BLACKHOLE;
if (kroute->flags & F_REJECT)
@@ -1984,6 +2635,37 @@ send_rtmsg(int fd, int action, struct kroute *kroute)
iov[iovcnt].iov_base = &mask;
iov[iovcnt++].iov_len = sizeof(mask);
+ if (kt->ifindex) {
+ bzero(&ifp, sizeof(ifp));
+ ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
+ ifp.dl.sdl_family = AF_LINK;
+ ifp.dl.sdl_index = kt->ifindex;
+ /* adjust header */
+ hdr.rtm_addrs |= RTA_IFP;
+ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
+ /* adjust iovec */
+ iov[iovcnt].iov_base = &ifp;
+ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
+ }
+
+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */
+ if (kroute->flags & F_MPLS) {
+ bzero(&mpls, sizeof(mpls));
+ mpls.smpls_len = sizeof(mpls);
+ mpls.smpls_family = AF_MPLS;
+ mpls.smpls_label = kroute->mplslabel;
+ /* adjust header */
+ hdr.rtm_flags |= RTF_MPLS;
+ hdr.rtm_mpls = MPLS_OP_PUSH;
+ hdr.rtm_addrs |= RTA_SRC;
+ hdr.rtm_msglen += sizeof(mpls);
+ /* adjust iovec */
+ iov[iovcnt].iov_base = &mpls;
+ iov[iovcnt++].iov_len = sizeof(mpls);
+ }
+#endif
+
+#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */
if (kroute->labelid) {
bzero(&label, sizeof(label));
label.sr_len = sizeof(label);
@@ -1996,11 +2678,11 @@ send_rtmsg(int fd, int action, struct kroute *kroute)
iov[iovcnt].iov_base = &label;
iov[iovcnt++].iov_len = sizeof(label);
}
+#endif /* !defined(__FreeBSD__) */
retry:
if (writev(fd, iov, iovcnt) == -1) {
- switch (errno) {
- case ESRCH:
+ if (errno == ESRCH) {
if (hdr.rtm_type == RTM_CHANGE) {
hdr.rtm_type = RTM_ADD;
goto retry;
@@ -2009,27 +2691,18 @@ retry:
inet_ntoa(kroute->prefix),
kroute->prefixlen);
return (0);
- } else {
- log_warnx("send_rtmsg: action %u, "
- "prefix %s/%u: %s", hdr.rtm_type,
- inet_ntoa(kroute->prefix),
- kroute->prefixlen, strerror(errno));
- return (0);
}
- break;
- default:
- log_warnx("send_rtmsg: action %u, prefix %s/%u: %s",
- hdr.rtm_type, inet_ntoa(kroute->prefix),
- kroute->prefixlen, strerror(errno));
- return (0);
}
+ log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type,
+ inet_ntoa(kroute->prefix), kroute->prefixlen);
+ return (0);
}
return (0);
}
int
-send_rt6msg(int fd, int action, struct kroute6 *kroute)
+send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute)
{
struct iovec iov[5];
struct rt_msghdr hdr;
@@ -2037,17 +2710,23 @@ send_rt6msg(int fd, int action, struct kroute6 *kroute)
struct sockaddr_in6 addr;
char pad[sizeof(long)];
} prefix, nexthop, mask;
+#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */
struct sockaddr_rtlabel label;
+#endif /* !defined(__FreeBSD__) */
int iovcnt = 0;
- if (kr_state.fib_sync == 0)
+ if (!kt->fib_sync)
return (0);
/* initialize header */
bzero(&hdr, sizeof(hdr));
hdr.rtm_version = RTM_VERSION;
hdr.rtm_type = action;
+#if !defined(__FreeBSD__) /* XXX: FreeBSD has no multiple routing tables */
hdr.rtm_tableid = kr_state.rtableid;
+#else
+ hdr.rtm_flags = RTF_PROTO1;
+#endif /* !defined(__FreeBSD__) */
if (kroute->flags & F_BLACKHOLE)
hdr.rtm_flags |= RTF_BLACKHOLE;
if (kroute->flags & F_REJECT)
@@ -2100,6 +2779,7 @@ send_rt6msg(int fd, int action, struct kroute6 *kroute)
iov[iovcnt].iov_base = &mask;
iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
+#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */
if (kroute->labelid) {
bzero(&label, sizeof(label));
label.sr_len = sizeof(label);
@@ -2112,11 +2792,11 @@ send_rt6msg(int fd, int action, struct kroute6 *kroute)
iov[iovcnt].iov_base = &label;
iov[iovcnt++].iov_len = sizeof(label);
}
+#endif /* !defined(__FreeBSD__) */
retry:
if (writev(fd, iov, iovcnt) == -1) {
- switch (errno) {
- case ESRCH:
+ if (errno == ESRCH) {
if (hdr.rtm_type == RTM_CHANGE) {
hdr.rtm_type = RTM_ADD;
goto retry;
@@ -2125,31 +2805,26 @@ retry:
log_in6addr(&kroute->prefix),
kroute->prefixlen);
return (0);
- } else {
- log_warnx("send_rt6msg: action %u, "
- "prefix %s/%u: %s", hdr.rtm_type,
- log_in6addr(&kroute->prefix),
- kroute->prefixlen, strerror(errno));
- return (0);
}
- break;
- default:
- log_warnx("send_rt6msg: action %u, prefix %s/%u: %s",
- hdr.rtm_type, log_in6addr(&kroute->prefix),
- kroute->prefixlen, strerror(errno));
- return (0);
}
+ log_warn("send_rt6msg: action %u, prefix %s/%u", hdr.rtm_type,
+ log_in6addr(&kroute->prefix), kroute->prefixlen);
+ return (0);
}
return (0);
}
int
-fetchtable(u_int rtableid, int connected_only)
+fetchtable(struct ktable *kt)
{
size_t len;
+#if !defined(__FreeBSD__) /* FreeBSD has no table id. */
int mib[7];
- char *buf, *next, *lim;
+#else
+ int mib[6];
+#endif
+ char *buf = NULL, *next, *lim;
struct rt_msghdr *rtm;
struct sockaddr *sa, *gw, *rti_info[RTAX_MAX];
struct sockaddr_in *sa_in;
@@ -2163,22 +2838,35 @@ fetchtable(u_int rtableid, int connected_only)
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
- mib[6] = rtableid;
+#if !defined(__FreeBSD__) /* FreeBSD has no table id. */
+ mib[6] = kt->rtableid;
+#endif
+#if !defined(__FreeBSD__) /* FreeBSD has no table id. */
if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
- if (rtableid != 0 && errno == EINVAL) /* table nonexistent */
+#else
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
+#endif
+ if (kt->rtableid != 0 && errno == EINVAL)
+ /* table nonexistent */
return (0);
log_warn("sysctl");
return (-1);
}
- if ((buf = malloc(len)) == NULL) {
- log_warn("fetchtable");
- return (-1);
- }
- if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
- log_warn("sysctl");
- free(buf);
- return (-1);
+ if (len > 0) {
+ if ((buf = malloc(len)) == NULL) {
+ log_warn("fetchtable");
+ return (-1);
+ }
+#if !defined(__FreeBSD__) /* FreeBSD has no table id. */
+ if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
+#else
+ if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
+#endif
+ log_warn("sysctl2");
+ free(buf);
+ return (-1);
+ }
}
lim = buf + len;
@@ -2186,7 +2874,11 @@ fetchtable(u_int rtableid, int connected_only)
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
+#if !defined(__FreeBSD__)
sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
+#else
+ sa = (struct sockaddr *)(next + sizeof(struct rt_msghdr));
+#endif
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
if ((sa = rti_info[RTAX_DST]) == NULL)
@@ -2205,7 +2897,11 @@ fetchtable(u_int rtableid, int connected_only)
}
kr->r.flags = F_KERNEL;
+#if defined(__FreeBSD__) /* no rtm_priority on FreeBSD */
+ kr->r.priority = RTP_BGP;
+#else
kr->r.priority = rtm->rtm_priority;
+#endif
kr->r.ifindex = rtm->rtm_index;
kr->r.prefix.s_addr =
((struct sockaddr_in *)sa)->sin_addr.s_addr;
@@ -2223,8 +2919,12 @@ fetchtable(u_int rtableid, int connected_only)
break;
kr->r.prefixlen =
mask2prefixlen(sa_in->sin_addr.s_addr);
- } else if (rtm->rtm_flags & RTF_HOST)
+ } else if (rtm->rtm_flags & RTF_HOST) {
kr->r.prefixlen = 32;
+#if defined(__FreeBSD__) /* RTF_HOST means connected route */
+ kr->r.flags |= F_CONNECTED;
+#endif
+ }
else
kr->r.prefixlen =
prefixlen_classful(kr->r.prefix.s_addr);
@@ -2238,7 +2938,11 @@ fetchtable(u_int rtableid, int connected_only)
}
kr6->r.flags = F_KERNEL;
+#if defined(__FreeBSD__) /* no rtm_priority on FreeBSD */
+ kr6->r.priority = RTP_BGP;
+#else
kr6->r.priority = rtm->rtm_priority;
+#endif
kr6->r.ifindex = rtm->rtm_index;
memcpy(&kr6->r.prefix,
&((struct sockaddr_in6 *)sa)->sin6_addr,
@@ -2257,8 +2961,12 @@ fetchtable(u_int rtableid, int connected_only)
if (sa_in6->sin6_len == 0)
break;
kr6->r.prefixlen = mask2prefixlen6(sa_in6);
- } else if (rtm->rtm_flags & RTF_HOST)
+ } else if (rtm->rtm_flags & RTF_HOST) {
kr6->r.prefixlen = 128;
+#if defined(__FreeBSD__) /* RTF_HOST means connected route */
+ kr6->r.flags |= F_CONNECTED;
+#endif
+ }
else
fatalx("INET6 route without netmask");
break;
@@ -2290,23 +2998,28 @@ fetchtable(u_int rtableid, int connected_only)
}
if (sa->sa_family == AF_INET) {
+#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */
if (rtm->rtm_priority == RTP_BGP) {
- send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
- free(kr);
- } else if (connected_only &&
- !(kr->r.flags & F_CONNECTED))
+#else
+ /* never delete route */
+ if (0) {
+#endif
+ send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r);
free(kr);
- else
- kroute_insert(kr);
+ } else
+ kroute_insert(kt, kr);
} else if (sa->sa_family == AF_INET6) {
+#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */
if (rtm->rtm_priority == RTP_BGP) {
- send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r);
- free(kr6);
- } else if (connected_only &&
- !(kr6->r.flags & F_CONNECTED))
+#else
+ /* never delete route */
+ if (0) {
+#endif
+ send_rt6msg(kr_state.fd, RTM_DELETE, kt,
+ &kr6->r);
free(kr6);
- else
- kroute6_insert(kr6);
+ } else
+ kroute6_insert(kt, kr6);
}
}
free(buf);
@@ -2327,7 +3040,7 @@ fetchifs(int ifindex)
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
- mib[3] = AF_INET;
+ mib[3] = AF_INET; /* AF does not matter but AF_INET is shorter */
mib[4] = NET_RT_IFLIST;
mib[5] = ifindex;
@@ -2396,7 +3109,7 @@ dispatch_rtmsg(void)
struct rt_msghdr *rtm;
struct if_msghdr ifm;
struct sockaddr *sa, *rti_info[RTAX_MAX];
- int connected_only;
+ struct ktable *kt;
if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
log_warn("dispatch_rtmsg: read error");
@@ -2418,7 +3131,11 @@ dispatch_rtmsg(void)
case RTM_ADD:
case RTM_CHANGE:
case RTM_DELETE:
+#if !defined(__FreeBSD__)
sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
+#else
+ sa = (struct sockaddr *)(next + sizeof(struct rt_msghdr));
+#endif
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
if (rtm->rtm_pid == kr_state.pid) /* cause by us */
@@ -2430,16 +3147,14 @@ dispatch_rtmsg(void)
if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */
continue;
- connected_only = 0;
- if (rtm->rtm_tableid != kr_state.rtableid) {
- if (rtm->rtm_tableid == 0)
- connected_only = 1;
- else
- continue;
- }
+#if !defined(__FreeBSD__) /* FreeBSD has no rtm_tableid. */
+ if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
+#else
+ if ((kt = ktable_get(0)) == NULL)
+#endif
+ continue;
- if (dispatch_rtmsg_addr(rtm, rti_info,
- connected_only) == -1)
+ if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1)
return (-1);
break;
case RTM_IFINFO:
@@ -2460,7 +3175,7 @@ dispatch_rtmsg(void)
int
dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
- int connected_only)
+ struct ktable *kt)
{
struct sockaddr *sa;
struct sockaddr_in *sa_in;
@@ -2494,31 +3209,44 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
mpath = 1;
#endif
+#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */
prio = rtm->rtm_priority;
- prefix.af = sa->sa_family;
- switch (prefix.af) {
+#else
+ prio = RTP_BGP;
+#endif
+ switch (sa->sa_family) {
case AF_INET:
+ prefix.aid = AID_INET;
prefix.v4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
if (sa_in != NULL) {
if (sa_in->sin_len != 0)
prefixlen = mask2prefixlen(
sa_in->sin_addr.s_addr);
- } else if (rtm->rtm_flags & RTF_HOST)
+ } else if (rtm->rtm_flags & RTF_HOST) {
prefixlen = 32;
+#if defined(__FreeBSD__) /* RTF_HOST means connected route */
+ flags |= F_CONNECTED;
+#endif
+ }
else
prefixlen =
prefixlen_classful(prefix.v4.s_addr);
break;
case AF_INET6:
+ prefix.aid = AID_INET6;
memcpy(&prefix.v6, &((struct sockaddr_in6 *)sa)->sin6_addr,
sizeof(struct in6_addr));
sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
if (sa_in6 != NULL) {
if (sa_in6->sin6_len != 0)
prefixlen = mask2prefixlen6(sa_in6);
- } else if (rtm->rtm_flags & RTF_HOST)
+ } else if (rtm->rtm_flags & RTF_HOST) {
prefixlen = 128;
+#if defined(__FreeBSD__) /* RTF_HOST means connected route */
+ flags |= F_CONNECTED;
+#endif
+ }
else
fatalx("in6 net addr without netmask");
break;
@@ -2537,10 +3265,10 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
}
if (rtm->rtm_type == RTM_DELETE) {
- switch (prefix.af) {
- case AF_INET:
+ switch (prefix.aid) {
+ case AID_INET:
sa_in = (struct sockaddr_in *)sa;
- if ((kr = kroute_find(prefix.v4.s_addr,
+ if ((kr = kroute_find(kt, prefix.v4.s_addr,
prefixlen, prio)) == NULL)
return (0);
if (!(kr->r.flags & F_KERNEL))
@@ -2554,12 +3282,12 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
return (0);
}
- if (kroute_remove(kr) == -1)
+ if (kroute_remove(kt, kr) == -1)
return (-1);
break;
- case AF_INET6:
+ case AID_INET6:
sa_in6 = (struct sockaddr_in6 *)sa;
- if ((kr6 = kroute6_find(&prefix.v6, prefixlen,
+ if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen,
prio)) == NULL)
return (0);
if (!(kr6->r.flags & F_KERNEL))
@@ -2574,26 +3302,23 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
return (0);
}
- if (kroute6_remove(kr6) == -1)
+ if (kroute6_remove(kt, kr6) == -1)
return (-1);
break;
}
return (0);
}
- if (connected_only && !(flags & F_CONNECTED))
- return (0);
-
if (sa == NULL && !(flags & F_CONNECTED)) {
log_warnx("dispatch_rtmsg no nexthop for %s/%u",
log_addr(&prefix), prefixlen);
return (0);
}
- switch (prefix.af) {
- case AF_INET:
+ switch (prefix.aid) {
+ case AID_INET:
sa_in = (struct sockaddr_in *)sa;
- if ((kr = kroute_find(prefix.v4.s_addr, prefixlen,
+ if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen,
prio)) != NULL) {
if (kr->r.flags & F_KERNEL) {
/* get the correct route */
@@ -2619,16 +3344,16 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
!(flags & F_CONNECTED)) {
kif_kr_remove(kr);
kr_redistribute(IMSG_NETWORK_REMOVE,
- &kr->r);
+ kt, &kr->r);
}
if ((flags & F_CONNECTED) &&
!(oflags & F_CONNECTED)) {
kif_kr_insert(kr);
kr_redistribute(IMSG_NETWORK_ADD,
- &kr->r);
+ kt, &kr->r);
}
if (kr->r.flags & F_NEXTHOP)
- knexthop_track(kr);
+ knexthop_track(kt, kr);
}
} else if (rtm->rtm_type == RTM_CHANGE) {
log_warnx("change req for %s/%u: not in table",
@@ -2651,12 +3376,13 @@ add4:
kr->r.ifindex = ifindex;
kr->r.priority = prio;
- kroute_insert(kr);
+ kroute_insert(kt, kr);
}
break;
- case AF_INET6:
+ case AID_INET6:
sa_in6 = (struct sockaddr_in6 *)sa;
- if ((kr6 = kroute6_find(&prefix.v6, prefixlen, prio)) != NULL) {
+ if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) !=
+ NULL) {
if (kr6->r.flags & F_KERNEL) {
/* get the correct route */
if (mpath && rtm->rtm_type == RTM_CHANGE &&
@@ -2685,16 +3411,16 @@ add4:
!(flags & F_CONNECTED)) {
kif_kr6_remove(kr6);
kr_redistribute6(IMSG_NETWORK_REMOVE,
- &kr6->r);
+ kt, &kr6->r);
}
if ((flags & F_CONNECTED) &&
!(oflags & F_CONNECTED)) {
kif_kr6_insert(kr6);
kr_redistribute6(IMSG_NETWORK_ADD,
- &kr6->r);
+ kt, &kr6->r);
}
if (kr6->r.flags & F_NEXTHOP)
- knexthop_track(kr6);
+ knexthop_track(kt, kr6);
}
} else if (rtm->rtm_type == RTM_CHANGE) {
log_warnx("change req for %s/%u: not in table",
@@ -2720,7 +3446,7 @@ add6:
kr6->r.ifindex = ifindex;
kr6->r.priority = prio;
- kroute6_insert(kr6);
+ kroute6_insert(kt, kr6);
}
break;
}
diff --git a/bgpd/log.c b/bgpd/log.c
index c426ee9..5c2d690 100644
--- a/bgpd/log.c
+++ b/bgpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.50 2007/04/23 13:04:24 claudio Exp $ */
+/* $OpenBSD: log.c,v 1.54 2010/11/18 12:51:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -32,6 +32,7 @@
#include "log.h"
int debug;
+int verbose;
void logit(int, const char *, ...);
@@ -42,8 +43,9 @@ log_fmt_peer(const struct peer_config *peer)
char *pfmt, *p;
ip = log_addr(&peer->remote_addr);
- if ((peer->remote_addr.af == AF_INET && peer->remote_masklen != 32) ||
- (peer->remote_addr.af == AF_INET6 && peer->remote_masklen != 128)) {
+ if ((peer->remote_addr.aid == AID_INET && peer->remote_masklen != 32) ||
+ (peer->remote_addr.aid == AID_INET6 &&
+ peer->remote_masklen != 128)) {
if (asprintf(&p, "%s/%u", ip, peer->remote_masklen) == -1)
fatal(NULL);
} else {
@@ -69,6 +71,7 @@ log_init(int n_debug)
extern char *__progname;
debug = n_debug;
+ verbose = n_debug;
if (!debug)
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
@@ -77,6 +80,12 @@ log_init(int n_debug)
}
void
+log_verbose(int v)
+{
+ verbose = v;
+}
+
+void
logit(int pri, const char *fmt, ...)
{
va_list ap;
@@ -193,7 +202,7 @@ log_debug(const char *emsg, ...)
{
va_list ap;
- if (debug) {
+ if (verbose) {
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
@@ -250,7 +259,7 @@ log_statechange(struct peer *peer, enum session_state nstate,
void
log_notification(const struct peer *peer, u_int8_t errcode, u_int8_t subcode,
- u_char *data, u_int16_t datalen)
+ u_char *data, u_int16_t datalen, const char *dir)
{
char *p;
const char *suberrname = NULL;
@@ -287,23 +296,22 @@ log_notification(const struct peer *peer, u_int8_t errcode, u_int8_t subcode,
uk = 1;
break;
default:
- logit(LOG_CRIT, "%s: received notification, unknown errcode "
- "%u, subcode %u", p, errcode, subcode);
+ logit(LOG_CRIT, "%s: %s notification, unknown errcode "
+ "%u, subcode %u", p, dir, errcode, subcode);
free(p);
return;
}
if (uk)
- logit(LOG_CRIT,
- "%s: received notification: %s, unknown subcode %u",
- p, errnames[errcode], subcode);
+ logit(LOG_CRIT, "%s: %s notification: %s, unknown subcode %u",
+ p, dir, errnames[errcode], subcode);
else {
if (suberrname == NULL)
- logit(LOG_CRIT, "%s: received notification: %s",
- p, errnames[errcode]);
+ logit(LOG_CRIT, "%s: %s notification: %s", p,
+ dir, errnames[errcode]);
else
- logit(LOG_CRIT, "%s: received notification: %s, %s",
- p, errnames[errcode], suberrname);
+ logit(LOG_CRIT, "%s: %s notification: %s, %s",
+ p, dir, errnames[errcode], suberrname);
}
free(p);
}
@@ -318,6 +326,9 @@ log_conn_attempt(const struct peer *peer, struct sockaddr *sa)
b = log_sockaddr(sa);
logit(LOG_INFO, "connection from non-peer %s refused", b);
} else {
+ /* only log if there is a chance that the session may come up */
+ if (peer->conf.down && peer->state == STATE_IDLE)
+ return;
p = log_fmt_peer(&peer->conf);
logit(LOG_INFO, "Connection attempt from %s while session is "
"in state %s", p, statenames[peer->state]);
diff --git a/bgpd/mrt.c b/bgpd/mrt.c
index 5fa497a..d2bfe64 100644
--- a/bgpd/mrt.c
+++ b/bgpd/mrt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mrt.c,v 1.63 2009/06/29 12:22:16 claudio Exp $ */
+/* $OpenBSD: mrt.c,v 1.70 2010/09/02 14:03:21 sobrado Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -32,20 +32,20 @@
#include "mrt.h"
-int mrt_attr_dump(struct buf *, struct rde_aspath *, struct bgpd_addr *);
+int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *);
int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t,
struct rde_peer*);
int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*);
-int mrt_dump_hdr_se(struct buf **, struct peer *, u_int16_t, u_int16_t,
+int mrt_dump_hdr_se(struct ibuf **, struct peer *, u_int16_t, u_int16_t,
u_int32_t, int);
-int mrt_dump_hdr_rde(struct buf **, u_int16_t type, u_int16_t, u_int32_t);
+int mrt_dump_hdr_rde(struct ibuf **, u_int16_t type, u_int16_t, u_int32_t);
int mrt_open(struct mrt *, time_t);
#define DUMP_BYTE(x, b) \
do { \
u_char t = (b); \
- if (buf_add((x), &t, sizeof(t)) == -1) { \
- log_warnx("mrt_dump1: buf_add error"); \
+ if (ibuf_add((x), &t, sizeof(t)) == -1) { \
+ log_warnx("mrt_dump1: ibuf_add error"); \
goto fail; \
} \
} while (0)
@@ -54,8 +54,8 @@ int mrt_open(struct mrt *, time_t);
do { \
u_int16_t t; \
t = htons((s)); \
- if (buf_add((x), &t, sizeof(t)) == -1) { \
- log_warnx("mrt_dump2: buf_add error"); \
+ if (ibuf_add((x), &t, sizeof(t)) == -1) { \
+ log_warnx("mrt_dump2: ibuf_add error"); \
goto fail; \
} \
} while (0)
@@ -64,8 +64,8 @@ int mrt_open(struct mrt *, time_t);
do { \
u_int32_t t; \
t = htonl((l)); \
- if (buf_add((x), &t, sizeof(t)) == -1) { \
- log_warnx("mrt_dump3: buf_add error"); \
+ if (ibuf_add((x), &t, sizeof(t)) == -1) { \
+ log_warnx("mrt_dump3: ibuf_add error"); \
goto fail; \
} \
} while (0)
@@ -73,8 +73,8 @@ int mrt_open(struct mrt *, time_t);
#define DUMP_NLONG(x, l) \
do { \
u_int32_t t = (l); \
- if (buf_add((x), &t, sizeof(t)) == -1) { \
- log_warnx("mrt_dump4: buf_add error"); \
+ if (ibuf_add((x), &t, sizeof(t)) == -1) { \
+ log_warnx("mrt_dump4: ibuf_add error"); \
goto fail; \
} \
} while (0)
@@ -83,55 +83,63 @@ void
mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen,
struct peer *peer)
{
- struct buf *buf;
+ struct ibuf *buf;
int incoming = 0;
+ u_int16_t subtype = BGP4MP_MESSAGE;
+
+ if (peer->capa.neg.as4byte)
+ subtype = BGP4MP_MESSAGE_AS4;
/* get the direction of the message to swap address and AS fields */
if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN)
incoming = 1;
- if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
+ if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype,
pkglen, incoming) == -1)
return;
- if (buf_add(buf, pkg, pkglen) == -1) {
+ if (ibuf_add(buf, pkg, pkglen) == -1) {
log_warnx("mrt_dump_bgp_msg: buf_add error");
- buf_free(buf);
+ ibuf_free(buf);
return;
}
- buf_close(&mrt->wbuf, buf);
+ ibuf_close(&mrt->wbuf, buf);
}
void
mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state,
struct peer *peer)
{
- struct buf *buf;
+ struct ibuf *buf;
+ u_int16_t subtype = BGP4MP_STATE_CHANGE;
+
+ if (peer->capa.neg.as4byte)
+ subtype = BGP4MP_STATE_CHANGE_AS4;
- if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
+ if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype,
2 * sizeof(short), 0) == -1)
return;
DUMP_SHORT(buf, old_state);
DUMP_SHORT(buf, new_state);
- buf_close(&mrt->wbuf, buf);
+ ibuf_close(&mrt->wbuf, buf);
return;
fail:
- buf_free(buf);
+ ibuf_free(buf);
}
int
-mrt_attr_dump(struct buf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop)
+mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop)
{
struct attr *oa;
u_char *pdata;
u_int32_t tmp;
int neednewpath = 0;
- u_int16_t plen;
- u_int8_t l;
+ u_int16_t plen, afi;
+ u_int8_t l, mpattr[21];
/* origin */
if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
@@ -141,11 +149,14 @@ mrt_attr_dump(struct buf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop)
/* aspath */
pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
pdata = aspath_deflate(pdata, &plen, &neednewpath);
- if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata, plen) == -1)
+ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
+ plen) == -1) {
+ free(pdata);
return (-1);
+ }
free(pdata);
- if (nexthop) {
+ if (nexthop && nexthop->aid == AID_INET) {
/* nexthop, already network byte order */
if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
&nexthop->v4.s_addr, 4) == -1)
@@ -173,12 +184,27 @@ mrt_attr_dump(struct buf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop)
return (-1);
}
+ if (nexthop && nexthop->aid != AID_INET) {
+ if (aid2afi(nexthop->aid, &afi, &mpattr[2]))
+ return (-1);
+ afi = htons(afi);
+ memcpy(mpattr, &afi, sizeof(afi));
+ mpattr[3] = sizeof(struct in6_addr);
+ memcpy(&mpattr[4], &nexthop->v6, sizeof(struct in6_addr));
+ mpattr[20] = 0; /* Reserved must be 0 */
+ if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
+ mpattr, sizeof(mpattr)) == -1)
+ return (-1);
+ }
+
if (neednewpath) {
pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
if (plen != 0)
if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_AS4_PATH, pdata, plen) == -1)
+ ATTR_AS4_PATH, pdata, plen) == -1) {
+ free(pdata);
return (-1);
+ }
free(pdata);
}
@@ -189,14 +215,14 @@ int
mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
struct rde_peer *peer)
{
- struct buf *buf, *hbuf = NULL, *h2buf = NULL;
+ struct ibuf *buf, *hbuf = NULL, *h2buf = NULL;
void *bptr;
struct bgpd_addr addr, nexthop, *nh;
u_int16_t len;
u_int8_t p_len;
- sa_family_t af;
+ u_int8_t aid;
- if ((buf = buf_dynamic(0, MAX_PKTSIZE)) == NULL) {
+ if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
log_warn("mrt_dump_entry_mp: buf_dynamic");
return (-1);
}
@@ -205,9 +231,9 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
log_warnx("mrt_dump_entry_mp: mrt_attr_dump error");
goto fail;
}
- len = buf_size(buf);
+ len = ibuf_size(buf);
- if ((h2buf = buf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
+ if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE +
MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL) {
log_warn("mrt_dump_entry_mp: buf_dynamic");
@@ -219,25 +245,26 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
DUMP_SHORT(h2buf, /* ifindex */ 0);
/* XXX is this for peer self? */
- af = peer->remote_addr.af == 0 ? p->prefix->af : peer->remote_addr.af;
- switch (af) {
- case AF_INET:
+ aid = peer->remote_addr.aid == AID_UNSPEC ? p->prefix->aid :
+ peer->remote_addr.aid;
+ switch (aid) {
+ case AID_INET:
DUMP_SHORT(h2buf, AFI_IPv4);
DUMP_NLONG(h2buf, peer->local_v4_addr.v4.s_addr);
DUMP_NLONG(h2buf, peer->remote_addr.v4.s_addr);
break;
- case AF_INET6:
+ case AID_INET6:
DUMP_SHORT(h2buf, AFI_IPv6);
- if (buf_add(h2buf, &peer->local_v6_addr.v6,
+ if (ibuf_add(h2buf, &peer->local_v6_addr.v6,
sizeof(struct in6_addr)) == -1 ||
- buf_add(h2buf, &peer->remote_addr.v6,
+ ibuf_add(h2buf, &peer->remote_addr.v6,
sizeof(struct in6_addr)) == -1) {
log_warnx("mrt_dump_entry_mp: buf_add error");
goto fail;
}
break;
default:
- log_warnx("king bula found new AF %d in mrt_dump_entry_mp", af);
+ log_warnx("king bula found new AF in mrt_dump_entry_mp");
goto fail;
}
@@ -247,24 +274,24 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
if (p->aspath->nexthop == NULL) {
bzero(&nexthop, sizeof(struct bgpd_addr));
- nexthop.af = addr.af;
+ nexthop.aid = addr.aid;
nh = &nexthop;
} else
nh = &p->aspath->nexthop->exit_nexthop;
pt_getaddr(p->prefix, &addr);
- switch (addr.af) {
- case AF_INET:
+ switch (addr.aid) {
+ case AID_INET:
DUMP_SHORT(h2buf, AFI_IPv4); /* afi */
DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */
DUMP_BYTE(h2buf, 4); /* nhlen */
DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */
break;
- case AF_INET6:
+ case AID_INET6:
DUMP_SHORT(h2buf, AFI_IPv6); /* afi */
DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */
DUMP_BYTE(h2buf, 16); /* nhlen */
- if (buf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) {
+ if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) {
log_warnx("mrt_dump_entry_mp: buf_add error");
goto fail;
}
@@ -275,7 +302,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
}
p_len = PREFIX_SIZE(p->prefix->prefixlen);
- if ((bptr = buf_reserve(h2buf, p_len)) == NULL) {
+ if ((bptr = ibuf_reserve(h2buf, p_len)) == NULL) {
log_warnx("mrt_dump_entry_mp: buf_reserve error");
goto fail;
}
@@ -285,24 +312,24 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
}
DUMP_SHORT(h2buf, len);
- len += buf_size(h2buf);
+ len += ibuf_size(h2buf);
if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY,
len) == -1)
goto fail;
- buf_close(&mrt->wbuf, hbuf);
- buf_close(&mrt->wbuf, h2buf);
- buf_close(&mrt->wbuf, buf);
+ ibuf_close(&mrt->wbuf, hbuf);
+ ibuf_close(&mrt->wbuf, h2buf);
+ ibuf_close(&mrt->wbuf, buf);
return (len + MRT_HEADER_SIZE);
fail:
if (hbuf)
- buf_free(hbuf);
- if (h2buf);
- buf_free(h2buf);
- buf_free(buf);
+ ibuf_free(hbuf);
+ if (h2buf)
+ ibuf_free(h2buf);
+ ibuf_free(buf);
return (-1);
}
@@ -310,34 +337,37 @@ int
mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
struct rde_peer *peer)
{
- struct buf *buf, *hbuf;
+ struct ibuf *buf, *hbuf;
struct bgpd_addr addr, *nh;
size_t len;
+ u_int16_t subtype;
+ u_int8_t dummy;
- if (p->prefix->af != AF_INET && peer->remote_addr.af == AF_INET)
- /* only able to dump IPv4 */
+ if (p->prefix->aid != peer->remote_addr.aid &&
+ p->prefix->aid != AID_INET && p->prefix->aid != AID_INET6)
+ /* only able to dump pure IPv4/IPv6 */
return (0);
- if ((buf = buf_dynamic(0, MAX_PKTSIZE)) == NULL) {
+ if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
log_warnx("mrt_dump_entry: buf_dynamic");
return (-1);
}
if (p->aspath->nexthop == NULL) {
bzero(&addr, sizeof(struct bgpd_addr));
- addr.af = AF_INET;
+ addr.aid = p->prefix->aid;
nh = &addr;
} else
nh = &p->aspath->nexthop->exit_nexthop;
if (mrt_attr_dump(buf, p->aspath, nh) == -1) {
log_warnx("mrt_dump_entry: mrt_attr_dump error");
- buf_free(buf);
+ ibuf_free(buf);
return (-1);
}
- len = buf_size(buf);
-
- if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, AFI_IPv4, len) == -1) {
- buf_free(buf);
+ len = ibuf_size(buf);
+ aid2afi(p->prefix->aid, &subtype, &dummy);
+ if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) {
+ ibuf_free(buf);
return (-1);
}
@@ -345,23 +375,44 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
DUMP_SHORT(hbuf, snum);
pt_getaddr(p->prefix, &addr);
- DUMP_NLONG(hbuf, addr.v4.s_addr);
+ switch (p->prefix->aid) {
+ case AID_INET:
+ DUMP_NLONG(hbuf, addr.v4.s_addr);
+ break;
+ case AID_INET6:
+ if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) {
+ log_warnx("mrt_dump_entry: buf_add error");
+ goto fail;
+ }
+ break;
+ }
DUMP_BYTE(hbuf, p->prefix->prefixlen);
DUMP_BYTE(hbuf, 1); /* state */
DUMP_LONG(hbuf, p->lastchange); /* originated */
- DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr);
+ switch (p->prefix->aid) {
+ case AID_INET:
+ DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr);
+ break;
+ case AID_INET6:
+ if (ibuf_add(hbuf, &peer->remote_addr.v6,
+ sizeof(struct in6_addr)) == -1) {
+ log_warnx("mrt_dump_entry: buf_add error");
+ goto fail;
+ }
+ break;
+ }
DUMP_SHORT(hbuf, peer->short_as);
DUMP_SHORT(hbuf, len);
- buf_close(&mrt->wbuf, hbuf);
- buf_close(&mrt->wbuf, buf);
+ ibuf_close(&mrt->wbuf, hbuf);
+ ibuf_close(&mrt->wbuf, buf);
return (len + MRT_HEADER_SIZE);
fail:
- buf_free(hbuf);
- buf_free(buf);
+ ibuf_free(hbuf);
+ ibuf_free(buf);
return (-1);
}
@@ -387,7 +438,7 @@ mrt_dump_upcall(struct rib_entry *re, void *ptr)
}
void
-mrt_dump_done(void *ptr)
+mrt_done(void *ptr)
{
struct mrt *mrtbuf = ptr;
@@ -395,12 +446,12 @@ mrt_dump_done(void *ptr)
}
int
-mrt_dump_hdr_se(struct buf ** bp, struct peer *peer, u_int16_t type,
+mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, u_int16_t type,
u_int16_t subtype, u_int32_t len, int swap)
{
time_t now;
- if ((*bp = buf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
+ if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) {
log_warnx("mrt_dump_hdr_se: buf_open error");
return (-1);
@@ -468,20 +519,20 @@ mrt_dump_hdr_se(struct buf ** bp, struct peer *peer, u_int16_t type,
case AF_INET6:
DUMP_SHORT(*bp, AFI_IPv6);
if (!swap)
- if (buf_add(*bp, &((struct sockaddr_in6 *)
+ if (ibuf_add(*bp, &((struct sockaddr_in6 *)
&peer->sa_local)->sin6_addr,
sizeof(struct in6_addr)) == -1) {
log_warnx("mrt_dump_hdr_se: buf_add error");
goto fail;
}
- if (buf_add(*bp,
+ if (ibuf_add(*bp,
&((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr,
sizeof(struct in6_addr)) == -1) {
log_warnx("mrt_dump_hdr_se: buf_add error");
goto fail;
}
if (swap)
- if (buf_add(*bp, &((struct sockaddr_in6 *)
+ if (ibuf_add(*bp, &((struct sockaddr_in6 *)
&peer->sa_local)->sin6_addr,
sizeof(struct in6_addr)) == -1) {
log_warnx("mrt_dump_hdr_se: buf_add error");
@@ -493,17 +544,17 @@ mrt_dump_hdr_se(struct buf ** bp, struct peer *peer, u_int16_t type,
return (0);
fail:
- buf_free(*bp);
+ ibuf_free(*bp);
return (-1);
}
int
-mrt_dump_hdr_rde(struct buf **bp, u_int16_t type, u_int16_t subtype,
+mrt_dump_hdr_rde(struct ibuf **bp, u_int16_t type, u_int16_t subtype,
u_int32_t len)
{
time_t now;
- if ((*bp = buf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
+ if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
NULL) {
log_warnx("mrt_dump_hdr_rde: buf_dynamic error");
@@ -517,7 +568,15 @@ mrt_dump_hdr_rde(struct buf **bp, u_int16_t type, u_int16_t subtype,
switch (type) {
case MSG_TABLE_DUMP:
- DUMP_LONG(*bp, MRT_DUMP_HEADER_SIZE + len);
+ switch (subtype) {
+ case AFI_IPv4:
+ len += MRT_DUMP_HEADER_SIZE;
+ break;
+ case AFI_IPv6:
+ len += MRT_DUMP_HEADER_SIZE_V6;
+ break;
+ }
+ DUMP_LONG(*bp, len);
break;
case MSG_PROTOCOL_BGP4MP:
DUMP_LONG(*bp, len);
@@ -525,11 +584,11 @@ mrt_dump_hdr_rde(struct buf **bp, u_int16_t type, u_int16_t subtype,
default:
log_warnx("mrt_dump_hdr_rde: unsupported type");
goto fail;
- }
+ }
return (0);
fail:
- buf_free(*bp);
+ ibuf_free(*bp);
return (-1);
}
@@ -538,21 +597,22 @@ mrt_write(struct mrt *mrt)
{
int r;
- if ((r = buf_write(&mrt->wbuf)) < 0) {
+ if ((r = ibuf_write(&mrt->wbuf)) < 0) {
log_warn("mrt dump aborted, mrt_write");
mrt_clean(mrt);
+ mrt_done(mrt);
}
}
void
mrt_clean(struct mrt *mrt)
{
- struct buf *b;
+ struct ibuf *b;
close(mrt->wbuf.fd);
while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) {
TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry);
- buf_free(b);
+ ibuf_free(b);
}
mrt->wbuf.queued = 0;
}
diff --git a/bgpd/mrt.h b/bgpd/mrt.h
index 4f43cd9..d88c01c 100644
--- a/bgpd/mrt.h
+++ b/bgpd/mrt.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mrt.h,v 1.23 2009/06/29 12:22:16 claudio Exp $ */
+/* $OpenBSD: mrt.h,v 1.27 2010/06/04 10:13:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -18,12 +18,10 @@
#ifndef __MRT_H__
#define __MRT_H__
-#include "bgpd.h"
-
/*
* MRT binary packet format
* For more info see:
- * draft-ietf-grow-mrt-04.txt, "MRT routing information export format"
+ * draft-ietf-grow-mrt-11.txt, "MRT routing information export format"
* http://www.quagga.net/docs/docs-multi/Packet-Binary-Dump-Format.html
*/
@@ -75,8 +73,10 @@ enum MRT_BGP4MP_TYPES {
BGP4MP_MESSAGE, /* bgp message */
BGP4MP_ENTRY, /* table dumps (deprecated) */
BGP4MP_SNAPSHOT, /* file name for dump (deprecated) */
+ BGP4MP_MESSAGE_AS4, /* same as BGP4MP_MESSAGE with 4byte AS */
BGP4MP_STATE_CHANGE_AS4,
- BGP4MP_MESSAGE_AS4 /* same as BGP4MP_MESSAGE with 4byte AS */
+ BGP4MP_MESSAGE_LOCAL, /* same as BGP4MP_MESSAGE but for self */
+ BGP4MP_MESSAGE_AS4_LOCAL /* originated updates. Not implemented */
};
/* size of the BGP4MP headers without payload */
@@ -184,6 +184,7 @@ enum MRT_BGP4MP_TYPES {
/* size of the dump header until attr_len */
#define MRT_DUMP_HEADER_SIZE 22
+#define MRT_DUMP_HEADER_SIZE_V6 46
/*
* OLD MRT message headers. These structs are here for completion but
@@ -235,7 +236,7 @@ enum MRT_BGP_TYPES {
* | new_state |
* +--------+--------+
*
- * State are defined in RFC 1771.
+ * State are defined in RFC 1771/4271.
*/
/*
@@ -303,7 +304,7 @@ void mrt_dump_state(struct mrt *, u_int16_t, u_int16_t,
struct peer *);
void mrt_clear_seq(void);
void mrt_dump_upcall(struct rib_entry *, void *);
-void mrt_dump_done(void *);
+void mrt_done(void *);
void mrt_write(struct mrt *);
void mrt_clean(struct mrt *);
void mrt_init(struct imsgbuf *, struct imsgbuf *);
diff --git a/bgpd/parse.y b/bgpd/parse.y
index 175a9a0..d76ac6a 100644
--- a/bgpd/parse.y
+++ b/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.250 2010/03/31 18:53:23 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -25,7 +25,10 @@
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-
+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */
+#include <netmpls/mpls.h>
+#endif
+
#include <ctype.h>
#include <err.h>
#include <unistd.h>
@@ -74,10 +77,12 @@ char *symget(const char *);
static struct bgpd_config *conf;
static struct mrt_head *mrtconf;
-static struct network_head *netconf;
+static struct network_head *netconf, *gnetconf;
static struct peer *peer_l, *peer_l_old;
static struct peer *curpeer;
static struct peer *curgroup;
+static struct rdomain *currdom;
+static struct rdomain_head *rdom_l;
static struct filter_head *filter_l;
static struct filter_head *peerfilter_l;
static struct filter_head *groupfilter_l;
@@ -105,7 +110,7 @@ struct filter_match_l {
struct filter_match m;
struct filter_prefix_l *prefix_l;
struct filter_as_l *as_l;
- sa_family_t af;
+ u_int8_t aid;
} fmopts;
struct peer *alloc_peer(void);
@@ -113,8 +118,8 @@ struct peer *new_peer(void);
struct peer *new_group(void);
int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *,
char *);
-int add_rib(char *, u_int16_t);
-int find_rib(char *);
+int add_rib(char *, u_int, u_int16_t);
+struct rde_rib *find_rib(char *);
int get_id(struct peer *);
int expand_rule(struct filter_rule *, struct filter_peers_l *,
struct filter_match_l *, struct filter_set_head *);
@@ -123,12 +128,14 @@ int neighbor_consistent(struct peer *);
int merge_filterset(struct filter_set_head *, struct filter_set *);
void copy_filterset(struct filter_set_head *,
struct filter_set_head *);
-void move_filterset(struct filter_set_head *,
- struct filter_set_head *);
struct filter_rule *get_rule(enum action_types);
int getcommunity(char *);
-int parsecommunity(char *, int *, int *);
+int parsecommunity(struct filter_community *, char *);
+int parsesubtype(char *);
+int parseextvalue(char *, u_int32_t *);
+int parseextcommunity(struct filter_extcommunity *, char *,
+ char *);
typedef struct {
union {
@@ -159,29 +166,33 @@ typedef struct {
%}
%token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE RTABLE
+%token RDOMAIN RD EXPORTTRGT IMPORTTRGT
%token RDE RIB EVALUATE IGNORE COMPARE
%token GROUP NEIGHBOR NETWORK
-%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
-%token ANNOUNCE DEMOTE CONNECTRETRY
-%token ENFORCE NEIGHBORAS CAPABILITIES REFLECTOR DEPEND DOWN SOFTRECONFIG
-%token DUMP IN OUT
+%token REMOTEAS DESCR LLIFACE LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
+%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
+%token DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN SOFTRECONFIG
+%token DUMP IN OUT SOCKET RESTRICTED
%token LOG ROUTECOLL TRANSPARENT
%token TCP MD5SIG PASSWORD KEY TTLSECURITY
%token ALLOW DENY MATCH
%token QUICK
%token FROM TO ANY
%token CONNECTED STATIC
-%token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS COMMUNITY DELETE
+%token COMMUNITY EXTCOMMUNITY
+%token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ
%token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
-%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL
+%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN
%token ERROR INCLUDE
%token IPSEC ESP AH SPI IKE
%token IPV4 IPV6
%token QUALIFY VIA
+%token NE LE GE XRANGE
%token <v.string> STRING
%token <v.number> NUMBER
-%type <v.number> asnumber as4number optnumber yesno inout
-%type <v.number> espah family restart
+%type <v.number> asnumber as4number optnumber
+%type <v.number> espah family restart origincode nettype
+%type <v.number> yesno inout restricted
%type <v.string> string filter_rib
%type <v.addr> address
%type <v.prefix> prefix addrspec
@@ -204,6 +215,7 @@ grammar : /* empty */
| grammar include '\n'
| grammar conf_main '\n'
| grammar varset '\n'
+ | grammar rdomain '\n'
| grammar neighbor '\n'
| grammar group '\n'
| grammar filterrule '\n'
@@ -211,8 +223,12 @@ grammar : /* empty */
;
asnumber : NUMBER {
- if ($1 < 0 || $1 >= ASNUM_MAX) {
- yyerror("AS too big: max %u", ASNUM_MAX - 1);
+ /*
+ * Accroding to iana 65535 and 4294967295 are reserved
+ * but enforcing this is not duty of the parser.
+ */
+ if ($1 < 0 || $1 > UINT_MAX) {
+ yyerror("AS too big: max %u", UINT_MAX);
YYERROR;
}
}
@@ -274,6 +290,8 @@ yesno : STRING {
else if (!strcmp($1, "no"))
$$ = 0;
else {
+ yyerror("syntax error, "
+ "either yes or no expected");
free($1);
YYERROR;
}
@@ -318,7 +336,7 @@ conf_main : AS as4number {
conf->short_as = $3;
}
| ROUTERID address {
- if ($2.af != AF_INET) {
+ if ($2.aid != AID_INET) {
yyerror("router-id must be an IPv4 address");
YYERROR;
}
@@ -342,42 +360,25 @@ conf_main : AS as4number {
}
| LISTEN ON address {
struct listen_addr *la;
- struct sockaddr_in *in;
- struct sockaddr_in6 *in6;
if ((la = calloc(1, sizeof(struct listen_addr))) ==
NULL)
fatal("parse conf_main listen on calloc");
la->fd = -1;
- la->sa.ss_family = $3.af;
- switch ($3.af) {
- case AF_INET:
- la->sa.ss_len = sizeof(struct sockaddr_in);
- in = (struct sockaddr_in *)&la->sa;
- in->sin_addr.s_addr = $3.v4.s_addr;
- in->sin_port = htons(BGP_PORT);
- break;
- case AF_INET6:
- la->sa.ss_len = sizeof(struct sockaddr_in6);
- in6 = (struct sockaddr_in6 *)&la->sa;
- memcpy(&in6->sin6_addr, &$3.v6,
- sizeof(in6->sin6_addr));
- in6->sin6_port = htons(BGP_PORT);
- break;
- default:
- yyerror("king bula does not like family %u",
- $3.af);
- YYERROR;
- }
-
+ memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa));
TAILQ_INSERT_TAIL(listen_addrs, la, entry);
}
| FIBUPDATE yesno {
+ struct rde_rib *rr;
+ rr = find_rib("Loc-RIB");
+ if (rr == NULL)
+ fatalx("RTABLE can not find the main RIB!");
+
if ($2 == 0)
- conf->flags |= BGPD_FLAG_NO_FIB_UPDATE;
+ rr->flags |= F_RIB_NOFIBSYNC;
else
- conf->flags &= ~BGPD_FLAG_NO_FIB_UPDATE;
+ rr->flags &= ~F_RIB_NOFIBSYNC;
}
| ROUTECOLL yesno {
if ($2 == 1)
@@ -386,7 +387,7 @@ conf_main : AS as4number {
conf->flags &= ~BGPD_FLAG_NO_EVALUATE;
}
| RDE RIB STRING {
- if (add_rib($3, F_RIB_NOFIB)) {
+ if (add_rib($3, 0, F_RIB_NOFIB)) {
free($3);
YYERROR;
}
@@ -395,9 +396,27 @@ conf_main : AS as4number {
| RDE RIB STRING yesno EVALUATE {
if ($4) {
free($3);
+ yyerror("bad rde rib definition");
YYERROR;
}
- if (!add_rib($3, F_RIB_NOEVALUATE)) {
+ if (add_rib($3, 0, F_RIB_NOFIB | F_RIB_NOEVALUATE)) {
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | RDE RIB STRING RTABLE NUMBER {
+ if (add_rib($3, $5, 0)) {
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno {
+ int flags = 0;
+ if ($7 == 0)
+ flags = F_RIB_NOFIBSYNC;
+ if (add_rib($3, $5, flags)) {
free($3);
YYERROR;
}
@@ -418,59 +437,7 @@ conf_main : AS as4number {
}
free($2);
}
- | NETWORK prefix filter_set {
- struct network *n;
-
- if ((n = calloc(1, sizeof(struct network))) == NULL)
- fatal("new_network");
- memcpy(&n->net.prefix, &$2.prefix,
- sizeof(n->net.prefix));
- n->net.prefixlen = $2.len;
- move_filterset($3, &n->net.attrset);
- free($3);
-
- TAILQ_INSERT_TAIL(netconf, n, entry);
- }
- | NETWORK family STATIC filter_set {
- if ($2 == AFI_IPv4) {
- conf->flags |= BGPD_FLAG_REDIST_STATIC;
- move_filterset($4, &conf->staticset);
- } else if ($2 == AFI_IPv6) {
- conf->flags |= BGPD_FLAG_REDIST6_STATIC;
- move_filterset($4, &conf->staticset6);
- } else {
- yyerror("unknown family");
- free($4);
- YYERROR;
- }
- free($4);
- }
- | NETWORK family CONNECTED filter_set {
- if ($2 == AFI_IPv4) {
- conf->flags |= BGPD_FLAG_REDIST_CONNECTED;
- move_filterset($4, &conf->connectset);
- } else if ($2 == AFI_IPv6) {
- conf->flags |= BGPD_FLAG_REDIST6_CONNECTED;
- move_filterset($4, &conf->connectset6);
- } else {
- yyerror("unknown family");
- free($4);
- YYERROR;
- }
- free($4);
- }
- | NETWORK STATIC filter_set {
- /* keep for compatibility till after next release */
- conf->flags |= BGPD_FLAG_REDIST_STATIC;
- move_filterset($3, &conf->staticset);
- free($3);
- }
- | NETWORK CONNECTED filter_set {
- /* keep for compatibility till after next release */
- conf->flags |= BGPD_FLAG_REDIST_CONNECTED;
- move_filterset($3, &conf->connectset);
- free($3);
- }
+ | network
| DUMP STRING STRING optnumber {
int action;
@@ -575,11 +542,20 @@ conf_main : AS as4number {
free($4);
}
| RTABLE NUMBER {
- if ($2 > RT_TABLEID_MAX || $2 < 0) {
- yyerror("invalid rtable id");
+#if defined(__FreeBSD__) /* FreeBSD does not support RTABLE */
+ yyerror("rtable id not supported in FreeBSD, yet");
+ YYERROR;
+#else
+ struct rde_rib *rr;
+ if (ktable_exists($2, NULL) != 1) {
+ yyerror("rtable id %lld does not exist", $2);
YYERROR;
}
- conf->rtableid = $2;
+ rr = find_rib("Loc-RIB");
+ if (rr == NULL)
+ fatalx("RTABLE can not find the main RIB!");
+ rr->rtableid = $2;
+#endif /* defined(__FreeBSD__) */
}
| CONNECTRETRY NUMBER {
if ($2 > USHRT_MAX || $2 < 1) {
@@ -588,6 +564,15 @@ conf_main : AS as4number {
}
conf->connectretry = $2;
}
+ | SOCKET STRING restricted {
+ if ($3) {
+ free(conf->rcsock);
+ conf->rcsock = $2;
+ } else {
+ free(conf->csock);
+ conf->csock = $2;
+ }
+ }
;
mrtdump : DUMP STRING inout STRING optnumber {
@@ -620,10 +605,47 @@ mrtdump : DUMP STRING inout STRING optnumber {
}
;
+network : NETWORK prefix filter_set {
+ struct network *n;
+
+ if ((n = calloc(1, sizeof(struct network))) == NULL)
+ fatal("new_network");
+ memcpy(&n->net.prefix, &$2.prefix,
+ sizeof(n->net.prefix));
+ n->net.prefixlen = $2.len;
+ filterset_move($3, &n->net.attrset);
+ free($3);
+
+ TAILQ_INSERT_TAIL(netconf, n, entry);
+ }
+ | NETWORK family nettype filter_set {
+ struct network *n;
+
+ if ((n = calloc(1, sizeof(struct network))) == NULL)
+ fatal("new_network");
+ if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
+ -1) {
+ yyerror("unknown family");
+ filterset_free($4);
+ free($4);
+ YYERROR;
+ }
+ n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
+ filterset_move($4, &n->net.attrset);
+ free($4);
+
+ TAILQ_INSERT_TAIL(netconf, n, entry);
+ }
+ ;
+
inout : IN { $$ = 1; }
| OUT { $$ = 0; }
;
+restricted : RESTRICTED { $$ = 1; }
+ | /* nothing */ { $$ = 0; }
+ ;
+
address : STRING {
u_int8_t len;
@@ -635,11 +657,11 @@ address : STRING {
}
free($1);
- if (($$.af == AF_INET && len != 32) ||
- ($$.af == AF_INET6 && len != 128)) {
+ if (($$.aid == AID_INET && len != 32) ||
+ ($$.aid == AID_INET6 && len != 128)) {
/* unreachable */
yyerror("got prefixlen %u, expected %u",
- len, $$.af == AF_INET ? 32 : 128);
+ len, $$.aid == AID_INET ? 32 : 128);
YYERROR;
}
}
@@ -653,7 +675,7 @@ prefix : STRING '/' NUMBER {
free($1);
YYERROR;
}
- if (asprintf(&s, "%s/%lld", $1, $3) == -1)
+ if (asprintf(&s, "%s/%lld", $1, (long long int)$3) == -1)
fatal(NULL);
free($1);
@@ -672,7 +694,7 @@ prefix : STRING '/' NUMBER {
yyerror("bad prefix %lld/%lld", $1, $3);
YYERROR;
}
- if (asprintf(&s, "%lld/%lld", $1, $3) == -1)
+ if (asprintf(&s, "%lld/%lld", (long long int)$1, (long long int)$3) == -1)
fatal(NULL);
if (!host(s, &$$.prefix, &$$.len)) {
@@ -686,7 +708,7 @@ prefix : STRING '/' NUMBER {
addrspec : address {
memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr));
- if ($$.prefix.af == AF_INET)
+ if ($$.prefix.aid == AID_INET)
$$.len = 32;
else
$$.len = 128;
@@ -705,14 +727,150 @@ optnumber : /* empty */ { $$ = 0; }
| NUMBER
;
+rdomain : RDOMAIN NUMBER optnl '{' optnl {
+ if (ktable_exists($2, NULL) != 1) {
+ yyerror("rdomain %lld does not exist", $2);
+ YYERROR;
+ }
+ if (!(currdom = calloc(1, sizeof(struct rdomain))))
+ fatal(NULL);
+ currdom->rtableid = $2;
+ TAILQ_INIT(&currdom->import);
+ TAILQ_INIT(&currdom->export);
+ TAILQ_INIT(&currdom->net_l);
+ netconf = &currdom->net_l;
+ }
+ rdomainopts_l '}' {
+ /* insert into list */
+ SIMPLEQ_INSERT_TAIL(rdom_l, currdom, entry);
+ currdom = NULL;
+ netconf = gnetconf;
+ }
+
+rdomainopts_l : rdomainopts_l rdomainoptsl
+ | rdomainoptsl
+ ;
+
+rdomainoptsl : rdomainopts nl
+ ;
+
+rdomainopts : RD STRING {
+ struct filter_extcommunity ext;
+ u_int64_t rd;
+
+ if (parseextcommunity(&ext, "rt", $2) == -1) {
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ /*
+ * RD is almost encode like an ext-community,
+ * but only almost so convert here.
+ */
+ if (community_ext_conv(&ext, 0, &rd)) {
+ yyerror("bad encoding of rd");
+ YYERROR;
+ }
+ rd = betoh64(rd) & 0xffffffffffffULL;
+ switch (ext.type) {
+ case EXT_COMMUNITY_TWO_AS:
+ rd |= (0ULL << 48);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ rd |= (1ULL << 48);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ rd |= (2ULL << 48);
+ break;
+ default:
+ yyerror("bad encoding of rd");
+ YYERROR;
+ }
+ currdom->rd = htobe64(rd);
+ }
+ | EXPORTTRGT STRING STRING {
+ struct filter_set *set;
+
+ if ((set = calloc(1, sizeof(struct filter_set))) ==
+ NULL)
+ fatal(NULL);
+ set->type = ACTION_SET_EXT_COMMUNITY;
+ if (parseextcommunity(&set->action.ext_community,
+ $2, $3) == -1) {
+ free($3);
+ free($2);
+ free(set);
+ YYERROR;
+ }
+ free($3);
+ free($2);
+ TAILQ_INSERT_TAIL(&currdom->export, set, entry);
+ }
+ | IMPORTTRGT STRING STRING {
+ struct filter_set *set;
+
+ if ((set = calloc(1, sizeof(struct filter_set))) ==
+ NULL)
+ fatal(NULL);
+ set->type = ACTION_SET_EXT_COMMUNITY;
+ if (parseextcommunity(&set->action.ext_community,
+ $2, $3) == -1) {
+ free($3);
+ free($2);
+ free(set);
+ YYERROR;
+ }
+ free($3);
+ free($2);
+ TAILQ_INSERT_TAIL(&currdom->import, set, entry);
+ }
+ | DESCR string {
+ if (strlcpy(currdom->descr, $2,
+ sizeof(currdom->descr)) >=
+ sizeof(currdom->descr)) {
+ yyerror("descr \"%s\" too long: max %u",
+ $2, sizeof(currdom->descr) - 1);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | FIBUPDATE yesno {
+ if ($2 == 0)
+ currdom->flags |= F_RIB_NOFIBSYNC;
+ else
+ currdom->flags &= ~F_RIB_NOFIBSYNC;
+ }
+ | network
+ | DEPEND ON STRING {
+ /* XXX this is a hack */
+ if (if_nametoindex($3) == 0) {
+ yyerror("interface %s does not exist", $3);
+ free($3);
+ YYERROR;
+ }
+ strlcpy(currdom->ifmpe, $3, IFNAMSIZ);
+ free($3);
+ if (get_mpe_label(currdom)) {
+ yyerror("failed to get mpls label from %s",
+ currdom->ifmpe);
+ YYERROR;
+ }
+ }
+ ;
+
neighbor : { curpeer = new_peer(); }
NEIGHBOR addrspec {
memcpy(&curpeer->conf.remote_addr, &$3.prefix,
sizeof(curpeer->conf.remote_addr));
curpeer->conf.remote_masklen = $3.len;
- if (($3.prefix.af == AF_INET && $3.len != 32) ||
- ($3.prefix.af == AF_INET6 && $3.len != 128))
+ if (($3.prefix.aid == AID_INET && $3.len != 32) ||
+ ($3.prefix.aid == AID_INET6 && $3.len != 128))
curpeer->conf.template = 1;
+ if (curpeer->conf.capabilities.mp[
+ curpeer->conf.remote_addr.aid] == -1)
+ curpeer->conf.capabilities.mp[
+ curpeer->conf.remote_addr.aid] = 1;
if (get_id(curpeer)) {
yyerror("get_id failed");
YYERROR;
@@ -802,6 +960,17 @@ peeropts : REMOTEAS as4number {
}
free($2);
}
+ | LLIFACE string {
+ if (strlcpy(curpeer->conf.lliface, $2,
+ sizeof(curpeer->conf.lliface)) >=
+ sizeof(curpeer->conf.lliface)) {
+ yyerror("lliface \"%s\" too long: max %u",
+ $2, sizeof(curpeer->conf.lliface) - 1);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
| LOCALADDR address {
memcpy(&curpeer->conf.local_addr, &$2,
sizeof(curpeer->conf.local_addr));
@@ -852,13 +1021,17 @@ peeropts : REMOTEAS as4number {
curpeer->conf.min_holdtime = $3;
}
| ANNOUNCE family STRING {
- u_int8_t safi;
+ u_int8_t aid, safi;
+ int8_t val = 1;
- if (!strcmp($3, "none"))
- safi = SAFI_NONE;
- else if (!strcmp($3, "unicast"))
+ if (!strcmp($3, "none")) {
safi = SAFI_UNICAST;
- else {
+ val = 0;
+ } else if (!strcmp($3, "unicast")) {
+ safi = SAFI_UNICAST;
+ } else if (!strcmp($3, "vpn")) {
+ safi = SAFI_MPLSVPN;
+ } else {
yyerror("unknown/unsupported SAFI \"%s\"",
$3);
free($3);
@@ -866,25 +1039,31 @@ peeropts : REMOTEAS as4number {
}
free($3);
- switch ($2) {
- case AFI_IPv4:
- curpeer->conf.capabilities.mp_v4 = safi;
- break;
- case AFI_IPv6:
- curpeer->conf.capabilities.mp_v6 = safi;
- break;
- default:
- fatal("king bula sees borked AFI");
+ if (afi2aid($2, safi, &aid) == -1) {
+ yyerror("unknown AFI/SAFI pair");
+ YYERROR;
}
+ curpeer->conf.capabilities.mp[aid] = val;
}
| ANNOUNCE CAPABILITIES yesno {
curpeer->conf.announce_capa = $3;
}
+ | ANNOUNCE REFRESH yesno {
+ curpeer->conf.capabilities.refresh = $3;
+ }
+ | ANNOUNCE RESTART yesno {
+ curpeer->conf.capabilities.restart = $3;
+ }
+ | ANNOUNCE AS4BYTE yesno {
+ curpeer->conf.capabilities.as4byte = $3;
+ }
| ANNOUNCE SELF {
curpeer->conf.announce_type = ANNOUNCE_SELF;
}
| ANNOUNCE STRING {
- if (!strcmp($2, "none"))
+ if (!strcmp($2, "self"))
+ curpeer->conf.announce_type = ANNOUNCE_SELF;
+ else if (!strcmp($2, "none"))
curpeer->conf.announce_type = ANNOUNCE_NONE;
else if (!strcmp($2, "all"))
curpeer->conf.announce_type = ANNOUNCE_ALL;
@@ -1083,7 +1262,7 @@ peeropts : REMOTEAS as4number {
curpeer->conf.reflector_client = 1;
}
| REFLECTOR address {
- if ($2.af != AF_INET) {
+ if ($2.aid != AID_INET) {
yyerror("route reflector cluster-id must be "
"an IPv4 address");
YYERROR;
@@ -1157,6 +1336,10 @@ family : IPV4 { $$ = AFI_IPv4; }
| IPV6 { $$ = AFI_IPv6; }
;
+nettype : STATIC { $$ = 1; },
+ | CONNECTED { $$ = 0; }
+ ;
+
espah : ESP { $$ = 1; }
| AH { $$ = 0; }
;
@@ -1336,12 +1519,12 @@ filter_prefix_l : filter_prefix { $$ = $1; }
;
filter_prefix : prefix {
- if (fmopts.af && fmopts.af != $1.prefix.af) {
+ if (fmopts.aid && fmopts.aid != $1.prefix.aid) {
yyerror("rules with mixed address families "
"are not allowed");
YYERROR;
} else
- fmopts.af = $1.prefix.af;
+ fmopts.aid = $1.prefix.aid;
if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
NULL)
fatal(NULL);
@@ -1410,6 +1593,12 @@ filter_as : as4number {
fatal(NULL);
$$->a.as = $1;
}
+ | NEIGHBORAS {
+ if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
+ NULL)
+ fatal(NULL);
+ $$->a.flags = AS_FLAG_NEIGHBORAS;
+ }
;
filter_match_h : /* empty */ {
@@ -1437,18 +1626,18 @@ filter_elm : filter_prefix_h {
fmopts.prefix_l = $1;
}
| PREFIXLEN prefixlenop {
- if (fmopts.af == 0) {
+ if (fmopts.aid == 0) {
yyerror("address family needs to be specified "
"before \"prefixlen\"");
YYERROR;
}
- if (fmopts.m.prefixlen.af) {
+ if (fmopts.m.prefixlen.aid) {
yyerror("\"prefixlen\" already specified");
YYERROR;
}
memcpy(&fmopts.m.prefixlen, &$2,
sizeof(fmopts.m.prefixlen));
- fmopts.m.prefixlen.af = fmopts.af;
+ fmopts.m.prefixlen.aid = fmopts.aid;
}
| filter_as_h {
if (fmopts.as_l != NULL) {
@@ -1457,32 +1646,73 @@ filter_elm : filter_prefix_h {
}
fmopts.as_l = $1;
}
+ | MAXASLEN NUMBER {
+ if (fmopts.m.aslen.type != ASLEN_NONE) {
+ yyerror("AS length filters already specified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("bad max-as-len %lld", $2);
+ YYERROR;
+ }
+ fmopts.m.aslen.type = ASLEN_MAX;
+ fmopts.m.aslen.aslen = $2;
+ }
+ | MAXASSEQ NUMBER {
+ if (fmopts.m.aslen.type != ASLEN_NONE) {
+ yyerror("AS length filters already specified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("bad max-as-seq %lld", $2);
+ YYERROR;
+ }
+ fmopts.m.aslen.type = ASLEN_SEQ;
+ fmopts.m.aslen.aslen = $2;
+ }
| COMMUNITY STRING {
if (fmopts.m.community.as != COMMUNITY_UNSET) {
yyerror("\"community\" already specified");
free($2);
YYERROR;
}
- if (parsecommunity($2, &fmopts.m.community.as,
- &fmopts.m.community.type) == -1) {
+ if (parsecommunity(&fmopts.m.community, $2) == -1) {
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | EXTCOMMUNITY STRING STRING {
+ if (fmopts.m.ext_community.flags &
+ EXT_COMMUNITY_FLAG_VALID) {
+ yyerror("\"ext-community\" already specified");
+ free($2);
+ free($3);
+ YYERROR;
+ }
+
+ if (parseextcommunity(&fmopts.m.ext_community,
+ $2, $3) == -1) {
free($2);
+ free($3);
YYERROR;
}
free($2);
+ free($3);
}
| IPV4 {
- if (fmopts.af) {
+ if (fmopts.aid) {
yyerror("address family already specified");
YYERROR;
}
- fmopts.af = AF_INET;
+ fmopts.aid = AID_INET;
}
| IPV6 {
- if (fmopts.af) {
+ if (fmopts.aid) {
yyerror("address family already specified");
YYERROR;
}
- fmopts.af = AF_INET6;
+ fmopts.aid = AID_INET6;
}
;
@@ -1782,8 +2012,7 @@ filter_set_opt : LOCALPREF NUMBER {
else
$$->type = ACTION_SET_COMMUNITY;
- if (parsecommunity($3, &$$->action.community.as,
- &$$->action.community.type) == -1) {
+ if (parsecommunity(&$$->action.community, $3) == -1) {
free($3);
free($$);
YYERROR;
@@ -1796,40 +2025,62 @@ filter_set_opt : LOCALPREF NUMBER {
free($$);
YYERROR;
}
- /* Don't allow setting of unknown well-known types */
- if ($$->action.community.as == COMMUNITY_WELLKNOWN) {
- switch ($$->action.community.type) {
- case COMMUNITY_NO_EXPORT:
- case COMMUNITY_NO_ADVERTISE:
- case COMMUNITY_NO_EXPSUBCONFED:
- case COMMUNITY_NO_PEER:
- /* valid */
- break;
- default:
- /* unknown */
- yyerror("Invalid well-known community");
- free($$);
- YYERROR;
- break;
- }
+ }
+ | EXTCOMMUNITY delete STRING STRING {
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ if ($2)
+ $$->type = ACTION_DEL_EXT_COMMUNITY;
+ else
+ $$->type = ACTION_SET_EXT_COMMUNITY;
+
+ if (parseextcommunity(&$$->action.ext_community,
+ $3, $4) == -1) {
+ free($3);
+ free($4);
+ free($$);
+ YYERROR;
}
+ free($3);
+ free($4);
+ }
+ | ORIGIN origincode {
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_ORIGIN;
+ $$->action.origin = $2;
}
;
+origincode : string {
+ if (!strcmp($1, "egp"))
+ $$ = ORIGIN_EGP;
+ else if (!strcmp($1, "igp"))
+ $$ = ORIGIN_IGP;
+ else if (!strcmp($1, "incomplete"))
+ $$ = ORIGIN_INCOMPLETE;
+ else {
+ yyerror("unknown origin \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ };
+
comma : ","
| /* empty */
;
unaryop : '=' { $$ = OP_EQ; }
- | '!' '=' { $$ = OP_NE; }
- | '<' '=' { $$ = OP_LE; }
+ | NE { $$ = OP_NE; }
+ | LE { $$ = OP_LE; }
| '<' { $$ = OP_LT; }
- | '>' '=' { $$ = OP_GE; }
+ | GE { $$ = OP_GE; }
| '>' { $$ = OP_GT; }
;
binaryop : '-' { $$ = OP_RANGE; }
- | '>' '<' { $$ = OP_XRANGE; }
+ | XRANGE { $$ = OP_XRANGE; }
;
%%
@@ -1873,6 +2124,7 @@ lookup(char *s)
{ "allow", ALLOW},
{ "announce", ANNOUNCE},
{ "any", ANY},
+ { "as-4byte", AS4BYTE },
{ "blackhole", BLACKHOLE},
{ "capabilities", CAPABILITIES},
{ "community", COMMUNITY},
@@ -1889,16 +2141,22 @@ lookup(char *s)
{ "enforce", ENFORCE},
{ "esp", ESP},
{ "evaluate", EVALUATE},
+ { "export-target", EXPORTTRGT},
+ { "ext-community", EXTCOMMUNITY},
{ "fib-update", FIBUPDATE},
{ "from", FROM},
{ "group", GROUP},
{ "holdtime", HOLDTIME},
{ "ignore", IGNORE},
{ "ike", IKE},
+ { "import-target", IMPORTTRGT},
{ "in", IN},
{ "include", INCLUDE},
{ "inet", IPV4},
{ "inet6", IPV6},
+#if defined(IPV6_LINKLOCAL_PEER)
+ { "interface", LLIFACE},
+#endif
{ "ipsec", IPSEC},
{ "key", KEY},
{ "listen", LISTEN},
@@ -1906,6 +2164,8 @@ lookup(char *s)
{ "localpref", LOCALPREF},
{ "log", LOG},
{ "match", MATCH},
+ { "max-as-len", MAXASLEN},
+ { "max-as-seq", MAXASSEQ},
{ "max-prefix", MAXPREFIX},
{ "md5sig", MD5SIG},
{ "med", MED},
@@ -1918,6 +2178,7 @@ lookup(char *s)
{ "nexthop", NEXTHOP},
{ "no-modify", NOMODIFY},
{ "on", ON},
+ { "origin", ORIGIN},
{ "out", OUT},
{ "passive", PASSIVE},
{ "password", PASSWORD},
@@ -1929,10 +2190,14 @@ lookup(char *s)
{ "prepend-self", PREPEND_SELF},
{ "qualify", QUALIFY},
{ "quick", QUICK},
+ { "rd", RD},
{ "rde", RDE},
+ { "rdomain", RDOMAIN},
+ { "refresh", REFRESH },
{ "reject", REJECT},
{ "remote-as", REMOTEAS},
{ "restart", RESTART},
+ { "restricted", RESTRICTED},
{ "rib", RIB},
{ "route-collector", ROUTECOLL},
{ "route-reflector", REFLECTOR},
@@ -1941,6 +2206,7 @@ lookup(char *s)
{ "rtlabel", RTLABEL},
{ "self", SELF},
{ "set", SET},
+ { "socket", SOCKET },
{ "softreconfig", SOFTRECONFIG},
{ "source-as", SOURCEAS},
{ "spi", SPI},
@@ -2117,9 +2383,10 @@ top:
return (0);
if (next == quotec || c == ' ' || c == '\t')
c = next;
- else if (next == '\n')
+ else if (next == '\n') {
+ file->lineno++;
continue;
- else
+ } else
lungetc(next);
} else if (c == quotec) {
*p = '\0';
@@ -2135,6 +2402,26 @@ top:
if (yylval.v.string == NULL)
fatal("yylex: strdup");
return (STRING);
+ case '!':
+ next = lgetc(0);
+ if (next == '=')
+ return (NE);
+ lungetc(next);
+ break;
+ case '<':
+ next = lgetc(0);
+ if (next == '=')
+ return (LE);
+ lungetc(next);
+ break;
+ case '>':
+ next = lgetc(0);
+ if (next == '<')
+ return (XRANGE);
+ else if (next == '=')
+ return (GE);
+ lungetc(next);
+ break;
}
#define allowed_to_end_number(x) \
@@ -2274,18 +2561,21 @@ popfile(void)
int
parse_config(char *filename, struct bgpd_config *xconf,
struct mrt_head *xmconf, struct peer **xpeers, struct network_head *nc,
- struct filter_head *xfilter_l)
+ struct filter_head *xfilter_l, struct rdomain_head *xrdom_l)
{
struct sym *sym, *next;
struct peer *p, *pnext;
struct listen_addr *la;
struct network *n;
struct filter_rule *r;
+ struct rde_rib *rr;
+ struct rdomain *rd;
int errors = 0;
if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
fatal(NULL);
conf->opts = xconf->opts;
+ conf->csock = strdup(SOCKET_NAME);
if ((file = pushfile(filename, 1)) == NULL) {
free(conf);
@@ -2316,13 +2606,15 @@ parse_config(char *filename, struct bgpd_config *xconf,
id = 1;
/* network list is always empty in the parent */
- netconf = nc;
+ gnetconf = netconf = nc;
TAILQ_INIT(netconf);
/* init the empty filter list for later */
TAILQ_INIT(xfilter_l);
+ SIMPLEQ_INIT(xrdom_l);
+ rdom_l = xrdom_l;
- add_rib("Adj-RIB-In", F_RIB_NOEVALUATE);
- add_rib("Loc-RIB", 0);
+ add_rib("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE);
+ add_rib("Loc-RIB", 0, 0);
yyparse();
errors = file->errors;
@@ -2344,6 +2636,9 @@ parse_config(char *filename, struct bgpd_config *xconf,
if (errors) {
/* XXX more leaks in this case */
+ free(conf->csock);
+ free(conf->rcsock);
+
while ((la = TAILQ_FIRST(listen_addrs)) != NULL) {
TAILQ_REMOVE(listen_addrs, la, entry);
free(la);
@@ -2357,23 +2652,44 @@ parse_config(char *filename, struct bgpd_config *xconf,
while ((n = TAILQ_FIRST(netconf)) != NULL) {
TAILQ_REMOVE(netconf, n, entry);
+ filterset_free(&n->net.attrset);
free(n);
}
while ((r = TAILQ_FIRST(filter_l)) != NULL) {
TAILQ_REMOVE(filter_l, r, entry);
+ filterset_free(&r->set);
free(r);
}
while ((r = TAILQ_FIRST(peerfilter_l)) != NULL) {
TAILQ_REMOVE(peerfilter_l, r, entry);
+ filterset_free(&r->set);
free(r);
}
while ((r = TAILQ_FIRST(groupfilter_l)) != NULL) {
TAILQ_REMOVE(groupfilter_l, r, entry);
+ filterset_free(&r->set);
free(r);
}
+ while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
+ free(rr);
+ }
+ while ((rd = SIMPLEQ_FIRST(rdom_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(rdom_l, entry);
+ filterset_free(&rd->export);
+ filterset_free(&rd->import);
+
+ while ((n = TAILQ_FIRST(&rd->net_l)) != NULL) {
+ TAILQ_REMOVE(&rd->net_l, n, entry);
+ filterset_free(&n->net.attrset);
+ free(n);
+ }
+
+ free(rd);
+ }
} else {
errors += merge_config(xconf, conf, peer_l, listen_addrs);
errors += mrt_mergeconfig(xmconf, mrtconf);
@@ -2505,27 +2821,27 @@ getcommunity(char *s)
}
int
-parsecommunity(char *s, int *as, int *type)
+parsecommunity(struct filter_community *c, char *s)
{
char *p;
- int i;
+ int i, as;
/* Well-known communities */
if (strcasecmp(s, "NO_EXPORT") == 0) {
- *as = COMMUNITY_WELLKNOWN;
- *type = COMMUNITY_NO_EXPORT;
+ c->as = COMMUNITY_WELLKNOWN;
+ c->type = COMMUNITY_NO_EXPORT;
return (0);
} else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
- *as = COMMUNITY_WELLKNOWN;
- *type = COMMUNITY_NO_ADVERTISE;
+ c->as = COMMUNITY_WELLKNOWN;
+ c->type = COMMUNITY_NO_ADVERTISE;
return (0);
} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
- *as = COMMUNITY_WELLKNOWN;
- *type = COMMUNITY_NO_EXPSUBCONFED;
+ c->as = COMMUNITY_WELLKNOWN;
+ c->type = COMMUNITY_NO_EXPSUBCONFED;
return (0);
} else if (strcasecmp(s, "NO_PEER") == 0) {
- *as = COMMUNITY_WELLKNOWN;
- *type = COMMUNITY_NO_PEER;
+ c->as = COMMUNITY_WELLKNOWN;
+ c->type = COMMUNITY_NO_PEER;
return (0);
}
@@ -2537,23 +2853,176 @@ parsecommunity(char *s, int *as, int *type)
if ((i = getcommunity(s)) == COMMUNITY_ERROR)
return (-1);
- if (i == USHRT_MAX) {
+ if (i == COMMUNITY_WELLKNOWN) {
yyerror("Bad community AS number");
return (-1);
}
- *as = i;
+ as = i;
if ((i = getcommunity(p)) == COMMUNITY_ERROR)
return (-1);
- *type = i;
+ c->as = as;
+ c->type = i;
return (0);
}
+int
+parsesubtype(char *type)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "bdc", EXT_COMMUNITY_BGP_COLLECT },
+ { "odi", EXT_COMMUNITY_OSPF_DOM_ID },
+ { "ori", EXT_COMMUNITY_OSPF_RTR_ID },
+ { "ort", EXT_COMMUNITY_OSPF_RTR_TYPE },
+ { "rt", EXT_COMMUNITY_ROUTE_TGT },
+ { "soo", EXT_CUMMUNITY_ROUTE_ORIG }
+ };
+ const struct keywords *p;
+
+ p = bsearch(type, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p)
+ return (p->k_val);
+ else
+ return (-1);
+}
+
+int
+parseextvalue(char *s, u_int32_t *v)
+{
+ const char *errstr;
+ char *p;
+ struct in_addr ip;
+ u_int32_t uvalh = 0, uval;
+
+ if ((p = strchr(s, '.')) == NULL) {
+ /* AS_PLAIN number (4 or 2 byte) */
+ uval = strtonum(s, 0, UINT_MAX, &errstr);
+ if (errstr) {
+ yyerror("Bad ext-community %s is %s", s, errstr);
+ return (-1);
+ }
+ *v = uval;
+ if (uval > USHRT_MAX)
+ return (EXT_COMMUNITY_FOUR_AS);
+ else
+ return (EXT_COMMUNITY_TWO_AS);
+ } else if (strchr(p + 1, '.') == NULL) {
+ /* AS_DOT number (4-byte) */
+ *p++ = '\0';
+ uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ yyerror("Bad ext-community %s is %s", s, errstr);
+ return (-1);
+ }
+ uval = strtonum(p, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ yyerror("Bad ext-community %s is %s", p, errstr);
+ return (-1);
+ }
+ *v = uval | (uvalh << 16);
+ return (EXT_COMMUNITY_FOUR_AS);
+ } else {
+ /* more then one dot -> IP address */
+ if (inet_aton(s, &ip) == 0) {
+ yyerror("Bad ext-community %s not parseable", s);
+ return (-1);
+ }
+ *v = ip.s_addr;
+ return (EXT_COMMUNITY_IPV4);
+ }
+ return (-1);
+}
+
+int
+parseextcommunity(struct filter_extcommunity *c, char *t, char *s)
+{
+ const struct ext_comm_pairs iana[] = IANA_EXT_COMMUNITIES;
+ const char *errstr;
+ u_int64_t ullval = 0;
+ u_int32_t uval;
+ char *p, *ep;
+ unsigned int i;
+ int type, subtype;
+
+ if ((subtype = parsesubtype(t)) == -1) {
+ yyerror("Bad ext-community unknown type");
+ return (-1);
+ }
+
+ if ((p = strchr(s, ':')) == NULL) {
+ type = EXT_COMMUNITY_OPAQUE,
+ errno = 0;
+ ullval = strtoull(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0') {
+ yyerror("Bad ext-community bad value");
+ return (-1);
+ }
+ if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
+ yyerror("Bad ext-community value to big");
+ return (-1);
+ }
+ c->data.ext_opaq = ullval;
+ } else {
+ *p++ = '\0';
+ if ((type = parseextvalue(s, &uval)) == -1)
+ return (-1);
+ switch (type) {
+ case EXT_COMMUNITY_TWO_AS:
+ ullval = strtonum(p, 0, UINT_MAX, &errstr);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ case EXT_COMMUNITY_FOUR_AS:
+ ullval = strtonum(p, 0, USHRT_MAX, &errstr);
+ break;
+ default:
+ fatalx("parseextcommunity: unexpected result");
+ }
+ if (errstr) {
+ yyerror("Bad ext-community %s is %s", p,
+ errstr);
+ return (-1);
+ }
+ switch (type) {
+ case EXT_COMMUNITY_TWO_AS:
+ c->data.ext_as.as = uval;
+ c->data.ext_as.val = ullval;
+ break;
+ case EXT_COMMUNITY_IPV4:
+ c->data.ext_ip.addr.s_addr = uval;
+ c->data.ext_ip.val = ullval;
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ c->data.ext_as4.as4 = uval;
+ c->data.ext_as4.val = ullval;
+ break;
+ }
+ }
+ c->type = type;
+ c->subtype = subtype;
+
+ /* verify type/subtype combo */
+ for (i = 0; i < sizeof(iana)/sizeof(iana[0]); i++) {
+ if (iana[i].type == type && iana[i].subtype == subtype) {
+ if (iana[i].transitive)
+ c->type |= EXT_COMMUNITY_TRANSITIVE;
+ c->flags |= EXT_COMMUNITY_FLAG_VALID;
+ return (0);
+ }
+ }
+
+ yyerror("Bad ext-community bad format for type");
+ return (-1);
+}
+
struct peer *
alloc_peer(void)
{
struct peer *p;
+ u_int8_t i;
if ((p = calloc(1, sizeof(struct peer))) == NULL)
fatal("new_peer");
@@ -2564,11 +3033,11 @@ alloc_peer(void)
p->conf.distance = 1;
p->conf.announce_type = ANNOUNCE_UNDEF;
p->conf.announce_capa = 1;
- p->conf.capabilities.mp_v4 = SAFI_UNICAST;
- p->conf.capabilities.mp_v6 = SAFI_NONE;
+ for (i = 0; i < AID_MAX; i++)
+ p->conf.capabilities.mp[i] = -1;
p->conf.capabilities.refresh = 1;
p->conf.capabilities.restart = 0;
- p->conf.capabilities.as4byte = 0;
+ p->conf.capabilities.as4byte = 1;
p->conf.local_as = conf->as;
p->conf.local_short_as = conf->short_as;
p->conf.softreconfig_in = 1;
@@ -2592,6 +3061,9 @@ new_peer(void)
if (strlcpy(p->conf.descr, curgroup->conf.descr,
sizeof(p->conf.descr)) >= sizeof(p->conf.descr))
fatalx("new_peer descr strlcpy");
+ if (strlcpy(p->conf.lliface, curgroup->conf.lliface,
+ sizeof(p->conf.lliface)) >= sizeof(p->conf.lliface))
+ fatalx("new_peer lliface strlcpy");
p->conf.groupid = curgroup->conf.id;
p->conf.local_as = curgroup->conf.local_as;
p->conf.local_short_as = curgroup->conf.local_short_as;
@@ -2674,39 +3146,52 @@ add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p,
}
int
-add_rib(char *name, u_int16_t flags)
+add_rib(char *name, u_int rtableid, u_int16_t flags)
{
struct rde_rib *rr;
+ u_int rdom;
- if (find_rib(name)) {
- yyerror("rib \"%s\" allready exists.", name);
- return (-1);
- }
-
- if ((rr = calloc(1, sizeof(*rr))) == NULL) {
- log_warn("add_rib");
- return (-1);
+ if ((rr = find_rib(name)) == NULL) {
+ if ((rr = calloc(1, sizeof(*rr))) == NULL) {
+ log_warn("add_rib");
+ return (-1);
+ }
}
if (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) {
yyerror("rib name \"%s\" too long: max %u",
name, sizeof(rr->name) - 1);
+ free(rr);
return (-1);
}
rr->flags |= flags;
+ if ((rr->flags & F_RIB_HASNOFIB) == 0) {
+ if (ktable_exists(rtableid, &rdom) != 1) {
+ yyerror("rtable id %lld does not exist", rtableid);
+ free(rr);
+ return (-1);
+ }
+ if (rdom != 0) {
+ yyerror("rtable %lld does not belong to rdomain 0",
+ rtableid);
+ free(rr);
+ return (-1);
+ }
+ rr->rtableid = rtableid;
+ }
SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
return (0);
}
-int
+struct rde_rib *
find_rib(char *name)
{
struct rde_rib *rr;
SIMPLEQ_FOREACH(rr, &ribnames, entry) {
if (!strcmp(rr->name, name))
- return (1);
+ return (rr);
}
- return (0);
+ return (NULL);
}
int
@@ -2715,7 +3200,7 @@ get_id(struct peer *newpeer)
struct peer *p;
for (p = peer_l_old; p != NULL; p = p->next)
- if (newpeer->conf.remote_addr.af) {
+ if (newpeer->conf.remote_addr.aid) {
if (!memcmp(&p->conf.remote_addr,
&newpeer->conf.remote_addr,
sizeof(p->conf.remote_addr))) {
@@ -2856,9 +3341,11 @@ str2key(char *s, char *dest, size_t max_len)
int
neighbor_consistent(struct peer *p)
{
+ u_int8_t i;
+
/* local-address and peer's address: same address family */
- if (p->conf.local_addr.af &&
- p->conf.local_addr.af != p->conf.remote_addr.af) {
+ if (p->conf.local_addr.aid &&
+ p->conf.local_addr.aid != p->conf.remote_addr.aid) {
yyerror("local-address and neighbor address "
"must be of the same address family");
return (-1);
@@ -2869,7 +3356,7 @@ neighbor_consistent(struct peer *p)
p->conf.auth.method == AUTH_IPSEC_IKE_AH ||
p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
- !p->conf.local_addr.af) {
+ !p->conf.local_addr.aid) {
yyerror("neighbors with any form of IPsec configured "
"need local-address to be specified");
return (-1);
@@ -2889,10 +3376,6 @@ neighbor_consistent(struct peer *p)
return (-1);
}
- /* for testing: enable 4-byte AS number capability if necessary */
- if (conf->as > USHRT_MAX || p->conf.remote_as > USHRT_MAX)
- p->conf.capabilities.as4byte = 1;
-
/* set default values if they where undefined */
p->conf.ebgp = (p->conf.remote_as != conf->as);
if (p->conf.announce_type == ANNOUNCE_UNDEF)
@@ -2909,6 +3392,11 @@ neighbor_consistent(struct peer *p)
return (-1);
}
+ /* the default MP capability is NONE */
+ for (i = 0; i < AID_MAX; i++)
+ if (p->conf.capabilities.mp[i] == -1)
+ p->conf.capabilities.mp[i] = 0;
+
return (0);
}
@@ -2927,6 +3415,11 @@ merge_filterset(struct filter_set_head *sh, struct filter_set *s)
yyerror("community is already set");
else if (s->type == ACTION_DEL_COMMUNITY)
yyerror("community will already be deleted");
+ else if (s->type == ACTION_SET_EXT_COMMUNITY)
+ yyerror("ext-community is already set");
+ else if (s->type == ACTION_DEL_EXT_COMMUNITY)
+ yyerror(
+ "ext-community will already be deleted");
else
yyerror("redefining set parameter %s",
filterset_name(s->type));
@@ -2953,9 +3446,18 @@ merge_filterset(struct filter_set_head *sh, struct filter_set *s)
return (0);
}
break;
+ case ACTION_SET_EXT_COMMUNITY:
+ case ACTION_DEL_EXT_COMMUNITY:
+ if (memcmp(&s->action.ext_community,
+ &t->action.ext_community,
+ sizeof(s->action.ext_community)) < 0) {
+ TAILQ_INSERT_BEFORE(t, s, entry);
+ return (0);
+ }
+ break;
case ACTION_SET_NEXTHOP:
- if (s->action.nexthop.af <
- t->action.nexthop.af) {
+ if (s->action.nexthop.aid <
+ t->action.nexthop.aid) {
TAILQ_INSERT_BEFORE(t, s, entry);
return (0);
}
@@ -2985,22 +3487,6 @@ copy_filterset(struct filter_set_head *source, struct filter_set_head *dest)
}
}
-void
-move_filterset(struct filter_set_head *source, struct filter_set_head *dest)
-{
- struct filter_set *s;
-
- TAILQ_INIT(dest);
-
- if (source == NULL)
- return;
-
- while ((s = TAILQ_FIRST(source)) != NULL) {
- TAILQ_REMOVE(source, s, entry);
- TAILQ_INSERT_TAIL(dest, s, entry);
- }
-}
-
struct filter_rule *
get_rule(enum action_types type)
{
diff --git a/bgpd/pfkey.c b/bgpd/pfkey.c
index 80936f4..30ed413 100644
--- a/bgpd/pfkey.c
+++ b/bgpd/pfkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkey.c,v 1.37 2009/04/21 15:25:52 henning Exp $ */
+/* $OpenBSD: pfkey.c,v 1.41 2010/12/09 13:50:41 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -74,6 +74,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
int len = 0;
int iov_cnt;
struct sockaddr_storage ssrc, sdst, speer, smask, dmask;
+ struct sockaddr *saptr;
if (!pid)
pid = getpid();
@@ -81,22 +82,17 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
/* we need clean sockaddr... no ports set */
bzero(&ssrc, sizeof(ssrc));
bzero(&smask, sizeof(smask));
- switch (src->af) {
- case AF_INET:
- ((struct sockaddr_in *)&ssrc)->sin_addr = src->v4;
- ssrc.ss_len = sizeof(struct sockaddr_in);
- ssrc.ss_family = AF_INET;
+ if ((saptr = addr2sa(src, 0)))
+ memcpy(&ssrc, saptr, sizeof(ssrc));
+ switch (src->aid) {
+ case AID_INET:
memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
break;
- case AF_INET6:
- memcpy(&((struct sockaddr_in6 *)&ssrc)->sin6_addr,
- &src->v6, sizeof(struct in6_addr));
- ssrc.ss_len = sizeof(struct sockaddr_in6);
- ssrc.ss_family = AF_INET6;
+ case AID_INET6:
memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff,
128/8);
break;
- case 0:
+ case AID_UNSPEC:
ssrc.ss_len = sizeof(struct sockaddr);
break;
default:
@@ -107,22 +103,17 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
bzero(&sdst, sizeof(sdst));
bzero(&dmask, sizeof(dmask));
- switch (dst->af) {
- case AF_INET:
- ((struct sockaddr_in *)&sdst)->sin_addr = dst->v4;
- sdst.ss_len = sizeof(struct sockaddr_in);
- sdst.ss_family = AF_INET;
+ if ((saptr = addr2sa(dst, 0)))
+ memcpy(&sdst, saptr, sizeof(sdst));
+ switch (dst->aid) {
+ case AID_INET:
memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
break;
- case AF_INET6:
- memcpy(&((struct sockaddr_in6 *)&sdst)->sin6_addr,
- &dst->v6, sizeof(struct in6_addr));
- sdst.ss_len = sizeof(struct sockaddr_in6);
- sdst.ss_family = AF_INET6;
+ case AID_INET6:
memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff,
128/8);
break;
- case 0:
+ case AID_UNSPEC:
sdst.ss_len = sizeof(struct sockaddr);
break;
default:
@@ -220,8 +211,8 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW;
bzero(&smask, sizeof(smask));
- switch (src->af) {
- case AF_INET:
+ switch (src->aid) {
+ case AID_INET:
smask.ss_len = sizeof(struct sockaddr_in);
smask.ss_family = AF_INET;
memset(&((struct sockaddr_in *)&smask)->sin_addr,
@@ -233,7 +224,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
htons(0xffff);
}
break;
- case AF_INET6:
+ case AID_INET6:
smask.ss_len = sizeof(struct sockaddr_in6);
smask.ss_family = AF_INET6;
memset(&((struct sockaddr_in6 *)&smask)->sin6_addr,
@@ -247,8 +238,8 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
break;
}
bzero(&dmask, sizeof(dmask));
- switch (dst->af) {
- case AF_INET:
+ switch (dst->aid) {
+ case AID_INET:
dmask.ss_len = sizeof(struct sockaddr_in);
dmask.ss_family = AF_INET;
memset(&((struct sockaddr_in *)&dmask)->sin_addr,
@@ -260,7 +251,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
htons(0xffff);
}
break;
- case AF_INET6:
+ case AID_INET6:
dmask.ss_len = sizeof(struct sockaddr_in6);
dmask.ss_family = AF_INET6;
memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr,
@@ -411,6 +402,33 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
}
int
+pfkey_read(int sd, struct sadb_msg *h)
+{
+ struct sadb_msg hdr;
+
+ if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
+ log_warn("pfkey peek");
+ return (-1);
+ }
+
+ /* XXX: Only one message can be outstanding. */
+ if (hdr.sadb_msg_seq == sadb_msg_seq &&
+ hdr.sadb_msg_pid == pid) {
+ if (h)
+ bcopy(&hdr, h, sizeof(hdr));
+ return (0);
+ }
+
+ /* not ours, discard */
+ if (read(sd, &hdr, sizeof(hdr)) == -1) {
+ log_warn("pfkey read");
+ return (-1);
+ }
+
+ return (1);
+}
+
+int
pfkey_reply(int sd, u_int32_t *spip)
{
struct sadb_msg hdr, *msg;
@@ -418,23 +436,13 @@ pfkey_reply(int sd, u_int32_t *spip)
struct sadb_sa *sa;
u_int8_t *data;
ssize_t len;
+ int rv;
- for (;;) {
- if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
- log_warn("pfkey peek");
+ do {
+ rv = pfkey_read(sd, &hdr);
+ if (rv == -1)
return (-1);
- }
-
- if (hdr.sadb_msg_seq == sadb_msg_seq &&
- hdr.sadb_msg_pid == pid)
- break;
-
- /* not ours, discard */
- if (read(sd, &hdr, sizeof(hdr)) == -1) {
- log_warn("pfkey read");
- return (-1);
- }
- }
+ } while (rv);
if (hdr.sadb_msg_errno != 0) {
errno = hdr.sadb_msg_errno;
@@ -730,11 +738,9 @@ pfkey_init(struct bgpd_sysdep *sysdep)
if (errno == EPROTONOSUPPORT) {
log_warnx("PF_KEY not available, disabling ipsec");
sysdep->no_pfkey = 1;
- return (0);
- } else {
- log_warn("PF_KEY socket");
return (-1);
- }
+ } else
+ fatal("pfkey setup failed");
}
- return (0);
+ return (fd);
}
diff --git a/bgpd/pftable.c b/bgpd/pftable.c
index 13b8c48..0a365df 100644
--- a/bgpd/pftable.c
+++ b/bgpd/pftable.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pftable.c,v 1.5 2005/07/01 09:19:24 claudio Exp $ */
+/* $OpenBSD: pftable.c,v 1.6 2009/12/01 14:28:05 claudio Exp $ */
/*
* Copyright (c) 2004 Damien Miller <djm@openbsd.org>
@@ -214,7 +214,7 @@ pftable_add_work(const char *table, struct bgpd_addr *addr,
bzero(pfa, sizeof(*pfa));
memcpy(&pfa->pfra_u, &addr->ba, (len + 7U) / 8);
- pfa->pfra_af = addr->af;
+ pfa->pfra_af = aid2af(addr->aid);
pfa->pfra_net = len;
pft->naddrs++;
diff --git a/bgpd/printconf.c b/bgpd/printconf.c
index c64d23d..3086b88 100644
--- a/bgpd/printconf.c
+++ b/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.70 2009/06/06 01:10:29 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.79 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,9 +16,13 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if defined(__FreeBSD__) /* limits.h */
+#include <limits.h>
+#endif
#include "bgpd.h"
#include "mrt.h"
@@ -27,14 +31,19 @@
void print_op(enum comp_ops);
void print_community(int, int);
+void print_extcommunity(struct filter_extcommunity *);
+void print_origin(u_int8_t);
void print_set(struct filter_set_head *);
void print_mainconf(struct bgpd_config *);
+void print_rdomain_targets(struct filter_set_head *, const char *);
+void print_rdomain(struct rdomain *);
+const char *print_af(u_int8_t);
void print_network(struct network_config *);
void print_peer(struct peer_config *, struct bgpd_config *,
const char *);
const char *print_auth_alg(u_int8_t);
const char *print_enc_alg(u_int8_t);
-const char *print_safi(u_int8_t);
+void print_announce(struct peer_config *, const char *);
void print_rule(struct peer *, struct filter_rule *);
const char * mrt_type(enum mrt_type);
void print_mrt(u_int32_t, u_int32_t, const char *, const char *);
@@ -94,6 +103,45 @@ print_community(int as, int type)
}
void
+print_extcommunity(struct filter_extcommunity *c)
+{
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ printf("%s %i:%i ", log_ext_subtype(c->subtype),
+ c->data.ext_as.as, c->data.ext_as.val);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ printf("%s %s:%i ", log_ext_subtype(c->subtype),
+ inet_ntoa(c->data.ext_ip.addr), c->data.ext_ip.val);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ printf("%s %s:%i ", log_ext_subtype(c->subtype),
+ log_as(c->data.ext_as4.as4), c->data.ext_as.val);
+ break;
+ case EXT_COMMUNITY_OPAQUE:
+ printf("%s 0x%llx ", log_ext_subtype(c->subtype),
+ (long long unsigned int)c->data.ext_opaq);
+ break;
+ default:
+ printf("0x%x 0x%llx ", c->type, (long long unsigned int)c->data.ext_opaq);
+ break;
+ }
+}
+
+void
+print_origin(u_int8_t o)
+{
+ if (o == ORIGIN_IGP)
+ printf("igp ");
+ else if (o == ORIGIN_EGP)
+ printf("egp ");
+ else if (o == ORIGIN_INCOMPLETE)
+ printf("incomplete ");
+ else
+ printf("%u ", o);
+}
+
+void
print_set(struct filter_set_head *set)
{
struct filter_set *s;
@@ -161,11 +209,23 @@ print_set(struct filter_set_head *set)
case ACTION_RTLABEL:
printf("rtlabel %s ", s->action.rtlabel);
break;
+ case ACTION_SET_ORIGIN:
+ printf("origin ");
+ print_origin(s->action.origin);
+ break;
case ACTION_RTLABEL_ID:
case ACTION_PFTABLE_ID:
/* not possible */
printf("king bula saiz: config broken");
break;
+ case ACTION_SET_EXT_COMMUNITY:
+ printf("ext-community ");
+ print_extcommunity(&s->action.ext_community);
+ break;
+ case ACTION_DEL_EXT_COMMUNITY:
+ printf("ext-community delete ");
+ print_extcommunity(&s->action.ext_community);
+ break;
}
}
printf("}");
@@ -182,6 +242,10 @@ print_mainconf(struct bgpd_config *conf)
printf(" %u", conf->short_as);
ina.s_addr = conf->bgpid;
printf("\nrouter-id %s\n", inet_ntoa(ina));
+
+ printf("socket \"%s\"\n", conf->csock);
+ if (conf->rcsock)
+ printf("socket \"%s\" restricted\n", conf->rcsock);
if (conf->holdtime)
printf("holdtime %u\n", conf->holdtime);
if (conf->min_holdtime)
@@ -189,11 +253,6 @@ print_mainconf(struct bgpd_config *conf)
if (conf->connectretry)
printf("connect-retry %u\n", conf->connectretry);
- if (conf->flags & BGPD_FLAG_NO_FIB_UPDATE)
- printf("fib-update no\n");
- else
- printf("fib-update yes\n");
-
if (conf->flags & BGPD_FLAG_NO_EVALUATE)
printf("route-collector yes\n");
@@ -214,43 +273,67 @@ print_mainconf(struct bgpd_config *conf)
printf("nexthop qualify via bgp\n");
if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
printf("nexthop qualify via default\n");
+}
- if (conf->flags & BGPD_FLAG_REDIST_CONNECTED) {
- printf("network inet connected");
- if (!TAILQ_EMPTY(&conf->connectset))
- printf(" ");
- print_set(&conf->connectset);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST_STATIC) {
- printf("network inet static");
- if (!TAILQ_EMPTY(&conf->staticset))
- printf(" ");
- print_set(&conf->staticset);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST6_CONNECTED) {
- printf("network inet6 connected");
- if (!TAILQ_EMPTY(&conf->connectset6))
- printf(" ");
- print_set(&conf->connectset6);
- printf("\n");
- }
- if (conf->flags & BGPD_FLAG_REDIST_STATIC) {
- printf("network inet6 static");
- if (!TAILQ_EMPTY(&conf->staticset6))
- printf(" ");
- print_set(&conf->staticset6);
+void
+print_rdomain_targets(struct filter_set_head *set, const char *tgt)
+{
+ struct filter_set *s;
+ TAILQ_FOREACH(s, set, entry) {
+ printf("\t%s ", tgt);
+ print_extcommunity(&s->action.ext_community);
printf("\n");
}
- if (conf->rtableid)
- printf("rtable %u\n", conf->rtableid);
+}
+
+void
+print_rdomain(struct rdomain *r)
+{
+ printf("rdomain %u {\n", r->rtableid);
+ printf("\tdescr \"%s\"\n", r->descr);
+ if (r->flags & F_RIB_NOFIBSYNC)
+ printf("\tfib-update no\n");
+ else
+ printf("\tfib-update yes\n");
+ printf("\tdepend on %s\n", r->ifmpe);
+
+ printf("\n\t%s\n", log_rd(r->rd));
+
+ print_rdomain_targets(&r->export, "export-target");
+ print_rdomain_targets(&r->import, "import-target");
+
+ printf("}\n");
+}
+
+const char *
+print_af(u_int8_t aid)
+{
+ /*
+ * Hack around the fact that aid2str() will return "IPv4 unicast"
+ * for AID_INET. AID_INET and AID_INET6 need special handling and
+ * the other AID should never end up here (at least for now).
+ */
+ if (aid == AID_INET)
+ return ("inet");
+ if (aid == AID_INET6)
+ return ("inet6");
+ return (aid2str(aid));
}
void
print_network(struct network_config *n)
{
- printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
+ switch (n->type) {
+ case NETWORK_STATIC:
+ printf("network %s static", print_af(n->prefix.aid));
+ break;
+ case NETWORK_CONNECTED:
+ printf("network %s connected", print_af(n->prefix.aid));
+ break;
+ default:
+ printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
+ break;
+ }
if (!TAILQ_EMPTY(&n->attrset))
printf(" ");
print_set(&n->attrset);
@@ -263,8 +346,8 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
char *method;
struct in_addr ina;
- if ((p->remote_addr.af == AF_INET && p->remote_masklen != 32) ||
- (p->remote_addr.af == AF_INET6 && p->remote_masklen != 128))
+ if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) ||
+ (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128))
printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr),
p->remote_masklen);
else
@@ -281,7 +364,7 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
printf("%s\tmultihop %u\n", c, p->distance);
if (p->passive)
printf("%s\tpassive\n", c);
- if (p->local_addr.af)
+ if (p->local_addr.aid)
printf("%s\tlocal-address %s\n", c, log_addr(&p->local_addr));
if (p->max_prefix) {
printf("%s\tmax-prefix %u", c, p->max_prefix);
@@ -295,6 +378,12 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
printf("%s\tholdtime min %u\n", c, p->min_holdtime);
if (p->announce_capa == 0)
printf("%s\tannounce capabilities no\n", c);
+ if (p->capabilities.refresh == 0)
+ printf("%s\tannounce refresh no\n", c);
+ if (p->capabilities.restart == 1)
+ printf("%s\tannounce restart yes\n", c);
+ if (p->capabilities.as4byte == 0)
+ printf("%s\tannounce as4byte no\n", c);
if (p->announce_type == ANNOUNCE_SELF)
printf("%s\tannounce self\n", c);
else if (p->announce_type == ANNOUNCE_NONE)
@@ -324,6 +413,10 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
printf("%s\tdepend on \"%s\"\n", c, p->if_depend);
if (p->flags & PEERFLAG_TRANS_AS)
printf("%s\ttransparent-as yes\n", c);
+#if defined(IPV6_LINKLOCAL_PEER)
+ if (p->lliface[0])
+ printf("%s\tinterface %s\n", c, p->lliface);
+#endif
if (p->auth.method == AUTH_MD5SIG)
printf("%s\ttcp md5sig\n", c);
@@ -354,8 +447,7 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
if (p->ttlsec)
printf("%s\tttl-security yes\n", c);
- printf("%s\tannounce IPv4 %s\n", c, print_safi(p->capabilities.mp_v4));
- printf("%s\tannounce IPv6 %s\n", c, print_safi(p->capabilities.mp_v6));
+ print_announce(p, c);
if (p->softreconfig_in == 1)
printf("%s\tsoftreconfig in yes\n", c);
@@ -399,17 +491,14 @@ print_enc_alg(u_int8_t alg)
}
}
-const char *
-print_safi(u_int8_t safi)
+void
+print_announce(struct peer_config *p, const char *c)
{
- switch (safi) {
- case SAFI_NONE:
- return ("none");
- case SAFI_UNICAST:
- return ("unicast");
- default:
- return ("?");
- }
+ u_int8_t aid;
+
+ for (aid = 0; aid < AID_MAX; aid++)
+ if (p->capabilities.mp[aid])
+ printf("%s\tannounce %s\n", c, aid2str(aid));
}
void
@@ -455,14 +544,14 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
} else
printf("any ");
- if (r->match.prefix.addr.af)
+ if (r->match.prefix.addr.aid)
printf("prefix %s/%u ", log_addr(&r->match.prefix.addr),
r->match.prefix.len);
- if (r->match.prefix.addr.af == 0 && r->match.prefixlen.af) {
- if (r->match.prefixlen.af == AF_INET)
+ if (r->match.prefix.addr.aid == 0 && r->match.prefixlen.aid) {
+ if (r->match.prefixlen.aid == AID_INET)
printf("inet ");
- if (r->match.prefixlen.af == AF_INET6)
+ if (r->match.prefixlen.aid == AID_INET6)
printf("inet6 ");
}
@@ -492,11 +581,20 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
printf("unfluffy-as %s ", log_as(r->match.as.as));
}
+ if (r->match.aslen.type) {
+ printf("%s %u ", r->match.aslen.type == ASLEN_MAX ?
+ "max-as-len" : "max-as-seq", r->match.aslen.aslen);
+ }
+
if (r->match.community.as != COMMUNITY_UNSET) {
printf("community ");
print_community(r->match.community.as,
r->match.community.type);
}
+ if (r->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID) {
+ printf("ext-community ");
+ print_extcommunity(&r->match.ext_community);
+ }
print_set(&r->set);
@@ -547,7 +645,7 @@ print_mrt(u_int32_t pid, u_int32_t gid, const char *prep, const char *prep2)
else
printf("%s %s %d\n", mrt_type(m->type),
MRT2MC(m)->name,
- MRT2MC(m)->ReopenTimerInterval);
+ (int)MRT2MC(m)->ReopenTimerInterval);
}
}
@@ -612,26 +710,34 @@ peer_compare(const void *aa, const void *bb)
void
print_config(struct bgpd_config *conf, struct rib_names *rib_l,
struct network_head *net_l, struct peer *peer_l,
- struct filter_head *rules_l, struct mrt_head *mrt_l)
+ struct filter_head *rules_l, struct mrt_head *mrt_l,
+ struct rdomain_head *rdom_l)
{
struct filter_rule *r;
struct network *n;
struct rde_rib *rr;
+ struct rdomain *rd;
xmrt_l = mrt_l;
- printf("\n");
print_mainconf(conf);
printf("\n");
+ TAILQ_FOREACH(n, net_l, entry)
+ print_network(&n->net);
+ printf("\n");
+ SIMPLEQ_FOREACH(rd, rdom_l, entry)
+ print_rdomain(rd);
+ printf("\n");
SIMPLEQ_FOREACH(rr, rib_l, entry) {
if (rr->flags & F_RIB_NOEVALUATE)
printf("rde rib %s no evaluate\n", rr->name);
- else
+ else if (rr->flags & F_RIB_NOFIB)
printf("rde rib %s\n", rr->name);
+ else
+ printf("rde rib %s rtable %u fib-update %s\n", rr->name,
+ rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ?
+ "no" : "yes");
}
printf("\n");
- TAILQ_FOREACH(n, net_l, entry)
- print_network(&n->net);
- printf("\n");
print_mrt(0, 0, "", "");
printf("\n");
print_groups(conf, peer_l);
diff --git a/bgpd/rde.c b/bgpd/rde.c
index 05b378e..74c07cd 100644
--- a/bgpd/rde.c
+++ b/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.290 2010/03/30 15:43:30 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <errno.h>
#include <ifaddrs.h>
@@ -51,12 +53,16 @@ void rde_update_withdraw(struct rde_peer *, struct bgpd_addr *,
int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *,
struct rde_aspath *, struct mpattr *);
u_int8_t rde_attr_missing(struct rde_aspath *, int, u_int16_t);
-int rde_get_mp_nexthop(u_char *, u_int16_t, u_int16_t,
- struct rde_aspath *);
+int rde_get_mp_nexthop(u_char *, u_int16_t, u_int8_t,
+ struct rde_aspath *, struct rde_peer *);
+int rde_update_extract_prefix(u_char *, u_int16_t, void *,
+ u_int8_t, u_int8_t);
int rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
+int rde_update_get_vpn4(u_char *, u_int16_t, struct bgpd_addr *,
+ u_int8_t *);
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void *, u_int16_t);
void rde_update_log(const char *, u_int16_t,
@@ -78,11 +84,15 @@ void rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t,
void rde_dump_mrt_new(struct mrt *, pid_t, int);
void rde_dump_done(void *);
+int rde_rdomain_import(struct rde_aspath *, struct rdomain *);
void rde_up_dump_upcall(struct rib_entry *, void *);
void rde_softreconfig_out(struct rib_entry *, void *);
void rde_softreconfig_in(struct rib_entry *, void *);
+void rde_softreconfig_load(struct rib_entry *, void *);
+void rde_softreconfig_load_peer(struct rib_entry *, void *);
+void rde_softreconfig_unload_peer(struct rib_entry *, void *);
void rde_update_queue_runner(void);
-void rde_update6_queue_runner(void);
+void rde_update6_queue_runner(u_int8_t);
void peer_init(u_int32_t);
void peer_shutdown(void);
@@ -91,10 +101,9 @@ struct rde_peer *peer_add(u_int32_t, struct peer_config *);
struct rde_peer *peer_get(u_int32_t);
void peer_up(u_int32_t, struct session_up *);
void peer_down(u_int32_t);
-void peer_dump(u_int32_t, u_int16_t, u_int8_t);
-void peer_send_eor(struct rde_peer *, u_int16_t, u_int16_t);
+void peer_dump(u_int32_t, u_int8_t);
+void peer_send_eor(struct rde_peer *, u_int8_t);
-void network_init(struct network_head *);
void network_add(struct network_config *, int);
void network_delete(struct network_config *, int);
void network_dump_upcall(struct rib_entry *, void *);
@@ -108,6 +117,7 @@ time_t reloadtime;
struct rde_peer_head peerlist;
struct rde_peer *peerself;
struct filter_head *rules_l, *newrules;
+struct rdomain_head *rdomains_l, *newdomains;
struct imsgbuf *ibuf_se;
struct imsgbuf *ibuf_se_ctl;
struct imsgbuf *ibuf_main;
@@ -120,11 +130,12 @@ struct rde_dump_ctx {
};
struct rde_mrt_ctx {
- struct mrt mrt;
- struct rib_context ribctx;
+ struct mrt mrt;
+ struct rib_context ribctx;
+ LIST_ENTRY(rde_mrt_ctx) entry;
};
-struct mrt_head rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts);
+LIST_HEAD(, rde_mrt_ctx) rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts);
u_int rde_mrt_cnt;
void
@@ -144,24 +155,18 @@ u_int32_t attrhashsize = 512;
u_int32_t nexthophashsize = 64;
pid_t
-rde_main(struct bgpd_config *config, struct peer *peer_l,
- struct network_head *net_l, struct filter_head *rules,
- struct mrt_head *mrt_l, struct rib_names *rib_n, int pipe_m2r[2],
- int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2], int debug)
+rde_main(int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2],
+ int debug)
{
+ struct rlimit rl;
pid_t pid;
struct passwd *pw;
- struct peer *p;
- struct listen_addr *la;
struct pollfd *pfd = NULL;
- struct filter_rule *f;
- struct filter_set *set;
- struct nexthop *nh;
- struct rde_rib *rr;
- struct mrt *mrt, *xmrt;
+ struct rde_mrt_ctx *mctx, *xmctx;
void *newp;
u_int pfd_elms = 0, i, j;
int timeout;
+ u_int8_t aid;
switch (pid = fork()) {
case -1:
@@ -172,8 +177,6 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
return (pid);
}
- conf = config;
-
if ((pw = getpwnam(BGPD_USER)) == NULL)
fatal("getpwnam");
@@ -185,6 +188,12 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
setproctitle("route decision engine");
bgpd_process = PROC_RDE;
+ if (getrlimit(RLIMIT_DATA, &rl) == -1)
+ fatal("getrlimit");
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_DATA, &rl) == -1)
+ fatal("setrlimit");
+
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
@@ -194,6 +203,8 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
signal(SIGINT, rde_sighdlr);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
close(pipe_s2r[0]);
close(pipe_s2rctl[0]);
@@ -210,50 +221,25 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
imsg_init(ibuf_se_ctl, pipe_s2rctl[1]);
imsg_init(ibuf_main, pipe_m2r[1]);
- /* peer list, mrt list and listener list are not used in the RDE */
- while ((p = peer_l) != NULL) {
- peer_l = p->next;
- free(p);
- }
-
- while ((mrt = LIST_FIRST(mrt_l)) != NULL) {
- LIST_REMOVE(mrt, entry);
- free(mrt);
- }
-
- while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) {
- TAILQ_REMOVE(config->listen_addrs, la, entry);
- close(la->fd);
- free(la);
- }
- free(config->listen_addrs);
-
pt_init();
- while ((rr = SIMPLEQ_FIRST(&ribnames))) {
- SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
- rib_new(-1, rr->name, rr->flags);
- free(rr);
- }
path_init(pathhashsize);
aspath_init(pathhashsize);
attr_init(attrhashsize);
nexthop_init(nexthophashsize);
peer_init(peerhashsize);
- rules_l = rules;
- network_init(net_l);
+ rules_l = calloc(1, sizeof(struct filter_head));
+ if (rules_l == NULL)
+ fatal(NULL);
+ TAILQ_INIT(rules_l);
+ rdomains_l = calloc(1, sizeof(struct rdomain_head));
+ if (rdomains_l == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(rdomains_l);
+ if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
+ fatal(NULL);
log_info("route decision engine ready");
- TAILQ_FOREACH(f, rules, entry) {
- f->peer.ribid = rib_find(f->rib);
- TAILQ_FOREACH(set, &f->set, entry) {
- if (set->type == ACTION_SET_NEXTHOP) {
- nh = nexthop_get(&set->action.nexthop);
- nh->refcnt++;
- }
- }
- }
-
while (rde_quit == 0) {
if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) {
if ((newp = realloc(pfd, sizeof(struct pollfd) *
@@ -287,11 +273,18 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
timeout = 0;
i = PFD_PIPE_COUNT;
- LIST_FOREACH(mrt, &rde_mrts, entry) {
- if (mrt->wbuf.queued) {
- pfd[i].fd = mrt->wbuf.fd;
+ for (mctx = LIST_FIRST(&rde_mrts); mctx != 0; mctx = xmctx) {
+ xmctx = LIST_NEXT(mctx, entry);
+ if (mctx->mrt.wbuf.queued) {
+ pfd[i].fd = mctx->mrt.wbuf.fd;
pfd[i].events = POLLOUT;
i++;
+ } else if (mctx->mrt.state == MRT_STATE_REMOVE) {
+ close(mctx->mrt.wbuf.fd);
+ LIST_REMOVE(&mctx->ribctx, entry);
+ LIST_REMOVE(mctx, entry);
+ free(mctx);
+ rde_mrt_cnt--;
}
}
@@ -325,24 +318,17 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
if (pfd[PFD_PIPE_SESSION_CTL].revents & POLLIN)
rde_dispatch_imsg_session(ibuf_se_ctl);
- for (j = PFD_PIPE_COUNT, mrt = LIST_FIRST(&rde_mrts);
- j < i && mrt != 0; j++) {
- xmrt = LIST_NEXT(mrt, entry);
- if (pfd[j].fd == mrt->wbuf.fd &&
+ for (j = PFD_PIPE_COUNT, mctx = LIST_FIRST(&rde_mrts);
+ j < i && mctx != 0; j++) {
+ if (pfd[j].fd == mctx->mrt.wbuf.fd &&
pfd[j].revents & POLLOUT)
- mrt_write(mrt);
- if (mrt->wbuf.queued == 0 &&
- mrt->state == MRT_STATE_REMOVE) {
- close(mrt->wbuf.fd);
- LIST_REMOVE(mrt, entry);
- free(mrt);
- rde_mrt_cnt--;
- }
- mrt = xmrt;
+ mrt_write(&mctx->mrt);
+ mctx = LIST_NEXT(mctx, entry);
}
rde_update_queue_runner();
- rde_update6_queue_runner();
+ for (aid = AID_INET6; aid < AID_MAX; aid++)
+ rde_update6_queue_runner(aid);
if (ibuf_se_ctl->w.queued <= 0)
rib_dump_runner();
}
@@ -351,11 +337,12 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
if (debug)
rde_shutdown();
- while ((mrt = LIST_FIRST(&rde_mrts)) != NULL) {
- msgbuf_clear(&mrt->wbuf);
- close(mrt->wbuf.fd);
- LIST_REMOVE(mrt, entry);
- free(mrt);
+ while ((mctx = LIST_FIRST(&rde_mrts)) != NULL) {
+ msgbuf_clear(&mctx->mrt.wbuf);
+ close(mctx->mrt.wbuf.fd);
+ LIST_REMOVE(&mctx->ribctx, entry);
+ LIST_REMOVE(mctx, entry);
+ free(mctx);
}
msgbuf_clear(&ibuf_se->w);
@@ -378,13 +365,14 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
struct imsg imsg;
struct peer p;
struct peer_config pconf;
- struct rrefresh r;
struct rde_peer *peer;
struct session_up sup;
struct ctl_show_rib_request req;
struct filter_set *s;
struct nexthop *nh;
- int n;
+ ssize_t n;
+ int verbose;
+ u_int8_t aid;
if ((n = imsg_read(ibuf)) == -1)
fatal("rde_dispatch_imsg_session: imsg_read error");
@@ -423,12 +411,14 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
peer_down(imsg.hdr.peerid);
break;
case IMSG_REFRESH:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(r)) {
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
log_warnx("rde_dispatch: wrong imsg len");
break;
}
- memcpy(&r, imsg.data, sizeof(r));
- peer_dump(imsg.hdr.peerid, r.afi, r.safi);
+ memcpy(&aid, imsg.data, sizeof(aid));
+ if (aid >= AID_MAX)
+ fatalx("IMSG_REFRESH: bad AID");
+ peer_dump(imsg.hdr.peerid, aid);
break;
case IMSG_NETWORK_ADD:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -446,13 +436,13 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
break;
}
session_set = NULL;
- switch (netconf_s.prefix.af) {
- case AF_INET:
+ switch (netconf_s.prefix.aid) {
+ case AID_INET:
if (netconf_s.prefixlen > 32)
goto badnet;
network_add(&netconf_s, 0);
break;
- case AF_INET6:
+ case AID_INET6:
if (netconf_s.prefixlen > 128)
goto badnet;
network_add(&netconf_s, 0);
@@ -544,6 +534,11 @@ badnet:
imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0,
imsg.hdr.pid, -1, &rdemem, sizeof(rdemem));
break;
+ case IMSG_CTL_LOG_VERBOSE:
+ /* already checked by SE */
+ memcpy(&verbose, imsg.data, sizeof(verbose));
+ log_verbose(verbose);
+ break;
default:
break;
}
@@ -554,14 +549,17 @@ badnet:
void
rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
{
+ static struct rdomain *rd;
struct imsg imsg;
struct mrt xmrt;
struct rde_rib rn;
struct rde_peer *peer;
+ struct peer_config *pconf;
struct filter_rule *r;
struct filter_set *s;
struct nexthop *nh;
- int n, fd, reconf_in = 0, reconf_out = 0;
+ int n, fd, reconf_in = 0, reconf_out = 0,
+ reconf_rib = 0;
u_int16_t rid;
if ((n = imsg_read(ibuf)) == -1)
@@ -576,20 +574,12 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
break;
switch (imsg.hdr.type) {
- case IMSG_RECONF_CONF:
- reloadtime = time(NULL);
- newrules = calloc(1, sizeof(struct filter_head));
- if (newrules == NULL)
- fatal(NULL);
- TAILQ_INIT(newrules);
- if ((nconf = malloc(sizeof(struct bgpd_config))) ==
- NULL)
- fatal(NULL);
- memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
- for (rid = 0; rid < rib_size; rid++)
- ribs[rid].state = RIB_DELETE;
- break;
case IMSG_NETWORK_ADD:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct network_config)) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
TAILQ_INIT(&netconf_p.attrset);
parent_set = &netconf_p.attrset;
@@ -608,6 +598,26 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
TAILQ_INIT(&netconf_p.attrset);
network_delete(&netconf_p, 1);
break;
+ case IMSG_RECONF_CONF:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct bgpd_config))
+ fatalx("IMSG_RECONF_CONF bad len");
+ reloadtime = time(NULL);
+ newrules = calloc(1, sizeof(struct filter_head));
+ if (newrules == NULL)
+ fatal(NULL);
+ TAILQ_INIT(newrules);
+ newdomains = calloc(1, sizeof(struct rdomain_head));
+ if (newdomains == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(newdomains);
+ if ((nconf = malloc(sizeof(struct bgpd_config))) ==
+ NULL)
+ fatal(NULL);
+ memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
+ for (rid = 0; rid < rib_size; rid++)
+ ribs[rid].state = RECONF_DELETE;
+ break;
case IMSG_RECONF_RIB:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct rde_rib))
@@ -615,9 +625,26 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
memcpy(&rn, imsg.data, sizeof(rn));
rid = rib_find(rn.name);
if (rid == RIB_FAILED)
- rib_new(-1, rn.name, rn.flags);
- else
- ribs[rid].state = RIB_ACTIVE;
+ rib_new(rn.name, rn.rtableid, rn.flags);
+ else if (ribs[rid].rtableid != rn.rtableid ||
+ (ribs[rid].flags & F_RIB_HASNOFIB) !=
+ (rn.flags & F_RIB_HASNOFIB)) {
+ /* Big hammer in the F_RIB_NOFIB case but
+ * not often enough used to optimise it more. */
+ rib_free(&ribs[rid]);
+ rib_new(rn.name, rn.rtableid, rn.flags);
+ } else
+ ribs[rid].state = RECONF_KEEP;
+ break;
+ case IMSG_RECONF_PEER:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct peer_config))
+ fatalx("IMSG_RECONF_PEER bad len");
+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL)
+ break;
+ pconf = imsg.data;
+ strlcpy(peer->conf.rib, pconf->rib,
+ sizeof(peer->conf.rib));
break;
case IMSG_RECONF_FILTER:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -631,12 +658,42 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
parent_set = &r->set;
TAILQ_INSERT_TAIL(newrules, r, entry);
break;
+ case IMSG_RECONF_RDOMAIN:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct rdomain))
+ fatalx("IMSG_RECONF_RDOMAIN bad len");
+ if ((rd = malloc(sizeof(struct rdomain))) == NULL)
+ fatal(NULL);
+ memcpy(rd, imsg.data, sizeof(struct rdomain));
+ TAILQ_INIT(&rd->import);
+ TAILQ_INIT(&rd->export);
+ SIMPLEQ_INSERT_TAIL(newdomains, rd, entry);
+ break;
+ case IMSG_RECONF_RDOMAIN_EXPORT:
+ if (rd == NULL) {
+ log_warnx("rde_dispatch_imsg_parent: "
+ "IMSG_RECONF_RDOMAIN_EXPORT unexpected");
+ break;
+ }
+ parent_set = &rd->export;
+ break;
+ case IMSG_RECONF_RDOMAIN_IMPORT:
+ if (rd == NULL) {
+ log_warnx("rde_dispatch_imsg_parent: "
+ "IMSG_RECONF_RDOMAIN_IMPORT unexpected");
+ break;
+ }
+ parent_set = &rd->import;
+ break;
+ case IMSG_RECONF_RDOMAIN_DONE:
+ parent_set = NULL;
+ break;
case IMSG_RECONF_DONE:
if (nconf == NULL)
fatalx("got IMSG_RECONF_DONE but no config");
if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
!= (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
- log_warnx( "change to/from route-collector "
+ log_warnx("change to/from route-collector "
"mode ignored");
if (conf->flags & BGPD_FLAG_NO_EVALUATE)
nconf->flags |= BGPD_FLAG_NO_EVALUATE;
@@ -644,10 +701,27 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
nconf->flags &= ~BGPD_FLAG_NO_EVALUATE;
}
memcpy(conf, nconf, sizeof(struct bgpd_config));
+ conf->listen_addrs = NULL;
+ conf->csock = NULL;
+ conf->rcsock = NULL;
free(nconf);
nconf = NULL;
parent_set = NULL;
- prefix_network_clean(peerself, reloadtime, 0);
+ /* sync peerself with conf */
+ peerself->remote_bgpid = ntohl(conf->bgpid);
+ peerself->conf.local_as = conf->as;
+ peerself->conf.remote_as = conf->as;
+ peerself->short_as = conf->short_as;
+
+ /* apply new set of rdomain, sync will be done later */
+ while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
+ filterset_free(&rd->import);
+ filterset_free(&rd->export);
+ free(rd);
+ }
+ free(rdomains_l);
+ rdomains_l = newdomains;
/* check if filter changed */
LIST_FOREACH(peer, &peerlist, peer_l) {
@@ -655,30 +729,59 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
continue;
peer->reconf_out = 0;
peer->reconf_in = 0;
- if (peer->conf.softreconfig_out &&
- !rde_filter_equal(rules_l, newrules, peer,
- DIR_OUT)) {
- peer->reconf_out = 1;
- reconf_out = 1;
- }
+ peer->reconf_rib = 0;
if (peer->conf.softreconfig_in &&
!rde_filter_equal(rules_l, newrules, peer,
DIR_IN)) {
peer->reconf_in = 1;
reconf_in = 1;
}
+ if (peer->ribid != rib_find(peer->conf.rib)) {
+ rib_dump(&ribs[peer->ribid],
+ rde_softreconfig_unload_peer, peer,
+ AID_UNSPEC);
+ peer->ribid = rib_find(peer->conf.rib);
+ peer->reconf_rib = 1;
+ reconf_rib = 1;
+ continue;
+ }
+ if (peer->conf.softreconfig_out &&
+ !rde_filter_equal(rules_l, newrules, peer,
+ DIR_OUT)) {
+ peer->reconf_out = 1;
+ reconf_out = 1;
+ }
}
- /* XXX this needs rework anyway */
- /* sync local-RIB first */
+ /* bring ribs in sync before softreconfig dance */
+ for (rid = 0; rid < rib_size; rid++) {
+ if (ribs[rid].state == RECONF_DELETE)
+ rib_free(&ribs[rid]);
+ else if (ribs[rid].state == RECONF_REINIT)
+ rib_dump(&ribs[0],
+ rde_softreconfig_load, &ribs[rid],
+ AID_UNSPEC);
+ }
+ /* sync local-RIBs first */
if (reconf_in)
rib_dump(&ribs[0], rde_softreconfig_in, NULL,
- AF_UNSPEC);
+ AID_UNSPEC);
/* then sync peers */
if (reconf_out) {
int i;
- for (i = 1; i < rib_size; i++)
+ for (i = 1; i < rib_size; i++) {
+ if (ribs[i].state == RECONF_REINIT)
+ /* already synced by _load */
+ continue;
rib_dump(&ribs[i], rde_softreconfig_out,
- NULL, AF_UNSPEC);
+ NULL, AID_UNSPEC);
+ }
+ }
+ if (reconf_rib) {
+ LIST_FOREACH(peer, &peerlist, peer_l) {
+ rib_dump(&ribs[peer->ribid],
+ rde_softreconfig_load_peer,
+ peer, AID_UNSPEC);
+ }
}
while ((r = TAILQ_FIRST(rules_l)) != NULL) {
@@ -688,16 +791,16 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
}
free(rules_l);
rules_l = newrules;
- for (rid = 0; rid < rib_size; rid++) {
- if (ribs[rid].state == RIB_DELETE)
- rib_free(&ribs[rid]);
- }
+
log_info("RDE reconfigured");
break;
case IMSG_NEXTHOP_UPDATE:
nexthop_update(imsg.data);
break;
case IMSG_FILTER_SET:
+ if (imsg.hdr.len > IMSG_HEADER_SIZE +
+ sizeof(struct filter_set))
+ fatalx("IMSG_RECONF_CONF bad len");
if (parent_set == NULL) {
log_warnx("rde_dispatch_imsg_parent: "
"IMSG_FILTER_SET unexpected");
@@ -744,6 +847,8 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
int
rde_update_dispatch(struct imsg *imsg)
{
+ struct bgpd_addr prefix;
+ struct mpattr mpa;
struct rde_peer *peer;
struct rde_aspath *asp = NULL;
u_char *p, *mpp = NULL;
@@ -752,9 +857,8 @@ rde_update_dispatch(struct imsg *imsg)
u_int16_t withdrawn_len;
u_int16_t attrpath_len;
u_int16_t nlri_len;
- u_int8_t prefixlen, safi, subtype;
- struct bgpd_addr prefix;
- struct mpattr mpa;
+ u_int8_t aid, prefixlen, safi, subtype;
+ u_int32_t fas;
peer = peer_get(imsg->hdr.peerid);
if (peer == NULL) /* unknown peer, cannot happen */
@@ -810,26 +914,21 @@ rde_update_dispatch(struct imsg *imsg)
goto done;
}
- /*
- * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present
- * try to fixup the attributes.
- * XXX do not fixup if F_ATTR_LOOP is set.
- */
- if (asp->flags & F_ATTR_AS4BYTE_NEW &&
- !(asp->flags & F_ATTR_LOOP))
- rde_as4byte_fixup(peer, asp);
+ rde_as4byte_fixup(peer, asp);
/* enforce remote AS if requested */
if (asp->flags & F_ATTR_ASPATH &&
- peer->conf.enforce_as == ENFORCE_AS_ON)
- if (peer->conf.remote_as !=
- aspath_neighbor(asp->aspath)) {
- log_peer_warnx(&peer->conf, "bad path, "
- "enforce remote-as enabled");
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
+ peer->conf.enforce_as == ENFORCE_AS_ON) {
+ fas = aspath_neighbor(asp->aspath);
+ if (peer->conf.remote_as != fas) {
+ log_peer_warnx(&peer->conf, "bad path, "
+ "starting with %s, "
+ "enforce neighbor-as enabled", log_as(fas));
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL, 0);
- goto done;
+ goto done;
}
+ }
rde_reflector(peer, asp);
}
@@ -860,9 +959,9 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
len -= pos;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled");
+ if (peer->capa.mp[AID_INET] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad withdraw, %s disabled", aid2str(AID_INET));
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
NULL, 0);
goto done;
@@ -892,15 +991,25 @@ rde_update_dispatch(struct imsg *imsg)
afi = ntohs(afi);
safi = *mpp++;
mplen--;
- switch (afi) {
- case AFI_IPv6:
- if (peer->capa_received.mp_v6 == SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, "
- "IPv6 disabled");
- rde_update_err(peer, ERR_UPDATE,
- ERR_UPD_OPTATTR, NULL, 0);
- goto done;
- }
+
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad AFI/SAFI pair in withdraw");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ if (peer->capa.mp[aid] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad withdraw, %s disabled", aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ switch (aid) {
+ case AID_INET6:
while (mplen > 0) {
if ((pos = rde_update_get_prefix6(mpp, mplen,
&prefix, &prefixlen)) == -1) {
@@ -926,6 +1035,32 @@ rde_update_dispatch(struct imsg *imsg)
rde_update_withdraw(peer, &prefix, prefixlen);
}
break;
+ case AID_VPN_IPv4:
+ while (mplen > 0) {
+ if ((pos = rde_update_get_vpn4(mpp, mplen,
+ &prefix, &prefixlen)) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad VPNv4 withdraw prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.unreach, mpa.unreach_len);
+ goto done;
+ }
+ if (prefixlen > 32) {
+ log_peer_warnx(&peer->conf,
+ "bad VPNv4 withdraw prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.unreach, mpa.unreach_len);
+ goto done;
+ }
+
+ mpp += pos;
+ mplen -= pos;
+
+ rde_update_withdraw(peer, &prefix, prefixlen);
+ }
+ break;
default:
/* silently ignore unsupported multiprotocol AF */
break;
@@ -963,9 +1098,9 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
nlri_len -= pos;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled");
+ if (peer->capa.mp[AID_INET] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad update, %s disabled", aid2str(AID_INET));
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
NULL, 0);
goto done;
@@ -995,6 +1130,22 @@ rde_update_dispatch(struct imsg *imsg)
safi = *mpp++;
mplen--;
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad AFI/SAFI pair in update");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ if (peer->capa.mp[aid] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad update, %s disabled", aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
/*
* this works because asp is not linked.
* But first unlock the previously locked nexthop.
@@ -1004,8 +1155,8 @@ rde_update_dispatch(struct imsg *imsg)
(void)nexthop_delete(asp->nexthop);
asp->nexthop = NULL;
}
- if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp)) == -1) {
- log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix");
+ if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, asp, peer)) == -1) {
+ log_peer_warnx(&peer->conf, "bad nlri prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
mpa.reach, mpa.reach_len);
goto done;
@@ -1013,16 +1164,8 @@ rde_update_dispatch(struct imsg *imsg)
mpp += pos;
mplen -= pos;
- switch (afi) {
- case AFI_IPv6:
- if (peer->capa_received.mp_v6 == SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, "
- "IPv6 disabled");
- rde_update_err(peer, ERR_UPDATE,
- ERR_UPD_OPTATTR, NULL, 0);
- goto done;
- }
-
+ switch (aid) {
+ case AID_INET6:
while (mplen > 0) {
if ((pos = rde_update_get_prefix6(mpp, mplen,
&prefix, &prefixlen)) == -1) {
@@ -1058,6 +1201,42 @@ rde_update_dispatch(struct imsg *imsg)
}
break;
+ case AID_VPN_IPv4:
+ while (mplen > 0) {
+ if ((pos = rde_update_get_vpn4(mpp, mplen,
+ &prefix, &prefixlen)) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad VPNv4 nlri prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.reach, mpa.reach_len);
+ goto done;
+ }
+ if (prefixlen > 32) {
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.reach, mpa.reach_len);
+ goto done;
+ }
+
+ mpp += pos;
+ mplen -= pos;
+
+ rde_update_update(peer, asp, &prefix,
+ prefixlen);
+
+ /* max prefix checker */
+ if (peer->conf.max_prefix &&
+ peer->prefix_cnt >= peer->conf.max_prefix) {
+ log_peer_warnx(&peer->conf,
+ "prefix limit reached");
+ rde_update_err(peer, ERR_CEASE,
+ ERR_CEASE_MAX_PREFIX, NULL, 0);
+ goto done;
+ }
+
+ }
+ break;
default:
/* silently ignore unsupported multiprotocol AF */
break;
@@ -1085,7 +1264,8 @@ rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
struct bgpd_addr *prefix, u_int8_t prefixlen)
{
struct rde_aspath *fasp;
- int r = 0;
+ enum filter_actions action;
+ int r = 0, f = 0;
u_int16_t i;
peer->prefix_rcvd_update++;
@@ -1095,18 +1275,24 @@ rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
for (i = 1; i < rib_size; i++) {
/* input filter */
- if (rde_filter(i, &fasp, rules_l, peer, asp, prefix, prefixlen,
- peer, DIR_IN) == ACTION_DENY)
- goto done;
+ action = rde_filter(i, &fasp, rules_l, peer, asp, prefix,
+ prefixlen, peer, DIR_IN);
if (fasp == NULL)
fasp = asp;
- rde_update_log("update", i, peer, &fasp->nexthop->exit_nexthop,
- prefix, prefixlen);
- r += path_update(&ribs[i], peer, fasp, prefix, prefixlen);
+ if (action == ACTION_ALLOW) {
+ rde_update_log("update", i, peer,
+ &fasp->nexthop->exit_nexthop, prefix, prefixlen);
+ r += path_update(&ribs[i], peer, fasp, prefix,
+ prefixlen);
+ } else if (prefix_remove(&ribs[i], peer, prefix, prefixlen,
+ 0)) {
+ rde_update_log("filtered withdraw", i, peer,
+ NULL, prefix, prefixlen);
+ f++;
+ }
-done:
/* free modified aspath */
if (fasp != asp)
path_put(fasp);
@@ -1114,6 +1300,8 @@ done:
if (r)
peer->prefix_cnt++;
+ else if (f)
+ peer->prefix_cnt--;
}
void
@@ -1161,6 +1349,7 @@ rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
struct bgpd_addr nexthop;
u_char *op = p, *npath;
u_int32_t tmp32;
+ int err;
u_int16_t attr_len, nlen;
u_int16_t plen = 0;
u_int8_t flags;
@@ -1195,6 +1384,7 @@ bad_len:
switch (type) {
case ATTR_UNDEF:
/* ignore and drop path attributes with a type code of 0 */
+ plen += attr_len;
break;
case ATTR_ORIGIN:
if (attr_len != 1)
@@ -1220,7 +1410,17 @@ bad_flags:
case ATTR_ASPATH:
if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
goto bad_flags;
- if (aspath_verify(p, attr_len, rde_as4byte(peer)) != 0) {
+ err = aspath_verify(p, attr_len, rde_as4byte(peer));
+ if (err == AS_ERR_SOFT) {
+ /*
+ * soft errors like unexpected segment types are
+ * not considered fatal and the path is just
+ * marked invalid.
+ */
+ a->flags |= F_ATTR_PARSE_ERR;
+ log_peer_warnx(&peer->conf, "bad ASPATH, "
+ "path invalidated and prefix withdrawn");
+ } else if (err != 0) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL, 0);
return (-1);
@@ -1248,7 +1448,7 @@ bad_flags:
a->flags |= F_ATTR_NEXTHOP;
bzero(&nexthop, sizeof(nexthop));
- nexthop.af = AF_INET;
+ nexthop.aid = AID_INET;
UPD_READ(&nexthop.v4.s_addr, p, plen, 4);
/*
* Check if the nexthop is a valid IP address. We consider
@@ -1305,9 +1505,21 @@ bad_flags:
goto optattr;
case ATTR_AGGREGATOR:
if ((!rde_as4byte(peer) && attr_len != 6) ||
- (rde_as4byte(peer) && attr_len != 8))
- goto bad_len;
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
+ (rde_as4byte(peer) && attr_len != 8)) {
+ /*
+ * ignore attribute in case of error as per
+ * draft-ietf-idr-optional-transitive-00.txt
+ * but only if partial bit is set
+ */
+ if ((flags & ATTR_PARTIAL) == 0)
+ goto bad_len;
+ log_peer_warnx(&peer->conf, "bad AGGREGATOR, "
+ "partial attribute ignored");
+ plen += attr_len;
+ break;
+ }
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
goto bad_flags;
if (!rde_as4byte(peer)) {
/* need to inflate aggregator AS to 4-byte */
@@ -1323,8 +1535,35 @@ bad_flags:
/* 4-byte ready server take the default route */
goto optattr;
case ATTR_COMMUNITIES:
- if ((attr_len & 0x3) != 0)
- goto bad_len;
+ if (attr_len % 4 != 0) {
+ /*
+ * mark update as bad and withdraw all routes as per
+ * draft-ietf-idr-optional-transitive-00.txt
+ * but only if partial bit is set
+ */
+ if ((flags & ATTR_PARTIAL) == 0)
+ goto bad_len;
+ a->flags |= F_ATTR_PARSE_ERR;
+ log_peer_warnx(&peer->conf, "bad COMMUNITIES, "
+ "path invalidated and prefix withdrawn");
+ }
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
+ goto bad_flags;
+ goto optattr;
+ case ATTR_EXT_COMMUNITIES:
+ if (attr_len % 8 != 0) {
+ /*
+ * mark update as bad and withdraw all routes as per
+ * draft-ietf-idr-optional-transitive-00.txt
+ * but only if partial bit is set
+ */
+ if ((flags & ATTR_PARTIAL) == 0)
+ goto bad_len;
+ a->flags |= F_ATTR_PARSE_ERR;
+ log_peer_warnx(&peer->conf, "bad EXT_COMMUNITIES, "
+ "path invalidated and prefix withdrawn");
+ }
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
@@ -1336,7 +1575,7 @@ bad_flags:
goto bad_flags;
goto optattr;
case ATTR_CLUSTER_LIST:
- if ((attr_len & 0x3) != 0)
+ if (attr_len % 4 != 0)
goto bad_len;
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
goto bad_flags;
@@ -1370,8 +1609,15 @@ bad_flags:
plen += attr_len;
break;
case ATTR_AS4_AGGREGATOR:
- if (attr_len != 8)
- goto bad_len;
+ if (attr_len != 8) {
+ /* see ATTR_AGGREGATOR ... */
+ if ((flags & ATTR_PARTIAL) == 0)
+ goto bad_len;
+ log_peer_warnx(&peer->conf, "bad AS4_AGGREGATOR, "
+ "partial attribute ignored");
+ plen += attr_len;
+ break;
+ }
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
@@ -1381,17 +1627,28 @@ bad_flags:
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
- if (aspath_verify(p, attr_len, 1) != 0) {
+ if ((err = aspath_verify(p, attr_len, 1)) != 0) {
/*
* XXX RFC does not specify how to handle errors.
* XXX Instead of dropping the session because of a
- * XXX bad path just mark the full update as not
- * XXX loop-free the update is no longer eligible and
- * XXX will not be considered for routing or
- * XXX redistribution. Something better is needed.
+ * XXX bad path just mark the full update as having
+ * XXX a parse error which makes the update no longer
+ * XXX eligible and will not be considered for routing
+ * XXX or redistribution.
+ * XXX We follow draft-ietf-idr-optional-transitive
+ * XXX by looking at the partial bit.
+ * XXX Consider soft errors similar to a partial attr.
*/
- a->flags |= F_ATTR_LOOP;
- goto optattr;
+ if (flags & ATTR_PARTIAL || err == AS_ERR_SOFT) {
+ a->flags |= F_ATTR_PARSE_ERR;
+ log_peer_warnx(&peer->conf, "bad AS4_PATH, "
+ "path invalidated and prefix withdrawn");
+ goto optattr;
+ } else {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
+ NULL, 0);
+ return (-1);
+ }
}
a->flags |= F_ATTR_AS4BYTE_NEW;
goto optattr;
@@ -1440,8 +1697,8 @@ rde_attr_missing(struct rde_aspath *a, int ebgp, u_int16_t nlrilen)
}
int
-rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi,
- struct rde_aspath *asp)
+rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int8_t aid,
+ struct rde_aspath *asp, struct rde_peer *peer)
{
struct bgpd_addr nexthop;
u_int8_t totlen, nhlen;
@@ -1457,8 +1714,9 @@ rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi,
return (-1);
bzero(&nexthop, sizeof(nexthop));
- switch (afi) {
- case AFI_IPv6:
+ nexthop.aid = aid;
+ switch (aid) {
+ case AID_INET6:
/*
* RFC2545 describes that there may be a link-local
* address carried in nexthop. Yikes!
@@ -1471,72 +1729,143 @@ rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi,
log_warnx("bad multiprotocol nexthop, bad size");
return (-1);
}
- nexthop.af = AF_INET6;
memcpy(&nexthop.v6.s6_addr, data, 16);
- asp->nexthop = nexthop_get(&nexthop);
+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER)
+ if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6) &&
+ peer->conf.lliface[0]) {
+ int ifindex;
+
+ ifindex = if_nametoindex(peer->conf.lliface);
+ if (ifindex != 0)
+ SET_IN6_LINKLOCAL_IFINDEX(nexthop.v6, ifindex);
+ else
+ log_warnx("bad interface: %s", peer->conf.lliface);
+ }
+#endif
+ break;
+ case AID_VPN_IPv4:
/*
- * lock the nexthop because it is not yet linked else
- * withdraws may remove this nexthop which in turn would
- * cause a use after free error.
+ * Neither RFC4364 nor RFC3107 specify the format of the
+ * nexthop in an explicit way. The quality of RFC went down
+ * the toilet the larger the the number got.
+ * RFC4364 is very confusing about VPN-IPv4 address and the
+ * VPN-IPv4 prefix that carries also a MPLS label.
+ * So the nexthop is a 12-byte address with a 64bit RD and
+ * an IPv4 address following. In the nexthop case the RD can
+ * be ignored.
+ * Since the nexthop has to be in the main IPv4 table just
+ * create an AID_INET nexthop. So we don't need to handle
+ * AID_VPN_IPv4 in nexthop and kroute.
*/
- asp->nexthop->refcnt++;
-
- /* ignore reserved (old SNPA) field as per RFC 4760 */
- totlen += nhlen + 1;
- data += nhlen + 1;
-
- return (totlen);
- default:
- log_warnx("bad multiprotocol nexthop, bad AF");
+ if (nhlen != 12) {
+ log_warnx("bad multiprotocol nexthop, bad size");
+ return (-1);
+ }
+ data += sizeof(u_int64_t);
+ nexthop.aid = AID_INET;
+ memcpy(&nexthop.v4, data, sizeof(nexthop.v4));
break;
+ default:
+ log_warnx("bad multiprotocol nexthop, bad AID");
+ return (-1);
}
- return (-1);
+ asp->nexthop = nexthop_get(&nexthop);
+ /*
+ * lock the nexthop because it is not yet linked else
+ * withdraws may remove this nexthop which in turn would
+ * cause a use after free error.
+ */
+ asp->nexthop->refcnt++;
+
+ /* ignore reserved (old SNPA) field as per RFC4760 */
+ totlen += nhlen + 1;
+ data += nhlen + 1;
+
+ return (totlen);
+}
+
+int
+rde_update_extract_prefix(u_char *p, u_int16_t len, void *va,
+ u_int8_t pfxlen, u_int8_t max)
+{
+ static u_char addrmask[] = {
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ u_char *a = va;
+ int i;
+ u_int16_t plen = 0;
+
+ for (i = 0; pfxlen && i < max; i++) {
+ if (len <= plen)
+ return (-1);
+ if (pfxlen < 8) {
+ a[i] = *p++ & addrmask[pfxlen];
+ plen++;
+ break;
+ } else {
+ a[i] = *p++;
+ plen++;
+ pfxlen -= 8;
+ }
+ }
+ return (plen);
}
int
rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
u_int8_t *prefixlen)
{
- int i;
- u_int8_t pfxlen;
- u_int16_t plen;
- union {
- struct in_addr a32;
- u_int8_t a8[4];
- } addr;
+ u_int8_t pfxlen;
+ int plen;
if (len < 1)
return (-1);
- memcpy(&pfxlen, p, 1);
- p += 1;
- plen = 1;
+ pfxlen = *p++;
+ len--;
bzero(prefix, sizeof(struct bgpd_addr));
- addr.a32.s_addr = 0;
- for (i = 0; i <= 3; i++) {
- if (pfxlen > i * 8) {
- if (len - plen < 1)
- return (-1);
- memcpy(&addr.a8[i], p++, 1);
- plen++;
- }
- }
- prefix->af = AF_INET;
- prefix->v4.s_addr = addr.a32.s_addr;
+ prefix->aid = AID_INET;
*prefixlen = pfxlen;
- return (plen);
+ if ((plen = rde_update_extract_prefix(p, len, &prefix->v4, pfxlen,
+ sizeof(prefix->v4))) == -1)
+ return (-1);
+
+ return (plen + 1); /* pfxlen needs to be added */
}
int
rde_update_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
u_int8_t *prefixlen)
{
- int i;
+ int plen;
u_int8_t pfxlen;
- u_int16_t plen;
+
+ if (len < 1)
+ return (-1);
+
+ pfxlen = *p++;
+ len--;
+
+ bzero(prefix, sizeof(struct bgpd_addr));
+ prefix->aid = AID_INET6;
+ *prefixlen = pfxlen;
+
+ if ((plen = rde_update_extract_prefix(p, len, &prefix->v6, pfxlen,
+ sizeof(prefix->v6))) == -1)
+ return (-1);
+
+ return (plen + 1); /* pfxlen needs to be added */
+}
+
+int
+rde_update_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
+ u_int8_t *prefixlen)
+{
+ int rv, done = 0;
+ u_int8_t pfxlen;
+ u_int16_t plen;
if (len < 1)
return (-1);
@@ -1546,25 +1875,50 @@ rde_update_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
plen = 1;
bzero(prefix, sizeof(struct bgpd_addr));
- for (i = 0; i <= 15; i++) {
- if (pfxlen > i * 8) {
- if (len - plen < 1)
- return (-1);
- memcpy(&prefix->v6.s6_addr[i], p++, 1);
- plen++;
- }
- }
- prefix->af = AF_INET6;
+
+ /* label stack */
+ do {
+ if (len - plen < 3 || pfxlen < 3 * 8)
+ return (-1);
+ if (prefix->vpn4.labellen + 3U >
+ sizeof(prefix->vpn4.labelstack))
+ return (-1);
+ prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
+ prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
+ prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++;
+ if (prefix->vpn4.labelstack[prefix->vpn4.labellen] &
+ BGP_MPLS_BOS)
+ done = 1;
+ prefix->vpn4.labellen++;
+ plen += 3;
+ pfxlen -= 3 * 8;
+ } while (!done);
+
+ /* RD */
+ if (len - plen < (int)sizeof(u_int64_t) ||
+ pfxlen < sizeof(u_int64_t) * 8)
+ return (-1);
+ memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t));
+ pfxlen -= sizeof(u_int64_t) * 8;
+ p += sizeof(u_int64_t);
+ plen += sizeof(u_int64_t);
+
+ /* prefix */
+ prefix->aid = AID_VPN_IPv4;
*prefixlen = pfxlen;
- return (plen);
+ if ((rv = rde_update_extract_prefix(p, len, &prefix->vpn4.addr,
+ pfxlen, sizeof(prefix->vpn4.addr))) == -1)
+ return (-1);
+
+ return (plen + rv);
}
void
rde_update_err(struct rde_peer *peer, u_int8_t error, u_int8_t suberr,
void *data, u_int16_t size)
{
- struct buf *wbuf;
+ struct ibuf *wbuf;
if ((wbuf = imsg_create(ibuf_se, IMSG_UPDATE_ERR, peer->conf.id, 0,
size + sizeof(error) + sizeof(suberr))) == NULL)
@@ -1616,16 +1970,30 @@ rde_as4byte_fixup(struct rde_peer *peer, struct rde_aspath *a)
struct attr *nasp, *naggr, *oaggr;
u_int32_t as;
+ /*
+ * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present
+ * try to fixup the attributes.
+ * Do not fixup if F_ATTR_PARSE_ERR is set.
+ */
+ if (!(a->flags & F_ATTR_AS4BYTE_NEW) || a->flags & F_ATTR_PARSE_ERR)
+ return;
+
/* first get the attributes */
nasp = attr_optget(a, ATTR_AS4_PATH);
naggr = attr_optget(a, ATTR_AS4_AGGREGATOR);
if (rde_as4byte(peer)) {
/* NEW session using 4-byte ASNs */
- if (nasp)
+ if (nasp) {
+ log_peer_warnx(&peer->conf, "uses 4-byte ASN "
+ "but sent AS4_PATH attribute.");
attr_free(a, nasp);
- if (naggr)
+ }
+ if (naggr) {
+ log_peer_warnx(&peer->conf, "uses 4-byte ASN "
+ "but sent AS4_AGGREGATOR attribute.");
attr_free(a, naggr);
+ }
return;
}
/* OLD session using 2-byte ASNs */
@@ -1669,6 +2037,10 @@ rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
u_int16_t len;
u_int32_t id;
+ /* do not consider updates with parse errors */
+ if (asp->flags & F_ATTR_PARSE_ERR)
+ return;
+
/* check for originator id if eq router_id drop */
if ((a = attr_optget(asp, ATTR_ORIGINATOR_ID)) != NULL) {
if (memcmp(&conf->bgpid, a->data, sizeof(conf->bgpid)) == 0) {
@@ -1724,7 +2096,7 @@ void
rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
{
struct ctl_show_rib rib;
- struct buf *wbuf;
+ struct ibuf *wbuf;
struct attr *a;
void *bp;
u_int8_t l;
@@ -1748,23 +2120,23 @@ rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
/* announced network may have a NULL nexthop */
bzero(&rib.true_nexthop, sizeof(rib.true_nexthop));
bzero(&rib.exit_nexthop, sizeof(rib.exit_nexthop));
- rib.true_nexthop.af = p->prefix->af;
- rib.exit_nexthop.af = p->prefix->af;
+ rib.true_nexthop.aid = p->prefix->aid;
+ rib.exit_nexthop.aid = p->prefix->aid;
}
pt_getaddr(p->prefix, &rib.prefix);
rib.prefixlen = p->prefix->prefixlen;
rib.origin = asp->origin;
rib.flags = 0;
if (p->rib->active == p)
- rib.flags |= F_RIB_ACTIVE;
+ rib.flags |= F_PREF_ACTIVE;
if (asp->peer->conf.ebgp == 0)
- rib.flags |= F_RIB_INTERNAL;
+ rib.flags |= F_PREF_INTERNAL;
if (asp->flags & F_PREFIX_ANNOUNCED)
- rib.flags |= F_RIB_ANNOUNCE;
+ rib.flags |= F_PREF_ANNOUNCE;
if (asp->nexthop == NULL || asp->nexthop->state == NEXTHOP_REACH)
- rib.flags |= F_RIB_ELIGIBLE;
+ rib.flags |= F_PREF_ELIGIBLE;
if (asp->flags & F_ATTR_LOOP)
- rib.flags &= ~F_RIB_ELIGIBLE;
+ rib.flags &= ~F_PREF_ELIGIBLE;
rib.aspath_len = aspath_length(asp->aspath);
if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
@@ -1784,13 +2156,13 @@ rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
IMSG_CTL_SHOW_RIB_ATTR, 0, pid,
attr_optlen(a))) == NULL)
return;
- if ((bp = buf_reserve(wbuf, attr_optlen(a))) == NULL) {
- buf_free(wbuf);
+ if ((bp = ibuf_reserve(wbuf, attr_optlen(a))) == NULL) {
+ ibuf_free(wbuf);
return;
}
if (attr_write(bp, attr_optlen(a), a->flags,
a->type, a->data, a->len) == -1) {
- buf_free(wbuf);
+ ibuf_free(wbuf);
return;
}
imsg_close(ibuf_se_ctl, wbuf);
@@ -1828,15 +2200,15 @@ rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
{
struct rde_peer *peer;
- if (req->flags & F_CTL_ADJ_IN ||
+ if (req->flags & F_CTL_ADJ_IN ||
!(req->flags & (F_CTL_ADJ_IN|F_CTL_ADJ_OUT))) {
if (req->peerid && req->peerid != p->aspath->peer->conf.id)
return;
- if (req->type == IMSG_CTL_SHOW_RIB_AS &&
+ if (req->type == IMSG_CTL_SHOW_RIB_AS &&
!aspath_match(p->aspath->aspath, req->as.type, req->as.as))
return;
if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
- !rde_filter_community(p->aspath, req->community.as,
+ !community_match(p->aspath, req->community.as,
req->community.type))
return;
rde_dump_rib_as(p, p->aspath, req->pid, req->flags);
@@ -1872,7 +2244,7 @@ rde_dump_prefix_upcall(struct rib_entry *re, void *ptr)
pt = re->prefix;
pt_getaddr(pt, &addr);
- if (addr.af != ctx->req.prefix.af)
+ if (addr.aid != ctx->req.prefix.aid)
return;
if (ctx->req.prefixlen > pt->prefixlen)
return;
@@ -1889,6 +2261,7 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
struct rib_entry *re;
u_int error;
u_int16_t id;
+ u_int8_t hostplen = 0;
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
log_warn("rde_dump_ctx_new");
@@ -1902,6 +2275,7 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
error = CTL_RES_NOSUCHPEER;
imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
sizeof(error));
+ free(ctx);
return;
}
@@ -1924,7 +2298,18 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall;
break;
}
- if (req->prefixlen == 32)
+ switch (req->prefix.aid) {
+ case AID_INET:
+ case AID_VPN_IPv4:
+ hostplen = 32;
+ break;
+ case AID_INET6:
+ hostplen = 128;
+ break;
+ default:
+ fatalx("rde_dump_ctx_new: unknown af");
+ }
+ if (req->prefixlen == hostplen)
re = rib_lookup(&ribs[id], &req->prefix);
else
re = rib_get(&ribs[id], &req->prefix, req->prefixlen);
@@ -1937,7 +2322,7 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
}
ctx->ribctx.ctx_done = rde_dump_done;
ctx->ribctx.ctx_arg = ctx;
- ctx->ribctx.ctx_af = ctx->req.af;
+ ctx->ribctx.ctx_aid = ctx->req.aid;
rib_dump_r(&ctx->ribctx);
}
@@ -1974,10 +2359,10 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS;
ctx->ribctx.ctx_rib = &ribs[id];
ctx->ribctx.ctx_upcall = mrt_dump_upcall;
- ctx->ribctx.ctx_done = mrt_dump_done;
+ ctx->ribctx.ctx_done = mrt_done;
ctx->ribctx.ctx_arg = &ctx->mrt;
- ctx->ribctx.ctx_af = AF_UNSPEC;
- LIST_INSERT_HEAD(&rde_mrts, &ctx->mrt, entry);
+ ctx->ribctx.ctx_aid = AID_UNSPEC;
+ LIST_INSERT_HEAD(&rde_mrts, ctx, entry);
rde_mrt_cnt++;
rib_dump_r(&ctx->ribctx);
}
@@ -1985,13 +2370,25 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
/*
* kroute specific functions
*/
+int
+rde_rdomain_import(struct rde_aspath *asp, struct rdomain *rd)
+{
+ struct filter_set *s;
+
+ TAILQ_FOREACH(s, &rd->import, entry) {
+ if (community_ext_match(asp, &s->action.ext_community, 0))
+ return (1);
+ }
+ return (0);
+}
+
void
-rde_send_kroute(struct prefix *new, struct prefix *old)
+rde_send_kroute(struct prefix *new, struct prefix *old, u_int16_t ribid)
{
- struct kroute_label kl;
- struct kroute6_label kl6;
+ struct kroute_full kr;
struct bgpd_addr addr;
struct prefix *p;
+ struct rdomain *rd;
enum imsg_type type;
/*
@@ -2011,43 +2408,45 @@ rde_send_kroute(struct prefix *new, struct prefix *old)
}
pt_getaddr(p->prefix, &addr);
- switch (addr.af) {
- case AF_INET:
- bzero(&kl, sizeof(kl));
- kl.kr.prefix.s_addr = addr.v4.s_addr;
- kl.kr.prefixlen = p->prefix->prefixlen;
- if (p->aspath->flags & F_NEXTHOP_REJECT)
- kl.kr.flags |= F_REJECT;
- if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
- kl.kr.flags |= F_BLACKHOLE;
- if (type == IMSG_KROUTE_CHANGE)
- kl.kr.nexthop.s_addr =
- p->aspath->nexthop->true_nexthop.v4.s_addr;
- strlcpy(kl.label, rtlabel_id2name(p->aspath->rtlabelid),
- sizeof(kl.label));
- if (imsg_compose(ibuf_main, type, 0, 0, -1, &kl,
- sizeof(kl)) == -1)
- fatal("imsg_compose error");
+ bzero(&kr, sizeof(kr));
+ memcpy(&kr.prefix, &addr, sizeof(kr.prefix));
+ kr.prefixlen = p->prefix->prefixlen;
+ if (p->aspath->flags & F_NEXTHOP_REJECT)
+ kr.flags |= F_REJECT;
+ if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
+ kr.flags |= F_BLACKHOLE;
+ if (type == IMSG_KROUTE_CHANGE)
+ memcpy(&kr.nexthop, &p->aspath->nexthop->true_nexthop,
+ sizeof(kr.nexthop));
+ strlcpy(kr.label, rtlabel_id2name(p->aspath->rtlabelid),
+ sizeof(kr.label));
+
+ switch (addr.aid) {
+ case AID_VPN_IPv4:
+ if (ribid != 1)
+ /* not Loc-RIB, no update for VPNs */
+ break;
+
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (addr.vpn4.rd != rd->rd)
+ continue;
+ if (!rde_rdomain_import(p->aspath, rd))
+ continue;
+ /* must send exit_nexthop so that correct MPLS tunnel
+ * is chosen
+ */
+ if (type == IMSG_KROUTE_CHANGE)
+ memcpy(&kr.nexthop,
+ &p->aspath->nexthop->exit_nexthop,
+ sizeof(kr.nexthop));
+ if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1,
+ &kr, sizeof(kr)) == -1)
+ fatal("imsg_compose error");
+ }
break;
- case AF_INET6:
- bzero(&kl6, sizeof(kl6));
- memcpy(&kl6.kr.prefix, &addr.v6, sizeof(struct in6_addr));
- kl6.kr.prefixlen = p->prefix->prefixlen;
- if (p->aspath->flags & F_NEXTHOP_REJECT)
- kl6.kr.flags |= F_REJECT;
- if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
- kl6.kr.flags |= F_BLACKHOLE;
- if (type == IMSG_KROUTE_CHANGE) {
- type = IMSG_KROUTE6_CHANGE;
- memcpy(&kl6.kr.nexthop,
- &p->aspath->nexthop->true_nexthop.v6,
- sizeof(struct in6_addr));
- } else
- type = IMSG_KROUTE6_DELETE;
- strlcpy(kl6.label, rtlabel_id2name(p->aspath->rtlabelid),
- sizeof(kl6.label));
- if (imsg_compose(ibuf_main, type, 0, 0, -1, &kl6,
- sizeof(kl6)) == -1)
+ default:
+ if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1,
+ &kr, sizeof(kr)) == -1)
fatal("imsg_compose error");
break;
}
@@ -2098,7 +2497,6 @@ rde_send_pftable_commit(void)
void
rde_send_nexthop(struct bgpd_addr *next, int valid)
{
- size_t size;
int type;
if (valid)
@@ -2106,8 +2504,6 @@ rde_send_nexthop(struct bgpd_addr *next, int valid)
else
type = IMSG_NEXTHOP_REMOVE;
- size = sizeof(struct bgpd_addr);
-
if (imsg_compose(ibuf_main, type, 0, 0, -1, next,
sizeof(struct bgpd_addr)) == -1)
fatal("imsg_compose error");
@@ -2201,6 +2597,10 @@ rde_softreconfig_in(struct rib_entry *re, void *ptr)
continue;
for (i = 1; i < rib_size; i++) {
+ /* only active ribs need a softreconfig rerun */
+ if (ribs[i].state != RECONF_KEEP)
+ continue;
+
/* check if prefix changed */
oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr,
pt->prefixlen, peer, DIR_IN);
@@ -2228,7 +2628,7 @@ rde_softreconfig_in(struct rib_entry *re, void *ptr)
if (path_compare(nasp, oasp) == 0)
goto done;
/* send update */
- path_update(&ribs[1], peer, nasp, &addr,
+ path_update(&ribs[i], peer, nasp, &addr,
pt->prefixlen);
}
@@ -2241,6 +2641,104 @@ done:
}
}
+void
+rde_softreconfig_load(struct rib_entry *re, void *ptr)
+{
+ struct rib *rib = ptr;
+ struct prefix *p, *np;
+ struct pt_entry *pt;
+ struct rde_peer *peer;
+ struct rde_aspath *asp, *nasp;
+ enum filter_actions action;
+ struct bgpd_addr addr;
+
+ pt = re->prefix;
+ pt_getaddr(pt, &addr);
+ for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) {
+ np = LIST_NEXT(p, rib_l);
+
+ /* store aspath as prefix may change till we're done */
+ asp = p->aspath;
+ peer = asp->peer;
+
+ action = rde_filter(rib->id, &nasp, newrules, peer, asp, &addr,
+ pt->prefixlen, peer, DIR_IN);
+ nasp = nasp != NULL ? nasp : asp;
+
+ if (action == ACTION_ALLOW) {
+ /* update Local-RIB */
+ path_update(rib, peer, nasp, &addr, pt->prefixlen);
+ }
+
+ if (nasp != asp)
+ path_put(nasp);
+ }
+}
+
+void
+rde_softreconfig_load_peer(struct rib_entry *re, void *ptr)
+{
+ struct rde_peer *peer = ptr;
+ struct prefix *p = re->active;
+ struct pt_entry *pt;
+ struct rde_aspath *nasp;
+ enum filter_actions na;
+ struct bgpd_addr addr;
+
+ pt = re->prefix;
+ pt_getaddr(pt, &addr);
+
+ /* check if prefix was announced */
+ if (up_test_update(peer, p) != 1)
+ return;
+
+ na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath,
+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
+ nasp = nasp != NULL ? nasp : p->aspath;
+
+ if (na == ACTION_DENY)
+ /* nothing todo */
+ goto done;
+
+ /* send update */
+ up_generate(peer, nasp, &addr, pt->prefixlen);
+done:
+ if (nasp != p->aspath)
+ path_put(nasp);
+}
+
+void
+rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
+{
+ struct rde_peer *peer = ptr;
+ struct prefix *p = re->active;
+ struct pt_entry *pt;
+ struct rde_aspath *oasp;
+ enum filter_actions oa;
+ struct bgpd_addr addr;
+
+ pt = re->prefix;
+ pt_getaddr(pt, &addr);
+
+ /* check if prefix was announced */
+ if (up_test_update(peer, p) != 1)
+ return;
+
+ oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath,
+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
+ oasp = oasp != NULL ? oasp : p->aspath;
+
+ if (oa == ACTION_DENY)
+ /* nothing todo */
+ goto done;
+
+ /* send withdraw */
+ up_generate(peer, NULL, &addr, pt->prefixlen);
+done:
+ if (oasp != p->aspath)
+ path_put(oasp);
+}
+
/*
* update specific functions
*/
@@ -2252,7 +2750,7 @@ rde_up_dump_upcall(struct rib_entry *re, void *ptr)
struct rde_peer *peer = ptr;
if (re->ribid != peer->ribid)
- fatalx("King Bula: monsterous evil horror.");
+ fatalx("King Bula: monstrous evil horror.");
if (re->active == NULL)
return;
up_generate_updates(rules_l, peer, re->active, NULL);
@@ -2265,7 +2763,7 @@ rde_generate_updates(u_int16_t ribid, struct prefix *new, struct prefix *old)
/*
* If old is != NULL we know it was active and should be removed.
- * If new is != NULL we know it is reachable and then we should
+ * If new is != NULL we know it is reachable and then we should
* generate an update.
*/
if (old == NULL && new == NULL)
@@ -2286,7 +2784,7 @@ void
rde_update_queue_runner(void)
{
struct rde_peer *peer;
- int r, sent, max = RDE_RUNNER_ROUNDS;
+ int r, sent, max = RDE_RUNNER_ROUNDS, eor = 0;
u_int16_t len, wd_len, wpos;
len = sizeof(queue_buf) - MSGSIZE_HEADER;
@@ -2300,7 +2798,7 @@ rde_update_queue_runner(void)
/* first withdraws */
wpos = 2; /* reserve space for the length field */
r = up_dump_prefix(queue_buf + wpos, len - wpos - 2,
- &peer->withdraws, peer);
+ &peer->withdraws[AID_INET], peer);
wd_len = r;
/* write withdraws length filed */
wd_len = htons(wd_len);
@@ -2310,31 +2808,49 @@ rde_update_queue_runner(void)
/* now bgp path attributes */
r = up_dump_attrnlri(queue_buf + wpos, len - wpos,
peer);
- wpos += r;
-
- if (wpos == 4)
- /*
- * No packet to send. The 4 bytes are the
- * needed withdraw and path attribute length.
- */
- continue;
+ switch (r) {
+ case -1:
+ eor = 1;
+ if (wd_len == 0) {
+ /* no withdraws queued just send EoR */
+ peer_send_eor(peer, AID_INET);
+ continue;
+ }
+ break;
+ case 2:
+ if (wd_len == 0) {
+ /*
+ * No packet to send. No withdraws and
+ * no path attributes. Skip.
+ */
+ continue;
+ }
+ /* FALLTHROUGH */
+ default:
+ wpos += r;
+ break;
+ }
/* finally send message to SE */
if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
0, -1, queue_buf, wpos) == -1)
fatal("imsg_compose error");
sent++;
+ if (eor) {
+ eor = 0;
+ peer_send_eor(peer, AID_INET);
+ }
}
max -= sent;
} while (sent != 0 && max > 0);
}
void
-rde_update6_queue_runner(void)
+rde_update6_queue_runner(u_int8_t aid)
{
struct rde_peer *peer;
u_char *b;
- int sent, max = RDE_RUNNER_ROUNDS / 2;
+ int r, sent, max = RDE_RUNNER_ROUNDS / 2;
u_int16_t len;
/* first withdraws ... */
@@ -2346,7 +2862,7 @@ rde_update6_queue_runner(void)
if (peer->state != PEER_UP)
continue;
len = sizeof(queue_buf) - MSGSIZE_HEADER;
- b = up_dump_mp_unreach(queue_buf, &len, peer);
+ b = up_dump_mp_unreach(queue_buf, &len, peer, aid);
if (b == NULL)
continue;
@@ -2369,10 +2885,18 @@ rde_update6_queue_runner(void)
if (peer->state != PEER_UP)
continue;
len = sizeof(queue_buf) - MSGSIZE_HEADER;
- b = up_dump_mp_reach(queue_buf, &len, peer);
-
- if (b == NULL)
+ r = up_dump_mp_reach(queue_buf, &len, peer, aid);
+ switch (r) {
+ case -2:
+ continue;
+ case -1:
+ peer_send_eor(peer, aid);
continue;
+ default:
+ b = queue_buf + r;
+ break;
+ }
+
/* finally send message to SE */
if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
0, -1, b, len) == -1)
@@ -2411,7 +2935,7 @@ rde_decisionflags(void)
int
rde_as4byte(struct rde_peer *peer)
{
- return (peer->capa_announced.as4byte && peer->capa_received.as4byte);
+ return (peer->capa.as4byte);
}
/*
@@ -2429,7 +2953,6 @@ void
peer_init(u_int32_t hashsize)
{
struct peer_config pc;
- struct in_addr id;
u_int32_t hs, i;
for (hs = 1; hs < hashsize; hs <<= 1)
@@ -2445,17 +2968,13 @@ peer_init(u_int32_t hashsize)
peertable.peer_hashmask = hs - 1;
bzero(&pc, sizeof(pc));
- pc.remote_as = conf->as;
- id.s_addr = conf->bgpid;
- snprintf(pc.descr, sizeof(pc.descr), "LOCAL: ID %s", inet_ntoa(id));
+ snprintf(pc.descr, sizeof(pc.descr), "LOCAL");
peerself = peer_add(0, &pc);
if (peerself == NULL)
fatalx("peer_init add self");
peerself->state = PEER_UP;
- peerself->remote_bgpid = ntohl(conf->bgpid);
- peerself->short_as = conf->short_as;
}
void
@@ -2534,14 +3053,10 @@ peer_localaddrs(struct rde_peer *peer, struct bgpd_addr *laddr)
if (ifa->ifa_addr->sa_family ==
match->ifa_addr->sa_family)
ifa = match;
- peer->local_v4_addr.af = AF_INET;
- peer->local_v4_addr.v4.s_addr =
- ((struct sockaddr_in *)ifa->ifa_addr)->
- sin_addr.s_addr;
+ sa2addr(ifa->ifa_addr, &peer->local_v4_addr);
break;
}
}
-
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family == AF_INET6 &&
strcmp(ifa->ifa_name, match->ifa_name) == 0) {
@@ -2559,13 +3074,7 @@ peer_localaddrs(struct rde_peer *peer, struct bgpd_addr *laddr)
&((struct sockaddr_in6 *)ifa->
ifa_addr)->sin6_addr))
continue;
- peer->local_v6_addr.af = AF_INET6;
- memcpy(&peer->local_v6_addr.v6,
- &((struct sockaddr_in6 *)ifa->ifa_addr)->
- sin6_addr, sizeof(struct in6_addr));
- peer->local_v6_addr.scope_id =
- ((struct sockaddr_in6 *)ifa->ifa_addr)->
- sin6_scope_id;
+ sa2addr(ifa->ifa_addr, &peer->local_v6_addr);
break;
}
}
@@ -2577,6 +3086,7 @@ void
peer_up(u_int32_t id, struct session_up *sup)
{
struct rde_peer *peer;
+ u_int8_t i;
peer = peer_get(id);
if (peer == NULL) {
@@ -2590,10 +3100,7 @@ peer_up(u_int32_t id, struct session_up *sup)
peer->short_as = sup->short_as;
memcpy(&peer->remote_addr, &sup->remote_addr,
sizeof(peer->remote_addr));
- memcpy(&peer->capa_announced, &sup->capa_announced,
- sizeof(peer->capa_announced));
- memcpy(&peer->capa_received, &sup->capa_received,
- sizeof(peer->capa_received));
+ memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
peer_localaddrs(peer, &sup->local_addr);
@@ -2607,7 +3114,10 @@ peer_up(u_int32_t id, struct session_up *sup)
*/
return;
- peer_dump(id, AFI_ALL, SAFI_ALL);
+ for (i = 0; i < AID_MAX; i++) {
+ if (peer->capa.mp[i] == 1)
+ peer_dump(id, i);
+ }
}
void
@@ -2642,42 +3152,32 @@ peer_down(u_int32_t id)
}
void
-peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi)
+peer_dump(u_int32_t id, u_int8_t aid)
{
struct rde_peer *peer;
peer = peer_get(id);
if (peer == NULL) {
- log_warnx("peer_down: unknown peer id %d", id);
+ log_warnx("peer_dump: unknown peer id %d", id);
return;
}
- if (afi == AFI_ALL || afi == AFI_IPv4)
- if (safi == SAFI_ALL || safi == SAFI_UNICAST) {
- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
- up_generate_default(rules_l, peer, AF_INET);
- else
- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall,
- peer, AF_INET);
- }
- if (afi == AFI_ALL || afi == AFI_IPv6)
- if (safi == SAFI_ALL || safi == SAFI_UNICAST) {
- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
- up_generate_default(rules_l, peer, AF_INET6);
- else
- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall,
- peer, AF_INET6);
- }
-
- if (peer->capa_received.restart && peer->capa_announced.restart)
- peer_send_eor(peer, afi, safi);
+ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
+ up_generate_default(rules_l, peer, aid);
+ else
+ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid);
+ if (peer->capa.restart)
+ up_generate_marker(peer, aid);
}
-/* End-of-RIB marker, draft-ietf-idr-restart-13.txt */
+/* End-of-RIB marker, RFC 4724 */
void
-peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
+peer_send_eor(struct rde_peer *peer, u_int8_t aid)
{
- if (afi == AFI_IPv4 && safi == SAFI_UNICAST) {
+ u_int16_t afi;
+ u_int8_t safi;
+
+ if (aid == AID_INET) {
u_char null[4];
bzero(&null, 4);
@@ -2688,6 +3188,9 @@ peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
u_int16_t i;
u_char buf[10];
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("peer_send_eor: bad AID");
+
i = 0; /* v4 withdrawn len */
bcopy(&i, &buf[0], sizeof(i));
i = htons(6); /* path attr len */
@@ -2709,25 +3212,43 @@ peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
* network announcement stuff
*/
void
-network_init(struct network_head *net_l)
-{
- struct network *n;
-
- reloadtime = time(NULL);
-
- while ((n = TAILQ_FIRST(net_l)) != NULL) {
- TAILQ_REMOVE(net_l, n, entry);
- network_add(&n->net, 1);
- free(n);
- }
-}
-
-void
network_add(struct network_config *nc, int flagstatic)
{
+ struct rdomain *rd;
struct rde_aspath *asp;
+ struct filter_set_head *vpnset = NULL;
+ in_addr_t prefix4;
u_int16_t i;
+ if (nc->rtableid) {
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (rd->rtableid != nc->rtableid)
+ continue;
+ switch (nc->prefix.aid) {
+ case AID_INET:
+ prefix4 = nc->prefix.v4.s_addr;
+ bzero(&nc->prefix, sizeof(nc->prefix));
+ nc->prefix.aid = AID_VPN_IPv4;
+ nc->prefix.vpn4.rd = rd->rd;
+ nc->prefix.vpn4.addr.s_addr = prefix4;
+ nc->prefix.vpn4.labellen = 3;
+ nc->prefix.vpn4.labelstack[0] =
+ (rd->label >> 12) & 0xff;
+ nc->prefix.vpn4.labelstack[1] =
+ (rd->label >> 4) & 0xff;
+ nc->prefix.vpn4.labelstack[2] =
+ (rd->label << 4) & 0xf0;
+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
+ vpnset = &rd->export;
+ break;
+ default:
+ log_warnx("unable to VPNize prefix");
+ filterset_free(&nc->attrset);
+ return;
+ }
+ }
+ }
+
asp = path_get();
asp->aspath = aspath_get(NULL, 0);
asp->origin = ORIGIN_IGP;
@@ -2737,7 +3258,9 @@ network_add(struct network_config *nc, int flagstatic)
if (!flagstatic)
asp->flags |= F_ANN_DYNAMIC;
- rde_apply_set(asp, &nc->attrset, nc->prefix.af, peerself, peerself);
+ rde_apply_set(asp, &nc->attrset, nc->prefix.aid, peerself, peerself);
+ if (vpnset)
+ rde_apply_set(asp, vpnset, nc->prefix.aid, peerself, peerself);
for (i = 1; i < rib_size; i++)
path_update(&ribs[i], peerself, asp, &nc->prefix,
nc->prefixlen);
@@ -2749,12 +3272,41 @@ network_add(struct network_config *nc, int flagstatic)
void
network_delete(struct network_config *nc, int flagstatic)
{
- u_int32_t flags = F_PREFIX_ANNOUNCED;
- u_int32_t i;
+ struct rdomain *rd;
+ in_addr_t prefix4;
+ u_int32_t flags = F_PREFIX_ANNOUNCED;
+ u_int32_t i;
if (!flagstatic)
flags |= F_ANN_DYNAMIC;
+ if (nc->rtableid) {
+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
+ if (rd->rtableid != nc->rtableid)
+ continue;
+ switch (nc->prefix.aid) {
+ case AID_INET:
+ prefix4 = nc->prefix.v4.s_addr;
+ bzero(&nc->prefix, sizeof(nc->prefix));
+ nc->prefix.aid = AID_VPN_IPv4;
+ nc->prefix.vpn4.rd = rd->rd;
+ nc->prefix.vpn4.addr.s_addr = prefix4;
+ nc->prefix.vpn4.labellen = 3;
+ nc->prefix.vpn4.labelstack[0] =
+ (rd->label >> 12) & 0xff;
+ nc->prefix.vpn4.labelstack[1] =
+ (rd->label >> 4) & 0xff;
+ nc->prefix.vpn4.labelstack[2] =
+ (rd->label << 4) & 0xf0;
+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
+ break;
+ default:
+ log_warnx("unable to VPNize prefix");
+ return;
+ }
+ }
+ }
+
for (i = rib_size - 1; i > 0; i--)
prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen,
flags);
@@ -2764,38 +3316,31 @@ void
network_dump_upcall(struct rib_entry *re, void *ptr)
{
struct prefix *p;
- struct kroute k;
- struct kroute6 k6;
+ struct kroute_full k;
struct bgpd_addr addr;
struct rde_dump_ctx *ctx = ptr;
LIST_FOREACH(p, &re->prefix_h, rib_l) {
if (!(p->aspath->flags & F_PREFIX_ANNOUNCED))
continue;
- if (p->prefix->af == AF_INET) {
- bzero(&k, sizeof(k));
- pt_getaddr(p->prefix, &addr);
- k.prefix.s_addr = addr.v4.s_addr;
- k.prefixlen = p->prefix->prefixlen;
- if (p->aspath->peer == peerself)
- k.flags = F_KERNEL;
- if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
- ctx->req.pid, -1, &k, sizeof(k)) == -1)
- log_warnx("network_dump_upcall: "
- "imsg_compose error");
- }
- if (p->prefix->af == AF_INET6) {
- bzero(&k6, sizeof(k6));
- pt_getaddr(p->prefix, &addr);
- memcpy(&k6.prefix, &addr.v6, sizeof(k6.prefix));
- k6.prefixlen = p->prefix->prefixlen;
- if (p->aspath->peer == peerself)
- k6.flags = F_KERNEL;
- if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK6, 0,
- ctx->req.pid, -1, &k6, sizeof(k6)) == -1)
- log_warnx("network_dump_upcall: "
- "imsg_compose error");
- }
+ pt_getaddr(p->prefix, &addr);
+
+ bzero(&k, sizeof(k));
+ memcpy(&k.prefix, &addr, sizeof(k.prefix));
+ if (p->aspath->nexthop == NULL ||
+ p->aspath->nexthop->state != NEXTHOP_REACH)
+ k.nexthop.aid = k.prefix.aid;
+ else
+ memcpy(&k.nexthop, &p->aspath->nexthop->true_nexthop,
+ sizeof(k.nexthop));
+ k.prefixlen = p->prefix->prefixlen;
+ k.flags = F_KERNEL;
+ if ((p->aspath->flags & F_ANN_DYNAMIC) == 0)
+ k.flags = F_STATIC;
+ if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
+ ctx->req.pid, -1, &k, sizeof(k)) == -1)
+ log_warnx("network_dump_upcall: "
+ "imsg_compose error");
}
}
@@ -2841,10 +3386,10 @@ sa_cmp(struct bgpd_addr *a, struct sockaddr *b)
struct sockaddr_in *in_b;
struct sockaddr_in6 *in6_b;
- if (a->af != b->sa_family)
+ if (aid2af(a->aid) != b->sa_family)
return (1);
- switch (a->af) {
+ switch (b->sa_family) {
case AF_INET:
in_b = (struct sockaddr_in *)b;
if (a->v4.s_addr != in_b->sin_addr.s_addr)
diff --git a/bgpd/rde.h b/bgpd/rde.h
index 2664fd4..d2a594b 100644
--- a/bgpd/rde.h
+++ b/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.120 2009/06/06 01:10:29 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.138 2010/11/18 12:18:31 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -56,12 +56,9 @@ struct rde_peer {
struct bgpd_addr local_v6_addr;
struct uptree_prefix up_prefix;
struct uptree_attr up_attrs;
- struct uplist_attr updates;
- struct uplist_prefix withdraws;
- struct uplist_attr updates6;
- struct uplist_prefix withdraws6;
- struct capabilities capa_announced;
- struct capabilities capa_received;
+ struct uplist_attr updates[AID_MAX];
+ struct uplist_prefix withdraws[AID_MAX];
+ struct capabilities capa;
u_int64_t prefix_rcvd_update;
u_int64_t prefix_rcvd_withdraw;
u_int64_t prefix_sent_update;
@@ -77,10 +74,13 @@ struct rde_peer {
u_int16_t short_as;
u_int8_t reconf_in; /* in filter changed */
u_int8_t reconf_out; /* out filter changed */
+ u_int8_t reconf_rib; /* rib changed */
};
#define AS_SET 1
#define AS_SEQUENCE 2
+#define AS_CONFED_SEQUENCE 3
+#define AS_CONFED_SET 4
#define ASPATH_HEADER_SIZE (sizeof(struct aspath) - sizeof(u_char))
LIST_HEAD(aspath_list, aspath);
@@ -163,6 +163,7 @@ LIST_HEAD(prefix_head, prefix);
#define F_NEXTHOP_REJECT 0x02000
#define F_NEXTHOP_BLACKHOLE 0x04000
#define F_NEXTHOP_NOMODIFY 0x08000
+#define F_ATTR_PARSE_ERR 0x10000
#define F_ATTR_LINKED 0x20000
@@ -220,14 +221,14 @@ struct nexthop {
/* generic entry without address specific part */
struct pt_entry {
RB_ENTRY(pt_entry) pt_e;
- sa_family_t af;
+ u_int8_t aid;
u_int8_t prefixlen;
u_int16_t refcnt;
};
struct pt_entry4 {
RB_ENTRY(pt_entry) pt_e;
- sa_family_t af;
+ u_int8_t aid;
u_int8_t prefixlen;
u_int16_t refcnt;
struct in_addr prefix4;
@@ -235,12 +236,25 @@ struct pt_entry4 {
struct pt_entry6 {
RB_ENTRY(pt_entry) pt_e;
- sa_family_t af;
+ u_int8_t aid;
u_int8_t prefixlen;
u_int16_t refcnt;
struct in6_addr prefix6;
};
+struct pt_entry_vpn4 {
+ RB_ENTRY(pt_entry) pt_e;
+ u_int8_t aid;
+ u_int8_t prefixlen;
+ u_int16_t refcnt;
+ struct in_addr prefix4;
+ u_int64_t rd;
+ u_int8_t labelstack[21];
+ u_int8_t labellen;
+ u_int8_t pad1;
+ u_int8_t pad2;
+};
+
struct rib_context {
LIST_ENTRY(rib_context) entry;
struct rib_entry *ctx_re;
@@ -250,7 +264,7 @@ struct rib_context {
void (*ctx_wait)(void *);
void *ctx_arg;
unsigned int ctx_count;
- sa_family_t ctx_af;
+ u_int8_t ctx_aid;
};
struct rib_entry {
@@ -262,23 +276,15 @@ struct rib_entry {
u_int16_t flags;
};
-enum rib_state {
- RIB_NONE,
- RIB_ACTIVE,
- RIB_DELETE
-};
-
struct rib {
char name[PEER_DESCR_LEN];
struct rib_tree rib;
- enum rib_state state;
+ u_int rtableid;
u_int16_t flags;
u_int16_t id;
+ enum reconf_action state;
};
-#define F_RIB_ENTRYLOCK 0x0001
-#define F_RIB_NOEVALUATE 0x0002
-#define F_RIB_NOFIB 0x0004
#define RIB_FAILED 0xffff
struct prefix {
@@ -293,7 +299,7 @@ extern struct rde_memstats rdemem;
/* prototypes */
/* rde.c */
-void rde_send_kroute(struct prefix *, struct prefix *);
+void rde_send_kroute(struct prefix *, struct prefix *, u_int16_t);
void rde_send_nexthop(struct bgpd_addr *, int);
void rde_send_pftable(u_int16_t, struct bgpd_addr *,
u_int8_t, int);
@@ -309,7 +315,7 @@ int rde_as4byte(struct rde_peer *);
/* rde_attr.c */
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
-int attr_writebuf(struct buf *, u_int8_t, u_int8_t, void *,
+int attr_writebuf(struct ibuf *, u_int8_t, u_int8_t, void *,
u_int16_t);
void attr_init(u_int32_t);
void attr_shutdown(void);
@@ -327,6 +333,7 @@ int aspath_verify(void *, u_int16_t, int);
#define AS_ERR_LEN -1
#define AS_ERR_TYPE -2
#define AS_ERR_BAD -3
+#define AS_ERR_SOFT -4
void aspath_init(u_int32_t);
void aspath_shutdown(void);
struct aspath *aspath_get(void *, u_int16_t);
@@ -342,21 +349,30 @@ int aspath_loopfree(struct aspath *, u_int32_t);
int aspath_compare(struct aspath *, struct aspath *);
u_char *aspath_prepend(struct aspath *, u_int32_t, int, u_int16_t *);
int aspath_match(struct aspath *, enum as_spec, u_int32_t);
-int community_match(void *, u_int16_t, int, int);
+int aspath_lenmatch(struct aspath *, enum aslen_spec, u_int);
+int community_match(struct rde_aspath *, int, int);
int community_set(struct rde_aspath *, int, int);
void community_delete(struct rde_aspath *, int, int);
+int community_ext_match(struct rde_aspath *,
+ struct filter_extcommunity *, u_int16_t);
+int community_ext_set(struct rde_aspath *,
+ struct filter_extcommunity *, u_int16_t);
+void community_ext_delete(struct rde_aspath *,
+ struct filter_extcommunity *, u_int16_t);
+int community_ext_conv(struct filter_extcommunity *, u_int16_t,
+ u_int64_t *);
/* rde_rib.c */
extern u_int16_t rib_size;
extern struct rib *ribs;
-u_int16_t rib_new(int, char *, u_int16_t);
+u_int16_t rib_new(char *, u_int, u_int16_t);
u_int16_t rib_find(char *);
void rib_free(struct rib *);
struct rib_entry *rib_get(struct rib *, struct bgpd_addr *, int);
struct rib_entry *rib_lookup(struct rib *, struct bgpd_addr *);
void rib_dump(struct rib *, void (*)(struct rib_entry *, void *),
- void *, sa_family_t);
+ void *, u_int8_t);
void rib_dump_r(struct rib_context *);
void rib_dump_runner(void);
int rib_dump_pending(void);
@@ -395,7 +411,7 @@ void prefix_network_clean(struct rde_peer *, time_t, u_int32_t);
void nexthop_init(u_int32_t);
void nexthop_shutdown(void);
void nexthop_modify(struct rde_aspath *, struct bgpd_addr *,
- enum action_types, sa_family_t);
+ enum action_types, u_int8_t);
void nexthop_link(struct rde_aspath *);
void nexthop_unlink(struct rde_aspath *);
int nexthop_delete(struct nexthop *);
@@ -415,12 +431,15 @@ int up_generate(struct rde_peer *, struct rde_aspath *,
void up_generate_updates(struct filter_head *, struct rde_peer *,
struct prefix *, struct prefix *);
void up_generate_default(struct filter_head *, struct rde_peer *,
- sa_family_t);
+ u_int8_t);
+int up_generate_marker(struct rde_peer *, u_int8_t);
int up_dump_prefix(u_char *, int, struct uplist_prefix *,
struct rde_peer *);
int up_dump_attrnlri(u_char *, int, struct rde_peer *);
-u_char *up_dump_mp_unreach(u_char *, u_int16_t *, struct rde_peer *);
-u_char *up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *);
+u_char *up_dump_mp_unreach(u_char *, u_int16_t *, struct rde_peer *,
+ u_int8_t);
+int up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *,
+ u_int8_t);
/* rde_prefix.c */
#define pt_empty(pt) ((pt)->refcnt == 0)
@@ -452,8 +471,7 @@ enum filter_actions rde_filter(u_int16_t, struct rde_aspath **,
struct rde_aspath *, struct bgpd_addr *, u_int8_t,
struct rde_peer *, enum directions);
void rde_apply_set(struct rde_aspath *, struct filter_set_head *,
- sa_family_t, struct rde_peer *, struct rde_peer *);
-int rde_filter_community(struct rde_aspath *, int, int);
+ u_int8_t, struct rde_peer *, struct rde_peer *);
int rde_filter_equal(struct filter_head *, struct filter_head *,
struct rde_peer *, enum directions);
diff --git a/bgpd/rde_attr.c b/bgpd/rde_attr.c
index 7b4591f..eab471f 100644
--- a/bgpd/rde_attr.c
+++ b/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.79 2009/03/19 06:52:59 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.83 2010/03/29 09:24:07 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -17,14 +17,22 @@
*/
#include <sys/types.h>
+#if defined(__FreeBSD__) /* sys/hash.h */
+#include "hash.h"
+#else
#include <sys/hash.h>
+#endif /* defined(__FreeBSD__) */
#include <sys/queue.h>
#include <netinet/in.h>
+#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#if defined(__FreeBSD__) /* limits.h */
+#include <limits.h>
+#endif /* defined(__FreeBSD__) */
#include "bgpd.h"
#include "rde.h"
@@ -63,7 +71,7 @@ attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
}
int
-attr_writebuf(struct buf *buf, u_int8_t flags, u_int8_t type, void *data,
+attr_writebuf(struct ibuf *buf, u_int8_t flags, u_int8_t type, void *data,
u_int16_t data_len)
{
u_char hdr[4];
@@ -80,9 +88,9 @@ attr_writebuf(struct buf *buf, u_int8_t flags, u_int8_t type, void *data,
hdr[0] = flags;
hdr[1] = type;
- if (buf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
+ if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
return (-1);
- if (buf_add(buf, data, data_len) == -1)
+ if (ibuf_add(buf, data, data_len) == -1)
return (-1);
return (0);
}
@@ -146,8 +154,11 @@ attr_optadd(struct rde_aspath *asp, u_int8_t flags, u_int8_t type,
for (l = 0; l < asp->others_len; l++) {
if (asp->others[l] == NULL)
break;
- if (type == asp->others[l]->type)
+ if (type == asp->others[l]->type) {
+ if (a->refcnt == 0)
+ attr_put(a);
return (-1);
+ }
}
/* add attribute to the table but first bump refcnt */
@@ -405,6 +416,7 @@ aspath_verify(void *data, u_int16_t len, int as4byte)
u_int8_t *seg = data;
u_int16_t seg_size, as_size = 2;
u_int8_t seg_len, seg_type;
+ int err = 0;
if (len & 1)
/* odd length aspath are invalid */
@@ -419,7 +431,15 @@ aspath_verify(void *data, u_int16_t len, int as4byte)
seg_type = seg[0];
seg_len = seg[1];
- if (seg_type != AS_SET && seg_type != AS_SEQUENCE)
+ /*
+ * BGP confederations should not show up but consider them
+ * as a soft error which invalidates the path but keeps the
+ * bgp session running.
+ */
+ if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
+ err = AS_ERR_SOFT;
+ if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
+ seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET)
return (AS_ERR_TYPE);
seg_size = 2 + as_size * seg_len;
@@ -431,7 +451,7 @@ aspath_verify(void *data, u_int16_t len, int as4byte)
/* empty aspath segments are not allowed */
return (AS_ERR_BAD);
}
- return (0); /* aspath is valid but probably not loop free */
+ return (err); /* aspath is valid but probably not loop free */
}
void
@@ -972,14 +992,62 @@ aspath_match(struct aspath *a, enum as_spec type, u_int32_t as)
}
int
-community_match(void *data, u_int16_t len, int as, int type)
+aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen)
{
- u_int8_t *p = data;
- u_int16_t eas, etype;
+ u_int8_t *seg;
+ u_int32_t as, lastas = 0;
+ u_int count = 0;
+ u_int16_t len, seg_size;
+ u_int8_t i, seg_type, seg_len;
+
+ if (type == ASLEN_MAX) {
+ if (aslen < aspath_count(a->data, a->len))
+ return (1);
+ else
+ return (0);
+ }
- len >>= 2; /* divide by four */
+ /* type == ASLEN_SEQ */
+ seg = a->data;
+ for (len = a->len; len > 0; len -= seg_size, seg += seg_size) {
+ seg_type = seg[0];
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
- for (; len > 0; len--) {
+ for (i = 0; i < seg_len; i++) {
+ /* what should we do with AS_SET? */
+ as = aspath_extract(seg, i);
+ if (as == lastas) {
+ if (aslen < ++count)
+ return (1);
+ } else
+ count = 1;
+ lastas = as;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Functions handling communities and extended communities.
+ */
+
+int community_ext_matchone(struct filter_extcommunity *, u_int16_t, u_int64_t);
+
+int
+community_match(struct rde_aspath *asp, int as, int type)
+{
+ struct attr *a;
+ u_int8_t *p;
+ u_int16_t eas, etype, len;
+
+ a = attr_optget(asp, ATTR_COMMUNITIES);
+ if (a == NULL)
+ /* no communities, no match */
+ return (0);
+
+ p = a->data;
+ for (len = a->len / 4; len > 0; len--) {
eas = *p++;
eas <<= 8;
eas |= *p++;
@@ -1000,7 +1068,6 @@ community_set(struct rde_aspath *asp, int as, int type)
u_int8_t *p = NULL;
unsigned int i, ncommunities = 0;
u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
- u_int8_t t = ATTR_COMMUNITIES;
attr = attr_optget(asp, ATTR_COMMUNITIES);
if (attr != NULL) {
@@ -1017,7 +1084,7 @@ community_set(struct rde_aspath *asp, int as, int type)
p += 4;
}
- if (ncommunities++ >= 0x3fff)
+ if (ncommunities++ >= USHRT_MAX / 4)
/* overflow */
return (0);
@@ -1032,11 +1099,10 @@ community_set(struct rde_aspath *asp, int as, int type)
if (attr != NULL) {
memcpy(p + 4, attr->data, attr->len);
f = attr->flags;
- t = attr->type;
attr_free(asp, attr);
}
- attr_optadd(asp, f, t, p, ncommunities << 2);
+ attr_optadd(asp, f, ATTR_COMMUNITIES, p, ncommunities << 2);
free(p);
return (1);
@@ -1049,7 +1115,7 @@ community_delete(struct rde_aspath *asp, int as, int type)
u_int8_t *p, *n;
u_int16_t l, len = 0;
u_int16_t eas, etype;
- u_int8_t f, t;
+ u_int8_t f;
attr = attr_optget(asp, ATTR_COMMUNITIES);
if (attr == NULL)
@@ -1100,10 +1166,250 @@ community_delete(struct rde_aspath *asp, int as, int type)
}
f = attr->flags;
- t = attr->type;
attr_free(asp, attr);
- attr_optadd(asp, f, t, n, len);
+ attr_optadd(asp, f, ATTR_COMMUNITIES, n, len);
free(n);
}
+int
+community_ext_match(struct rde_aspath *asp, struct filter_extcommunity *c,
+ u_int16_t neighas)
+{
+ struct attr *attr;
+ u_int8_t *p;
+ u_int64_t ec;
+ u_int16_t len;
+
+ attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
+ if (attr == NULL)
+ /* no communities, no match */
+ return (0);
+
+ p = attr->data;
+ for (len = attr->len / sizeof(ec); len > 0; len--) {
+ memcpy(&ec, p, sizeof(ec));
+ if (community_ext_matchone(c, neighas, ec))
+ return (1);
+ p += sizeof(ec);
+ }
+
+ return (0);
+}
+
+int
+community_ext_set(struct rde_aspath *asp, struct filter_extcommunity *c,
+ u_int16_t neighas)
+{
+ struct attr *attr;
+ u_int8_t *p = NULL;
+ u_int64_t community;
+ unsigned int i, ncommunities = 0;
+ u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
+
+ if (community_ext_conv(c, neighas, &community))
+ return (0);
+
+ attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
+ if (attr != NULL) {
+ p = attr->data;
+ ncommunities = attr->len / sizeof(community);
+ }
+
+ /* first check if the community is not already set */
+ for (i = 0; i < ncommunities; i++) {
+ if (memcmp(&community, p, sizeof(community)) == 0)
+ /* already present, nothing todo */
+ return (1);
+ p += sizeof(community);
+ }
+
+ if (ncommunities++ >= USHRT_MAX / sizeof(community))
+ /* overflow */
+ return (0);
+
+ if ((p = malloc(ncommunities * sizeof(community))) == NULL)
+ fatal("community_ext_set");
+
+ memcpy(p, &community, sizeof(community));
+ if (attr != NULL) {
+ memcpy(p + sizeof(community), attr->data, attr->len);
+ f = attr->flags;
+ attr_free(asp, attr);
+ }
+
+ attr_optadd(asp, f, ATTR_EXT_COMMUNITIES, p,
+ ncommunities * sizeof(community));
+
+ free(p);
+ return (1);
+}
+
+void
+community_ext_delete(struct rde_aspath *asp, struct filter_extcommunity *c,
+ u_int16_t neighas)
+{
+ struct attr *attr;
+ u_int8_t *p, *n;
+ u_int64_t community;
+ u_int16_t l, len = 0;
+ u_int8_t f;
+
+ if (community_ext_conv(c, neighas, &community))
+ return;
+
+ attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
+ if (attr == NULL)
+ /* no attr nothing to do */
+ return;
+
+ p = attr->data;
+ for (l = 0; l < attr->len; l += sizeof(community)) {
+ if (memcmp(&community, p + l, sizeof(community)) == 0)
+ /* match */
+ continue;
+ len += sizeof(community);
+ }
+
+ if (len == 0) {
+ attr_free(asp, attr);
+ return;
+ }
+
+ if ((n = malloc(len)) == NULL)
+ fatal("community_delete");
+
+ p = attr->data;
+ for (l = 0; l < len && p < attr->data + attr->len;
+ p += sizeof(community)) {
+ if (memcmp(&community, p, sizeof(community)) == 0)
+ /* match */
+ continue;
+ memcpy(n + l, p, sizeof(community));
+ l += sizeof(community);
+ }
+
+ f = attr->flags;
+
+ attr_free(asp, attr);
+ attr_optadd(asp, f, ATTR_EXT_COMMUNITIES, n, len);
+ free(n);
+}
+
+int
+community_ext_conv(struct filter_extcommunity *c, u_int16_t neighas,
+ u_int64_t *community)
+{
+ u_int64_t com;
+ u_int32_t ip;
+
+ com = (u_int64_t)c->type << 56;
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ com |= (u_int64_t)c->subtype << 48;
+ com |= (u_int64_t)c->data.ext_as.as << 32;
+ com |= c->data.ext_as.val;
+ break;
+ case EXT_COMMUNITY_IPV4:
+ com |= (u_int64_t)c->subtype << 48;
+ ip = ntohl(c->data.ext_ip.addr.s_addr);
+ com |= (u_int64_t)ip << 16;
+ com |= c->data.ext_ip.val;
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ com |= (u_int64_t)c->subtype << 48;
+ com |= (u_int64_t)c->data.ext_as4.as4 << 16;
+ com |= c->data.ext_as4.val;
+ break;
+ case EXT_COMMUNITY_OPAQUE:
+ com |= (u_int64_t)c->subtype << 48;
+ com |= c->data.ext_opaq & EXT_COMMUNITY_OPAQUE_MAX;
+ break;
+ default:
+ com |= c->data.ext_opaq & 0xffffffffffffffULL;
+ break;
+ }
+
+ *community = htobe64(com);
+
+ return (0);
+}
+
+int
+community_ext_matchone(struct filter_extcommunity *c, u_int16_t neighas,
+ u_int64_t community)
+{
+ u_int64_t com, mask;
+ u_int32_t ip;
+
+ community = betoh64(community);
+
+ com = (u_int64_t)c->type << 56;
+ mask = 0xffULL << 56;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ case EXT_COMMUNITY_IPV4:
+ case EXT_COMMUNITY_FOUR_AS:
+ case EXT_COMMUNITY_OPAQUE:
+ com = (u_int64_t)c->subtype << 48;
+ mask = 0xffULL << 48;
+ if ((com & mask) != (community & mask))
+ return (0);
+ break;
+ default:
+ com = c->data.ext_opaq & 0xffffffffffffffULL;
+ mask = 0xffffffffffffffULL;
+ if ((com & mask) == (community & mask))
+ return (1);
+ return (0);
+ }
+
+
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ com = (u_int64_t)c->data.ext_as.as << 32;
+ mask = 0xffffULL << 32;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_as.val;
+ mask = 0xffffffffULL;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ ip = ntohl(c->data.ext_ip.addr.s_addr);
+ com = (u_int64_t)ip << 16;
+ mask = 0xffffffff0000ULL;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_ip.val;
+ mask = 0xffff;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ com = (u_int64_t)c->data.ext_as4.as4 << 16;
+ mask = 0xffffffffULL << 16;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_as4.val;
+ mask = 0xffff;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_OPAQUE:
+ com = c->data.ext_opaq & EXT_COMMUNITY_OPAQUE_MAX;
+ mask = EXT_COMMUNITY_OPAQUE_MAX;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ }
+
+ return (0);
+}
diff --git a/bgpd/rde_decide.c b/bgpd/rde_decide.c
index 2a94aa9..d872527 100644
--- a/bgpd/rde_decide.c
+++ b/bgpd/rde_decide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_decide.c,v 1.58 2009/06/29 14:10:13 claudio Exp $ */
+/* $OpenBSD: rde_decide.c,v 1.59 2009/08/06 08:53:11 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -118,6 +118,12 @@ prefix_cmp(struct prefix *p1, struct prefix *p2)
asp1 = p1->aspath;
asp2 = p2->aspath;
+ /* pathes with errors are not eligible */
+ if (asp1->flags & F_ATTR_PARSE_ERR)
+ return (-1);
+ if (asp2->flags & F_ATTR_PARSE_ERR)
+ return (1);
+
/* only loop free pathes are eligible */
if (asp1->flags & F_ATTR_LOOP)
return (-1);
@@ -204,7 +210,7 @@ prefix_cmp(struct prefix *p1, struct prefix *p2)
}
fatalx("Uh, oh a politician in the decision process");
- /* NOTREACHED */
+ return(0); /* NOTREACHED */
}
/*
@@ -245,7 +251,7 @@ prefix_evaluate(struct prefix *p, struct rib_entry *re)
}
xp = LIST_FIRST(&re->prefix_h);
- if (xp == NULL || xp->aspath->flags & F_ATTR_LOOP ||
+ if (xp == NULL || xp->aspath->flags & (F_ATTR_LOOP|F_ATTR_PARSE_ERR) ||
(xp->aspath->nexthop != NULL &&
xp->aspath->nexthop->state != NEXTHOP_REACH))
/* xp is ineligible */
@@ -263,7 +269,7 @@ prefix_evaluate(struct prefix *p, struct rib_entry *re)
*/
rde_generate_updates(re->ribid, xp, re->active);
if ((re->flags & F_RIB_NOFIB) == 0)
- rde_send_kroute(xp, re->active);
+ rde_send_kroute(xp, re->active, re->ribid);
re->active = xp;
if (xp != NULL)
diff --git a/bgpd/rde_filter.c b/bgpd/rde_filter.c
index 001b796..e791fa1 100644
--- a/bgpd/rde_filter.c
+++ b/bgpd/rde_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_filter.c,v 1.56 2009/06/06 01:10:29 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.62 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -40,6 +40,13 @@ rde_filter(u_int16_t ribid, struct rde_aspath **new, struct filter_head *rules,
if (new != NULL)
*new = NULL;
+ if (asp->flags & F_ATTR_PARSE_ERR)
+ /*
+ * don't try to filter bad updates just deny them
+ * so they act as implicit withdraws
+ */
+ return (ACTION_DENY);
+
TAILQ_FOREACH(f, rules, entry) {
if (dir != f->dir)
continue;
@@ -59,7 +66,7 @@ rde_filter(u_int16_t ribid, struct rde_aspath **new, struct filter_head *rules,
/* ... and use the copy from now on */
asp = *new;
}
- rde_apply_set(asp, &f->set, prefix->af,
+ rde_apply_set(asp, &f->set, prefix->aid,
from, peer);
}
if (f->action != ACTION_NONE)
@@ -73,7 +80,7 @@ rde_filter(u_int16_t ribid, struct rde_aspath **new, struct filter_head *rules,
void
rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
- sa_family_t af, struct rde_peer *from, struct rde_peer *peer)
+ u_int8_t aid, struct rde_peer *from, struct rde_peer *peer)
{
struct filter_set *set;
u_char *np;
@@ -167,7 +174,7 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
case ACTION_SET_NEXTHOP_NOMODIFY:
case ACTION_SET_NEXTHOP_SELF:
nexthop_modify(asp, &set->action.nexthop, set->type,
- af);
+ aid);
break;
case ACTION_SET_COMMUNITY:
switch (set->action.community.as) {
@@ -243,6 +250,17 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
asp->rtlabelid = set->action.id;
rtlabel_ref(asp->rtlabelid);
break;
+ case ACTION_SET_ORIGIN:
+ asp->origin = set->action.origin;
+ break;
+ case ACTION_SET_EXT_COMMUNITY:
+ community_ext_set(asp, &set->action.ext_community,
+ peer->conf.remote_as);
+ break;
+ case ACTION_DEL_EXT_COMMUNITY:
+ community_ext_delete(asp, &set->action.ext_community,
+ peer->conf.remote_as);
+ break;
}
}
}
@@ -251,11 +269,21 @@ int
rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer)
{
- int as, type;
+ u_int32_t pas;
+ int cas, type;
+
+ if (asp != NULL && f->match.as.type != AS_NONE) {
+ if (f->match.as.flags & AS_FLAG_NEIGHBORAS)
+ pas = peer->conf.remote_as;
+ else
+ pas = f->match.as.as;
+ if (aspath_match(asp->aspath, f->match.as.type, pas) == 0)
+ return (0);
+ }
- if (asp != NULL && f->match.as.type != AS_NONE)
- if (aspath_match(asp->aspath, f->match.as.type,
- f->match.as.as) == 0)
+ if (asp != NULL && f->match.aslen.type != ASLEN_NONE)
+ if (aspath_lenmatch(asp->aspath, f->match.aslen.type,
+ f->match.aslen.aslen) == 0)
return (0);
if (asp != NULL && f->match.community.as != COMMUNITY_UNSET) {
@@ -263,10 +291,10 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
case COMMUNITY_ERROR:
fatalx("rde_apply_set bad community string");
case COMMUNITY_NEIGHBOR_AS:
- as = peer->conf.remote_as;
+ cas = peer->conf.remote_as;
break;
default:
- as = f->match.community.as;
+ cas = f->match.community.as;
break;
}
@@ -281,12 +309,17 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
break;
}
- if (rde_filter_community(asp, as, type) == 0)
+ if (community_match(asp, cas, type) == 0)
return (0);
}
+ if (asp != NULL &&
+ (f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID))
+ if (community_ext_match(asp, &f->match.ext_community,
+ peer->conf.remote_as) == 0)
+ return (0);
- if (f->match.prefix.addr.af != 0) {
- if (f->match.prefix.addr.af != prefix->af)
+ if (f->match.prefix.addr.aid != 0) {
+ if (f->match.prefix.addr.aid != prefix->aid)
/* don't use IPv4 rules for IPv6 and vice versa */
return (0);
@@ -322,7 +355,7 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
} else if (f->match.prefixlen.op != OP_NONE) {
/* only prefixlen without a prefix */
- if (f->match.prefixlen.af != prefix->af)
+ if (f->match.prefixlen.aid != prefix->aid)
/* don't use IPv4 rules for IPv6 and vice versa */
return (0);
@@ -356,19 +389,6 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
}
int
-rde_filter_community(struct rde_aspath *asp, int as, int type)
-{
- struct attr *a;
-
- a = attr_optget(asp, ATTR_COMMUNITIES);
- if (a == NULL)
- /* no communities, no match */
- return (0);
-
- return (community_match(a->data, a->len, as, type));
-}
-
-int
rde_filter_equal(struct filter_head *a, struct filter_head *b,
struct rde_peer *peer, enum directions dir)
{
@@ -476,6 +496,12 @@ filterset_cmp(struct filter_set *a, struct filter_set *b)
return (a->action.community.type - b->action.community.type);
}
+ if (a->type == ACTION_SET_EXT_COMMUNITY ||
+ a->type == ACTION_DEL_EXT_COMMUNITY) { /* a->type == b->type */
+ return (memcmp(&a->action.ext_community,
+ &b->action.ext_community, sizeof(a->action.ext_community)));
+ }
+
if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) {
/*
* This is the only interesting case, all others are considered
@@ -483,13 +509,29 @@ filterset_cmp(struct filter_set *a, struct filter_set *b)
* reject it at the same time. Allow one IPv4 and one IPv6
* per filter set or only one of the other nexthop modifiers.
*/
- return (a->action.nexthop.af - b->action.nexthop.af);
+ return (a->action.nexthop.aid - b->action.nexthop.aid);
}
/* equal */
return (0);
}
+void
+filterset_move(struct filter_set_head *source, struct filter_set_head *dest)
+{
+ struct filter_set *s;
+
+ TAILQ_INIT(dest);
+
+ if (source == NULL)
+ return;
+
+ while ((s = TAILQ_FIRST(source)) != NULL) {
+ TAILQ_REMOVE(source, s, entry);
+ TAILQ_INSERT_TAIL(dest, s, entry);
+ }
+}
+
int
filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh)
{
@@ -574,6 +616,19 @@ filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh)
if (strcmp(as, bs) == 0)
continue;
break;
+ case ACTION_SET_ORIGIN:
+ if (a->type == b->type &&
+ a->action.origin == b->action.origin)
+ continue;
+ break;
+ case ACTION_SET_EXT_COMMUNITY:
+ case ACTION_DEL_EXT_COMMUNITY:
+ if (a->type == b->type && memcmp(
+ &a->action.ext_community,
+ &b->action.ext_community,
+ sizeof(a->action.ext_community)) == 0)
+ continue;
+ break;
}
/* compare failed */
return (0);
@@ -616,7 +671,14 @@ filterset_name(enum action_types type)
case ACTION_RTLABEL:
case ACTION_RTLABEL_ID:
return ("rtlabel");
+ case ACTION_SET_ORIGIN:
+ return ("origin");
+ case ACTION_SET_EXT_COMMUNITY:
+ return ("ext-community");
+ case ACTION_DEL_EXT_COMMUNITY:
+ return ("ext-community delete");
}
fatalx("filterset_name: got lost");
+ return (NULL); /* NOT REACHED */
}
diff --git a/bgpd/rde_prefix.c b/bgpd/rde_prefix.c
index 0c8e211..eb97613 100644
--- a/bgpd/rde_prefix.c
+++ b/bgpd/rde_prefix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_prefix.c,v 1.29 2009/05/30 18:27:17 claudio Exp $ */
+/* $OpenBSD: rde_prefix.c,v 1.32 2010/03/26 15:41:04 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -38,15 +38,16 @@
* pt_lookup: lookup a IP in the prefix table. Mainly for "show ip bgp".
* pt_empty: returns true if there is no bgp prefix linked to the pt_entry.
* pt_init: initialize prefix table.
- * pt_alloc?: allocate a AF specific pt_entry. Internal function.
+ * pt_alloc: allocate a AF specific pt_entry. Internal function.
* pt_free: free a pt_entry. Internal function.
*/
/* internal prototypes */
-static struct pt_entry4 *pt_alloc4(void);
-static struct pt_entry6 *pt_alloc6(void);
+static struct pt_entry *pt_alloc(struct pt_entry *);
static void pt_free(struct pt_entry *);
+size_t pt_sizes[AID_MAX] = AID_PTSIZE;
+
RB_HEAD(pt_tree, pt_entry);
RB_PROTOTYPE(pt_tree, pt_entry, pt_e, pt_prefix_cmp);
RB_GENERATE(pt_tree, pt_entry, pt_e, pt_prefix_cmp);
@@ -70,17 +71,24 @@ void
pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr)
{
bzero(addr, sizeof(struct bgpd_addr));
- switch (pte->af) {
- case AF_INET:
- addr->af = pte->af;
+ addr->aid = pte->aid;
+ switch (addr->aid) {
+ case AID_INET:
addr->v4 = ((struct pt_entry4 *)pte)->prefix4;
break;
- case AF_INET6:
- addr->af = pte->af;
+ case AID_INET6:
memcpy(&addr->v6, &((struct pt_entry6 *)pte)->prefix6,
sizeof(addr->v6));
/* XXX scope_id ??? */
break;
+ case AID_VPN_IPv4:
+ addr->vpn4.addr = ((struct pt_entry_vpn4 *)pte)->prefix4;
+ addr->vpn4.rd = ((struct pt_entry_vpn4 *)pte)->rd;
+ addr->vpn4.labellen = ((struct pt_entry_vpn4 *)pte)->labellen;
+ memcpy(addr->vpn4.labelstack,
+ ((struct pt_entry_vpn4 *)pte)->labelstack,
+ addr->vpn4.labellen);
+ break;
default:
fatalx("pt_getaddr: unknown af");
}
@@ -89,33 +97,49 @@ pt_getaddr(struct pt_entry *pte, struct bgpd_addr *addr)
struct pt_entry *
pt_fill(struct bgpd_addr *prefix, int prefixlen)
{
- static struct pt_entry4 pte4;
- static struct pt_entry6 pte6;
- in_addr_t addr_hbo;
+ static struct pt_entry4 pte4;
+ static struct pt_entry6 pte6;
+ static struct pt_entry_vpn4 pte_vpn4;
+ in_addr_t addr_hbo;
- switch (prefix->af) {
- case AF_INET:
+ switch (prefix->aid) {
+ case AID_INET:
bzero(&pte4, sizeof(pte4));
+ pte4.aid = prefix->aid;
if (prefixlen > 32)
- fatalx("pt_get: bad IPv4 prefixlen");
- pte4.af = AF_INET;
+ fatalx("pt_fill: bad IPv4 prefixlen");
addr_hbo = ntohl(prefix->v4.s_addr);
pte4.prefix4.s_addr = htonl(addr_hbo &
prefixlen2mask(prefixlen));
pte4.prefixlen = prefixlen;
return ((struct pt_entry *)&pte4);
- case AF_INET6:
+ case AID_INET6:
bzero(&pte6, sizeof(pte6));
+ pte6.aid = prefix->aid;
if (prefixlen > 128)
fatalx("pt_get: bad IPv6 prefixlen");
- pte6.af = AF_INET6;
pte6.prefixlen = prefixlen;
inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen);
return ((struct pt_entry *)&pte6);
+ case AID_VPN_IPv4:
+ bzero(&pte_vpn4, sizeof(pte_vpn4));
+ pte_vpn4.aid = prefix->aid;
+ if (prefixlen > 32)
+ fatalx("pt_fill: bad IPv4 prefixlen");
+ addr_hbo = ntohl(prefix->vpn4.addr.s_addr);
+ pte_vpn4.prefix4.s_addr = htonl(addr_hbo &
+ prefixlen2mask(prefixlen));
+ pte_vpn4.prefixlen = prefixlen;
+ pte_vpn4.rd = prefix->vpn4.rd;
+ pte_vpn4.labellen = prefix->vpn4.labellen;
+ memcpy(pte_vpn4.labelstack, prefix->vpn4.labelstack,
+ prefix->vpn4.labellen);
+ return ((struct pt_entry *)&pte_vpn4);
default:
- log_warnx("pt_get: unknown af");
- return (NULL);
+ fatalx("pt_fill: unknown af");
}
+ /* NOT REACHED */
+ return (NULL);
}
struct pt_entry *
@@ -131,39 +155,12 @@ struct pt_entry *
pt_add(struct bgpd_addr *prefix, int prefixlen)
{
struct pt_entry *p = NULL;
- struct pt_entry4 *p4;
- struct pt_entry6 *p6;
- in_addr_t addr_hbo;
- switch (prefix->af) {
- case AF_INET:
- p4 = pt_alloc4();
- if (prefixlen > 32)
- fatalx("pt_add: bad IPv4 prefixlen");
- p4->af = AF_INET;
- p4->prefixlen = prefixlen;
- addr_hbo = ntohl(prefix->v4.s_addr);
- p4->prefix4.s_addr = htonl(addr_hbo &
- prefixlen2mask(prefixlen));
- p = (struct pt_entry *)p4;
- break;
- case AF_INET6:
- p6 = pt_alloc6();
- if (prefixlen > 128)
- fatalx("pt_add: bad IPv6 prefixlen");
- p6->af = AF_INET6;
- p6->prefixlen = prefixlen;
- inet6applymask(&p6->prefix6, &prefix->v6, prefixlen);
- p = (struct pt_entry *)p6;
- break;
- default:
- fatalx("pt_add: unknown af");
- }
+ p = pt_fill(prefix, prefixlen);
+ p = pt_alloc(p);
- if (RB_INSERT(pt_tree, &pttable, p) != NULL) {
- log_warnx("pt_add: insert failed");
- return (NULL);
- }
+ if (RB_INSERT(pt_tree, &pttable, p) != NULL)
+ fatalx("pt_add: insert failed");
return (p);
}
@@ -183,13 +180,14 @@ struct pt_entry *
pt_lookup(struct bgpd_addr *addr)
{
struct pt_entry *p;
- int i;
+ int i = 0;
- switch (addr->af) {
- case AF_INET:
+ switch (addr->aid) {
+ case AID_INET:
+ case AID_VPN_IPv4:
i = 32;
break;
- case AF_INET6:
+ case AID_INET6:
i = 128;
break;
default:
@@ -206,17 +204,18 @@ pt_lookup(struct bgpd_addr *addr)
int
pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b)
{
- const struct pt_entry4 *a4, *b4;
- const struct pt_entry6 *a6, *b6;
- int i;
+ const struct pt_entry4 *a4, *b4;
+ const struct pt_entry6 *a6, *b6;
+ const struct pt_entry_vpn4 *va4, *vb4;
+ int i;
- if (a->af > b->af)
+ if (a->aid > b->aid)
return (1);
- if (a->af < b->af)
+ if (a->aid < b->aid)
return (-1);
- switch (a->af) {
- case AF_INET:
+ switch (a->aid) {
+ case AID_INET:
a4 = (const struct pt_entry4 *)a;
b4 = (const struct pt_entry4 *)b;
if (ntohl(a4->prefix4.s_addr) > ntohl(b4->prefix4.s_addr))
@@ -228,7 +227,7 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b)
if (a4->prefixlen < b4->prefixlen)
return (-1);
return (0);
- case AF_INET6:
+ case AID_INET6:
a6 = (const struct pt_entry6 *)a;
b6 = (const struct pt_entry6 *)b;
@@ -242,49 +241,49 @@ pt_prefix_cmp(const struct pt_entry *a, const struct pt_entry *b)
if (a6->prefixlen > b6->prefixlen)
return (1);
return (0);
+ case AID_VPN_IPv4:
+ va4 = (const struct pt_entry_vpn4 *)a;
+ vb4 = (const struct pt_entry_vpn4 *)b;
+ if (ntohl(va4->prefix4.s_addr) > ntohl(vb4->prefix4.s_addr))
+ return (1);
+ if (ntohl(va4->prefix4.s_addr) < ntohl(vb4->prefix4.s_addr))
+ return (-1);
+ if (va4->prefixlen > vb4->prefixlen)
+ return (1);
+ if (va4->prefixlen < vb4->prefixlen)
+ return (-1);
+ if (betoh64(va4->rd) > betoh64(vb4->rd))
+ return (1);
+ if (betoh64(va4->rd) < betoh64(vb4->rd))
+ return (-1);
+ return (0);
default:
fatalx("pt_prefix_cmp: unknown af");
}
return (-1);
}
-/* returns a zeroed pt_entry function may not return on fail */
-static struct pt_entry4 *
-pt_alloc4(void)
+/*
+ * Returns a pt_entry cloned from the one passed in.
+ * Function may not return on failure.
+ */
+static struct pt_entry *
+pt_alloc(struct pt_entry *op)
{
- struct pt_entry4 *p;
+ struct pt_entry *p;
- p = calloc(1, sizeof(*p));
+ p = malloc(pt_sizes[op->aid]);
if (p == NULL)
fatal("pt_alloc");
- rdemem.pt4_cnt++;
- return (p);
-}
+ rdemem.pt_cnt[op->aid]++;
+ memcpy(p, op, pt_sizes[op->aid]);
-static struct pt_entry6 *
-pt_alloc6(void)
-{
- struct pt_entry6 *p;
-
- p = calloc(1, sizeof(*p));
- if (p == NULL)
- fatal("pt_alloc");
- rdemem.pt6_cnt++;
return (p);
}
static void
pt_free(struct pt_entry *pte)
{
- switch (pte->af) {
- case AF_INET:
- rdemem.pt4_cnt--;
- break;
- case AF_INET6:
- rdemem.pt6_cnt--;
- break;
- default:
- break;
- }
+ rdemem.pt_cnt[pte->aid]--;
free(pte);
}
diff --git a/bgpd/rde_rib.c b/bgpd/rde_rib.c
index 78dc203..afc01c9 100644
--- a/bgpd/rde_rib.c
+++ b/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.116 2009/06/29 14:13:48 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.125 2010/04/07 09:44:11 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -18,7 +18,11 @@
#include <sys/types.h>
#include <sys/queue.h>
+#if defined(__FreeBSD__) /* sys/hash.h */
+#include "hash.h"
+#else
#include <sys/hash.h>
+#endif /* defined(__FreeBSD__) */
#include <stdlib.h>
#include <string.h>
@@ -50,16 +54,15 @@ RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare);
/* RIB specific functions */
u_int16_t
-rib_new(int id, char *name, u_int16_t flags)
+rib_new(char *name, u_int rtableid, u_int16_t flags)
{
struct rib *xribs;
size_t newsize;
+ u_int16_t id;
- if (id < 0) {
- for (id = 0; id < rib_size; id++) {
- if (*ribs[id].name == '\0')
- break;
- }
+ for (id = 0; id < rib_size; id++) {
+ if (*ribs[id].name == '\0')
+ break;
}
if (id == RIB_FAILED)
@@ -78,9 +81,10 @@ rib_new(int id, char *name, u_int16_t flags)
bzero(&ribs[id], sizeof(struct rib));
strlcpy(ribs[id].name, name, sizeof(ribs[id].name));
RB_INIT(&ribs[id].rib);
- ribs[id].state = RIB_ACTIVE;
+ ribs[id].state = RECONF_REINIT;
ribs[id].id = id;
ribs[id].flags = flags;
+ ribs[id].rtableid = rtableid;
return (id);
}
@@ -173,15 +177,16 @@ rib_lookup(struct rib *rib, struct bgpd_addr *addr)
struct rib_entry *re;
int i;
- switch (addr->af) {
- case AF_INET:
+ switch (addr->aid) {
+ case AID_INET:
+ case AID_VPN_IPv4:
for (i = 32; i >= 0; i--) {
re = rib_get(rib, addr, i);
if (re != NULL)
return (re);
}
break;
- case AF_INET6:
+ case AID_INET6:
for (i = 128; i >= 0; i--) {
re = rib_get(rib, addr, i);
if (re != NULL)
@@ -215,6 +220,7 @@ rib_add(struct rib *rib, struct bgpd_addr *prefix, int prefixlen)
if (RB_INSERT(rib_tree, &rib->rib, re) != NULL) {
log_warnx("rib_add: insert failed");
+ free(re);
return (NULL);
}
@@ -254,7 +260,7 @@ rib_empty(struct rib_entry *re)
void
rib_dump(struct rib *rib, void (*upcall)(struct rib_entry *, void *),
- void *arg, sa_family_t af)
+ void *arg, u_int8_t aid)
{
struct rib_context *ctx;
@@ -263,7 +269,7 @@ rib_dump(struct rib *rib, void (*upcall)(struct rib_entry *, void *),
ctx->ctx_rib = rib;
ctx->ctx_upcall = upcall;
ctx->ctx_arg = arg;
- ctx->ctx_af = af;
+ ctx->ctx_aid = aid;
rib_dump_r(ctx);
}
@@ -280,7 +286,8 @@ rib_dump_r(struct rib_context *ctx)
re = rib_restart(ctx);
for (i = 0; re != NULL; re = RB_NEXT(rib_tree, unused, re)) {
- if (ctx->ctx_af != AF_UNSPEC && ctx->ctx_af != re->prefix->af)
+ if (ctx->ctx_aid != AID_UNSPEC &&
+ ctx->ctx_aid != re->prefix->aid)
continue;
if (ctx->ctx_count && i++ >= ctx->ctx_count &&
(re->flags & F_RIB_ENTRYLOCK) == 0) {
@@ -308,7 +315,7 @@ rib_restart(struct rib_context *ctx)
re->flags &= ~F_RIB_ENTRYLOCK;
/* find first non empty element */
- while (rib_empty(re))
+ while (re && rib_empty(re))
re = RB_NEXT(rib_tree, unused, re);
/* free the previously locked rib element if empty */
@@ -632,11 +639,11 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
int i;
u_int8_t m;
- if (a->af != b->af)
- return (a->af - b->af);
+ if (a->aid != b->aid)
+ return (a->aid - b->aid);
- switch (a->af) {
- case AF_INET:
+ switch (a->aid) {
+ case AID_INET:
if (prefixlen > 32)
fatalx("prefix_cmp: bad IPv4 prefixlen");
mask = htonl(prefixlen2mask(prefixlen));
@@ -645,7 +652,7 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
if (aa != ba)
return (aa - ba);
return (0);
- case AF_INET6:
+ case AID_INET6:
if (prefixlen > 128)
fatalx("prefix_cmp: bad IPv6 prefixlen");
for (i = 0; i < prefixlen / 8; i++)
@@ -660,6 +667,24 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
(b->v6.s6_addr[prefixlen / 8] & m));
}
return (0);
+ case AID_VPN_IPv4:
+ if (prefixlen > 32)
+ fatalx("prefix_cmp: bad IPv4 VPN prefixlen");
+ if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd))
+ return (1);
+ if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd))
+ return (-1);
+ mask = htonl(prefixlen2mask(prefixlen));
+ aa = ntohl(a->vpn4.addr.s_addr & mask);
+ ba = ntohl(b->vpn4.addr.s_addr & mask);
+ if (aa != ba)
+ return (aa - ba);
+ if (a->vpn4.labellen > b->vpn4.labellen)
+ return (1);
+ if (a->vpn4.labellen < b->vpn4.labellen)
+ return (-1);
+ return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack,
+ a->vpn4.labellen));
default:
fatalx("prefix_cmp: unknown af");
}
@@ -806,16 +831,33 @@ prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen)
{
int totlen;
- if (prefix->af != AF_INET && prefix->af != AF_INET6)
- return (-1);
-
- totlen = PREFIX_SIZE(plen);
+ switch (prefix->aid) {
+ case AID_INET:
+ case AID_INET6:
+ totlen = PREFIX_SIZE(plen);
- if (totlen > len)
+ if (totlen > len)
+ return (-1);
+ *buf++ = plen;
+ memcpy(buf, &prefix->ba, totlen - 1);
+ return (totlen);
+ case AID_VPN_IPv4:
+ totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd) +
+ prefix->vpn4.labellen;
+ plen += (sizeof(prefix->vpn4.rd) + prefix->vpn4.labellen) * 8;
+
+ if (totlen > len)
+ return (-1);
+ *buf++ = plen;
+ memcpy(buf, &prefix->vpn4.labelstack, prefix->vpn4.labellen);
+ buf += prefix->vpn4.labellen;
+ memcpy(buf, &prefix->vpn4.rd, sizeof(prefix->vpn4.rd));
+ buf += sizeof(prefix->vpn4.rd);
+ memcpy(buf, &prefix->vpn4.addr, PREFIX_SIZE(plen) - 1);
+ return (totlen);
+ default:
return (-1);
- *buf++ = plen;
- memcpy(buf, &prefix->ba, totlen - 1);
- return (totlen);
+ }
}
/*
@@ -861,7 +903,7 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state,
*/
if ((p->rib->flags & F_RIB_NOFIB) == 0 &&
p == p->rib->active)
- rde_send_kroute(p, NULL);
+ rde_send_kroute(p, NULL, p->rib->ribid);
continue;
}
@@ -885,16 +927,12 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state,
void
prefix_destroy(struct prefix *p)
{
- struct rib_entry *re;
struct rde_aspath *asp;
- re = p->rib;
asp = p->aspath;
prefix_unlink(p);
prefix_free(p);
- if (rib_empty(re))
- rib_remove(re);
if (path_empty(asp))
path_destroy(asp);
}
@@ -907,7 +945,6 @@ prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags)
{
struct rde_aspath *asp, *xasp;
struct prefix *p, *xp;
- struct pt_entry *pte;
for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = xasp) {
xasp = LIST_NEXT(asp, peer_l);
@@ -916,12 +953,8 @@ prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags)
for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = xp) {
xp = LIST_NEXT(p, path_l);
if (reloadtime > p->lastchange) {
- pte = p->prefix;
prefix_unlink(p);
prefix_free(p);
-
- if (pt_empty(pte))
- pt_remove(pte);
}
}
if (path_empty(asp))
@@ -954,11 +987,11 @@ prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp)
static void
prefix_unlink(struct prefix *pref)
{
- if (pref->rib) {
- /* make route decision */
- LIST_REMOVE(pref, rib_l);
- prefix_evaluate(NULL, pref->rib);
- }
+ struct rib_entry *re = pref->rib;
+
+ /* make route decision */
+ LIST_REMOVE(pref, rib_l);
+ prefix_evaluate(NULL, re);
LIST_REMOVE(pref, path_l);
PREFIX_COUNT(pref->aspath, -1);
@@ -966,6 +999,8 @@ prefix_unlink(struct prefix *pref)
pt_unref(pref->prefix);
if (pt_empty(pref->prefix))
pt_remove(pref->prefix);
+ if (rib_empty(re))
+ rib_remove(re);
/* destroy all references to other objects */
pref->aspath = NULL;
@@ -973,8 +1008,8 @@ prefix_unlink(struct prefix *pref)
pref->rib = NULL;
/*
- * It's the caller's duty to remove empty aspath respectively pt_entry
- * structures. Also freeing the unlinked prefix is the caller's duty.
+ * It's the caller's duty to remove empty aspath structures.
+ * Also freeing the unlinked prefix is the caller's duty.
*/
}
@@ -1070,10 +1105,6 @@ nexthop_update(struct kroute_nexthop *msg)
return;
}
- if (nexthop_delete(nh))
- /* nexthop no longer used */
- return;
-
oldstate = nh->state;
if (msg->valid)
nh->state = NEXTHOP_REACH;
@@ -1088,21 +1119,13 @@ nexthop_update(struct kroute_nexthop *msg)
memcpy(&nh->true_nexthop, &msg->gateway,
sizeof(nh->true_nexthop));
- switch (msg->nexthop.af) {
- case AF_INET:
- nh->nexthop_netlen = msg->kr.kr4.prefixlen;
- nh->nexthop_net.af = AF_INET;
- nh->nexthop_net.v4.s_addr = msg->kr.kr4.prefix.s_addr;
- break;
- case AF_INET6:
- nh->nexthop_netlen = msg->kr.kr6.prefixlen;
- nh->nexthop_net.af = AF_INET6;
- memcpy(&nh->nexthop_net.v6, &msg->kr.kr6.prefix,
- sizeof(struct in6_addr));
- break;
- default:
- fatalx("nexthop_update: unknown af");
- }
+ memcpy(&nh->nexthop_net, &msg->net,
+ sizeof(nh->nexthop_net));
+ nh->nexthop_netlen = msg->netlen;
+
+ if (nexthop_delete(nh))
+ /* nexthop no longer used */
+ return;
if (rde_noevaluate())
/*
@@ -1118,7 +1141,7 @@ nexthop_update(struct kroute_nexthop *msg)
void
nexthop_modify(struct rde_aspath *asp, struct bgpd_addr *nexthop,
- enum action_types type, sa_family_t af)
+ enum action_types type, u_int8_t aid)
{
struct nexthop *nh;
@@ -1138,7 +1161,7 @@ nexthop_modify(struct rde_aspath *asp, struct bgpd_addr *nexthop,
asp->flags |= F_NEXTHOP_SELF;
return;
}
- if (af != nexthop->af)
+ if (aid != nexthop->aid)
return;
nh = nexthop_get(nexthop);
@@ -1233,17 +1256,17 @@ nexthop_compare(struct nexthop *na, struct nexthop *nb)
a = &na->exit_nexthop;
b = &nb->exit_nexthop;
- if (a->af != b->af)
- return (a->af - b->af);
+ if (a->aid != b->aid)
+ return (a->aid - b->aid);
- switch (a->af) {
- case AF_INET:
+ switch (a->aid) {
+ case AID_INET:
if (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr))
return (1);
if (ntohl(a->v4.s_addr) < ntohl(b->v4.s_addr))
return (-1);
return (0);
- case AF_INET6:
+ case AID_INET6:
return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
default:
fatalx("nexthop_cmp: unknown af");
@@ -1269,14 +1292,14 @@ nexthop_hash(struct bgpd_addr *nexthop)
{
u_int32_t h = 0;
- switch (nexthop->af) {
- case AF_INET:
+ switch (nexthop->aid) {
+ case AID_INET:
h = (AF_INET ^ ntohl(nexthop->v4.s_addr) ^
ntohl(nexthop->v4.s_addr) >> 13) &
nexthoptable.nexthop_hashmask;
break;
- case AF_INET6:
- h = hash32_buf(nexthop->v6.s6_addr, sizeof(struct in6_addr),
+ case AID_INET6:
+ h = hash32_buf(&nexthop->v6, sizeof(struct in6_addr),
HASHINIT) & nexthoptable.nexthop_hashmask;
break;
default:
diff --git a/bgpd/rde_update.c b/bgpd/rde_update.c
index 209664f..f50223b 100644
--- a/bgpd/rde_update.c
+++ b/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.68 2009/06/06 01:10:29 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.77 2010/01/13 06:02:37 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -17,19 +17,27 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
+#if defined(__FreeBSD__) /* sys/hash.h */
+#include "hash.h"
+#else
#include <sys/hash.h>
+#endif /* defined(__FreeBSD__) */
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#if defined(__FreeBSD__) /* limits.h */
+#include <limits.h>
+#endif /* defined(__FreeBSD__) */
#include "bgpd.h"
#include "rde.h"
in_addr_t up_get_nexthop(struct rde_peer *, struct rde_aspath *);
int up_generate_mp_reach(struct rde_peer *, struct update_attr *,
- struct rde_aspath *, sa_family_t);
+ struct rde_aspath *, u_int8_t);
int up_generate_attr(struct rde_peer *, struct update_attr *,
- struct rde_aspath *, sa_family_t);
+ struct rde_aspath *, u_int8_t);
/* update stuff. */
struct update_prefix {
@@ -65,10 +73,12 @@ RB_GENERATE(uptree_attr, update_attr, entry, up_attr_cmp)
void
up_init(struct rde_peer *peer)
{
- TAILQ_INIT(&peer->updates);
- TAILQ_INIT(&peer->withdraws);
- TAILQ_INIT(&peer->updates6);
- TAILQ_INIT(&peer->withdraws6);
+ u_int8_t i;
+
+ for (i = 0; i < AID_MAX; i++) {
+ TAILQ_INIT(&peer->updates[i]);
+ TAILQ_INIT(&peer->withdraws[i]);
+ }
RB_INIT(&peer->up_prefix);
RB_INIT(&peer->up_attrs);
peer->up_pcnt = 0;
@@ -103,8 +113,10 @@ up_clear(struct uplist_attr *updates, struct uplist_prefix *withdraws)
void
up_down(struct rde_peer *peer)
{
- up_clear(&peer->updates, &peer->withdraws);
- up_clear(&peer->updates6, &peer->withdraws6);
+ u_int8_t i;
+
+ for (i = 0; i < AID_MAX; i++)
+ up_clear(&peer->updates[i], &peer->withdraws[i]);
RB_INIT(&peer->up_prefix);
RB_INIT(&peer->up_attrs);
@@ -120,19 +132,19 @@ up_prefix_cmp(struct update_prefix *a, struct update_prefix *b)
{
int i;
- if (a->prefix.af < b->prefix.af)
+ if (a->prefix.aid < b->prefix.aid)
return (-1);
- if (a->prefix.af > b->prefix.af)
+ if (a->prefix.aid > b->prefix.aid)
return (1);
- switch (a->prefix.af) {
- case AF_INET:
+ switch (a->prefix.aid) {
+ case AID_INET:
if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr))
return (-1);
if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr))
return (1);
break;
- case AF_INET6:
+ case AID_INET6:
i = memcmp(&a->prefix.v6, &b->prefix.v6,
sizeof(struct in6_addr));
if (i > 0)
@@ -140,6 +152,25 @@ up_prefix_cmp(struct update_prefix *a, struct update_prefix *b)
if (i < 0)
return (-1);
break;
+ case AID_VPN_IPv4:
+ if (betoh64(a->prefix.vpn4.rd) < betoh64(b->prefix.vpn4.rd))
+ return (-1);
+ if (betoh64(a->prefix.vpn4.rd) > betoh64(b->prefix.vpn4.rd))
+ return (1);
+ if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr))
+ return (-1);
+ if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr))
+ return (1);
+ if (a->prefixlen < b->prefixlen)
+ return (-1);
+ if (a->prefixlen > b->prefixlen)
+ return (1);
+ if (a->prefix.vpn4.labellen < b->prefix.vpn4.labellen)
+ return (-1);
+ if (a->prefix.vpn4.labellen > b->prefix.vpn4.labellen)
+ return (1);
+ return (memcmp(a->prefix.vpn4.labelstack,
+ b->prefix.vpn4.labelstack, a->prefix.vpn4.labellen));
default:
fatalx("pt_prefix_cmp: unknown af");
}
@@ -174,18 +205,8 @@ up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
struct uplist_attr *upl = NULL;
struct uplist_prefix *wdl = NULL;
- switch (p->prefix.af) {
- case AF_INET:
- upl = &peer->updates;
- wdl = &peer->withdraws;
- break;
- case AF_INET6:
- upl = &peer->updates6;
- wdl = &peer->withdraws6;
- break;
- default:
- fatalx("up_add: unknown AF");
- }
+ upl = &peer->updates[p->prefix.aid];
+ wdl = &peer->withdraws[p->prefix.aid];
/* 1. search for attr */
if (a != NULL && (na = RB_FIND(uptree_attr, &peer->up_attrs, a)) ==
@@ -270,21 +291,14 @@ up_test_update(struct rde_peer *peer, struct prefix *p)
/* Do not send routes back to sender */
return (0);
+ if (p->aspath->flags & F_ATTR_PARSE_ERR)
+ fatalx("try to send out a botched path");
if (p->aspath->flags & F_ATTR_LOOP)
fatalx("try to send out a looped path");
pt_getaddr(p->prefix, &addr);
- switch (addr.af) {
- case AF_INET:
- if (peer->capa_announced.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE)
- return (-1);
- break;
- case AF_INET6:
- if (peer->capa_announced.mp_v6 == SAFI_NONE)
- return (-1);
- break;
- }
+ if (peer->capa.mp[addr.aid] == 0)
+ return (-1);
if (p->aspath->peer->conf.ebgp == 0 && peer->conf.ebgp == 0) {
/*
@@ -325,13 +339,13 @@ up_test_update(struct rde_peer *peer, struct prefix *p)
}
/* well known communities */
- if (rde_filter_community(p->aspath,
+ if (community_match(p->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE))
return (0);
- if (peer->conf.ebgp && rde_filter_community(p->aspath,
+ if (peer->conf.ebgp && community_match(p->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT))
return (0);
- if (peer->conf.ebgp && rde_filter_community(p->aspath,
+ if (peer->conf.ebgp && community_match(p->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED))
return (0);
@@ -362,7 +376,7 @@ up_generate(struct rde_peer *peer, struct rde_aspath *asp,
if (ua == NULL)
fatal("up_generate");
- if (up_generate_attr(peer, ua, asp, addr->af) == -1) {
+ if (up_generate_attr(peer, ua, asp, addr->aid) == -1) {
log_warnx("generation of bgp path attributes failed");
free(ua);
return (-1);
@@ -444,18 +458,12 @@ up_generate_updates(struct filter_head *rules, struct rde_peer *peer,
/* send a default route to the specified peer */
void
up_generate_default(struct filter_head *rules, struct rde_peer *peer,
- sa_family_t af)
+ u_int8_t aid)
{
struct rde_aspath *asp, *fasp;
struct bgpd_addr addr;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE &&
- af == AF_INET)
- return;
-
- if (peer->capa_received.mp_v6 == SAFI_NONE &&
- af == AF_INET6)
+ if (peer->capa.mp[aid] == 0)
return;
asp = path_get();
@@ -471,7 +479,7 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
/* filter as usual */
bzero(&addr, sizeof(addr));
- addr.af = af;
+ addr.aid = aid;
if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL,
DIR_OUT) == ACTION_DENY) {
@@ -491,6 +499,43 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
path_put(asp);
}
+/* generate a EoR marker in the update list. This is a horrible hack. */
+int
+up_generate_marker(struct rde_peer *peer, u_int8_t aid)
+{
+ struct update_attr *ua;
+ struct update_attr *na = NULL;
+ struct uplist_attr *upl = NULL;
+
+ ua = calloc(1, sizeof(struct update_attr));
+ if (ua == NULL)
+ fatal("up_generate_marker");
+
+ upl = &peer->updates[aid];
+
+ /* 1. search for attr */
+ if ((na = RB_FIND(uptree_attr, &peer->up_attrs, ua)) == NULL) {
+ /* 1.1 if not found -> add */
+ TAILQ_INIT(&ua->prefix_h);
+ if (RB_INSERT(uptree_attr, &peer->up_attrs, ua) != NULL) {
+ log_warnx("uptree_attr insert failed");
+ /* cleanup */
+ free(ua);
+ return (-1);
+ }
+ TAILQ_INSERT_TAIL(upl, ua, attr_l);
+ peer->up_acnt++;
+ } else {
+ /* 1.2 if found -> use that, free ua */
+ free(ua);
+ ua = na;
+ /* move to end of update queue */
+ TAILQ_REMOVE(upl, ua, attr_l);
+ TAILQ_INSERT_TAIL(upl, ua, attr_l);
+ }
+ return (0);
+}
+
u_char up_attr_buf[4096];
/* only for IPv4 */
@@ -551,28 +596,41 @@ up_get_nexthop(struct rde_peer *peer, struct rde_aspath *a)
int
up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
- struct rde_aspath *a, sa_family_t af)
+ struct rde_aspath *a, u_int8_t aid)
{
u_int16_t tmp;
- switch (af) {
- case AF_INET6:
+ switch (aid) {
+ case AID_INET6:
upa->mpattr_len = 21; /* AFI + SAFI + NH LEN + NH + Reserved */
upa->mpattr = malloc(upa->mpattr_len);
if (upa->mpattr == NULL)
fatal("up_generate_mp_reach");
- tmp = htons(AFI_IPv6);
+ if (aid2afi(aid, &tmp, &upa->mpattr[2]))
+ fatalx("up_generate_mp_reachi: bad AID");
+ tmp = htons(tmp);
memcpy(upa->mpattr, &tmp, sizeof(tmp));
- upa->mpattr[2] = SAFI_UNICAST;
upa->mpattr[3] = sizeof(struct in6_addr);
upa->mpattr[20] = 0; /* Reserved must be 0 */
/* nexthop dance see also up_get_nexthop() */
- if (peer->conf.ebgp == 0) {
+ if (a->flags & F_NEXTHOP_NOMODIFY) {
+ /* no modify flag set */
+ if (a->nexthop == NULL)
+ memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
+ sizeof(struct in6_addr));
+ else
+ memcpy(&upa->mpattr[4],
+ &a->nexthop->exit_nexthop.v6,
+ sizeof(struct in6_addr));
+ } else if (a->flags & F_NEXTHOP_SELF)
+ memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
+ sizeof(struct in6_addr));
+ else if (!peer->conf.ebgp) {
/* ibgp */
if (a->nexthop == NULL ||
- (a->nexthop->exit_nexthop.af == AF_INET6 &&
- memcmp(&a->nexthop->exit_nexthop.v6,
+ (a->nexthop->exit_nexthop.aid == AID_INET6 &&
+ !memcmp(&a->nexthop->exit_nexthop.v6,
&peer->remote_addr.v6, sizeof(struct in6_addr))))
memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
sizeof(struct in6_addr));
@@ -603,6 +661,68 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6,
sizeof(struct in6_addr));
return (0);
+ case AID_VPN_IPv4:
+ upa->mpattr_len = 17; /* AFI + SAFI + NH LEN + NH + Reserved */
+ upa->mpattr = calloc(upa->mpattr_len, 1);
+ if (upa->mpattr == NULL)
+ fatal("up_generate_mp_reach");
+ if (aid2afi(aid, &tmp, &upa->mpattr[2]))
+ fatalx("up_generate_mp_reachi: bad AID");
+ tmp = htons(tmp);
+ memcpy(upa->mpattr, &tmp, sizeof(tmp));
+ upa->mpattr[3] = sizeof(u_int64_t) + sizeof(struct in_addr);
+
+ /* nexthop dance see also up_get_nexthop() */
+ if (a->flags & F_NEXTHOP_NOMODIFY) {
+ /* no modify flag set */
+ if (a->nexthop == NULL)
+ memcpy(&upa->mpattr[12],
+ &peer->local_v4_addr.v4,
+ sizeof(struct in_addr));
+ else
+ /* nexthops are stored as IPv4 addrs */
+ memcpy(&upa->mpattr[12],
+ &a->nexthop->exit_nexthop.v4,
+ sizeof(struct in_addr));
+ } else if (a->flags & F_NEXTHOP_SELF)
+ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
+ sizeof(struct in_addr));
+ else if (!peer->conf.ebgp) {
+ /* ibgp */
+ if (a->nexthop == NULL ||
+ (a->nexthop->exit_nexthop.aid == AID_INET &&
+ !memcmp(&a->nexthop->exit_nexthop.v4,
+ &peer->remote_addr.v4, sizeof(struct in_addr))))
+ memcpy(&upa->mpattr[12],
+ &peer->local_v4_addr.v4,
+ sizeof(struct in_addr));
+ else
+ memcpy(&upa->mpattr[12],
+ &a->nexthop->exit_nexthop.v4,
+ sizeof(struct in_addr));
+ } else if (peer->conf.distance == 1) {
+ /* ebgp directly connected */
+ if (a->nexthop != NULL &&
+ a->nexthop->flags & NEXTHOP_CONNECTED)
+ if (prefix_compare(&peer->remote_addr,
+ &a->nexthop->nexthop_net,
+ a->nexthop->nexthop_netlen) == 0) {
+ /*
+ * nexthop and peer are in the same
+ * subnet
+ */
+ memcpy(&upa->mpattr[12],
+ &a->nexthop->exit_nexthop.v4,
+ sizeof(struct in_addr));
+ return (0);
+ }
+ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
+ sizeof(struct in_addr));
+ } else
+ /* ebgp multihop */
+ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4,
+ sizeof(struct in_addr));
+ return (0);
default:
break;
}
@@ -611,7 +731,7 @@ up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa,
int
up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
- struct rde_aspath *a, sa_family_t af)
+ struct rde_aspath *a, u_int8_t aid)
{
struct attr *oa, *newaggr = NULL;
u_char *pdata;
@@ -643,8 +763,8 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
wlen += r; len -= r;
free(pdata);
- switch (af) {
- case AF_INET:
+ switch (aid) {
+ case AID_INET:
nexthop = up_get_nexthop(peer, a);
if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,
ATTR_NEXTHOP, &nexthop, 4)) == -1)
@@ -659,9 +779,11 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
/*
* The old MED from other peers MUST not be announced to others
* unless the MED is originating from us or the peer is an IBGP one.
+ * Only exception are routers with "transparent-as yes" set.
*/
if (a->flags & F_ATTR_MED && (peer->conf.ebgp == 0 ||
- a->flags & F_ATTR_MED_ANNOUNCE)) {
+ a->flags & F_ATTR_MED_ANNOUNCE ||
+ peer->conf.flags & PEERFLAG_TRANS_AS)) {
tmp32 = htonl(a->med);
if ((r = attr_write(up_attr_buf + wlen, len, ATTR_OPTIONAL,
ATTR_MED, &tmp32, 4)) == -1)
@@ -791,7 +913,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
/* write mp attribute to different buffer */
if (ismp)
- if (up_generate_mp_reach(peer, upa, a, AF_INET6) == -1)
+ if (up_generate_mp_reach(peer, upa, a, aid) == -1)
return (-1);
/* the bgp path attributes are now stored in the global buf */
@@ -810,6 +932,7 @@ up_dump_prefix(u_char *buf, int len, struct uplist_prefix *prefix_head,
{
struct update_prefix *upp;
int r, wpos = 0;
+ u_int8_t i;
while ((upp = TAILQ_FIRST(prefix_head)) != NULL) {
if ((r = prefix_write(buf + wpos, len - wpos,
@@ -820,13 +943,14 @@ up_dump_prefix(u_char *buf, int len, struct uplist_prefix *prefix_head,
log_warnx("dequeuing update failed.");
TAILQ_REMOVE(upp->prefix_h, upp, prefix_l);
peer->up_pcnt--;
- if (upp->prefix_h == &peer->withdraws ||
- upp->prefix_h == &peer->withdraws6) {
- peer->up_wcnt--;
- peer->prefix_sent_withdraw++;
- } else {
- peer->up_nlricnt--;
- peer->prefix_sent_update++;
+ for (i = 0; i < AID_MAX; i++) {
+ if (upp->prefix_h == &peer->withdraws[i]) {
+ peer->up_wcnt--;
+ peer->prefix_sent_withdraw++;
+ } else {
+ peer->up_nlricnt--;
+ peer->prefix_sent_update++;
+ }
}
free(upp);
}
@@ -844,16 +968,21 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
* It is possible that a queued path attribute has no nlri prefix.
* Ignore and remove those path attributes.
*/
- while ((upa = TAILQ_FIRST(&peer->updates)) != NULL)
+ while ((upa = TAILQ_FIRST(&peer->updates[AID_INET])) != NULL)
if (TAILQ_EMPTY(&upa->prefix_h)) {
+ attr_len = upa->attr_len;
if (RB_REMOVE(uptree_attr, &peer->up_attrs,
upa) == NULL)
log_warnx("dequeuing update failed.");
- TAILQ_REMOVE(&peer->updates, upa, attr_l);
+ TAILQ_REMOVE(&peer->updates[AID_INET], upa, attr_l);
free(upa->attr);
free(upa->mpattr);
free(upa);
peer->up_acnt--;
+ /* XXX horrible hack,
+ * if attr_len is 0, it is a EoR marker */
+ if (attr_len == 0)
+ return (-1);
} else
break;
@@ -884,7 +1013,7 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
if (TAILQ_EMPTY(&upa->prefix_h)) {
if (RB_REMOVE(uptree_attr, &peer->up_attrs, upa) == NULL)
log_warnx("dequeuing update failed.");
- TAILQ_REMOVE(&peer->updates, upa, attr_l);
+ TAILQ_REMOVE(&peer->updates[AID_INET], upa, attr_l);
free(upa->attr);
free(upa->mpattr);
free(upa);
@@ -895,12 +1024,13 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
}
u_char *
-up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
+up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer,
+ u_int8_t aid)
{
int wpos;
u_int16_t datalen, tmp;
u_int16_t attrlen = 2; /* attribute header (without len) */
- u_int8_t flags = ATTR_OPTIONAL;
+ u_int8_t flags = ATTR_OPTIONAL, safi;
/*
* reserve space for withdraw len, attr len, the attribute header
@@ -912,7 +1042,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
return (NULL);
datalen = up_dump_prefix(buf + wpos, *len - wpos,
- &peer->withdraws6, peer);
+ &peer->withdraws[aid], peer);
if (datalen == 0)
return (NULL);
@@ -920,9 +1050,11 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
/* prepend header, need to do it reverse */
/* safi & afi */
- buf[--wpos] = SAFI_UNICAST;
+ if (aid2afi(aid, &tmp, &safi))
+ fatalx("up_dump_mp_unreach: bad AID");
+ buf[--wpos] = safi;
wpos -= sizeof(u_int16_t);
- tmp = htons(AFI_IPv6);
+ tmp = htons(tmp);
memcpy(buf + wpos, &tmp, sizeof(u_int16_t));
/* attribute length */
@@ -959,33 +1091,39 @@ up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
return (buf + wpos);
}
-u_char *
-up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
+int
+up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer,
+ u_int8_t aid)
{
struct update_attr *upa;
int wpos;
- u_int16_t datalen, tmp;
+ u_int16_t attr_len, datalen, tmp;
u_int8_t flags = ATTR_OPTIONAL;
/*
* It is possible that a queued path attribute has no nlri prefix.
* Ignore and remove those path attributes.
*/
- while ((upa = TAILQ_FIRST(&peer->updates6)) != NULL)
+ while ((upa = TAILQ_FIRST(&peer->updates[aid])) != NULL)
if (TAILQ_EMPTY(&upa->prefix_h)) {
+ attr_len = upa->attr_len;
if (RB_REMOVE(uptree_attr, &peer->up_attrs,
upa) == NULL)
log_warnx("dequeuing update failed.");
- TAILQ_REMOVE(&peer->updates6, upa, attr_l);
+ TAILQ_REMOVE(&peer->updates[aid], upa, attr_l);
free(upa->attr);
free(upa->mpattr);
free(upa);
peer->up_acnt--;
+ /* XXX horrible hack,
+ * if attr_len is 0, it is a EoR marker */
+ if (attr_len == 0)
+ return (-1);
} else
break;
if (upa == NULL)
- return (NULL);
+ return (-2);
/*
* reserve space for attr len, the attributes, the
@@ -993,12 +1131,12 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
*/
wpos = 2 + 2 + upa->attr_len + 4 + upa->mpattr_len;
if (*len < wpos)
- return (NULL);
+ return (-2);
datalen = up_dump_prefix(buf + wpos, *len - wpos,
&upa->prefix_h, peer);
if (datalen == 0)
- return (NULL);
+ return (-2);
if (upa->mpattr_len == 0 || upa->mpattr == NULL)
fatalx("mulitprotocol update without MP attrs");
@@ -1038,7 +1176,7 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
if (TAILQ_EMPTY(&upa->prefix_h)) {
if (RB_REMOVE(uptree_attr, &peer->up_attrs, upa) == NULL)
log_warnx("dequeuing update failed.");
- TAILQ_REMOVE(&peer->updates6, upa, attr_l);
+ TAILQ_REMOVE(&peer->updates[aid], upa, attr_l);
free(upa->attr);
free(upa->mpattr);
free(upa);
@@ -1046,6 +1184,5 @@ up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer)
}
*len = datalen + 4;
- return (buf + wpos);
+ return (wpos);
}
-
diff --git a/bgpd/session.c b/bgpd/session.c
index 4f7f787..3cdafc8 100644
--- a/bgpd/session.c
+++ b/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.293 2009/06/07 05:56:24 eric Exp $ */
+/* $OpenBSD: session.c,v 1.304 2010/01/05 08:49:57 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -21,6 +21,8 @@
#include <sys/mman.h>
#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <sys/un.h>
#include <net/if_types.h>
#include <netinet/in.h>
@@ -50,7 +52,12 @@
#define PFD_PIPE_ROUTE_CTL 2
#define PFD_SOCK_CTL 3
#define PFD_SOCK_RCTL 4
-#define PFD_LISTENERS_START 5
+#define PFD_SOCK_PFKEY 5
+#define PFD_LISTENERS_START 6
+
+#if defined(__FreeBSD__) /* FreeBSD has no LINK_STATE_IS_UP macro. */
+#define LINK_STATE_IS_UP(_s) ((_s) >= LINK_STATE_UP)
+#endif /* defined(__FreeBSD__) */
void session_sighdlr(int);
int setup_listeners(u_int *);
@@ -65,9 +72,8 @@ void session_accept(int);
int session_connect(struct peer *);
void session_tcp_established(struct peer *);
void session_capa_ann_none(struct peer *);
-int session_capa_add(struct peer *, struct buf *, u_int8_t, u_int8_t,
- u_int8_t *);
-int session_capa_add_mp(struct buf *, u_int16_t, u_int8_t);
+int session_capa_add(struct ibuf *, u_int8_t, u_int8_t);
+int session_capa_add_mp(struct ibuf *, u_int8_t);
struct bgp_msg *session_newmsg(enum msg_type, u_int16_t);
int session_sendmsg(struct bgp_msg *, struct peer *);
void session_open(struct peer *);
@@ -75,7 +81,7 @@ void session_keepalive(struct peer *);
void session_update(u_int32_t, void *, size_t);
void session_notification(struct peer *, u_int8_t, u_int8_t, void *,
ssize_t);
-void session_rrefresh(struct peer *, u_int16_t, u_int8_t);
+void session_rrefresh(struct peer *, u_int8_t);
int session_dispatch_msg(struct pollfd *, struct peer *);
int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *);
int parse_open(struct peer *);
@@ -83,22 +89,22 @@ int parse_update(struct peer *);
int parse_refresh(struct peer *);
int parse_notification(struct peer *);
int parse_capabilities(struct peer *, u_char *, u_int16_t, u_int32_t *);
+int capa_neg_calc(struct peer *);
void session_dispatch_imsg(struct imsgbuf *, int, u_int *);
void session_up(struct peer *);
void session_down(struct peer *);
void session_demote(struct peer *, int);
-int la_cmp(struct listen_addr *, struct listen_addr *);
-struct peer *getpeerbyip(struct sockaddr *);
-int session_match_mask(struct peer *, struct sockaddr *);
-struct peer *getpeerbyid(u_int32_t);
-static struct sockaddr *addr2sa(struct bgpd_addr *, u_int16_t);
+int la_cmp(struct listen_addr *, struct listen_addr *);
+struct peer *getpeerbyip(struct sockaddr *);
+int session_match_mask(struct peer *, struct bgpd_addr *);
+struct peer *getpeerbyid(u_int32_t);
-struct bgpd_config *conf, *nconf = NULL;
+struct bgpd_config *conf, *nconf;
struct bgpd_sysdep sysdep;
-struct peer *npeers;
-volatile sig_atomic_t session_quit = 0;
-int pending_reconf = 0;
+struct peer *peers, *npeers;
+volatile sig_atomic_t session_quit;
+int pending_reconf;
int csock = -1, rcsock = -1;
u_int peer_cnt;
struct imsgbuf *ibuf_rde;
@@ -175,12 +181,11 @@ setup_listeners(u_int *la_cnt)
}
pid_t
-session_main(struct bgpd_config *config, struct peer *cpeers,
- struct network_head *net_l, struct filter_head *rules,
- struct mrt_head *m_l, struct rib_names *rib_l, int pipe_m2s[2],
- int pipe_s2r[2], int pipe_m2r[2], int pipe_s2rctl[2])
+session_main(int pipe_m2s[2], int pipe_s2r[2], int pipe_m2r[2],
+ int pipe_s2rctl[2])
{
- int nfds, timeout;
+ struct rlimit rl;
+ int nfds, timeout, pfkeysock;
unsigned int i, j, idx_peers, idx_listeners, idx_mrts;
pid_t pid;
u_int pfd_elms = 0, peer_l_elms = 0, mrt_l_elms = 0;
@@ -189,19 +194,13 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
u_int32_t ctl_queued;
struct passwd *pw;
struct peer *p, **peer_l = NULL, *last, *next;
- struct network *net;
- struct mrt *m, **mrt_l = NULL;
- struct filter_rule *r;
+ struct mrt *m, *xm, **mrt_l = NULL;
struct pollfd *pfd = NULL;
struct ctl_conn *ctl_conn;
struct listen_addr *la;
- struct rde_rib *rr;
void *newp;
short events;
- conf = config;
- peers = cpeers;
-
switch (pid = fork()) {
case -1:
fatal("cannot fork");
@@ -211,13 +210,6 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
return (pid);
}
- /* control socket is outside chroot */
- if ((csock = control_init(0, conf->csock)) == -1)
- fatalx("control socket setup failed");
- if (conf->rcsock != NULL &&
- (rcsock = control_init(1, conf->rcsock)) == -1)
- fatalx("control socket setup failed");
-
if ((pw = getpwnam(BGPD_USER)) == NULL)
fatal(NULL);
@@ -229,28 +221,31 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
setproctitle("session engine");
bgpd_process = PROC_SE;
- if (pfkey_init(&sysdep) == -1)
- fatalx("pfkey setup failed");
+ if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
+ fatal("getrlimit");
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
+ fatal("setrlimit");
+
+ pfkeysock = pfkey_init(&sysdep);
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");
- listener_cnt = 0;
- setup_listeners(&listener_cnt);
-
signal(SIGTERM, session_sighdlr);
signal(SIGINT, session_sighdlr);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
- log_info("session engine ready");
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
+
close(pipe_m2s[0]);
close(pipe_s2r[1]);
close(pipe_s2rctl[1]);
close(pipe_m2r[0]);
close(pipe_m2r[1]);
- init_conf(conf);
if ((ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL ||
(ibuf_rde_ctl = malloc(sizeof(struct imsgbuf))) == NULL ||
(ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
@@ -258,37 +253,21 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
imsg_init(ibuf_rde, pipe_s2r[0]);
imsg_init(ibuf_rde_ctl, pipe_s2rctl[0]);
imsg_init(ibuf_main, pipe_m2s[1]);
+
TAILQ_INIT(&ctl_conns);
- control_listen(csock);
- control_listen(rcsock);
LIST_INIT(&mrthead);
+ listener_cnt = 0;
peer_cnt = 0;
ctl_cnt = 0;
- /* filter rules are not used in the SE */
- while ((r = TAILQ_FIRST(rules)) != NULL) {
- TAILQ_REMOVE(rules, r, entry);
- free(r);
- }
- free(rules);
-
- /* network list is not used in the SE */
- while ((net = TAILQ_FIRST(net_l)) != NULL) {
- TAILQ_REMOVE(net_l, net, entry);
- filterset_free(&net->net.attrset);
- free(net);
- }
+ if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
+ fatal(NULL);
+ if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
+ NULL)
+ fatal(NULL);
+ TAILQ_INIT(conf->listen_addrs);
- /* main mrt list is not used in the SE */
- while ((m = LIST_FIRST(m_l)) != NULL) {
- LIST_REMOVE(m, entry);
- free(m);
- }
- /* rib names not used in the SE */
- while ((rr = SIMPLEQ_FIRST(&ribnames))) {
- SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
- free(rr);
- }
+ log_info("session engine ready");
while (session_quit == 0) {
/* check for peers to be initialized or deleted */
@@ -308,8 +287,9 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
/* reinit due? */
if (p->conf.reconf_action == RECONF_REINIT) {
- bgp_fsm(p, EVNT_STOP);
- timer_set(p, Timer_IdleHold, 0);
+ session_stop(p, ERR_CEASE_ADMIN_RESET);
+ if (!p->conf.down)
+ timer_set(p, Timer_IdleHold, 0);
}
/* deletion due? */
@@ -317,7 +297,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
if (p->demoted)
session_demote(p, -1);
p->conf.demote_group[0] = 0;
- bgp_fsm(p, EVNT_STOP);
+ session_stop(p, ERR_CEASE_PEER_UNCONF);
log_peer_warnx(&p->conf, "removed");
if (last != NULL)
last->next = next;
@@ -346,9 +326,17 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
}
mrt_cnt = 0;
- LIST_FOREACH(m, &mrthead, entry)
+ for (m = LIST_FIRST(&mrthead); m != NULL; m = xm) {
+ xm = LIST_NEXT(m, entry);
+ if (m->state == MRT_STATE_REMOVE) {
+ mrt_clean(m);
+ LIST_REMOVE(m, entry);
+ free(m);
+ continue;
+ }
if (m->wbuf.queued)
mrt_cnt++;
+ }
if (mrt_cnt > mrt_l_elms) {
if ((newp = realloc(mrt_l, sizeof(struct mrt *) *
@@ -394,14 +382,19 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
if (ctl_queued < SESSION_CTL_QUEUE_MAX)
/*
* Do not act as unlimited buffer. Don't read in more
- * messages if the ctl sockets are getting full.
+ * messages if the ctl sockets are getting full.
*/
pfd[PFD_PIPE_ROUTE_CTL].events = POLLIN;
pfd[PFD_SOCK_CTL].fd = csock;
pfd[PFD_SOCK_CTL].events = POLLIN;
pfd[PFD_SOCK_RCTL].fd = rcsock;
pfd[PFD_SOCK_RCTL].events = POLLIN;
-
+ pfd[PFD_SOCK_PFKEY].fd = pfkeysock;
+#if !defined(__FreeBSD__)
+ pfd[PFD_SOCK_PFKEY].events = POLLIN;
+#else
+ pfd[PFD_SOCK_PFKEY].events = 0;
+#endif
i = PFD_LISTENERS_START;
TAILQ_FOREACH(la, conf->listen_addrs, entry) {
pfd[i].fd = la->fd;
@@ -534,6 +527,14 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
ctl_cnt += control_accept(rcsock, 1);
}
+ if (nfds > 0 && pfd[PFD_SOCK_PFKEY].revents & POLLIN) {
+ nfds--;
+ if (pfkey_read(pfkeysock, NULL) == -1) {
+ log_warnx("pfkey_read failed, exiting...");
+ session_quit = 1;
+ }
+ }
+
for (j = PFD_LISTENERS_START; nfds > 0 && j < idx_listeners;
j++)
if (pfd[j].revents & POLLIN) {
@@ -557,7 +558,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers,
while ((p = peers) != NULL) {
peers = p->next;
- bgp_fsm(p, EVNT_STOP);
+ session_stop(p, ERR_CEASE_ADMIN_DOWN);
pfkey_remove(p);
free(p);
}
@@ -643,10 +644,9 @@ bgp_fsm(struct peer *peer, enum session_events event)
timer_stop(peer, Timer_IdleHold);
/* allocate read buffer */
- peer->rbuf = calloc(1, sizeof(struct buf_read));
+ peer->rbuf = calloc(1, sizeof(struct ibuf_read));
if (peer->rbuf == NULL)
fatal(NULL);
- peer->rbuf->wpos = 0;
/* init write buffer */
msgbuf_init(&peer->wbuf);
@@ -746,7 +746,6 @@ bgp_fsm(struct peer *peer, enum session_events event)
/* ignore */
break;
case EVNT_STOP:
- session_notification(peer, ERR_CEASE, 0, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
case EVNT_CON_CLOSED:
@@ -780,7 +779,8 @@ bgp_fsm(struct peer *peer, enum session_events event)
change_state(peer, STATE_IDLE, event);
break;
default:
- session_notification(peer, ERR_FSM, 0, NULL, 0);
+ session_notification(peer,
+ ERR_FSM, ERR_FSM_UNEX_OPENSENT, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
}
@@ -791,7 +791,6 @@ bgp_fsm(struct peer *peer, enum session_events event)
/* ignore */
break;
case EVNT_STOP:
- session_notification(peer, ERR_CEASE, 0, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
case EVNT_CON_CLOSED:
@@ -815,7 +814,8 @@ bgp_fsm(struct peer *peer, enum session_events event)
change_state(peer, STATE_IDLE, event);
break;
default:
- session_notification(peer, ERR_FSM, 0, NULL, 0);
+ session_notification(peer,
+ ERR_FSM, ERR_FSM_UNEX_OPENCONFIRM, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
}
@@ -826,7 +826,6 @@ bgp_fsm(struct peer *peer, enum session_events event)
/* ignore */
break;
case EVNT_STOP:
- session_notification(peer, ERR_CEASE, 0, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
case EVNT_CON_CLOSED:
@@ -856,7 +855,8 @@ bgp_fsm(struct peer *peer, enum session_events event)
change_state(peer, STATE_IDLE, event);
break;
default:
- session_notification(peer, ERR_FSM, 0, NULL, 0);
+ session_notification(peer,
+ ERR_FSM, ERR_FSM_UNEX_ESTABLISHED, NULL, 0);
change_state(peer, STATE_IDLE, event);
break;
}
@@ -923,6 +923,7 @@ change_state(struct peer *peer, enum session_state state,
timer_stop(peer, Timer_ConnectRetry);
timer_stop(peer, Timer_Keepalive);
timer_stop(peer, Timer_Hold);
+ timer_stop(peer, Timer_IdleHold);
timer_stop(peer, Timer_IdleHoldReset);
session_close_connection(peer);
msgbuf_clear(&peer->wbuf);
@@ -1069,7 +1070,7 @@ session_connect(struct peer *peer)
if (peer->fd != -1)
return (-1);
- if ((peer->fd = socket(peer->conf.remote_addr.af, SOCK_STREAM,
+ if ((peer->fd = socket(aid2af(peer->conf.remote_addr.aid), SOCK_STREAM,
IPPROTO_TCP)) == -1) {
log_peer_warn(&peer->conf, "session_connect socket");
bgp_fsm(peer, EVNT_CON_OPENFAIL);
@@ -1100,8 +1101,7 @@ session_connect(struct peer *peer)
peer->wbuf.fd = peer->fd;
/* if update source is set we need to bind() */
- if (peer->conf.local_addr.af) {
- sa = addr2sa(&peer->conf.local_addr, 0);
+ if ((sa = addr2sa(&peer->conf.local_addr, 0)) != NULL) {
if (bind(peer->fd, sa, sa->sa_len) == -1) {
log_peer_warn(&peer->conf, "session_connect bind");
bgp_fsm(peer, EVNT_CON_OPENFAIL);
@@ -1139,42 +1139,50 @@ session_setup_socket(struct peer *p)
int nodelay = 1;
int bsize;
- if (p->conf.ebgp && p->conf.remote_addr.af == AF_INET) {
- /* set TTL to foreign router's distance - 1=direct n=multihop
- with ttlsec, we always use 255 */
- if (p->conf.ttlsec) {
- ttl = 256 - p->conf.distance;
- if (setsockopt(p->fd, IPPROTO_IP, IP_MINTTL, &ttl,
+ switch (p->conf.remote_addr.aid) {
+ case AID_INET:
+ /* set precedence, see RFC 1771 appendix 5 */
+ if (setsockopt(p->fd, IPPROTO_IP, IP_TOS, &pre, sizeof(pre)) ==
+ -1) {
+ log_peer_warn(&p->conf,
+ "session_setup_socket setsockopt TOS");
+ return (-1);
+ }
+
+ if (p->conf.ebgp) {
+ /* set TTL to foreign router's distance
+ 1=direct n=multihop with ttlsec, we always use 255 */
+ if (p->conf.ttlsec) {
+ ttl = 256 - p->conf.distance;
+ if (setsockopt(p->fd, IPPROTO_IP, IP_MINTTL,
+ &ttl, sizeof(ttl)) == -1) {
+ log_peer_warn(&p->conf,
+ "session_setup_socket: "
+ "setsockopt MINTTL");
+ return (-1);
+ }
+ ttl = 255;
+ }
+
+ if (setsockopt(p->fd, IPPROTO_IP, IP_TTL, &ttl,
sizeof(ttl)) == -1) {
log_peer_warn(&p->conf,
- "session_setup_socket setsockopt MINTTL");
+ "session_setup_socket setsockopt TTL");
return (-1);
}
- ttl = 255;
}
-
- if (setsockopt(p->fd, IPPROTO_IP, IP_TTL, &ttl,
- sizeof(ttl)) == -1) {
- log_peer_warn(&p->conf,
- "session_setup_socket setsockopt TTL");
- return (-1);
- }
- }
-
- if (p->conf.ebgp && p->conf.remote_addr.af == AF_INET6)
- /* set hoplimit to foreign router's distance */
- if (setsockopt(p->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl,
- sizeof(ttl)) == -1) {
- log_peer_warn(&p->conf,
- "session_setup_socket setsockopt hoplimit");
- return (-1);
+ break;
+ case AID_INET6:
+ if (p->conf.ebgp) {
+ /* set hoplimit to foreign router's distance */
+ if (setsockopt(p->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &ttl, sizeof(ttl)) == -1) {
+ log_peer_warn(&p->conf,
+ "session_setup_socket setsockopt hoplimit");
+ return (-1);
+ }
}
-
- /* if ttlsec is in use, set minttl */
- if (p->conf.ttlsec) {
- ttl = 256 - p->conf.distance;
- setsockopt(p->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl));
-
+ break;
}
/* set TCP_NODELAY */
@@ -1185,14 +1193,6 @@ session_setup_socket(struct peer *p)
return (-1);
}
- /* set precedence, see RFC 1771 appendix 5 */
- if (p->conf.remote_addr.af == AF_INET &&
- setsockopt(p->fd, IPPROTO_IP, IP_TOS, &pre, sizeof(pre)) == -1) {
- log_peer_warn(&p->conf,
- "session_setup_socket setsockopt TOS");
- return (-1);
- }
-
/* only increase bufsize (and thus window) if md5 or ipsec is in use */
if (p->conf.auth.method != AUTH_NONE) {
/* try to increase bufsize. no biggie if it fails */
@@ -1244,40 +1244,32 @@ session_tcp_established(struct peer *peer)
void
session_capa_ann_none(struct peer *peer)
{
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.refresh = 0;
- peer->capa.ann.restart = 0;
- peer->capa.ann.as4byte = 0;
+ bzero(&peer->capa.ann, sizeof(peer->capa.ann));
}
int
-session_capa_add(struct peer *p, struct buf *opb, u_int8_t capa_code,
- u_int8_t capa_len, u_int8_t *optparamlen)
+session_capa_add(struct ibuf *opb, u_int8_t capa_code, u_int8_t capa_len)
{
- u_int8_t op_type, op_len, tot_len, errs = 0;
-
- op_type = OPT_PARAM_CAPABILITIES;
- op_len = sizeof(capa_code) + sizeof(capa_len) + capa_len;
- tot_len = sizeof(op_type) + sizeof(op_len) + op_len;
- errs += buf_add(opb, &op_type, sizeof(op_type));
- errs += buf_add(opb, &op_len, sizeof(op_len));
- errs += buf_add(opb, &capa_code, sizeof(capa_code));
- errs += buf_add(opb, &capa_len, sizeof(capa_len));
- *optparamlen += tot_len;
+ int errs = 0;
+
+ errs += ibuf_add(opb, &capa_code, sizeof(capa_code));
+ errs += ibuf_add(opb, &capa_len, sizeof(capa_len));
return (errs);
}
int
-session_capa_add_mp(struct buf *buf, u_int16_t afi, u_int8_t safi)
+session_capa_add_mp(struct ibuf *buf, u_int8_t aid)
{
- u_int8_t pad = 0;
+ u_int8_t safi, pad = 0;
+ u_int16_t afi;
int errs = 0;
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("session_capa_add_mp: bad afi/safi pair");
afi = htons(afi);
- errs += buf_add(buf, &afi, sizeof(afi));
- errs += buf_add(buf, &pad, sizeof(pad));
- errs += buf_add(buf, &safi, sizeof(safi));
+ errs += ibuf_add(buf, &afi, sizeof(afi));
+ errs += ibuf_add(buf, &pad, sizeof(pad));
+ errs += ibuf_add(buf, &safi, sizeof(safi));
return (errs);
}
@@ -1287,23 +1279,22 @@ session_newmsg(enum msg_type msgtype, u_int16_t len)
{
struct bgp_msg *msg;
struct msg_header hdr;
- struct buf *buf;
+ struct ibuf *buf;
int errs = 0;
memset(&hdr.marker, 0xff, sizeof(hdr.marker));
hdr.len = htons(len);
hdr.type = msgtype;
- if ((buf = buf_open(len)) == NULL)
+ if ((buf = ibuf_open(len)) == NULL)
return (NULL);
- errs += buf_add(buf, &hdr.marker, sizeof(hdr.marker));
- errs += buf_add(buf, &hdr.len, sizeof(hdr.len));
- errs += buf_add(buf, &hdr.type, sizeof(hdr.type));
+ errs += ibuf_add(buf, &hdr.marker, sizeof(hdr.marker));
+ errs += ibuf_add(buf, &hdr.len, sizeof(hdr.len));
+ errs += ibuf_add(buf, &hdr.type, sizeof(hdr.type));
- if (errs > 0 ||
- (msg = calloc(1, sizeof(*msg))) == NULL) {
- buf_free(buf);
+ if (errs || (msg = calloc(1, sizeof(*msg))) == NULL) {
+ ibuf_free(buf);
return (NULL);
}
@@ -1329,7 +1320,7 @@ session_sendmsg(struct bgp_msg *msg, struct peer *p)
mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p);
}
- buf_close(&p->wbuf, msg->buf);
+ ibuf_close(&p->wbuf, msg->buf);
free(msg);
return (0);
}
@@ -1338,40 +1329,38 @@ void
session_open(struct peer *p)
{
struct bgp_msg *buf;
- struct buf *opb;
+ struct ibuf *opb;
struct msg_open msg;
u_int16_t len;
- u_int8_t optparamlen = 0;
- u_int errs = 0;
+ u_int8_t i, op_type, optparamlen = 0;
+ int errs = 0;
- if ((opb = buf_dynamic(0, MAX_PKTSIZE - MSGSIZE_OPEN_MIN)) == NULL) {
+ if ((opb = ibuf_dynamic(0, UCHAR_MAX - sizeof(op_type) -
+ sizeof(optparamlen))) == NULL) {
bgp_fsm(p, EVNT_CON_FATAL);
return;
}
/* multiprotocol extensions, RFC 4760 */
- if (p->capa.ann.mp_v4) { /* 4 bytes data */
- errs += session_capa_add(p, opb, CAPA_MP, 4, &optparamlen);
- errs += session_capa_add_mp(opb, AFI_IPv4, p->capa.ann.mp_v4);
- }
- if (p->capa.ann.mp_v6) { /* 4 bytes data */
- errs += session_capa_add(p, opb, CAPA_MP, 4, &optparamlen);
- errs += session_capa_add_mp(opb, AFI_IPv6, p->capa.ann.mp_v6);
- }
+ for (i = 0; i < AID_MAX; i++)
+ if (p->capa.ann.mp[i]) { /* 4 bytes data */
+ errs += session_capa_add(opb, CAPA_MP, 4);
+ errs += session_capa_add_mp(opb, i);
+ }
/* route refresh, RFC 2918 */
if (p->capa.ann.refresh) /* no data */
- errs += session_capa_add(p, opb, CAPA_REFRESH, 0, &optparamlen);
+ errs += session_capa_add(opb, CAPA_REFRESH, 0);
/* End-of-RIB marker, RFC 4724 */
if (p->capa.ann.restart) { /* 2 bytes data */
u_char c[2];
- bzero(&c, 2);
c[0] = 0x80; /* we're always restarting */
- errs += session_capa_add(p, opb, CAPA_RESTART, 2, &optparamlen);
- errs += buf_add(opb, &c, 2);
+ c[1] = 0;
+ errs += session_capa_add(opb, CAPA_RESTART, 2);
+ errs += ibuf_add(opb, &c, 2);
}
/* 4-bytes AS numbers, draft-ietf-idr-as4bytes-13 */
@@ -1379,13 +1368,17 @@ session_open(struct peer *p)
u_int32_t nas;
nas = htonl(conf->as);
- errs += session_capa_add(p, opb, CAPA_AS4BYTE, 4, &optparamlen);
- errs += buf_add(opb, &nas, 4);
+ errs += session_capa_add(opb, CAPA_AS4BYTE, sizeof(nas));
+ errs += ibuf_add(opb, &nas, sizeof(nas));
}
+ if (ibuf_size(opb))
+ optparamlen = ibuf_size(opb) + sizeof(op_type) +
+ sizeof(optparamlen);
+
len = MSGSIZE_OPEN_MIN + optparamlen;
if (errs || (buf = session_newmsg(OPEN, len)) == NULL) {
- buf_free(opb);
+ ibuf_free(opb);
bgp_fsm(p, EVNT_CON_FATAL);
return;
}
@@ -1399,19 +1392,24 @@ session_open(struct peer *p)
msg.bgpid = conf->bgpid; /* is already in network byte order */
msg.optparamlen = optparamlen;
- errs += buf_add(buf->buf, &msg.version, sizeof(msg.version));
- errs += buf_add(buf->buf, &msg.myas, sizeof(msg.myas));
- errs += buf_add(buf->buf, &msg.holdtime, sizeof(msg.holdtime));
- errs += buf_add(buf->buf, &msg.bgpid, sizeof(msg.bgpid));
- errs += buf_add(buf->buf, &msg.optparamlen, sizeof(msg.optparamlen));
+ errs += ibuf_add(buf->buf, &msg.version, sizeof(msg.version));
+ errs += ibuf_add(buf->buf, &msg.myas, sizeof(msg.myas));
+ errs += ibuf_add(buf->buf, &msg.holdtime, sizeof(msg.holdtime));
+ errs += ibuf_add(buf->buf, &msg.bgpid, sizeof(msg.bgpid));
+ errs += ibuf_add(buf->buf, &msg.optparamlen, sizeof(msg.optparamlen));
- if (optparamlen)
- errs += buf_add(buf->buf, opb->buf, optparamlen);
+ if (optparamlen) {
+ op_type = OPT_PARAM_CAPABILITIES;
+ optparamlen = ibuf_size(opb);
+ errs += ibuf_add(buf->buf, &op_type, sizeof(op_type));
+ errs += ibuf_add(buf->buf, &optparamlen, sizeof(optparamlen));
+ errs += ibuf_add(buf->buf, opb->buf, ibuf_size(opb));
+ }
- buf_free(opb);
+ ibuf_free(opb);
- if (errs > 0) {
- buf_free(buf->buf);
+ if (errs) {
+ ibuf_free(buf->buf);
free(buf);
bgp_fsm(p, EVNT_CON_FATAL);
return;
@@ -1459,8 +1457,8 @@ session_update(u_int32_t peerid, void *data, size_t datalen)
return;
}
- if (buf_add(buf->buf, data, datalen)) {
- buf_free(buf->buf);
+ if (ibuf_add(buf->buf, data, datalen)) {
+ ibuf_free(buf->buf);
free(buf);
bgp_fsm(p, EVNT_CON_FATAL);
return;
@@ -1480,29 +1478,27 @@ session_notification(struct peer *p, u_int8_t errcode, u_int8_t subcode,
void *data, ssize_t datalen)
{
struct bgp_msg *buf;
- u_int errs = 0;
- u_int8_t null8 = 0;
+ int errs = 0;
if (p->stats.last_sent_errcode) /* some notification already sent */
return;
+ log_notification(p, errcode, subcode, data, datalen, "sending");
+
if ((buf = session_newmsg(NOTIFICATION,
MSGSIZE_NOTIFICATION_MIN + datalen)) == NULL) {
bgp_fsm(p, EVNT_CON_FATAL);
return;
}
- errs += buf_add(buf->buf, &errcode, sizeof(errcode));
- if (errcode == ERR_CEASE)
- errs += buf_add(buf->buf, &null8, sizeof(null8));
- else
- errs += buf_add(buf->buf, &subcode, sizeof(subcode));
+ errs += ibuf_add(buf->buf, &errcode, sizeof(errcode));
+ errs += ibuf_add(buf->buf, &subcode, sizeof(subcode));
if (datalen > 0)
- errs += buf_add(buf->buf, data, datalen);
+ errs += ibuf_add(buf->buf, data, datalen);
- if (errs > 0) {
- buf_free(buf->buf);
+ if (errs) {
+ ibuf_free(buf->buf);
free(buf);
bgp_fsm(p, EVNT_CON_FATAL);
return;
@@ -1521,23 +1517,29 @@ session_notification(struct peer *p, u_int8_t errcode, u_int8_t subcode,
int
session_neighbor_rrefresh(struct peer *p)
{
+ u_int8_t i;
+
if (!p->capa.peer.refresh)
return (-1);
- if (p->capa.peer.mp_v4 != SAFI_NONE)
- session_rrefresh(p, AFI_IPv4, p->capa.peer.mp_v4);
- if (p->capa.peer.mp_v6 != SAFI_NONE)
- session_rrefresh(p, AFI_IPv6, p->capa.peer.mp_v6);
+ for (i = 0; i < AID_MAX; i++) {
+ if (p->capa.peer.mp[i] != 0)
+ session_rrefresh(p, i);
+ }
return (0);
}
void
-session_rrefresh(struct peer *p, u_int16_t afi, u_int8_t safi)
+session_rrefresh(struct peer *p, u_int8_t aid)
{
struct bgp_msg *buf;
int errs = 0;
- u_int8_t null8 = 0;
+ u_int16_t afi;
+ u_int8_t safi, null8 = 0;
+
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("session_rrefresh: bad afi/safi pair");
if ((buf = session_newmsg(RREFRESH, MSGSIZE_RREFRESH)) == NULL) {
bgp_fsm(p, EVNT_CON_FATAL);
@@ -1545,12 +1547,12 @@ session_rrefresh(struct peer *p, u_int16_t afi, u_int8_t safi)
}
afi = htons(afi);
- errs += buf_add(buf->buf, &afi, sizeof(afi));
- errs += buf_add(buf->buf, &null8, sizeof(null8));
- errs += buf_add(buf->buf, &safi, sizeof(safi));
+ errs += ibuf_add(buf->buf, &afi, sizeof(afi));
+ errs += ibuf_add(buf->buf, &null8, sizeof(null8));
+ errs += ibuf_add(buf->buf, &safi, sizeof(safi));
- if (errs > 0) {
- buf_free(buf->buf);
+ if (errs) {
+ ibuf_free(buf->buf);
free(buf);
bgp_fsm(p, EVNT_CON_FATAL);
return;
@@ -1853,12 +1855,6 @@ parse_open(struct peer *peer)
p += sizeof(short_as);
as = peer->short_as = ntohs(short_as);
- /* if remote-as is zero and it's a cloned neighbor, accept any */
- if (peer->conf.cloned && !peer->conf.remote_as && as != AS_TRANS) {
- peer->conf.remote_as = as;
- peer->conf.ebgp = (peer->conf.remote_as != conf->as);
- }
-
memcpy(&oholdtime, p, sizeof(oholdtime));
p += sizeof(oholdtime);
@@ -1966,6 +1962,15 @@ parse_open(struct peer *peer)
}
}
+ /* if remote-as is zero and it's a cloned neighbor, accept any */
+ if (peer->conf.cloned && !peer->conf.remote_as && as != AS_TRANS) {
+ peer->conf.remote_as = as;
+ peer->conf.ebgp = (peer->conf.remote_as != conf->as);
+ if (!peer->conf.ebgp)
+ /* force enforce_as off for iBGP sessions */
+ peer->conf.enforce_as = ENFORCE_AS_OFF;
+ }
+
if (peer->conf.remote_as != as) {
log_peer_warnx(&peer->conf, "peer sent wrong AS %s",
log_as(as));
@@ -1974,6 +1979,14 @@ parse_open(struct peer *peer)
return (-1);
}
+ if (capa_neg_calc(peer) == -1) {
+ log_peer_warnx(&peer->conf,
+ "capabilitiy negotiation calculation failed");
+ session_notification(peer, ERR_OPEN, 0, NULL, 0);
+ change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN);
+ return (-1);
+ }
+
return (0);
}
@@ -2008,24 +2021,35 @@ int
parse_refresh(struct peer *peer)
{
u_char *p;
- struct rrefresh r;
+ u_int16_t afi;
+ u_int8_t aid, safi;
p = peer->rbuf->rptr;
p += MSGSIZE_HEADER; /* header is already checked */
+ /*
+ * We could check if we actually announced the capability but
+ * as long as the message is correctly encoded we don't care.
+ */
+
/* afi, 2 byte */
- memcpy(&r.afi, p, sizeof(r.afi));
- r.afi = ntohs(r.afi);
+ memcpy(&afi, p, sizeof(afi));
+ afi = ntohs(afi);
p += 2;
/* reserved, 1 byte */
p += 1;
/* safi, 1 byte */
- memcpy(&r.safi, p, sizeof(r.safi));
+ memcpy(&safi, p, sizeof(safi));
/* afi/safi unchecked - unrecognized values will be ignored anyway */
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf, "peer sent bad refresh, "
+ "invalid afi/safi pair");
+ return (0);
+ }
- if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &r,
- sizeof(r)) == -1)
+ if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &aid,
+ sizeof(aid)) == -1)
return (-1);
return (0);
@@ -2035,11 +2059,12 @@ int
parse_notification(struct peer *peer)
{
u_char *p;
+ u_int16_t datalen;
u_int8_t errcode;
u_int8_t subcode;
- u_int16_t datalen;
u_int8_t capa_code;
u_int8_t capa_len;
+ u_int8_t i;
/* just log */
p = peer->rbuf->rptr;
@@ -2059,7 +2084,7 @@ parse_notification(struct peer *peer)
p += sizeof(subcode);
datalen -= sizeof(subcode);
- log_notification(peer, errcode, subcode, p, datalen);
+ log_notification(peer, errcode, subcode, p, datalen, "received");
peer->errcnt++;
if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
@@ -2094,8 +2119,8 @@ parse_notification(struct peer *peer)
datalen -= capa_len;
switch (capa_code) {
case CAPA_MP:
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.mp_v6 = SAFI_NONE;
+ for (i = 0; i < AID_MAX; i++)
+ peer->capa.ann.mp[i] = 0;
log_peer_warnx(&peer->conf,
"disabling multiprotocol capability");
break;
@@ -2139,13 +2164,14 @@ parse_notification(struct peer *peer)
int
parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
{
+ u_char *capa_val;
+ u_int32_t remote_as;
u_int16_t len;
+ u_int16_t afi;
+ u_int8_t safi;
+ u_int8_t aid;
u_int8_t capa_code;
u_int8_t capa_len;
- u_char *capa_val;
- u_int16_t mp_afi;
- u_int8_t mp_safi;
- u_int32_t remote_as;
len = dlen;
while (len > 0) {
@@ -2182,29 +2208,16 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
"expect len 4, len is %u", capa_len);
return (-1);
}
- memcpy(&mp_afi, capa_val, sizeof(mp_afi));
- mp_afi = ntohs(mp_afi);
- memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi));
- switch (mp_afi) {
- case AFI_IPv4:
- if (mp_safi < 1 || mp_safi > 3)
- log_peer_warnx(&peer->conf,
- "parse_capabilities: AFI IPv4, "
- "mp_safi %u unknown", mp_safi);
- else
- peer->capa.peer.mp_v4 = mp_safi;
- break;
- case AFI_IPv6:
- if (mp_safi < 1 || mp_safi > 3)
- log_peer_warnx(&peer->conf,
- "parse_capabilities: AFI IPv6, "
- "mp_safi %u unknown", mp_safi);
- else
- peer->capa.peer.mp_v6 = mp_safi;
- break;
- default: /* ignore */
+ memcpy(&afi, capa_val, sizeof(afi));
+ afi = ntohs(afi);
+ memcpy(&safi, capa_val + 3, sizeof(safi));
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "parse_capabilities: AFI %u, "
+ "safi %u unknown", afi, safi);
break;
}
+ peer->capa.peer.mp[aid] = 1;
break;
case CAPA_REFRESH:
peer->capa.peer.refresh = 1;
@@ -2232,6 +2245,37 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
return (0);
}
+int
+capa_neg_calc(struct peer *p)
+{
+ u_int8_t i, hasmp = 0;
+
+ /* refresh: does not realy matter here, use peer setting */
+ p->capa.neg.refresh = p->capa.peer.refresh;
+
+ /* as4byte: both side must announce capability */
+ if (p->capa.ann.as4byte && p->capa.peer.as4byte)
+ p->capa.neg.as4byte = 1;
+ else
+ p->capa.neg.as4byte = 0;
+
+ /* MP: both side must announce capability */
+ for (i = 0; i < AID_MAX; i++) {
+ if (p->capa.ann.mp[i] && p->capa.peer.mp[i]) {
+ p->capa.neg.mp[i] = 1;
+ hasmp = 1;
+ } else
+ p->capa.neg.mp[i] = 0;
+ }
+ /* if no MP capability present for default IPv4 unicast mode */
+ if (!hasmp)
+ p->capa.neg.mp[AID_INET] = 1;
+
+ p->capa.neg.restart = p->capa.peer.restart;
+
+ return (0);
+}
+
void
session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
{
@@ -2244,7 +2288,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
struct kif *kif;
u_char *data;
enum reconf_action reconf;
- int n, depend_ok;
+ int n, depend_ok, restricted;
u_int8_t errcode, subcode;
if ((n = imsg_read(ibuf)) == -1)
@@ -2332,15 +2376,42 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
}
break;
+ case IMSG_RECONF_CTRL:
+ if (idx != PFD_PIPE_MAIN)
+ fatalx("reconf request not from parent");
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(restricted))
+ fatalx("IFINFO imsg with wrong len");
+ memcpy(&restricted, imsg.data, sizeof(restricted));
+ if (imsg.fd == -1) {
+ log_warnx("expected to receive fd for control "
+ "socket but didn't receive any");
+ break;
+ }
+ if (restricted) {
+ control_shutdown(rcsock);
+ rcsock = imsg.fd;
+ control_listen(rcsock);
+ } else {
+ control_shutdown(csock);
+ csock = imsg.fd;
+ control_listen(csock);
+ }
+ break;
case IMSG_RECONF_DONE:
if (idx != PFD_PIPE_MAIN)
fatalx("reconf request not from parent");
if (nconf == NULL)
fatalx("got IMSG_RECONF_DONE but no config");
+ conf->flags = nconf->flags;
+ conf->log = nconf->log;
+ conf->bgpid = nconf->bgpid;
+ conf->clusterid = nconf->clusterid;
conf->as = nconf->as;
+ conf->short_as = nconf->short_as;
conf->holdtime = nconf->holdtime;
- conf->bgpid = nconf->bgpid;
conf->min_holdtime = nconf->min_holdtime;
+ conf->connectretry = nconf->connectretry;
/* add new peers */
for (p = npeers; p != NULL; p = next) {
@@ -2408,7 +2479,8 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
bgp_fsm(p, EVNT_START);
} else if (!depend_ok && p->depend_ok) {
p->depend_ok = depend_ok;
- bgp_fsm(p, EVNT_STOP);
+ session_stop(p,
+ ERR_CEASE_OTHER_CHANGE);
}
}
break;
@@ -2456,10 +2528,10 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
}
break;
case IMSG_CTL_KROUTE:
- case IMSG_CTL_KROUTE6:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_SHOW_NEXTHOP:
case IMSG_CTL_SHOW_INTERFACE:
+ case IMSG_CTL_SHOW_FIB_TABLES:
if (idx != PFD_PIPE_MAIN)
fatalx("ctl kroute request not from parent");
control_imsg_relay(&imsg);
@@ -2469,7 +2541,6 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
case IMSG_CTL_SHOW_RIB_ATTR:
case IMSG_CTL_SHOW_RIB_MEM:
case IMSG_CTL_SHOW_NETWORK:
- case IMSG_CTL_SHOW_NETWORK6:
case IMSG_CTL_SHOW_NEIGHBOR:
if (idx != PFD_PIPE_ROUTE_CTL)
fatalx("ctl rib request not from RDE");
@@ -2612,29 +2683,23 @@ getpeerbydesc(const char *descr)
struct peer *
getpeerbyip(struct sockaddr *ip)
{
+ struct bgpd_addr addr;
struct peer *p, *newpeer, *loose = NULL;
u_int32_t id;
+ sa2addr(ip, &addr);
+
/* we might want a more effective way to find peers by IP */
for (p = peers; p != NULL; p = p->next)
if (!p->conf.template &&
- p->conf.remote_addr.af == ip->sa_family) {
- if (p->conf.remote_addr.af == AF_INET &&
- p->conf.remote_addr.v4.s_addr ==
- ((struct sockaddr_in *)ip)->sin_addr.s_addr)
- return (p);
- if (p->conf.remote_addr.af == AF_INET6 &&
- !bcmp(&p->conf.remote_addr.v6,
- &((struct sockaddr_in6 *)ip)->sin6_addr,
- sizeof(p->conf.remote_addr.v6)))
- return (p);
- }
+ !memcmp(&addr, &p->conf.remote_addr, sizeof(addr)))
+ return (p);
/* try template matching */
for (p = peers; p != NULL; p = p->next)
if (p->conf.template &&
- p->conf.remote_addr.af == ip->sa_family &&
- session_match_mask(p, ip))
+ p->conf.remote_addr.aid == addr.aid &&
+ session_match_mask(p, &addr))
if (loose == NULL || loose->conf.remote_masklen <
p->conf.remote_masklen)
loose = p;
@@ -2653,21 +2718,19 @@ getpeerbyip(struct sockaddr *ip)
break;
}
}
- if (newpeer->conf.remote_addr.af == AF_INET) {
- newpeer->conf.remote_addr.v4.s_addr =
- ((struct sockaddr_in *)ip)->sin_addr.s_addr;
+ sa2addr(ip, &newpeer->conf.remote_addr);
+ switch (ip->sa_family) {
+ case AF_INET:
newpeer->conf.remote_masklen = 32;
- }
- if (newpeer->conf.remote_addr.af == AF_INET6) {
- memcpy(&p->conf.remote_addr.v6,
- &((struct sockaddr_in6 *)ip)->sin6_addr,
- sizeof(newpeer->conf.remote_addr.v6));
+ break;
+ case AF_INET6:
newpeer->conf.remote_masklen = 128;
+ break;
}
newpeer->conf.template = 0;
newpeer->conf.cloned = 1;
newpeer->state = newpeer->prev_state = STATE_NONE;
- newpeer->conf.reconf_action = RECONF_REINIT;
+ newpeer->conf.reconf_action = RECONF_KEEP;
newpeer->rbuf = NULL;
init_peer(newpeer);
bgp_fsm(newpeer, EVNT_START);
@@ -2680,40 +2743,24 @@ getpeerbyip(struct sockaddr *ip)
}
int
-session_match_mask(struct peer *p, struct sockaddr *ip)
+session_match_mask(struct peer *p, struct bgpd_addr *a)
{
- int i;
in_addr_t v4mask;
- struct in6_addr *in;
- struct in6_addr mask;
+ struct in6_addr masked;
- if (p->conf.remote_addr.af == AF_INET) {
+ switch (p->conf.remote_addr.aid) {
+ case AID_INET:
v4mask = htonl(prefixlen2mask(p->conf.remote_masklen));
- if (p->conf.remote_addr.v4.s_addr ==
- ((((struct sockaddr_in *)ip)->sin_addr.s_addr) & v4mask))
+ if (p->conf.remote_addr.v4.s_addr == (a->v4.s_addr & v4mask))
return (1);
- else
- return (0);
- }
-
- if (p->conf.remote_addr.af == AF_INET6) {
- bzero(&mask, sizeof(mask));
- for (i = 0; i < p->conf.remote_masklen / 8; i++)
- mask.s6_addr[i] = 0xff;
- i = p->conf.remote_masklen % 8;
- if (i)
- mask.s6_addr[p->conf.remote_masklen / 8] = 0xff00 >> i;
-
- in = &((struct sockaddr_in6 *)ip)->sin6_addr;
-
- for (i = 0; i < 16; i++)
- if ((in->s6_addr[i] & mask.s6_addr[i]) !=
- p->conf.remote_addr.addr8[i])
- return (0);
+ return (0);
+ case AID_INET6:
+ inet6applymask(&masked, &a->v6, p->conf.remote_masklen);
- return (1);
+ if (!memcmp(&masked, &p->conf.remote_addr.v6, sizeof(masked)))
+ return (1);
+ return (0);
}
-
return (0);
}
@@ -2733,6 +2780,7 @@ getpeerbyid(u_int32_t peerid)
void
session_down(struct peer *peer)
{
+ bzero(&peer->capa.neg, sizeof(peer->capa.neg));
peer->stats.last_updown = time(NULL);
if (imsg_compose(ibuf_rde, IMSG_SESSION_DOWN, peer->conf.id, 0, -1,
NULL, 0) == -1)
@@ -2748,35 +2796,12 @@ session_up(struct peer *p)
&p->conf, sizeof(p->conf)) == -1)
fatalx("imsg_compose error");
- switch (p->sa_local.ss_family) {
- case AF_INET:
- sup.local_addr.af = AF_INET;
- memcpy(&sup.local_addr.v4,
- &((struct sockaddr_in *)&p->sa_local)->sin_addr,
- sizeof(sup.local_addr.v4));
- sup.remote_addr.af = AF_INET;
- memcpy(&sup.remote_addr.v4,
- &((struct sockaddr_in *)&p->sa_remote)->sin_addr,
- sizeof(sup.remote_addr.v4));
- break;
- case AF_INET6:
- sup.local_addr.af = AF_INET6;
- memcpy(&sup.local_addr.v6,
- &((struct sockaddr_in6 *)&p->sa_local)->sin6_addr,
- sizeof(sup.local_addr.v6));
- sup.remote_addr.af = AF_INET6;
- memcpy(&sup.remote_addr.v6,
- &((struct sockaddr_in6 *)&p->sa_remote)->sin6_addr,
- sizeof(sup.remote_addr.v6));
- break;
- default:
- fatalx("session_up: unsupported address family");
- }
+ sa2addr((struct sockaddr *)&p->sa_local, &sup.local_addr);
+ sa2addr((struct sockaddr *)&p->sa_remote, &sup.remote_addr);
sup.remote_bgpid = p->remote_bgpid;
sup.short_as = p->short_as;
- memcpy(&sup.capa_announced, &p->capa.ann, sizeof(sup.capa_announced));
- memcpy(&sup.capa_received, &p->capa.peer, sizeof(sup.capa_received));
+ memcpy(&sup.capa, &p->capa.neg, sizeof(sup.capa));
p->stats.last_updown = time(NULL);
if (imsg_compose(ibuf_rde, IMSG_SESSION_UP, p->conf.id, 0, -1,
&sup, sizeof(sup)) == -1)
@@ -2784,9 +2809,10 @@ session_up(struct peer *p)
}
int
-imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
+imsg_compose_parent(int type, u_int32_t peerid, pid_t pid, void *data,
+ u_int16_t datalen)
{
- return (imsg_compose(ibuf_main, type, 0, pid, -1, data, datalen));
+ return (imsg_compose(ibuf_main, type, peerid, pid, -1, data, datalen));
}
int
@@ -2795,34 +2821,6 @@ imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
return (imsg_compose(ibuf_rde, type, 0, pid, -1, data, datalen));
}
-static struct sockaddr *
-addr2sa(struct bgpd_addr *addr, u_int16_t port)
-{
- static struct sockaddr_storage ss;
- struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
- struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
-
- bzero(&ss, sizeof(ss));
- switch (addr->af) {
- case AF_INET:
- sa_in->sin_family = AF_INET;
- sa_in->sin_len = sizeof(struct sockaddr_in);
- sa_in->sin_addr.s_addr = addr->v4.s_addr;
- sa_in->sin_port = htons(port);
- break;
- case AF_INET6:
- sa_in6->sin6_family = AF_INET6;
- sa_in6->sin6_len = sizeof(struct sockaddr_in6);
- memcpy(&sa_in6->sin6_addr, &addr->v6,
- sizeof(sa_in6->sin6_addr));
- sa_in6->sin6_port = htons(port);
- sa_in6->sin6_scope_id = addr->scope_id;
- break;
- }
-
- return ((struct sockaddr *)&ss);
-}
-
void
session_demote(struct peer *p, int level)
{
@@ -2837,3 +2835,19 @@ session_demote(struct peer *p, int level)
p->demoted += level;
}
+
+void
+session_stop(struct peer *peer, u_int8_t subcode)
+{
+ switch (peer->state) {
+ case STATE_OPENSENT:
+ case STATE_OPENCONFIRM:
+ case STATE_ESTABLISHED:
+ session_notification(peer, ERR_CEASE, subcode, NULL, 0);
+ break;
+ default:
+ /* session not open, no need to send notification */
+ break;
+ }
+ bgp_fsm(peer, EVNT_STOP);
+}
diff --git a/bgpd/session.h b/bgpd/session.h
index 9c33239..2bfa138 100644
--- a/bgpd/session.h
+++ b/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.101 2009/06/05 20:26:38 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.111 2010/12/09 13:50:41 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -94,6 +94,13 @@ enum suberr_open {
ERR_OPEN_CAPA
};
+enum suberr_fsm {
+ ERR_FSM_UNSPECIFIC = 0,
+ ERR_FSM_UNEX_OPENSENT,
+ ERR_FSM_UNEX_OPENCONFIRM,
+ ERR_FSM_UNEX_ESTABLISHED
+};
+
enum opt_params {
OPT_PARAM_NONE,
OPT_PARAM_AUTH,
@@ -109,7 +116,7 @@ enum capa_codes {
};
struct bgp_msg {
- struct buf *buf;
+ struct ibuf *buf;
enum msg_type type;
u_int16_t len;
};
@@ -189,6 +196,7 @@ struct peer {
struct {
struct capabilities ann;
struct capabilities peer;
+ struct capabilities neg;
} capa;
struct {
struct bgpd_addr local_addr;
@@ -201,7 +209,7 @@ struct peer {
struct sockaddr_storage sa_remote;
struct peer_timer_head timers;
struct msgbuf wbuf;
- struct buf_read *rbuf;
+ struct ibuf_read *rbuf;
struct peer *next;
int fd;
int lasterr;
@@ -217,7 +225,7 @@ struct peer {
u_int8_t passive;
};
-struct peer *peers;
+extern struct peer *peers;
struct ctl_timer {
enum Timer type;
@@ -226,38 +234,36 @@ struct ctl_timer {
/* session.c */
void session_socket_blockmode(int, enum blockmodes);
-pid_t session_main(struct bgpd_config *, struct peer *,
- struct network_head *, struct filter_head *,
- struct mrt_head *, struct rib_names *,
- int[2], int[2], int[2], int[2]);
+pid_t session_main(int[2], int[2], int[2], int[2]);
void bgp_fsm(struct peer *, enum session_events);
int session_neighbor_rrefresh(struct peer *p);
struct peer *getpeerbyaddr(struct bgpd_addr *);
struct peer *getpeerbydesc(const char *);
-int imsg_compose_parent(int, pid_t, void *, u_int16_t);
+int imsg_compose_parent(int, u_int32_t, pid_t, void *, u_int16_t);
int imsg_compose_rde(int, pid_t, void *, u_int16_t);
+void session_stop(struct peer *, u_int8_t);
/* log.c */
char *log_fmt_peer(const struct peer_config *);
void log_statechange(struct peer *, enum session_state,
enum session_events);
void log_notification(const struct peer *, u_int8_t, u_int8_t,
- u_char *, u_int16_t);
+ u_char *, u_int16_t, const char *);
void log_conn_attempt(const struct peer *, struct sockaddr *);
/* parse.y */
int parse_config(char *, struct bgpd_config *, struct mrt_head *,
- struct peer **, struct network_head *, struct filter_head *);
+ struct peer **, struct network_head *, struct filter_head *,
+ struct rdomain_head *);
/* config.c */
int merge_config(struct bgpd_config *, struct bgpd_config *,
struct peer *, struct listen_addrs *);
void prepare_listeners(struct bgpd_config *);
+int get_mpe_label(struct rdomain *);
/* rde.c */
-pid_t rde_main(struct bgpd_config *, struct peer *, struct network_head *,
- struct filter_head *, struct mrt_head *, struct rib_names *,
- int[2], int[2], int[2], int[2], int);
+pid_t rde_main(int[2], int[2], int[2], int[2], int);
/* control.c */
int control_init(int, char *);
@@ -267,6 +273,7 @@ int control_dispatch_msg(struct pollfd *, u_int *);
unsigned int control_accept(int, int);
/* pfkey.c */
+int pfkey_read(int, struct sadb_msg *);
int pfkey_establish(struct peer *);
int pfkey_remove(struct peer *);
int pfkey_init(struct bgpd_sysdep *);
@@ -274,7 +281,7 @@ int pfkey_init(struct bgpd_sysdep *);
/* printconf.c */
void print_config(struct bgpd_config *, struct rib_names *,
struct network_head *, struct peer *, struct filter_head *,
- struct mrt_head *);
+ struct mrt_head *, struct rdomain_head *);
/* carp.c */
int carp_demote_init(char *, int);
diff --git a/bgpd/timer.c b/bgpd/timer.c
index 41ccede..0aaba08 100644
--- a/bgpd/timer.c
+++ b/bgpd/timer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: timer.c,v 1.13 2009/01/21 20:32:53 henning Exp $ */
+/* $OpenBSD: timer.c,v 1.14 2010/10/24 17:20:08 deraadt Exp $ */
/*
* Copyright (c) 2003-2007 Henning Brauer <henning@openbsd.org>
@@ -43,7 +43,7 @@ timer_get(struct peer *p, enum Timer timer)
TAILQ_FOREACH(pt, &p->timers, entry)
if (pt->type == timer)
- break;
+ break;
return (pt);
}
diff --git a/bgpd/util.c b/bgpd/util.c
index b361b8c..7763458 100644
--- a/bgpd/util.c
+++ b/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.6 2009/06/12 16:42:53 claudio Exp $ */
+/* $OpenBSD: util.c,v 1.11 2010/03/29 09:04:43 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -18,6 +18,9 @@
*/
#include <sys/types.h>
#include <sys/socket.h>
+#if defined(__FreeBSD__) /* sys/limits.h */
+#include <sys/limits.h>
+#endif /* defined(__FreeBSD__) */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -28,15 +31,30 @@
#include "bgpd.h"
#include "rde.h"
+const char *aspath_delim(u_int8_t, int);
+
const char *
log_addr(const struct bgpd_addr *addr)
{
static char buf[48];
+ char tbuf[16];
- if (inet_ntop(addr->af, &addr->ba, buf, sizeof(buf)) == NULL)
- return ("?");
- else
+ switch (addr->aid) {
+ case AID_INET:
+ case AID_INET6:
+ if (inet_ntop(aid2af(addr->aid), &addr->ba, buf,
+ sizeof(buf)) == NULL)
+ return ("?");
+ return (buf);
+ case AID_VPN_IPv4:
+ if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf,
+ sizeof(tbuf)) == NULL)
+ return ("?");
+ snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd),
+ tbuf);
return (buf);
+ }
+ return ("???");
}
const char *
@@ -90,6 +108,96 @@ log_as(u_int32_t as)
return (buf);
}
+const char *
+log_rd(u_int64_t rd)
+{
+ static char buf[32];
+ struct in_addr addr;
+ u_int32_t u32;
+ u_int16_t u16;
+
+ rd = betoh64(rd);
+ switch (rd >> 48) {
+ case EXT_COMMUNITY_TWO_AS:
+ u32 = rd & 0xffffffff;
+ u16 = (rd >> 32) & 0xffff;
+ snprintf(buf, sizeof(buf), "rd %i:%i", u16, u32);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ u32 = (rd >> 16) & 0xffffffff;
+ u16 = rd & 0xffff;
+ snprintf(buf, sizeof(buf), "rd %s:%i", log_as(u32), u16);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ u32 = (rd >> 16) & 0xffffffff;
+ u16 = rd & 0xffff;
+ addr.s_addr = htonl(u32);
+ snprintf(buf, sizeof(buf), "rd %s:%i", inet_ntoa(addr), u16);
+ break;
+ default:
+ return ("rd ?");
+ }
+ return (buf);
+}
+
+/* NOTE: this function does not check if the type/subtype combo is
+ * actually valid. */
+const char *
+log_ext_subtype(u_int8_t subtype)
+{
+ static char etype[6];
+
+ switch (subtype) {
+ case EXT_COMMUNITY_ROUTE_TGT:
+ return ("rt"); /* route target */
+ case EXT_CUMMUNITY_ROUTE_ORIG:
+ return ("soo"); /* source of origin */
+ case EXT_COMMUNITY_OSPF_DOM_ID:
+ return ("odi"); /* ospf domain id */
+ case EXT_COMMUNITY_OSPF_RTR_TYPE:
+ return ("ort"); /* ospf route type */
+ case EXT_COMMUNITY_OSPF_RTR_ID:
+ return ("ori"); /* ospf router id */
+ case EXT_COMMUNITY_BGP_COLLECT:
+ return ("bdc"); /* bgp data collection */
+ default:
+ snprintf(etype, sizeof(etype), "[%u]", subtype);
+ return (etype);
+ }
+}
+
+const char *
+aspath_delim(u_int8_t seg_type, int closing)
+{
+ static char db[8];
+
+ switch (seg_type) {
+ case AS_SET:
+ if (!closing)
+ return ("{ ");
+ else
+ return (" }");
+ case AS_SEQUENCE:
+ return ("");
+ case AS_CONFED_SEQUENCE:
+ if (!closing)
+ return ("( ");
+ else
+ return (" )");
+ case AS_CONFED_SET:
+ if (!closing)
+ return ("[ ");
+ else
+ return (" ]");
+ default:
+ if (!closing)
+ snprintf(db, sizeof(db), "!%u ", seg_type);
+ else
+ snprintf(db, sizeof(db), " !%u", seg_type);
+ return (db);
+ }
+}
+
int
aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
{
@@ -118,16 +226,10 @@ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
seg_len = seg[1];
seg_size = 2 + sizeof(u_int32_t) * seg_len;
- if (seg_type == AS_SET) {
- if (total_size != 0)
- r = snprintf(buf, size, " { ");
- else
- r = snprintf(buf, size, "{ ");
- UPDATE();
- } else if (total_size != 0) {
- r = snprintf(buf, size, " ");
- UPDATE();
- }
+ r = snprintf(buf, size, "%s%s",
+ total_size != 0 ? " " : "",
+ aspath_delim(seg_type, 0));
+ UPDATE();
for (i = 0; i < seg_len; i++) {
r = snprintf(buf, size, "%s",
@@ -138,10 +240,8 @@ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
UPDATE();
}
}
- if (seg_type == AS_SET) {
- r = snprintf(buf, size, " }");
- UPDATE();
- }
+ r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
+ UPDATE();
}
/* ensure that we have a valid C-string especially for empty as path */
if (size > 0)
@@ -276,3 +376,115 @@ inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
for (i = 0; i < 16; i++)
dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
}
+
+/* address family translation functions */
+const struct aid aid_vals[AID_MAX] = AID_VALS;
+
+const char *
+aid2str(u_int8_t aid)
+{
+ if (aid < AID_MAX)
+ return (aid_vals[aid].name);
+ return ("unknown AID");
+}
+
+int
+aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
+{
+ if (aid < AID_MAX) {
+ *afi = aid_vals[aid].afi;
+ *safi = aid_vals[aid].safi;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid)
+{
+ u_int8_t i;
+
+ for (i = 0; i < AID_MAX; i++)
+ if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
+ *aid = i;
+ return (0);
+ }
+
+ return (-1);
+}
+
+sa_family_t
+aid2af(u_int8_t aid)
+{
+ if (aid < AID_MAX)
+ return (aid_vals[aid].af);
+ return (AF_UNSPEC);
+}
+
+int
+af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid)
+{
+ u_int8_t i;
+
+ if (safi == 0) /* default to unicast subclass */
+ safi = SAFI_UNICAST;
+
+ for (i = 0; i < AID_MAX; i++)
+ if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
+ *aid = i;
+ return (0);
+ }
+
+ return (-1);
+}
+
+struct sockaddr *
+addr2sa(struct bgpd_addr *addr, u_int16_t port)
+{
+ static struct sockaddr_storage ss;
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
+
+ if (addr->aid == AID_UNSPEC)
+ return (NULL);
+
+ bzero(&ss, sizeof(ss));
+ switch (addr->aid) {
+ case AID_INET:
+ sa_in->sin_family = AF_INET;
+ sa_in->sin_len = sizeof(struct sockaddr_in);
+ sa_in->sin_addr.s_addr = addr->v4.s_addr;
+ sa_in->sin_port = htons(port);
+ break;
+ case AID_INET6:
+ sa_in6->sin6_family = AF_INET6;
+ sa_in6->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&sa_in6->sin6_addr, &addr->v6,
+ sizeof(sa_in6->sin6_addr));
+ sa_in6->sin6_port = htons(port);
+ sa_in6->sin6_scope_id = addr->scope_id;
+ break;
+ }
+
+ return ((struct sockaddr *)&ss);
+}
+
+void
+sa2addr(struct sockaddr *sa, struct bgpd_addr *addr)
+{
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
+
+ bzero(addr, sizeof(*addr));
+ switch (sa->sa_family) {
+ case AF_INET:
+ addr->aid = AID_INET;
+ memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
+ break;
+ case AF_INET6:
+ addr->aid = AID_INET6;
+ memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
+ addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
+ break;
+ }
+}
diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c
new file mode 100644
index 0000000..134dbfb
--- /dev/null
+++ b/openbsd-compat/fmt_scaled.c
@@ -0,0 +1,268 @@
+/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * fmt_scaled: Format numbers scaled for human comprehension
+ * scan_scaled: Scan numbers in this format.
+ *
+ * "Human-readable" output uses 4 digits max, and puts a unit suffix at
+ * the end. Makes output compact and easy-to-read esp. on huge disks.
+ * Formatting code was originally in OpenBSD "df", converted to library routine.
+ * Scanning code written for OpenBSD libutil.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "util.h"
+
+typedef enum {
+ NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6
+} unit_type;
+
+/* These three arrays MUST be in sync! XXX make a struct */
+static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA };
+static char scale_chars[] = "BKMGTPE";
+static long long scale_factors[] = {
+ 1LL,
+ 1024LL,
+ 1024LL*1024,
+ 1024LL*1024*1024,
+ 1024LL*1024*1024*1024,
+ 1024LL*1024*1024*1024*1024,
+ 1024LL*1024*1024*1024*1024*1024,
+};
+#define SCALE_LENGTH (sizeof(units)/sizeof(units[0]))
+
+#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */
+
+/** Convert the given input string "scaled" into numeric in "result".
+ * Return 0 on success, -1 and errno set on error.
+ */
+int
+scan_scaled(char *scaled, long long *result)
+{
+ char *p = scaled;
+ int sign = 0;
+ unsigned int i, ndigits = 0, fract_digits = 0;
+ long long scale_fact = 1, whole = 0, fpart = 0;
+
+ /* Skip leading whitespace */
+ while (isascii(*p) && isspace(*p))
+ ++p;
+
+ /* Then at most one leading + or - */
+ while (*p == '-' || *p == '+') {
+ if (*p == '-') {
+ if (sign) {
+ errno = EINVAL;
+ return -1;
+ }
+ sign = -1;
+ ++p;
+ } else if (*p == '+') {
+ if (sign) {
+ errno = EINVAL;
+ return -1;
+ }
+ sign = +1;
+ ++p;
+ }
+ }
+
+ /* Main loop: Scan digits, find decimal point, if present.
+ * We don't allow exponentials, so no scientific notation
+ * (but note that E for Exa might look like e to some!).
+ * Advance 'p' to end, to get scale factor.
+ */
+ for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) {
+ if (*p == '.') {
+ if (fract_digits > 0) { /* oops, more than one '.' */
+ errno = EINVAL;
+ return -1;
+ }
+ fract_digits = 1;
+ continue;
+ }
+
+ i = (*p) - '0'; /* whew! finally a digit we can use */
+ if (fract_digits > 0) {
+ if (fract_digits >= MAX_DIGITS-1)
+ /* ignore extra fractional digits */
+ continue;
+ fract_digits++; /* for later scaling */
+ fpart *= 10;
+ fpart += i;
+ } else { /* normal digit */
+ if (++ndigits >= MAX_DIGITS) {
+ errno = ERANGE;
+ return -1;
+ }
+ whole *= 10;
+ whole += i;
+ }
+ }
+
+ if (sign) {
+ whole *= sign;
+ fpart *= sign;
+ }
+
+ /* If no scale factor given, we're done. fraction is discarded. */
+ if (!*p) {
+ *result = whole;
+ return 0;
+ }
+
+ /* Validate scale factor, and scale whole and fraction by it. */
+ for (i = 0; i < SCALE_LENGTH; i++) {
+
+ /** Are we there yet? */
+ if (*p == scale_chars[i] ||
+ *p == tolower(scale_chars[i])) {
+
+ /* If it ends with alphanumerics after the scale char, bad. */
+ if (isalnum(*(p+1))) {
+ errno = EINVAL;
+ return -1;
+ }
+ scale_fact = scale_factors[i];
+
+ /* scale whole part */
+ whole *= scale_fact;
+
+ /* truncate fpart so it does't overflow.
+ * then scale fractional part.
+ */
+ while (fpart >= LLONG_MAX / scale_fact) {
+ fpart /= 10;
+ fract_digits--;
+ }
+ fpart *= scale_fact;
+ if (fract_digits > 0) {
+ for (i = 0; i < fract_digits -1; i++)
+ fpart /= 10;
+ }
+ whole += fpart;
+ *result = whole;
+ return 0;
+ }
+ }
+ errno = ERANGE;
+ return -1;
+}
+
+/* Format the given "number" into human-readable form in "result".
+ * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE.
+ * Return 0 on success, -1 and errno set if error.
+ */
+int
+fmt_scaled(long long number, char *result)
+{
+ long long abval, fract = 0;
+ unsigned int i;
+ unit_type unit = NONE;
+
+ abval = (number < 0LL) ? -number : number; /* no long long_abs yet */
+
+ /* Not every negative long long has a positive representation.
+ * Also check for numbers that are just too darned big to format
+ */
+ if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ /* scale whole part; get unscaled fraction */
+ for (i = 0; i < SCALE_LENGTH; i++) {
+ if (abval/1024 < scale_factors[i]) {
+ unit = units[i];
+ fract = (i == 0) ? 0 : abval % scale_factors[i];
+ number /= scale_factors[i];
+ if (i > 0)
+ fract /= scale_factors[i - 1];
+ break;
+ }
+ }
+
+ fract = (10 * fract + 512) / 1024;
+ /* if the result would be >= 10, round main number */
+ if (fract == 10) {
+ if (number >= 0)
+ number++;
+ else
+ number--;
+ fract = 0;
+ }
+
+ if (number == 0)
+ strlcpy(result, "0B", FMT_SCALED_STRSIZE);
+ else if (unit == NONE || number >= 100 || number <= -100) {
+ if (fract >= 5) {
+ if (number >= 0)
+ number++;
+ else
+ number--;
+ }
+ (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c",
+ number, scale_chars[unit]);
+ } else
+ (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c",
+ number, fract, scale_chars[unit]);
+
+ return 0;
+}
+
+#ifdef MAIN
+/*
+ * This is the original version of the program in the man page.
+ * Copy-and-paste whatever you need from it.
+ */
+int
+main(int argc, char **argv)
+{
+ char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE];
+ long long ninput = 10483892, result;
+
+ if (scan_scaled(cinput, &result) == 0)
+ printf("\"%s\" -> %lld\n", cinput, result);
+ else
+ perror(cinput);
+
+ if (fmt_scaled(ninput, buf) == 0)
+ printf("%lld -> \"%s\"\n", ninput, buf);
+ else
+ fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno));
+
+ return 0;
+}
+#endif
diff --git a/openbsd-compat/hash.h b/openbsd-compat/hash.h
new file mode 100644
index 0000000..2f0283f
--- /dev/null
+++ b/openbsd-compat/hash.h
@@ -0,0 +1,127 @@
+/* $OpenBSD: hash.h,v 1.4 2004/05/25 18:37:23 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001 Tobias Weingartner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_HASH_H_
+#define _SYS_HASH_H_
+#include <sys/types.h>
+
+/*
+ * Note: SMALL_KERNEL might be used to shrink these, right now I
+ * do not see the point, as my kernel did not grow appreciably when
+ * I switched to these from other inline code. This may have to be
+ * revisited when/if these functions become more prevalent in the
+ * kernel.
+ */
+
+/* Convenience */
+#ifndef HASHINIT
+#define HASHINIT 5381
+#define HASHSTEP(x,c) (((x << 5) + x) + (c))
+#endif
+
+/*
+ * Return a 32-bit hash of the given buffer. The init
+ * value should be 0, or the previous hash value to extend
+ * the previous hash.
+ */
+static __inline uint32_t
+hash32_buf(const void *buf, size_t len, uint32_t hash)
+{
+ const unsigned char *p = buf;
+
+ while (len--)
+ hash = HASHSTEP(hash, *p++);
+
+ return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string.
+ */
+static __inline uint32_t
+hash32_str(const void *buf, uint32_t hash)
+{
+ const unsigned char *p = buf;
+
+ while (*p)
+ hash = HASHSTEP(hash, *p++);
+
+ return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string, limited by N.
+ */
+static __inline uint32_t
+hash32_strn(const void *buf, size_t len, uint32_t hash)
+{
+ const unsigned char *p = buf;
+
+ while (*p && len--)
+ hash = HASHSTEP(hash, *p++);
+
+ return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string terminated by C,
+ * (as well as 0). This is mainly here as a helper for the
+ * namei() hashing of path name parts.
+ */
+static __inline uint32_t
+hash32_stre(const void *buf, int end, char **ep, uint32_t hash)
+{
+ const unsigned char *p = buf;
+
+ while (*p && (*p != end))
+ hash = HASHSTEP(hash, *p++);
+
+ if (ep)
+ *ep = (char *)p;
+
+ return hash;
+}
+
+/*
+ * Return a 32-bit hash of the given string, limited by N,
+ * and terminated by C (as well as 0). This is mainly here
+ * as a helper for the namei() hashing of path name parts.
+ */
+static __inline uint32_t
+hash32_strne(const void *buf, size_t len, int end, char **ep, uint32_t hash)
+{
+ const unsigned char *p = buf;
+
+ while (*p && (*p != end) && len--)
+ hash = HASHSTEP(hash, *p++);
+
+ if (ep)
+ *ep = (char *)p;
+
+ return hash;
+}
+#endif /* !_SYS_HASH_H_ */
diff --git a/openbsd-compat/if_media.h b/openbsd-compat/if_media.h
new file mode 100644
index 0000000..8bc0d12
--- /dev/null
+++ b/openbsd-compat/if_media.h
@@ -0,0 +1,612 @@
+/* $OpenBSD: if_media.h,v 1.17 2004/11/02 02:12:16 reyk Exp $ */
+/* $NetBSD: if_media.h,v 1.22 2000/02/17 21:53:16 sommerfeld Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997
+ * Jonathan Stone and Jason R. Thorpe. All rights reserved.
+ *
+ * This software is derived from information provided by Matt Thomas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jonathan Stone
+ * and Jason R. Thorpe for the NetBSD Project.
+ * 4. The names of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NET_IF_MEDIA_H_
+#define _NET_IF_MEDIA_H_
+
+/*
+ * Prototypes and definitions for BSD/OS-compatible network interface
+ * media selection.
+ *
+ * Where it is safe to do so, this code strays slightly from the BSD/OS
+ * design. Software which uses the API (device drivers, basically)
+ * shouldn't notice any difference.
+ *
+ * Many thanks to Matt Thomas for providing the information necessary
+ * to implement this interface.
+ */
+
+#ifdef _KERNEL
+
+#include <sys/queue.h>
+
+/*
+ * Driver callbacks for media status and change requests.
+ */
+typedef int (*ifm_change_cb_t)(struct ifnet *ifp);
+typedef void (*ifm_stat_cb_t)(struct ifnet *ifp, struct ifmediareq *req);
+
+/*
+ * In-kernel representation of a single supported media type.
+ */
+struct ifmedia_entry {
+ TAILQ_ENTRY(ifmedia_entry) ifm_list;
+ int ifm_media; /* description of this media attachment */
+ int ifm_data; /* for driver-specific use */
+ void *ifm_aux; /* for driver-specific use */
+};
+
+/*
+ * One of these goes into a network interface's softc structure.
+ * It is used to keep general media state.
+ */
+struct ifmedia {
+ int ifm_mask; /* mask of changes we don't care about */
+ int ifm_media; /* current user-set media word */
+ struct ifmedia_entry *ifm_cur; /* currently selected media */
+ TAILQ_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */
+ ifm_change_cb_t ifm_change; /* media change driver callback */
+ ifm_stat_cb_t ifm_status; /* media status driver callback */
+};
+
+/* Initialize an interface's struct if_media field. */
+void ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
+ ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback);
+
+/* Add one supported medium to a struct ifmedia. */
+void ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux);
+
+/* Add an array (of ifmedia_entry) media to a struct ifmedia. */
+void ifmedia_list_add(struct ifmedia *mp, struct ifmedia_entry *lp,
+ int count);
+
+/* Set default media type on initialization. */
+void ifmedia_set(struct ifmedia *ifm, int mword);
+
+/* Common ioctl function for getting/setting media, called by driver. */
+int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
+ struct ifmedia *ifm, u_long cmd);
+
+/* Locate a media entry */
+struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm,
+ int flags, int mask);
+
+/* Delete all media for a given media instance */
+void ifmedia_delete_instance(struct ifmedia *, int);
+
+/* Compute baudrate for a given media. */
+int ifmedia_baudrate(int);
+#endif /*_KERNEL */
+
+/*
+ * if_media Options word:
+ * Bits Use
+ * ---- -------
+ * 0-4 Media subtype MAX SUBTYPE == 31!
+ * 5-7 Media type
+ * 8-15 Type specific options
+ * 16-19 RFU
+ * 20-27 Shared (global) options
+ * 28-31 Instance
+ */
+
+/*
+ * Ethernet
+ */
+#define IFM_ETHER 0x00000020
+#define IFM_10_T 3 /* 10BaseT - RJ45 */
+#define IFM_10_2 4 /* 10Base2 - Thinnet */
+#define IFM_10_5 5 /* 10Base5 - AUI */
+#define IFM_100_TX 6 /* 100BaseTX - RJ45 */
+#define IFM_100_FX 7 /* 100BaseFX - Fiber */
+#define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */
+#define IFM_100_VG 9 /* 100VG-AnyLAN */
+#define IFM_100_T2 10 /* 100BaseT2 */
+#define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */
+#define IFM_10_STP 12 /* 10BaseT over shielded TP */
+#define IFM_10_FL 13 /* 10BaseFL - Fiber */
+#define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */
+#define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */
+#define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */
+#define IFM_1000_TX IFM_1000_T /* for backwards compatibility */
+#define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */
+
+#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */
+
+/*
+ * Token ring
+ */
+#define IFM_TOKEN 0x00000040
+#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */
+#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */
+#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */
+#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */
+#define IFM_TOK_ETR 0x00000200 /* Early token release */
+#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */
+#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */
+
+/*
+ * FDDI
+ */
+#define IFM_FDDI 0x00000060
+#define IFM_FDDI_SMF 3 /* Single-mode fiber */
+#define IFM_FDDI_MMF 4 /* Multi-mode fiber */
+#define IFM_FDDI_UTP 5 /* CDDI / UTP */
+#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */
+
+/*
+ * IEEE 802.11 Wireless
+ */
+#define IFM_IEEE80211 0x00000080
+#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */
+#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */
+#define IFM_IEEE80211_DS2 5 /* Direct Sequence 2Mbps */
+#define IFM_IEEE80211_DS5 6 /* Direct Sequence 5Mbps*/
+#define IFM_IEEE80211_DS11 7 /* Direct Sequence 11Mbps*/
+#define IFM_IEEE80211_DS1 8 /* Direct Sequence 1Mbps*/
+#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */
+#define IFM_IEEE80211_OFDM6 10 /* OFDM 6Mbps */
+#define IFM_IEEE80211_OFDM9 11 /* OFDM 9Mbps */
+#define IFM_IEEE80211_OFDM12 12 /* OFDM 12Mbps */
+#define IFM_IEEE80211_OFDM18 13 /* OFDM 18Mbps */
+#define IFM_IEEE80211_OFDM24 14 /* OFDM 24Mbps */
+#define IFM_IEEE80211_OFDM36 15 /* OFDM 36Mbps */
+#define IFM_IEEE80211_OFDM48 16 /* OFDM 48Mbps */
+#define IFM_IEEE80211_OFDM54 17 /* OFDM 54Mbps */
+#define IFM_IEEE80211_OFDM72 18 /* OFDM 72Mbps */
+
+#define IFM_IEEE80211_ADHOC 0x100 /* Operate in Adhoc mode */
+#define IFM_IEEE80211_HOSTAP 0x200 /* Operate in Host AP mode */
+#define IFM_IEEE80211_IBSS 0x400 /* Operate in IBSS mode */
+#define IFM_IEEE80211_IBSSMASTER 0x800 /* Operate as an IBSS master */
+#define IFM_IEEE80211_MONITOR 0x1000 /* Operate in Monitor mode */
+#define IFM_IEEE80211_TURBO 0x2000 /* Operate in Turbo mode */
+
+/* operating mode for multi-mode devices */
+#define IFM_IEEE80211_11A 0x00010000 /* 5Ghz, OFDM mode */
+#define IFM_IEEE80211_11B 0x00020000 /* Direct Sequence mode */
+#define IFM_IEEE80211_11G 0x00030000 /* 2Ghz, CCK mode */
+#define IFM_IEEE80211_FH 0x00040000 /* 2Ghz, GFSK mode */
+
+/*
+ * Digitally multiplexed "Carrier" Serial Interfaces
+ */
+#define IFM_TDM 0x000000a0
+#define IFM_TDM_T1 3 /* T1 B8ZS+ESF 24 ts */
+#define IFM_TDM_T1_AMI 4 /* T1 AMI+SF 24 ts */
+#define IFM_TDM_E1 5 /* E1 HDB3+G.703 clearchannel 32 ts */
+#define IFM_TDM_E1_G704 6 /* E1 HDB3+G.703+G.704 channelized 31 ts */
+#define IFM_TDM_E1_AMI 7 /* E1 AMI+G.703 32 ts */
+#define IFM_TDM_E1_AMI_G704 8 /* E1 AMI+G.703+G.704 31 ts */
+#define IFM_TDM_T3 9 /* T3 B3ZS+C-bit 672 ts */
+#define IFM_TDM_T3_M13 10 /* T3 B3ZS+M13 672 ts */
+#define IFM_TDM_E3 11 /* E3 HDB3+G.751 512? ts */
+#define IFM_TDM_E3_G751 12 /* E3 G.751 512 ts */
+#define IFM_TDM_E3_G832 13 /* E3 G.832 512 ts */
+/*
+ * 6 major ways that networks talk: Drivers enforce independent selection,
+ * meaning, a driver will ensure that only one of these is set at a time.
+ */
+#define IFM_TDM_HDLC_CRC16 0x0100 /* Use 16-bit CRC for HDLC instead */
+#define IFM_TDM_PPP 0x0200 /* SPPP (dumb) */
+#define IFM_TDM_FR_ANSI 0x0400 /* Frame Relay + LMI ANSI "Annex D" */
+#define IFM_TDM_FR_CISCO 0x0800 /* Frame Relay + LMI Cisco */
+#define IFM_TDM_FR_ITU 0x1000 /* Frame Relay + LMI ITU "Q933A" */
+
+/*
+ * Common Access Redundancy Protocol
+ */
+#define IFM_CARP 0x000000c0
+
+/*
+ * Shared media sub-types
+ */
+#define IFM_AUTO 0 /* Autoselect best media */
+#define IFM_MANUAL 1 /* Jumper/dipswitch selects media */
+#define IFM_NONE 2 /* Deselect all media */
+
+/*
+ * Shared options
+ */
+#define IFM_FDX 0x00100000 /* Force full duplex */
+#define IFM_HDX 0x00200000 /* Force half duplex */
+#define IFM_FLOW 0x00400000 /* enable hardware flow control */
+#define IFM_FLAG0 0x01000000 /* Driver defined flag */
+#define IFM_FLAG1 0x02000000 /* Driver defined flag */
+#define IFM_FLAG2 0x04000000 /* Driver defined flag */
+#define IFM_LOOP 0x08000000 /* Put hardware in loopback */
+
+/*
+ * Masks
+ */
+#define IFM_NMASK 0x000000e0 /* Network type */
+#define IFM_TMASK 0x0000001f /* Media sub-type */
+#define IFM_IMASK 0xf0000000 /* Instance */
+#define IFM_ISHIFT 28 /* Instance shift */
+#define IFM_OMASK 0x0000ff00 /* Type specific options */
+#define IFM_MMASK 0x00070000 /* Mode */
+#define IFM_MSHIFT 16 /* Mode shift */
+#define IFM_GMASK 0x0ff00000 /* Global options */
+
+#define IFM_NMIN IFM_ETHER /* lowest Network type */
+#define IFM_NMAX IFM_NMASK /* highest Network type */
+
+/*
+ * Status bits
+ */
+#define IFM_AVALID 0x00000001 /* Active bit valid */
+#define IFM_ACTIVE 0x00000002 /* Interface attached to working net */
+
+/* Mask of "status valid" bits, for ifconfig(8). */
+#define IFM_STATUS_VALID IFM_AVALID
+
+/* List of "status valid" bits, for ifconfig(8). */
+#define IFM_STATUS_VALID_LIST { \
+ IFM_AVALID, \
+ 0 \
+}
+
+/*
+ * Macros to extract various bits of information from the media word.
+ */
+#define IFM_TYPE(x) ((x) & IFM_NMASK)
+#define IFM_SUBTYPE(x) ((x) & IFM_TMASK)
+#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT)
+#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK))
+#define IFM_MODE(x) ((x) & IFM_MMASK)
+
+#define IFM_INST_MAX IFM_INST(IFM_IMASK)
+#define IFM_INST_ANY (-1)
+
+/*
+ * Macro to create a media word.
+ */
+#define IFM_MAKEWORD(type, subtype, options, instance) \
+ ((type) | (subtype) | (options) | ((instance) << IFM_ISHIFT))
+#define IFM_MAKEMODE(mode) \
+ (((mode) << IFM_MSHIFT) & IFM_MMASK)
+/*
+ * NetBSD extension not defined in the BSDI API. This is used in various
+ * places to get the canonical description for a given type/subtype.
+ *
+ * In the subtype and mediaopt descriptions, the valid TYPE bits are OR'd
+ * in to indicate which TYPE the subtype/option corresponds to. If no
+ * TYPE is present, it is a shared media/mediaopt.
+ *
+ * Note that these are parsed case-insensitive.
+ *
+ * Order is important. The first matching entry is the canonical name
+ * for a media type; subsequent matches are aliases.
+ */
+struct ifmedia_description {
+ int ifmt_word; /* word value; may be masked */
+ const char *ifmt_string; /* description */
+};
+
+#define IFM_TYPE_DESCRIPTIONS { \
+ { IFM_ETHER, "Ethernet" }, \
+ { IFM_ETHER, "ether" }, \
+ { IFM_TOKEN, "TokenRing" }, \
+ { IFM_TOKEN, "token" }, \
+ { IFM_FDDI, "FDDI" }, \
+ { IFM_IEEE80211, "IEEE802.11" }, \
+ { IFM_TDM, "TDM" }, \
+ { IFM_CARP, "CARP" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_TYPE_MATCH(dt, t) \
+ (IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t)))
+
+#define IFM_SUBTYPE_DESCRIPTIONS { \
+ { IFM_AUTO, "autoselect" }, \
+ { IFM_AUTO, "auto" }, \
+ { IFM_MANUAL, "manual" }, \
+ { IFM_NONE, "none" }, \
+ \
+ { IFM_ETHER|IFM_10_T, "10baseT" }, \
+ { IFM_ETHER|IFM_10_T, "10baseT/UTP" }, \
+ { IFM_ETHER|IFM_10_T, "UTP" }, \
+ { IFM_ETHER|IFM_10_T, "10UTP" }, \
+ { IFM_ETHER|IFM_10_2, "10base2" }, \
+ { IFM_ETHER|IFM_10_2, "10base2/BNC" }, \
+ { IFM_ETHER|IFM_10_2, "BNC" }, \
+ { IFM_ETHER|IFM_10_2, "10BNC" }, \
+ { IFM_ETHER|IFM_10_5, "10base5" }, \
+ { IFM_ETHER|IFM_10_5, "10base5/AUI" }, \
+ { IFM_ETHER|IFM_10_5, "AUI" }, \
+ { IFM_ETHER|IFM_10_5, "10AUI" }, \
+ { IFM_ETHER|IFM_100_TX, "100baseTX" }, \
+ { IFM_ETHER|IFM_100_TX, "100TX" }, \
+ { IFM_ETHER|IFM_100_FX, "100baseFX" }, \
+ { IFM_ETHER|IFM_100_FX, "100FX" }, \
+ { IFM_ETHER|IFM_100_T4, "100baseT4" }, \
+ { IFM_ETHER|IFM_100_T4, "100T4" }, \
+ { IFM_ETHER|IFM_100_VG, "100baseVG" }, \
+ { IFM_ETHER|IFM_100_VG, "100VG" }, \
+ { IFM_ETHER|IFM_100_T2, "100baseT2" }, \
+ { IFM_ETHER|IFM_100_T2, "100T2" }, \
+ { IFM_ETHER|IFM_1000_SX, "1000baseSX" }, \
+ { IFM_ETHER|IFM_1000_SX, "1000SX" }, \
+ { IFM_ETHER|IFM_10_STP, "10baseSTP" }, \
+ { IFM_ETHER|IFM_10_STP, "STP" }, \
+ { IFM_ETHER|IFM_10_STP, "10STP" }, \
+ { IFM_ETHER|IFM_10_FL, "10baseFL" }, \
+ { IFM_ETHER|IFM_10_FL, "FL" }, \
+ { IFM_ETHER|IFM_10_FL, "10FL" }, \
+ { IFM_ETHER|IFM_1000_LX, "1000baseLX" }, \
+ { IFM_ETHER|IFM_1000_LX, "1000LX" }, \
+ { IFM_ETHER|IFM_1000_CX, "1000baseCX" }, \
+ { IFM_ETHER|IFM_1000_CX, "1000CX" }, \
+ { IFM_ETHER|IFM_1000_T, "1000baseT" }, \
+ { IFM_ETHER|IFM_1000_T, "1000T" }, \
+ { IFM_ETHER|IFM_1000_T, "1000baseTX" }, \
+ { IFM_ETHER|IFM_1000_T, "1000TX" }, \
+ { IFM_ETHER|IFM_HPNA_1, "HomePNA1" }, \
+ { IFM_ETHER|IFM_HPNA_1, "HPNA1" }, \
+ \
+ { IFM_TOKEN|IFM_TOK_STP4, "DB9/4Mbit" }, \
+ { IFM_TOKEN|IFM_TOK_STP4, "4STP" }, \
+ { IFM_TOKEN|IFM_TOK_STP16, "DB9/16Mbit" }, \
+ { IFM_TOKEN|IFM_TOK_STP16, "16STP" }, \
+ { IFM_TOKEN|IFM_TOK_UTP4, "UTP/4Mbit" }, \
+ { IFM_TOKEN|IFM_TOK_UTP4, "4UTP" }, \
+ { IFM_TOKEN|IFM_TOK_UTP16, "UTP/16Mbit" }, \
+ { IFM_TOKEN|IFM_TOK_UTP16, "16UTP" }, \
+ \
+ { IFM_FDDI|IFM_FDDI_SMF, "Single-mode" }, \
+ { IFM_FDDI|IFM_FDDI_SMF, "SMF" }, \
+ { IFM_FDDI|IFM_FDDI_MMF, "Multi-mode" }, \
+ { IFM_FDDI|IFM_FDDI_MMF, "MMF" }, \
+ { IFM_FDDI|IFM_FDDI_UTP, "UTP" }, \
+ { IFM_FDDI|IFM_FDDI_UTP, "CDDI" }, \
+ \
+ { IFM_IEEE80211|IFM_IEEE80211_FH1, "FH1" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_FH2, "FH2" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS2, "DS2" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS5, "DS5" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS11, "DS11" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS1, "DS1" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS22, "DS22" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM6, "OFDM6" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM9, "OFDM9" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM12, "OFDM12" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM18, "OFDM18" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM24, "OFDM24" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM36, "OFDM36" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM48, "OFDM48" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM54, "OFDM54" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM72, "OFDM72" }, \
+ \
+ { IFM_TDM|IFM_TDM_T1, "t1" }, \
+ { IFM_TDM|IFM_TDM_T1_AMI, "t1-ami" }, \
+ { IFM_TDM|IFM_TDM_E1, "e1" }, \
+ { IFM_TDM|IFM_TDM_E1_G704, "e1-g.704" }, \
+ { IFM_TDM|IFM_TDM_E1_AMI, "e1-ami" }, \
+ { IFM_TDM|IFM_TDM_E1_AMI_G704, "e1-ami-g.704" }, \
+ { IFM_TDM|IFM_TDM_T3, "t3" }, \
+ { IFM_TDM|IFM_TDM_T3_M13, "t3-m13" }, \
+ { IFM_TDM|IFM_TDM_E3, "e3" }, \
+ { IFM_TDM|IFM_TDM_E3_G751, "e3-g.751" }, \
+ { IFM_TDM|IFM_TDM_E3_G832, "e3-g.832" }, \
+ \
+ { 0, NULL }, \
+}
+
+#define IFM_MODE_DESCRIPTIONS { \
+ { IFM_AUTO, "autoselect" }, \
+ { IFM_AUTO, "auto" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_11A, "11a" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_11B, "11b" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_11G, "11g" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_FH, "fh" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_OPTION_DESCRIPTIONS { \
+ { IFM_FDX, "full-duplex" }, \
+ { IFM_FDX, "fdx" }, \
+ { IFM_HDX, "half-duplex" }, \
+ { IFM_HDX, "hdx" }, \
+ { IFM_FLAG0, "flag0" }, \
+ { IFM_FLAG1, "flag1" }, \
+ { IFM_FLAG2, "flag2" }, \
+ { IFM_LOOP, "loopback" }, \
+ { IFM_LOOP, "hw-loopback"}, \
+ { IFM_LOOP, "loop" }, \
+ \
+ { IFM_ETHER|IFM_ETH_MASTER, "master" }, \
+ \
+ { IFM_TOKEN|IFM_TOK_ETR, "EarlyTokenRelease" }, \
+ { IFM_TOKEN|IFM_TOK_ETR, "ETR" }, \
+ { IFM_TOKEN|IFM_TOK_SRCRT, "SourceRouting" }, \
+ { IFM_TOKEN|IFM_TOK_SRCRT, "SRCRT" }, \
+ { IFM_TOKEN|IFM_TOK_ALLR, "AllRoutes" }, \
+ { IFM_TOKEN|IFM_TOK_ALLR, "ALLR" }, \
+ \
+ { IFM_FDDI|IFM_FDDI_DA, "dual-attach" }, \
+ { IFM_FDDI|IFM_FDDI_DA, "das" }, \
+ \
+ { IFM_IEEE80211|IFM_IEEE80211_ADHOC, "adhoc" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_HOSTAP, "hostap" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_IBSS, "ibss" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_MONITOR, "monitor" }, \
+ { IFM_IEEE80211|IFM_IEEE80211_TURBO, "turbo" }, \
+ \
+ { IFM_TDM|IFM_TDM_HDLC_CRC16, "hdlc-crc16" }, \
+ { IFM_TDM|IFM_TDM_PPP, "ppp" }, \
+ { IFM_TDM|IFM_TDM_FR_ANSI, "framerelay-ansi" }, \
+ { IFM_TDM|IFM_TDM_FR_CISCO, "framerelay-cisco" }, \
+ { IFM_TDM|IFM_TDM_FR_ANSI, "framerelay-itu" }, \
+ \
+ { 0, NULL }, \
+}
+
+/*
+ * Baudrate descriptions for the various media types.
+ */
+struct ifmedia_baudrate {
+ int ifmb_word; /* media word */
+ int ifmb_baudrate; /* corresponding baudrate */
+};
+
+#define IFM_BAUDRATE_DESCRIPTIONS { \
+ { IFM_ETHER|IFM_10_T, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_2, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_5, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_100_TX, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_FX, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_T4, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_VG, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_T2, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_1000_SX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_10_STP, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_FL, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_1000_LX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_1000_CX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_1000_T, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_HPNA_1, IF_Mbps(1) }, \
+ \
+ { IFM_TOKEN|IFM_TOK_STP4, IF_Mbps(4) }, \
+ { IFM_TOKEN|IFM_TOK_STP16, IF_Mbps(16) }, \
+ { IFM_TOKEN|IFM_TOK_UTP4, IF_Mbps(4) }, \
+ { IFM_TOKEN|IFM_TOK_UTP16, IF_Mbps(16) }, \
+ \
+ { IFM_FDDI|IFM_FDDI_SMF, IF_Mbps(100) }, \
+ { IFM_FDDI|IFM_FDDI_MMF, IF_Mbps(100) }, \
+ { IFM_FDDI|IFM_FDDI_UTP, IF_Mbps(100) }, \
+ \
+ { IFM_IEEE80211|IFM_IEEE80211_FH1, IF_Mbps(1) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_FH2, IF_Mbps(2) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS1, IF_Mbps(1) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS2, IF_Mbps(2) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS5, IF_Mbps(5) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS11, IF_Mbps(11) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS22, IF_Mbps(22) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM6, IF_Mbps(6) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM9, IF_Mbps(9) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM12, IF_Mbps(12) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM18, IF_Mbps(18) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM24, IF_Mbps(24) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM36, IF_Mbps(36) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM48, IF_Mbps(48) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM54, IF_Mbps(54) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM72, IF_Mbps(72) }, \
+ \
+ { IFM_TDM|IFM_TDM_T1, IF_Kbps(1536) }, \
+ { IFM_TDM|IFM_TDM_T1_AMI, IF_Kbps(1536) }, \
+ { IFM_TDM|IFM_TDM_E1, IF_Kbps(2048) }, \
+ { IFM_TDM|IFM_TDM_E1_G704, IF_Kbps(2048) }, \
+ { IFM_TDM|IFM_TDM_E1_AMI, IF_Kbps(2048) }, \
+ { IFM_TDM|IFM_TDM_E1_AMI_G704, IF_Kbps(2048) }, \
+ { IFM_TDM|IFM_TDM_T3, IF_Kbps(44736) }, \
+ { IFM_TDM|IFM_TDM_T3_M13, IF_Kbps(44736) }, \
+ { IFM_TDM|IFM_TDM_E3, IF_Kbps(34368) }, \
+ { IFM_TDM|IFM_TDM_E3_G751, IF_Kbps(34368) }, \
+ { IFM_TDM|IFM_TDM_E3_G832, IF_Kbps(34368) }, \
+ \
+ { 0, 0 }, \
+}
+
+/*
+ * Status bit descriptions for the various media types.
+ */
+struct ifmedia_status_description {
+ int ifms_type;
+ int ifms_valid;
+ int ifms_bit;
+ const char *ifms_string[2];
+};
+
+#define IFM_STATUS_DESC(ifms, bit) \
+ (ifms)->ifms_string[((ifms)->ifms_bit & (bit)) ? 1 : 0]
+
+#define IFM_STATUS_DESCRIPTIONS { \
+ { IFM_ETHER, IFM_AVALID, IFM_ACTIVE, \
+ { "no carrier", "active" } }, \
+ { IFM_FDDI, IFM_AVALID, IFM_ACTIVE, \
+ { "no ring", "inserted" } }, \
+ { IFM_TOKEN, IFM_AVALID, IFM_ACTIVE, \
+ { "no ring", "inserted" } }, \
+ { IFM_IEEE80211, IFM_AVALID, IFM_ACTIVE, \
+ { "no network", "active" } }, \
+ { IFM_TDM, IFM_AVALID, IFM_ACTIVE, \
+ { "no carrier", "active" } }, \
+ { IFM_CARP, IFM_AVALID, IFM_ACTIVE, \
+ { "backup", "master" } }, \
+ { 0, 0, 0, \
+ { NULL, NULL } } \
+}
+#endif /* _NET_IF_MEDIA_H_ */
diff --git a/openbsd-compat/imsg-buffer.c b/openbsd-compat/imsg-buffer.c
new file mode 100644
index 0000000..dec27ff
--- /dev/null
+++ b/openbsd-compat/imsg-buffer.c
@@ -0,0 +1,303 @@
+/* $OpenBSD: imsg-buffer.c,v 1.1 2010/05/26 16:44:32 nicm Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@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
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "imsg.h"
+
+int ibuf_realloc(struct ibuf *, size_t);
+void ibuf_enqueue(struct msgbuf *, struct ibuf *);
+void ibuf_dequeue(struct msgbuf *, struct ibuf *);
+
+struct ibuf *
+ibuf_open(size_t len)
+{
+ struct ibuf *buf;
+
+ if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
+ return (NULL);
+ if ((buf->buf = malloc(len)) == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ buf->size = buf->max = len;
+ buf->fd = -1;
+
+ return (buf);
+}
+
+struct ibuf *
+ibuf_dynamic(size_t len, size_t max)
+{
+ struct ibuf *buf;
+
+ if (max < len)
+ return (NULL);
+
+ if ((buf = ibuf_open(len)) == NULL)
+ return (NULL);
+
+ if (max > 0)
+ buf->max = max;
+
+ return (buf);
+}
+
+int
+ibuf_realloc(struct ibuf *buf, size_t len)
+{
+ u_char *b;
+
+ /* on static buffers max is eq size and so the following fails */
+ if (buf->wpos + len > buf->max) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ b = realloc(buf->buf, buf->wpos + len);
+ if (b == NULL)
+ return (-1);
+ buf->buf = b;
+ buf->size = buf->wpos + len;
+
+ return (0);
+}
+
+int
+ibuf_add(struct ibuf *buf, const void *data, size_t len)
+{
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (-1);
+
+ memcpy(buf->buf + buf->wpos, data, len);
+ buf->wpos += len;
+ return (0);
+}
+
+void *
+ibuf_reserve(struct ibuf *buf, size_t len)
+{
+ void *b;
+
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (NULL);
+
+ b = buf->buf + buf->wpos;
+ buf->wpos += len;
+ return (b);
+}
+
+void *
+ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
+{
+ /* only allowed to seek in already written parts */
+ if (pos + len > buf->wpos)
+ return (NULL);
+
+ return (buf->buf + pos);
+}
+
+size_t
+ibuf_size(struct ibuf *buf)
+{
+ return (buf->wpos);
+}
+
+size_t
+ibuf_left(struct ibuf *buf)
+{
+ return (buf->max - buf->wpos);
+}
+
+void
+ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ ibuf_enqueue(msgbuf, buf);
+}
+
+int
+ibuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+
+ bzero(&iov, sizeof(iov));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ }
+
+ if ((n = writev(msgbuf->fd, iov, i)) == -1) {
+ if (errno == EAGAIN || errno == ENOBUFS ||
+ errno == EINTR) /* try later */
+ return (0);
+ else
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (-2);
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (0);
+}
+
+void
+ibuf_free(struct ibuf *buf)
+{
+ free(buf->buf);
+ free(buf);
+}
+
+void
+msgbuf_init(struct msgbuf *msgbuf)
+{
+ msgbuf->queued = 0;
+ msgbuf->fd = -1;
+ TAILQ_INIT(&msgbuf->bufs);
+}
+
+void
+msgbuf_drain(struct msgbuf *msgbuf, size_t n)
+{
+ struct ibuf *buf, *next;
+
+ for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
+ buf = next) {
+ next = TAILQ_NEXT(buf, entry);
+ if (buf->rpos + n >= buf->wpos) {
+ n -= buf->wpos - buf->rpos;
+ ibuf_dequeue(msgbuf, buf);
+ } else {
+ buf->rpos += n;
+ n = 0;
+ }
+ }
+}
+
+void
+msgbuf_clear(struct msgbuf *msgbuf)
+{
+ struct ibuf *buf;
+
+ while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
+ ibuf_dequeue(msgbuf, buf);
+}
+
+int
+msgbuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+ } cmsgbuf;
+
+ bzero(&iov, sizeof(iov));
+ bzero(&msg, sizeof(msg));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ if (buf->fd != -1)
+ break;
+ }
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = i;
+
+ if (buf != NULL && buf->fd != -1) {
+ msg.msg_control = (caddr_t)&cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = buf->fd;
+ }
+
+ if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
+ if (errno == EAGAIN || errno == ENOBUFS ||
+ errno == EINTR) /* try later */
+ return (0);
+ else
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (-2);
+ }
+
+ /*
+ * assumption: fd got sent if sendmsg sent anything
+ * this works because fds are passed one at a time
+ */
+ if (buf != NULL && buf->fd != -1) {
+ close(buf->fd);
+ buf->fd = -1;
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (0);
+}
+
+void
+ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
+ msgbuf->queued++;
+}
+
+void
+ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
+
+ if (buf->fd != -1)
+ close(buf->fd);
+
+ msgbuf->queued--;
+ ibuf_free(buf);
+}
diff --git a/openbsd-compat/imsg.c b/openbsd-compat/imsg.c
new file mode 100644
index 0000000..a0be894
--- /dev/null
+++ b/openbsd-compat/imsg.c
@@ -0,0 +1,271 @@
+/* $OpenBSD: imsg.c,v 1.1 2010/05/26 16:44:32 nicm Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@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
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "imsg.h"
+
+int imsg_get_fd(struct imsgbuf *);
+
+void
+imsg_init(struct imsgbuf *ibuf, int fd)
+{
+ msgbuf_init(&ibuf->w);
+ bzero(&ibuf->r, sizeof(ibuf->r));
+ ibuf->fd = fd;
+ ibuf->w.fd = fd;
+ ibuf->pid = getpid();
+ TAILQ_INIT(&ibuf->fds);
+}
+
+ssize_t
+imsg_read(struct imsgbuf *ibuf)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int) * 16)];
+ } cmsgbuf;
+ struct iovec iov;
+ ssize_t n;
+ int fd;
+ struct imsg_fd *ifd;
+
+ bzero(&msg, sizeof(msg));
+
+ iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
+ iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+ if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ if (errno != EINTR && errno != EAGAIN) {
+ return (-1);
+ }
+ return (-2);
+ }
+
+ ibuf->r.wpos += n;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ fd = (*(int *)CMSG_DATA(cmsg));
+ if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
+ close(fd);
+ return (-1);
+ }
+ ifd->fd = fd;
+ TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry);
+ }
+ /* we do not handle other ctl data level */
+ }
+
+ return (n);
+}
+
+ssize_t
+imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
+{
+ size_t av, left, datalen;
+
+ av = ibuf->r.wpos;
+
+ if (IMSG_HEADER_SIZE > av)
+ return (0);
+
+ memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
+ if (imsg->hdr.len < IMSG_HEADER_SIZE ||
+ imsg->hdr.len > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (-1);
+ }
+ if (imsg->hdr.len > av)
+ return (0);
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
+ if ((imsg->data = malloc(datalen)) == NULL)
+ return (-1);
+
+ if (imsg->hdr.flags & IMSGF_HASFD)
+ imsg->fd = imsg_get_fd(ibuf);
+ else
+ imsg->fd = -1;
+
+ memcpy(imsg->data, ibuf->r.rptr, datalen);
+
+ if (imsg->hdr.len < av) {
+ left = av - imsg->hdr.len;
+ memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
+ ibuf->r.wpos = left;
+ } else
+ ibuf->r.wpos = 0;
+
+ return (datalen + IMSG_HEADER_SIZE);
+}
+
+int
+imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, int fd, void *data, u_int16_t datalen)
+{
+ struct ibuf *wbuf;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ if (imsg_add(wbuf, data, datalen) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+int
+imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, int fd, const struct iovec *iov, int iovcnt)
+{
+ struct ibuf *wbuf;
+ int i, datalen = 0;
+
+ for (i = 0; i < iovcnt; i++)
+ datalen += iov[i].iov_len;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ for (i = 0; i < iovcnt; i++)
+ if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+/* ARGSUSED */
+struct ibuf *
+imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
+ pid_t pid, u_int16_t datalen)
+{
+ struct ibuf *wbuf;
+ struct imsg_hdr hdr;
+
+ datalen += IMSG_HEADER_SIZE;
+ if (datalen > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (NULL);
+ }
+
+ hdr.type = type;
+ hdr.flags = 0;
+ hdr.peerid = peerid;
+ if ((hdr.pid = pid) == 0)
+ hdr.pid = ibuf->pid;
+ if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
+ return (NULL);
+ }
+ if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
+ return (NULL);
+
+ return (wbuf);
+}
+
+int
+imsg_add(struct ibuf *msg, void *data, u_int16_t datalen)
+{
+ if (datalen)
+ if (ibuf_add(msg, data, datalen) == -1) {
+ ibuf_free(msg);
+ return (-1);
+ }
+ return (datalen);
+}
+
+void
+imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
+{
+ struct imsg_hdr *hdr;
+
+ hdr = (struct imsg_hdr *)msg->buf;
+
+ hdr->flags &= ~IMSGF_HASFD;
+ if (msg->fd != -1)
+ hdr->flags |= IMSGF_HASFD;
+
+ hdr->len = (u_int16_t)msg->wpos;
+
+ ibuf_close(&ibuf->w, msg);
+}
+
+void
+imsg_free(struct imsg *imsg)
+{
+ free(imsg->data);
+}
+
+int
+imsg_get_fd(struct imsgbuf *ibuf)
+{
+ int fd;
+ struct imsg_fd *ifd;
+
+ if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
+ return (-1);
+
+ fd = ifd->fd;
+ TAILQ_REMOVE(&ibuf->fds, ifd, entry);
+ free(ifd);
+
+ return (fd);
+}
+
+int
+imsg_flush(struct imsgbuf *ibuf)
+{
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) < 0)
+ return (-1);
+ return (0);
+}
+
+void
+imsg_clear(struct imsgbuf *ibuf)
+{
+ int fd;
+
+ msgbuf_clear(&ibuf->w);
+ while ((fd = imsg_get_fd(ibuf)) != -1)
+ close(fd);
+}
diff --git a/openbsd-compat/imsg.h b/openbsd-compat/imsg.h
new file mode 100644
index 0000000..d691f7d
--- /dev/null
+++ b/openbsd-compat/imsg.h
@@ -0,0 +1,112 @@
+/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm Exp $ */
+
+/*
+ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@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
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IMSG_H_
+#define _IMSG_H_
+
+#define IBUF_READ_SIZE 65535
+#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
+#define MAX_IMSGSIZE 16384
+
+struct ibuf {
+ TAILQ_ENTRY(ibuf) entry;
+ u_char *buf;
+ size_t size;
+ size_t max;
+ size_t wpos;
+ size_t rpos;
+ int fd;
+};
+
+struct msgbuf {
+ TAILQ_HEAD(, ibuf) bufs;
+ u_int32_t queued;
+ int fd;
+};
+
+struct ibuf_read {
+ u_char buf[IBUF_READ_SIZE];
+ u_char *rptr;
+ size_t wpos;
+};
+
+struct imsg_fd {
+ TAILQ_ENTRY(imsg_fd) entry;
+ int fd;
+};
+
+struct imsgbuf {
+ TAILQ_HEAD(, imsg_fd) fds;
+ struct ibuf_read r;
+ struct msgbuf w;
+ int fd;
+ pid_t pid;
+};
+
+#define IMSGF_HASFD 1
+
+struct imsg_hdr {
+ u_int32_t type;
+ u_int16_t len;
+ u_int16_t flags;
+ u_int32_t peerid;
+ u_int32_t pid;
+};
+
+struct imsg {
+ struct imsg_hdr hdr;
+ int fd;
+ void *data;
+};
+
+
+/* buffer.c */
+struct ibuf *ibuf_open(size_t);
+struct ibuf *ibuf_dynamic(size_t, size_t);
+int ibuf_add(struct ibuf *, const void *, size_t);
+void *ibuf_reserve(struct ibuf *, size_t);
+void *ibuf_seek(struct ibuf *, size_t, size_t);
+size_t ibuf_size(struct ibuf *);
+size_t ibuf_left(struct ibuf *);
+void ibuf_close(struct msgbuf *, struct ibuf *);
+int ibuf_write(struct msgbuf *);
+void ibuf_free(struct ibuf *);
+void msgbuf_init(struct msgbuf *);
+void msgbuf_clear(struct msgbuf *);
+int msgbuf_write(struct msgbuf *);
+void msgbuf_drain(struct msgbuf *, size_t);
+
+/* imsg.c */
+void imsg_init(struct imsgbuf *, int);
+ssize_t imsg_read(struct imsgbuf *);
+ssize_t imsg_get(struct imsgbuf *, struct imsg *);
+int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ int, void *, u_int16_t);
+int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ int, const struct iovec *, int);
+struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ u_int16_t);
+int imsg_add(struct ibuf *, void *, u_int16_t);
+void imsg_close(struct imsgbuf *, struct ibuf *);
+void imsg_free(struct imsg *);
+int imsg_flush(struct imsgbuf *);
+void imsg_clear(struct imsgbuf *);
+
+#endif
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
new file mode 100644
index 0000000..79322d5
--- /dev/null
+++ b/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,87 @@
+/*
+ * $hrs: openbgpd/openbsd-compat/openbsd-compat.h,v 1.6 2011/07/03 04:46:38 hrs Exp $
+ */
+
+#ifndef _OPENBSD_COMPAT_H
+#define _OPENBSD_COMPAT_H
+
+#define __dead
+
+/* bgpctl/bgpctl.c */
+#include <sys/endian.h>
+#define betoh64(x) (be64toh(x))
+
+/* bgpd/irrfilter.c */
+typedef unsigned long ulong;
+
+/* bgpd/bgpd.c */
+#ifndef RTLABEL_LEN /* defined in net/pfvar.h */
+#define RTLABEL_LEN 32
+#endif
+#define RTA_LABEL 0
+
+#define SIMPLEQ_FOREACH STAILQ_FOREACH
+#define SIMPLEQ_FIRST STAILQ_FIRST
+#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD
+#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
+#define SIMPLEQ_ENTRY STAILQ_ENTRY
+#define SIMPLEQ_HEAD STAILQ_HEAD
+#define SIMPLEQ_INIT STAILQ_INIT
+#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER
+
+/* Routing priorities used by the different routing protocols */
+#define RTP_NONE 0 /* unset priority use sane default */
+#define RTP_CONNECTED 4 /* directly connected routes */
+#define RTP_STATIC 8 /* static routes base priority */
+#define RTP_OSPF 32 /* OSPF routes */
+#define RTP_ISIS 36 /* IS-IS routes */
+#define RTP_RIP 40 /* RIP routes */
+#define RTP_BGP 48 /* BGP routes */
+#define RTP_DEFAULT 56 /* routes that have nothing set */
+#define RTP_MAX 63 /* maximum priority */
+#define RTP_ANY 64 /* any of the above */
+#define RTP_MASK 0x7f
+#define RTP_DOWN 0x80 /* route/link is down */
+
+/* missing LINK_STATE_* macros in net/if.h */
+#define LINK_STATE_INVALID LINK_STATE_UNKNOWN /* link invalid */
+#define LINK_STATE_KALIVE_DOWN 7 /* keepalive reports down */
+#define LINK_STATE_HALF_DUPLEX 5 /* link is up and half duplex */
+#define LINK_STATE_FULL_DUPLEX 6 /* link is up and full duplex */
+
+/*
+ * Status bit descriptions for the various interface types.
+ */
+struct if_status_description {
+ unsigned char ifs_type;
+ unsigned char ifs_state;
+ const char *ifs_string;
+};
+
+#define LINK_STATE_DESC_MATCH(_ifs, _t, _s) \
+ (((_ifs)->ifs_type == (_t) || (_ifs)->ifs_type == 0) && \
+ (_ifs)->ifs_state == (_s))
+
+#define LINK_STATE_DESCRIPTIONS { \
+ { IFT_ETHER, LINK_STATE_DOWN, "no carrier" }, \
+ \
+ { IFT_IEEE80211, LINK_STATE_DOWN, "no network" }, \
+ \
+ { IFT_PPP, LINK_STATE_DOWN, "no carrier" }, \
+ \
+ { IFT_CARP, LINK_STATE_DOWN, "backup" }, \
+ { IFT_CARP, LINK_STATE_UP, "master" }, \
+ { IFT_CARP, LINK_STATE_HALF_DUPLEX, "master" }, \
+ { IFT_CARP, LINK_STATE_FULL_DUPLEX, "master" }, \
+ \
+ { 0, LINK_STATE_UP, "active" }, \
+ { 0, LINK_STATE_HALF_DUPLEX, "active" }, \
+ { 0, LINK_STATE_FULL_DUPLEX, "active" }, \
+ \
+/* { 0, LINK_STATE_UNKNOWN, "unknown" }, */ \
+ { 0, LINK_STATE_INVALID, "invalid" }, \
+ { 0, LINK_STATE_DOWN, "down" }, \
+ { 0, LINK_STATE_KALIVE_DOWN, "keepalive down" }, \
+ { 0, 0, NULL } \
+}
+#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/pfkey_compat.c b/openbsd-compat/pfkey_compat.c
new file mode 100644
index 0000000..b0d5907
--- /dev/null
+++ b/openbsd-compat/pfkey_compat.c
@@ -0,0 +1,32 @@
+#include "bgpd.h"
+#include "session.h"
+
+int
+pfkey_establish(struct peer *p)
+{
+ if (p->conf.auth.method)
+ return (-1);
+ return (0);
+}
+
+int
+pfkey_remove(struct peer *p)
+{
+ if (p->conf.auth.method)
+ return (-1);
+ return (0);
+}
+
+int
+pfkey_init(struct bgpd_sysdep *sysdep)
+{
+ log_warnx("no kernel support for PF_KEY");
+ sysdep->no_pfkey = 1;
+ return (-1);
+}
+
+int
+pfkey_read(int sd, struct sadb_msg *h)
+{
+ return (1);
+}
diff --git a/openbsd-compat/util.h b/openbsd-compat/util.h
new file mode 100644
index 0000000..aac35cf
--- /dev/null
+++ b/openbsd-compat/util.h
@@ -0,0 +1,119 @@
+/* $OpenBSD: util.h,v 1.27 2006/06/14 02:14:25 krw Exp $ */
+/* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1996, Jason Downs. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/*
+ * fparseln() specific operation flags.
+ */
+#define FPARSELN_UNESCESC 0x01
+#define FPARSELN_UNESCCONT 0x02
+#define FPARSELN_UNESCCOMM 0x04
+#define FPARSELN_UNESCREST 0x08
+#define FPARSELN_UNESCALL 0x0f
+
+/*
+ * opendev() specific operation flags.
+ */
+#define OPENDEV_PART 0x01 /* Try to open the raw partition. */
+#define OPENDEV_BLCK 0x04 /* Open block, not character device. */
+
+/*
+ * uucplock(3) specific flags.
+ */
+#define UU_LOCK_INUSE (1)
+#define UU_LOCK_OK (0)
+#define UU_LOCK_OPEN_ERR (-1)
+#define UU_LOCK_READ_ERR (-2)
+#define UU_LOCK_CREAT_ERR (-3)
+#define UU_LOCK_WRITE_ERR (-4)
+#define UU_LOCK_LINK_ERR (-5)
+#define UU_LOCK_TRY_ERR (-6)
+#define UU_LOCK_OWNER_ERR (-7)
+
+/*
+ * fmt_scaled(3) specific flags.
+ */
+#define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */
+
+/*
+ * stub struct definitions.
+ */
+struct __sFILE;
+struct login_cap;
+struct passwd;
+struct termios;
+struct utmp;
+struct winsize;
+
+__BEGIN_DECLS
+char *fparseln(struct __sFILE *, size_t *, size_t *, const char[3], int);
+void login(struct utmp *);
+int login_tty(int);
+int logout(const char *);
+void logwtmp(const char *, const char *, const char *);
+int opendev(char *, int, int, char **);
+int pidfile(const char *);
+void pw_setdir(const char *);
+char *pw_file(const char *);
+int pw_lock(int retries);
+int pw_mkdb(char *, int);
+int pw_abort(void);
+void pw_init(void);
+void pw_edit(int, const char *);
+void pw_prompt(void);
+void pw_copy(int, int, const struct passwd *, const struct passwd *);
+int pw_scan(char *, struct passwd *, int *);
+void pw_error(const char *, int, int);
+int openpty(int *, int *, char *, struct termios *, struct winsize *);
+int opendisk(const char *path, int flags, char *buf, size_t buflen,
+ int iscooked);
+pid_t forkpty(int *, char *, struct termios *, struct winsize *);
+int getmaxpartitions(void);
+int getrawpartition(void);
+void login_fbtab(const char *, uid_t, gid_t);
+int login_check_expire(struct __sFILE *, struct passwd *, char *, int);
+char *readlabelfs(char *, int);
+const char *uu_lockerr(int _uu_lockresult);
+int uu_lock(const char *_ttyname);
+int uu_lock_txfr(const char *_ttyname, pid_t _pid);
+int uu_unlock(const char *_ttyname);
+int fmt_scaled(long long number, char *result);
+int scan_scaled(char *scaled, long long *result);
+__END_DECLS
+
+#endif /* !_UTIL_H_ */
--