Index: net/openbgpd/Makefile =================================================================== --- net/openbgpd/Makefile +++ net/openbgpd/Makefile @@ -1,12 +1,9 @@ # $FreeBSD$ PORTNAME= openbgpd -PORTVERSION= 5.2.20121209 -PORTREVISION= 3 +PORTVERSION= 6.5p0 CATEGORIES= net MASTER_SITES= OPENBSD/OpenBGPD -DISTNAME= ${PORTNAME}-4.6 -DIST_SUBDIR= ${PORTNAME} MAINTAINER= hrs@FreeBSD.org COMMENT= Free implementation of the Border Gateway Protocol, Version 4 @@ -14,27 +11,21 @@ LICENSE= ISCL LICENSE_FILE= ${FILESDIR}/COPYING -CONFLICTS= zebra-[0-9]* quagga-[0-9]* - -USES= tar:tgz uidfix +USES= autoreconf libtool uidfix USE_RC_SUBR= ${PORTNAME} -NO_WRKSUBDIR= yes -PLIST_FILES= sbin/bgpctl sbin/bgpd man/man5/bgpd.conf.5.gz \ - man/man8/bgpctl.8.gz man/man8/bgpd.8.gz +GNU_CONFIGURE= yes + SUB_FILES= pkg-message + USERS= _bgpd GROUPS= _bgpd -OPTIONS_DEFINE= IPV6LLPEER -OPTIONS_DEFAULT=IPV6LLPEER -IPV6LLPEER_DESC=Support nexthop using IPv6 link-local address -IPV6LLPEER_MAKE_ARGS= -DIPV6_LINKLOCAL_PEER +CONFLICTS= zebra-[0-9]* quagga-[0-9]* -post-patch: - @${REINPLACE_CMD} -e "s|%%PREFIX%%|${PREFIX}|g" \ - ${WRKSRC}/bgpd/bgpd.8 \ - ${WRKSRC}/bgpd/bgpd.conf.5 \ - ${WRKSRC}/bgpctl/bgpctl.8 +OPTIONS_DEFINE= IPV6LLPEER +OPTIONS_DEFAULT= IPV6LLPEER +IPV6LLPEER_DESC= Support nexthop using IPv6 link-local address +IPV6LLPEER_MAKE_ARGS= -DIPV6_LINKLOCAL_PEER .include Index: net/openbgpd/distinfo =================================================================== --- net/openbgpd/distinfo +++ net/openbgpd/distinfo @@ -1,2 +1,3 @@ -SHA256 (openbgpd/openbgpd-4.6.tgz) = d9a0a3542e5ec744889ca12871f01aa1d86f12844e093010f37d0601796e15cf -SIZE (openbgpd/openbgpd-4.6.tgz) = 168197 +TIMESTAMP = 1556692508 +SHA256 (openbgpd-6.5p0.tar.gz) = 20c1a40bafcbbea60c4ecc6dd2e87fcba6847bfad62739b705a3806b6b442a56 +SIZE (openbgpd-6.5p0.tar.gz) = 677691 Index: net/openbgpd/files/patch-Makefile =================================================================== --- net/openbgpd/files/patch-Makefile +++ /dev/null @@ -1,12 +0,0 @@ -Index: Makefile -=================================================================== -RCS file: Makefile -diff -N Makefile ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ Makefile 30 Jun 2009 07:07:55 -0000 1.2 -@@ -0,0 +1,5 @@ -+# $hrs: openbgpd/Makefile,v 1.2 2009/06/30 07:07:55 hrs Exp $ -+ -+SUBDIR= bgpd bgpctl -+ -+.include Index: net/openbgpd/files/patch-Makefile.am =================================================================== --- /dev/null +++ net/openbgpd/files/patch-Makefile.am @@ -0,0 +1,20 @@ +--- Makefile.am.orig 2019-05-01 11:22:14 UTC ++++ Makefile.am +@@ -19,13 +19,14 @@ + EXTRA_DIST = README.md VERSION bgpd.conf + + install-data-hook: +- @if [ ! -d "$(DESTDIR)$(localstatedir)/run" ]; then \ ++ if [ ! -d "$(DESTDIR)$(localstatedir)/run" ]; then \ + $(INSTALL) -m 755 -d "$(DESTDIR)$(localstatedir)/run"; \ + fi +- @if [ ! -d "$(DESTDIR)$(sysconfdir)" ]; then \ ++ if [ ! -d "$(DESTDIR)$(sysconfdir)" ]; then \ + $(INSTALL) -m 755 -d "$(DESTDIR)$(sysconfdir)"; \ + fi +- @if [ ! -f "$(DESTDIR)$(sysconfdir)/bgpd.conf" ]; then \ ++ $(INSTALL) -m 644 "$(srcdir)/bgpd.conf" "$(DESTDIR)$(sysconfdir)/bgpd.conf.sample"; \ ++ if [ ! -f "$(DESTDIR)$(sysconfdir)/bgpd.conf" ]; then \ + $(INSTALL) -m 644 "$(srcdir)/bgpd.conf" "$(DESTDIR)$(sysconfdir)/bgpd.conf"; \ + else \ + echo; \ Index: net/openbgpd/files/patch-Makefile.inc =================================================================== --- net/openbgpd/files/patch-Makefile.inc +++ /dev/null @@ -1,12 +0,0 @@ -Index: Makefile.inc -=================================================================== -RCS file: Makefile.inc -diff -N Makefile.inc ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ Makefile.inc 16 May 2014 01:06:14 -0000 1.5 -@@ -0,0 +1,5 @@ -+# $hrs: openbgpd/Makefile.inc,v 1.5 2014/05/16 01:06:14 hrs Exp $ -+ -+PREFIX?= /usr/local -+BINDIR?= ${PREFIX}/sbin -+MANDIR?= ${PREFIX}/man/man Index: net/openbgpd/files/patch-bgpctl_Makefile =================================================================== --- net/openbgpd/files/patch-bgpctl_Makefile +++ /dev/null @@ -1,31 +0,0 @@ -Index: bgpctl/Makefile -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/Makefile,v -retrieving revision 1.1.1.1 -retrieving revision 1.4 -diff -u -p -r1.1.1.1 -r1.4 ---- bgpctl/Makefile 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/Makefile 13 Oct 2012 18:35:56 -0000 1.4 -@@ -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+= irr_parser.c mrtparser.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} Index: net/openbgpd/files/patch-bgpctl_bgpctl.8 =================================================================== --- net/openbgpd/files/patch-bgpctl_bgpctl.8 +++ /dev/null @@ -1,287 +0,0 @@ -Index: bgpctl/bgpctl.8 -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.8,v -retrieving revision 1.1.1.6 -retrieving revision 1.6 -diff -u -p -r1.1.1.6 -r1.6 ---- bgpctl/bgpctl.8 14 Feb 2010 20:20:13 -0000 1.1.1.6 -+++ bgpctl/bgpctl.8 13 Oct 2012 18:35:56 -0000 1.6 -@@ -1,4 +1,4 @@ --.\" $OpenBSD: bgpctl.8,v 1.49 2009/06/06 06:11:17 claudio Exp $ -+.\" $OpenBSD: bgpctl.8,v 1.59 2012/05/27 20:49:42 jmc Exp $ - .\" - .\" Copyright (c) 2003 Henning Brauer - .\" -@@ -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 27 2012 $ - .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,12 +113,21 @@ Note that the neighbor is not obliged to - 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 - Remove all dynamically added prefixes from the list of announced networks. -+.It Cm network mrt file Ar file filter -+Import networks from an MRT table dump for debugging purposes. -+.Ar filter -+can be specified similarly to the -+.Ar show mrt -+command. -+Only networks matching the filter will be imported. - .It Cm network show Ar family - Show all announced networks. - .Ar family , -@@ -122,7 +146,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,9 +157,81 @@ 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. -+.It Xo -+.Cm show mrt -+.Op Ar options -+.Ar filter -+.Xc -+Show routes from an MRT table dump file. -+.Ar filter -+can be an IP address, a CIDR prefix, an AS filter, a combination or nothing: -+.Pp -+.Bl -tag -width "address/len all" -compact -+.It Ar address -+Show best matching route for address. -+.It Ar address Ns Li / Ns Ar len -+Show RIB entry for this CIDR prefix. -+.It Xo -+.Ar address Ns Li / Ns Ar len -+.Cm all -+.Xc -+Show all entries in the specified range. -+.\".It Ar address/len Cm longer-prefixes -+.It Cm as Ar as -+Show all entries with -+.Ar as -+anywhere in the AS path. -+.It Cm empty-as -+Show all entries that are internal routes with no AS's in the AS path. -+.It Cm neighbor Ar ip -+Show only entries from the specified peer. -+.It Cm peer-as Ar as -+Show all entries with -+.Ar as -+as leftmost AS. -+.It Cm source-as Ar as -+Show all entries with -+.Ar as -+as rightmost AS. -+.It Cm transit-as Ar as -+Show all entries with -+.Ar as -+anywhere but rightmost. -+.El -+.Pp -+Additionally, the following -+.Ar options -+are defined: -+.Pp -+.Bl -tag -width "file name" -compact -+.It Cm detail -+Show more detailed output for matching routes. -+.It Ar family -+Limit the output to the given address family. -+.It Cm file Ar name -+Read the MRT dump from file -+.Ar name -+instead of using stdin. -+.El -+.Pp -+Multiple options and filters can be used at the same time. -+.It Cm show summary -+Show a list of all neighbors, including information about the session state -+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 neighbor Ar peer modifier - Show detailed information about the neighbor identified by - .Ar peer , -@@ -183,33 +279,33 @@ Show all entries in the specified range. - Show all entries with - .Ar as - anywhere in the AS path. --.It Cm source-as Ar as --Show all entries with --.Ar as --as rightmost AS. --.It Cm transit-as Ar as --Show all entries with --.Ar as --anywhere but rightmost. --.It Cm peer-as Ar as --Show all entries with --.Ar as --as leftmost AS. --.It Cm empty-as --Show all entries that are internal routes with no AS's in the AS path. - .It Cm community Ar community - Show all entries with community - .Ar community . -+.It Cm empty-as -+Show all entries that are internal routes with no AS's in the AS path. -+.It Cm memory -+Show RIB memory statistics. - .It Cm neighbor Ar peer - Show only entries from the specified peer. --.It Cm table Ar rib --Show only entries from the specified RIB table. -+.It Cm peer-as Ar as -+Show all entries with -+.Ar as -+as leftmost AS. -+.It Cm source-as Ar as -+Show all entries with -+.Ar as -+as rightmost AS. - .It Cm summary - This is the same as the - .Ic show summary - command. --.It Cm memory --Show RIB memory statistics. -+.It Cm table Ar rib -+Show only entries from the specified RIB table. -+.It Cm transit-as Ar as -+Show all entries with -+.Ar as -+anywhere but rightmost. - .El - .Pp - Additionally, the following -@@ -217,8 +313,10 @@ Additionally, the following - are defined: - .Pp - .Bl -tag -width "detail" -compact -+.It Cm selected -+Show only selected routes. - .It Cm detail --Show more detailed output for matched routes. -+Show more detailed output for matching routes. - .It Ar family - Limit the output to the given address family. - .It Cm in -@@ -243,10 +341,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 -@@ -260,10 +360,19 @@ control socket - .Xr bgpd 8 , - .Xr bgplg 8 , - .Xr bgplgsh 8 -+.Sh STANDARDS - .Rs --.%R RFC 2622 --.%T "Routing Policy Specification Language (RPSL)" -+.%A C. Alaettinoglu -+.%A C. Villamizar -+.%A E. Gerich -+.%A D. Kessens -+.%A D. Meyer -+.%A T. Bates -+.%A D. Karrenberg -+.%A M. Terpstra - .%D June 1999 -+.%R RFC 2622 -+.%T Routing Policy Specification Language (RPSL) - .Re - .Sh HISTORY - The Index: net/openbgpd/files/patch-bgpctl_bgpctl.c =================================================================== --- net/openbgpd/files/patch-bgpctl_bgpctl.c +++ /dev/null @@ -1,1529 +0,0 @@ -Index: bgpctl/bgpctl.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.10 -diff -u -p -r1.1.1.7 -r1.10 ---- bgpctl/bgpctl.c 14 Feb 2010 20:20:14 -0000 1.1.1.7 -+++ bgpctl/bgpctl.c 8 Dec 2012 20:17:55 -0000 1.10 -@@ -1,4 +1,4 @@ --/* $OpenBSD: bgpctl.c,v 1.142 2009/06/06 06:33:15 eric Exp $ */ -+/* $OpenBSD: bgpctl.c,v 1.167 2012/11/15 19:55:08 sthen Exp $ */ - - /* - * Copyright (c) 2003 Henning Brauer -@@ -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 - #include - #include - #include -+#if defined(__FreeBSD__) /* net/if_media.h */ -+#include "if_media.h" -+#else - #include -+#endif /* defined(__FreeBSD__) */ - #include - - #include -@@ -29,7 +37,11 @@ - #include - #include - #include -+#if defined(__FreeBSD__) /* util.h */ -+#include "util.h" -+#else - #include -+#endif /* defined(__FreeBSD__) */ - - #include "bgpd.h" - #include "session.h" -@@ -37,6 +49,11 @@ - #include "log.h" - #include "parser.h" - #include "irrfilter.h" -+#include "mrtparser.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, -@@ -50,12 +67,14 @@ int show_summary_msg(struct imsg *, in - 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_capa_restart(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 +84,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); -@@ -73,16 +92,25 @@ const char * print_origin(u_int8_t, int - void print_flags(u_int8_t, int); - int show_rib_summary_msg(struct imsg *); - int show_rib_detail_msg(struct imsg *, int); -+void show_rib_brief(struct ctl_show_rib *, u_char *); -+void show_rib_detail(struct ctl_show_rib *, u_char *, int); -+void show_attr(void *, u_int16_t); - 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 *); - void send_filterset(struct imsgbuf *, struct filter_set_head *); - static const char *get_errstr(u_int8_t, u_int8_t); - int show_result(struct imsg *); -+void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); -+void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); -+void show_mrt_state(struct mrt_bgp_state *, void *); -+void show_mrt_msg(struct mrt_bgp_msg *, void *); -+void mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *); - - struct imsgbuf *ibuf; -+struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg }; -+struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL }; - - __dead void - usage(void) -@@ -98,7 +126,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 +156,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)); -@@ -154,7 +185,7 @@ main(int argc, char *argv[]) - case NONE: - case IRRFILTER: - usage(); -- /* not reached */ -+ /* NOTREACHED */ - case SHOW: - case SHOW_SUMMARY: - imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0); -@@ -164,24 +195,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 +231,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 +245,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; -@@ -217,15 +256,35 @@ main(int argc, char *argv[]) - sizeof(res->community)); - type = IMSG_CTL_SHOW_RIB_COMMUNITY; - } -- memcpy(&ribreq.neighbor, &neighbor, -- sizeof(ribreq.neighbor)); -+ 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)) - show_rib_summary_head(); - break; -+ case SHOW_MRT: -+ close(fd); -+ bzero(&ribreq, sizeof(ribreq)); -+ if (res->as.type != AS_NONE) -+ memcpy(&ribreq.as, &res->as, sizeof(res->as)); -+ if (res->addr.aid) { -+ memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr)); -+ ribreq.prefixlen = res->prefixlen; -+ } -+ if (res->community.as != COMMUNITY_UNSET && -+ res->community.type != COMMUNITY_UNSET) -+ memcpy(&ribreq.community, &res->community, -+ sizeof(res->community)); -+ memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor)); -+ ribreq.aid = res->aid; -+ ribreq.flags = res->flags; -+ show_mrt.arg = &ribreq; -+ if (!(res->flags & F_CTL_DETAIL)) -+ show_rib_summary_head(); -+ mrt_parse(res->mrtfd, &show_mrt, 1); -+ exit(0); - case SHOW_RIB_MEM: - imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); - break; -@@ -237,12 +296,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 +351,40 @@ 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 NETWORK_MRT: -+ bzero(&ribreq, sizeof(ribreq)); -+ if (res->as.type != AS_NONE) -+ memcpy(&ribreq.as, &res->as, sizeof(res->as)); -+ if (res->addr.aid) { -+ memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr)); -+ ribreq.prefixlen = res->prefixlen; -+ } -+ if (res->community.as != COMMUNITY_UNSET && -+ res->community.type != COMMUNITY_UNSET) -+ memcpy(&ribreq.community, &res->community, -+ sizeof(res->community)); -+ memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor)); -+ ribreq.aid = res->aid; -+ ribreq.flags = res->flags; -+ net_mrt.arg = &ribreq; -+ mrt_parse(res->mrtfd, &net_mrt, 1); -+ done = 1; -+ 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 +393,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 +418,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 +447,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 +461,10 @@ main(int argc, char *argv[]) - case NETWORK_REMOVE: - case NETWORK_FLUSH: - case IRRFILTER: -+ case LOG_VERBOSE: -+ case LOG_BRIEF: -+ case SHOW_MRT: -+ case NETWORK_MRT: - break; - } - imsg_free(&imsg); -@@ -398,8 +490,8 @@ fmt_peer(const char *descr, const struct - } - - 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 { -@@ -430,7 +522,7 @@ show_summary_msg(struct imsg *imsg, int - p->conf.remote_masklen, nodescr); - if (strlen(s) >= 20) - s[20] = 0; -- printf("%-20s %8s %10llu %10llu %5u %-8s ", -+ printf("%-20s %8s %10" PRIu64 " %10" PRIu64 " %5u %-8s ", - s, log_as(p->conf.remote_as), - p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + - p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + -@@ -492,8 +584,8 @@ show_neighbor_terse(struct imsg *imsg) - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_NEIGHBOR: - p = imsg->data; -- printf("%llu %llu %llu %llu %llu %llu %llu " -- "%llu %llu %llu %u %u %llu %llu %llu %llu\n", -+ printf("%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " " -+ "%" PRIu64 " %" PRIu64 " %" PRIu64 " %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", - p->stats.msg_sent_open, p->stats.msg_rcvd_open, - p->stats.msg_sent_notification, - p->stats.msg_rcvd_notification, -@@ -521,13 +613,15 @@ show_neighbor_msg(struct imsg *imsg, enu - 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,9 +643,20 @@ show_neighbor_msg(struct imsg *imsg, enu - 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); -+ if (p->conf.max_prefix) { -+ printf(" Max-prefix: %u", p->conf.max_prefix); -+ if (p->conf.max_prefix_restart) -+ printf(" (restart %u)", -+ p->conf.max_prefix_restart); -+ printf("\n"); -+ } - printf(" BGP version 4, remote router-id %s\n", - inet_ntoa(ina)); - printf(" BGP state = %s", statenames[p->state]); -@@ -563,22 +668,24 @@ show_neighbor_msg(struct imsg *imsg, enu - 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.grestart.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"); -- if (p->capa.peer.restart) -- printf(" Graceful Restart\n"); -+ if (p->capa.peer.grestart.restart) { -+ printf(" Graceful Restart"); -+ print_neighbor_capa_restart(p); -+ printf("\n"); -+ } - if (p->capa.peer.as4byte) - printf(" 4-byte AS numbers\n"); - } -@@ -633,20 +740,38 @@ show_neighbor_msg(struct imsg *imsg, enu - } - - 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 -+print_neighbor_capa_restart(struct peer *p) -+{ -+ int comma; -+ u_int8_t i; -+ -+ if (p->capa.peer.grestart.timeout) -+ printf(": Timeout: %d, ", p->capa.peer.grestart.timeout); -+ for (i = 0, comma = 0; i < AID_MAX; i++) -+ if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) { -+ if (!comma && -+ p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART) -+ printf("restarted, "); -+ if (comma) -+ printf(", "); -+ printf("%s", aid2str(i)); -+ if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD) -+ printf(" (preserved)"); -+ comma = 1; -+ } - } - - void -@@ -654,17 +779,17 @@ print_neighbor_msgstats(struct peer *p) - { - printf(" Message statistics:\n"); - printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); -- printf(" %-15s %10llu %10llu\n", "Opens", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Opens", - p->stats.msg_sent_open, p->stats.msg_rcvd_open); -- printf(" %-15s %10llu %10llu\n", "Notifications", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Notifications", - p->stats.msg_sent_notification, p->stats.msg_rcvd_notification); -- printf(" %-15s %10llu %10llu\n", "Updates", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Updates", - p->stats.msg_sent_update, p->stats.msg_rcvd_update); -- printf(" %-15s %10llu %10llu\n", "Keepalives", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Keepalives", - p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive); -- printf(" %-15s %10llu %10llu\n", "Route Refresh", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Route Refresh", - p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh); -- printf(" %-15s %10llu %10llu\n\n", "Total", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n\n", "Total", - p->stats.msg_sent_open + p->stats.msg_sent_notification + - p->stats.msg_sent_update + p->stats.msg_sent_keepalive + - p->stats.msg_sent_rrefresh, -@@ -673,14 +798,16 @@ print_neighbor_msgstats(struct peer *p) - p->stats.msg_rcvd_rrefresh); - printf(" Update statistics:\n"); - printf(" %-15s %-10s %-10s\n", "", "Sent", "Received"); -- printf(" %-15s %10llu %10llu\n", "Updates", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Updates", - p->stats.prefix_sent_update, p->stats.prefix_rcvd_update); -- printf(" %-15s %10llu %10llu\n", "Withdraws", -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Withdraws", - p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw); -+ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "End-of-Rib", -+ p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor); - } - - void --print_timer(const char *name, timer_t d) -+print_timer(const char *name, time_t d) - { - printf(" %-20s ", name); - -@@ -745,6 +872,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 +921,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; -- -- show_fib_flags(k6->flags); -+ kt = imsg->data; - -- 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 +969,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 +1054,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 +1091,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), "%" PRIu64 " 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), "%" PRIu64 " 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), "%" PRIu64 " K%s", -+ baudrate / IF_Kbps(1), unit); - else -- printf("%llu Bit/s", baudrate); -+ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " %s", -+ baudrate, unit); -+ -+ return (bbuf); - } - - int -@@ -982,17 +1137,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: -@@ -1008,10 +1158,10 @@ show_interface_msg(struct imsg *imsg) - void - show_rib_summary_head(void) - { -- printf( -- "flags: * = Valid, > = Selected, I = via IBGP, A = Announced\n"); -+ printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced, " -+ "S = Stale\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 +1199,30 @@ 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_STALE) -+ *p++ = 'S'; -+ 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_STALE) -+ printf(", stale"); -+ 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"); - } - } -@@ -1077,27 +1231,14 @@ int - show_rib_summary_msg(struct imsg *imsg) - { - struct ctl_show_rib rib; -- char *aspath; - u_char *asdata; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_RIB: - memcpy(&rib, imsg->data, sizeof(rib)); -- -- print_prefix(&rib.prefix, rib.prefixlen, rib.flags); -- printf("%-15s ", log_addr(&rib.exit_nexthop)); -- -- printf(" %5u %5u ", rib.local_pref, rib.med); -- - asdata = imsg->data; - asdata += sizeof(struct ctl_show_rib); -- if (aspath_asprint(&aspath, asdata, rib.aspath_len) == -1) -- err(1, NULL); -- if (strlen(aspath) > 0) -- printf("%s ", aspath); -- free(aspath); -- -- printf("%s\n", print_origin(rib.origin, 1)); -+ show_rib_brief(&rib, asdata); - break; - case IMSG_CTL_END: - return (1); -@@ -1112,108 +1253,21 @@ int - show_rib_detail_msg(struct imsg *imsg, int nodescr) - { - struct ctl_show_rib rib; -- struct in_addr id; -- char *aspath, *s; -- u_char *data; -- u_int32_t as; -- u_int16_t ilen, alen, ioff; -- u_int8_t flags, type; -- time_t now; -+ u_char *asdata; -+ u_int16_t ilen; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_RIB: - memcpy(&rib, imsg->data, sizeof(rib)); -- -- printf("\nBGP routing table entry for %s/%u\n", -- log_addr(&rib.prefix), rib.prefixlen); -- -- data = imsg->data; -- data += sizeof(struct ctl_show_rib); -- if (aspath_asprint(&aspath, data, rib.aspath_len) == -1) -- err(1, NULL); -- if (strlen(aspath) > 0) -- printf(" %s\n", aspath); -- free(aspath); -- -- s = fmt_peer(rib.descr, &rib.remote_addr, -1, nodescr); -- printf(" Nexthop %s ", log_addr(&rib.exit_nexthop)); -- printf("(via %s) from %s (", log_addr(&rib.true_nexthop), s); -- free(s); -- id.s_addr = htonl(rib.remote_id); -- printf("%s)\n", inet_ntoa(id)); -- -- printf(" Origin %s, metric %u, localpref %u, ", -- print_origin(rib.origin, 0), rib.med, rib.local_pref); -- print_flags(rib.flags, 0); -- -- now = time(NULL); -- if (now > rib.lastchange) -- now -= rib.lastchange; -- else -- now = 0; -- -- printf("\n Last update: %s ago\n", -- fmt_timeframe_core(now)); -+ asdata = imsg->data; -+ asdata += sizeof(struct ctl_show_rib); -+ show_rib_detail(&rib, asdata, nodescr); - break; - case IMSG_CTL_SHOW_RIB_ATTR: - ilen = imsg->hdr.len - IMSG_HEADER_SIZE; - if (ilen < 3) - errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received"); -- data = imsg->data; -- flags = data[0]; -- type = data[1]; -- -- /* get the attribute length */ -- if (flags & ATTR_EXTLEN) { -- if (ilen < 4) -- errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received"); -- memcpy(&alen, data+2, sizeof(u_int16_t)); -- alen = ntohs(alen); -- data += 4; -- ilen -= 4; -- } else { -- alen = data[2]; -- data += 3; -- ilen -= 3; -- } -- /* bad imsg len how can that happen!? */ -- if (alen != ilen) -- errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received"); -- -- switch (type) { -- case ATTR_COMMUNITIES: -- printf(" Communities: "); -- show_community(data, alen); -- printf("\n"); -- break; -- 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)); -- break; -- case ATTR_ORIGINATOR_ID: -- memcpy(&id, data, sizeof(id)); -- printf(" Originator Id: %s\n", inet_ntoa(id)); -- break; -- case ATTR_CLUSTER_LIST: -- printf(" Cluster ID List:"); -- for (ioff = 0; ioff + sizeof(id) <= ilen; -- ioff += sizeof(id)) { -- memcpy(&id, data + ioff, sizeof(id)); -- printf(" %s", inet_ntoa(id)); -- } -- printf("\n"); -- break; -- case ATTR_EXT_COMMUNITIES: -- printf(" Ext. communities: "); -- show_ext_community(data, alen); -- printf("\n"); -- break; -- default: -- /* ignore unknown attributes */ -- break; -- } -+ show_attr(imsg->data, ilen); - break; - case IMSG_CTL_END: - printf("\n"); -@@ -1225,67 +1279,128 @@ show_rib_detail_msg(struct imsg *imsg, i - return (0); - } - --char * --fmt_mem(int64_t num) -+void -+show_rib_brief(struct ctl_show_rib *r, u_char *asdata) - { -- static char buf[16]; -+ char *aspath; - -- if (fmt_scaled(num, buf) == -1) -- snprintf(buf, sizeof(buf), "%lldB", (long long)num); -+ print_prefix(&r->prefix, r->prefixlen, r->flags); -+ printf(" %-15s ", log_addr(&r->exit_nexthop)); -+ printf(" %5u %5u ", r->local_pref, r->med); - -- return (buf); -+ if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) -+ err(1, NULL); -+ if (strlen(aspath) > 0) -+ printf("%s ", aspath); -+ free(aspath); -+ -+ printf("%s\n", print_origin(r->origin, 1)); - } - --int --show_rib_memory_msg(struct imsg *imsg) -+void -+show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr) - { -- struct rde_memstats stats; -+ struct in_addr id; -+ char *aspath, *s; -+ time_t now; - -- 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))); -- printf("%10lld rib entries using %s of memory\n", -- (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt * -- sizeof(struct rib_entry))); -- printf("%10lld prefix entries using %s of memory\n", -- (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt * -- sizeof(struct prefix))); -- printf("%10lld BGP path attribute entries using %s of memory\n", -- (long long)stats.path_cnt, fmt_mem(stats.path_cnt * -- sizeof(struct rde_aspath))); -- printf("%10lld BGP AS-PATH attribute entries using " -- "%s of memory,\n\t and holding %lld references\n", -- (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size), -- (long long)stats.aspath_refs); -- printf("%10lld BGP attributes entries using %s of memory\n", -- (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt * -- sizeof(struct attr))); -- printf("\t and holding %lld references\n", -- (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) + -- stats.prefix_cnt * sizeof(struct prefix) + -- stats.rib_cnt * sizeof(struct rib_entry) + -- stats.path_cnt * sizeof(struct rde_aspath) + -- stats.aspath_size + stats.attr_cnt * sizeof(struct attr) + -- stats.attr_data)); -+ printf("\nBGP routing table entry for %s/%u\n", -+ log_addr(&r->prefix), r->prefixlen); -+ -+ if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1) -+ err(1, NULL); -+ if (strlen(aspath) > 0) -+ printf(" %s\n", aspath); -+ free(aspath); -+ -+ s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr); -+ printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); -+ printf("(via %s) from %s (", log_addr(&r->true_nexthop), s); -+ free(s); -+ id.s_addr = htonl(r->remote_id); -+ printf("%s)\n", inet_ntoa(id)); -+ -+ printf(" Origin %s, metric %u, localpref %u, weight %u, ", -+ print_origin(r->origin, 0), r->med, r->local_pref, r->weight); -+ print_flags(r->flags, 0); -+ -+ now = time(NULL); -+ if (now > r->lastchange) -+ now -= r->lastchange; -+ else -+ now = 0; -+ -+ printf("\n Last update: %s ago\n", fmt_timeframe_core(now)); -+} -+ -+void -+show_attr(void *b, u_int16_t len) -+{ -+ char *data = b; -+ struct in_addr id; -+ u_int32_t as; -+ u_int16_t alen, ioff; -+ u_int8_t flags, type; -+ -+ data = b; -+ if (len < 3) -+ errx(1, "show_attr: too short bgp attr"); -+ -+ flags = data[0]; -+ type = data[1]; -+ -+ /* get the attribute length */ -+ if (flags & ATTR_EXTLEN) { -+ if (len < 4) -+ errx(1, "show_attr: too short bgp attr"); -+ memcpy(&alen, data+2, sizeof(u_int16_t)); -+ alen = ntohs(alen); -+ data += 4; -+ len -= 4; -+ } else { -+ alen = data[2]; -+ data += 3; -+ len -= 3; -+ } -+ -+ /* bad imsg len how can that happen!? */ -+ if (alen > len) -+ errx(1, "show_attr: bad length"); -+ -+ switch (type) { -+ case ATTR_COMMUNITIES: -+ printf(" Communities: "); -+ show_community(data, alen); -+ printf("\n"); -+ break; -+ case ATTR_AGGREGATOR: -+ memcpy(&as, data, sizeof(as)); -+ memcpy(&id, data + sizeof(as), sizeof(id)); -+ printf(" Aggregator: %s [%s]\n", -+ log_as(ntohl(as)), inet_ntoa(id)); -+ break; -+ case ATTR_ORIGINATOR_ID: -+ memcpy(&id, data, sizeof(id)); -+ printf(" Originator Id: %s\n", inet_ntoa(id)); -+ break; -+ case ATTR_CLUSTER_LIST: -+ printf(" Cluster ID List:"); -+ for (ioff = 0; ioff + sizeof(id) <= alen; -+ ioff += sizeof(id)) { -+ memcpy(&id, data + ioff, sizeof(id)); -+ printf(" %s", inet_ntoa(id)); -+ } -+ printf("\n"); -+ break; -+ case ATTR_EXT_COMMUNITIES: -+ printf(" Ext. communities: "); -+ show_ext_community(data, alen); -+ printf("\n"); - break; - default: -+ /* ignore unknown attributes */ - break; - } -- -- return (1); - } - - void -@@ -1328,30 +1443,6 @@ show_community(u_char *data, u_int16_t l - } - } - --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,34 +1463,101 @@ show_ext_community(u_char *data, u_int16 - 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%" PRIx64, log_ext_subtype(subtype), ext); - break; - default: - memcpy(&ext, data + i, sizeof(ext)); -- printf("0x%llx", betoh64(ext)); -+ printf("0x%" PRIx64, betoh64(ext)); - } - if (i + 8 < len) - printf(", "); - } - } - -+char * -+fmt_mem(int64_t num) -+{ -+ static char buf[16]; -+ -+ if (fmt_scaled(num, buf) == -1) -+ snprintf(buf, sizeof(buf), "%lldB", (long long)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"); -+ 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))); -+ printf("%10lld prefix entries using %s of memory\n", -+ (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt * -+ sizeof(struct prefix))); -+ printf("%10lld BGP path attribute entries using %s of memory\n", -+ (long long)stats.path_cnt, fmt_mem(stats.path_cnt * -+ sizeof(struct rde_aspath))); -+ printf("%10lld BGP AS-PATH attribute entries using " -+ "%s of memory,\n\t and holding %lld references\n", -+ (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size), -+ (long long)stats.aspath_refs); -+ printf("%10lld BGP attributes entries using %s of memory\n", -+ (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt * -+ sizeof(struct attr))); -+ printf("\t and holding %lld references\n", -+ (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(pts + -+ stats.prefix_cnt * sizeof(struct prefix) + -+ stats.rib_cnt * sizeof(struct rib_entry) + -+ stats.path_cnt * sizeof(struct rde_aspath) + -+ stats.aspath_size + stats.attr_cnt * sizeof(struct attr) + -+ stats.attr_data)); -+ break; -+ default: -+ break; -+ } -+ -+ return (1); -+} -+ - void - send_filterset(struct imsgbuf *i, struct filter_set_head *set) - { -@@ -1469,6 +1627,183 @@ show_result(struct imsg *imsg) - return (1); - } - -+void -+show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) -+{ -+ struct ctl_show_rib ctl; -+ struct ctl_show_rib_request *req = arg; -+ struct mrt_rib_entry *mre; -+ u_int16_t i, j; -+ -+ for (i = 0; i < mr->nentries; i++) { -+ mre = &mr->entries[i]; -+ bzero(&ctl, sizeof(ctl)); -+ mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix); -+ ctl.prefixlen = mr->prefixlen; -+ ctl.lastchange = mre->originated; -+ mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop); -+ mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop); -+ ctl.origin = mre->origin; -+ ctl.local_pref = mre->local_pref; -+ ctl.med = mre->med; -+ /* weight is not part of the mrt dump so it can't be set */ -+ ctl.aspath_len = mre->aspath_len; -+ -+ if (mre->peer_idx < mp->npeers) { -+ mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr, -+ &ctl.remote_addr); -+ ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; -+ } -+ -+ /* filter by neighbor */ -+ if (req->neighbor.addr.aid != AID_UNSPEC && -+ memcmp(&req->neighbor.addr, &ctl.remote_addr, -+ sizeof(ctl.remote_addr)) != 0) -+ continue; -+ /* filter by AF */ -+ if (req->aid && req->aid != ctl.prefix.aid) -+ return; -+ /* filter by prefix */ -+ if (req->prefix.aid != AID_UNSPEC) { -+ if (!prefix_compare(&req->prefix, &ctl.prefix, -+ req->prefixlen)) { -+ if (req->flags & F_LONGER) { -+ if (req->prefixlen > ctl.prefixlen) -+ return; -+ } else if (req->prefixlen != ctl.prefixlen) -+ return; -+ } else -+ return; -+ } -+ /* filter by AS */ -+ if (req->as.type != AS_NONE && -+ !aspath_match(mre->aspath, mre->aspath_len, -+ req->as.type, req->as.as)) -+ continue; -+ -+ if (req->flags & F_CTL_DETAIL) { -+ show_rib_detail(&ctl, mre->aspath, 1); -+ for (j = 0; j < mre->nattrs; j++) -+ show_attr(mre->attrs[j].attr, -+ mre->attrs[j].attr_len); -+ } else -+ show_rib_brief(&ctl, mre->aspath); -+ } -+} -+ -+void -+network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) -+{ -+ struct ctl_show_rib ctl; -+ struct network_config net; -+ struct ctl_show_rib_request *req = arg; -+ struct mrt_rib_entry *mre; -+ struct ibuf *msg; -+ u_int16_t i, j; -+ -+ for (i = 0; i < mr->nentries; i++) { -+ mre = &mr->entries[i]; -+ bzero(&ctl, sizeof(ctl)); -+ mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix); -+ ctl.prefixlen = mr->prefixlen; -+ ctl.lastchange = mre->originated; -+ mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop); -+ mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop); -+ ctl.origin = mre->origin; -+ ctl.local_pref = mre->local_pref; -+ ctl.med = mre->med; -+ ctl.aspath_len = mre->aspath_len; -+ -+ if (mre->peer_idx < mp->npeers) { -+ mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr, -+ &ctl.remote_addr); -+ ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; -+ } -+ -+ /* filter by neighbor */ -+ if (req->neighbor.addr.aid != AID_UNSPEC && -+ memcmp(&req->neighbor.addr, &ctl.remote_addr, -+ sizeof(ctl.remote_addr)) != 0) -+ continue; -+ /* filter by AF */ -+ if (req->aid && req->aid != ctl.prefix.aid) -+ return; -+ /* filter by prefix */ -+ if (req->prefix.aid != AID_UNSPEC) { -+ if (!prefix_compare(&req->prefix, &ctl.prefix, -+ req->prefixlen)) { -+ if (req->flags & F_LONGER) { -+ if (req->prefixlen > ctl.prefixlen) -+ return; -+ } else if (req->prefixlen != ctl.prefixlen) -+ return; -+ } else -+ return; -+ } -+ /* filter by AS */ -+ if (req->as.type != AS_NONE && -+ !aspath_match(mre->aspath, mre->aspath_len, -+ req->as.type, req->as.as)) -+ continue; -+ -+ bzero(&net, sizeof(net)); -+ memcpy(&net.prefix, &ctl.prefix, sizeof(net.prefix)); -+ net.prefixlen = ctl.prefixlen; -+ net.type = NETWORK_MRTCLONE; -+ /* XXX rtableid */ -+ -+ imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, -+ &net, sizeof(net)); -+ if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, -+ 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) -+ errx(1, "imsg_create failure"); -+ if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || -+ imsg_add(msg, mre->aspath, mre->aspath_len) == -1) -+ errx(1, "imsg_add failure"); -+ imsg_close(ibuf, msg); -+ for (j = 0; j < mre->nattrs; j++) -+ imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, -+ mre->attrs[j].attr, mre->attrs[j].attr_len); -+ imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); -+ -+ while (ibuf->w.queued) { -+ if (msgbuf_write(&ibuf->w) < 0) -+ err(1, "write error"); -+ } -+ } -+} -+ -+void -+show_mrt_state(struct mrt_bgp_state *ms, void *arg) -+{ -+ printf("show_mrt_state\n"); -+} -+ -+void -+show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) -+{ -+ printf("show_mrt_msg\n"); -+} -+ -+void -+mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba) -+{ -+ switch (ma->sa.sa_family) { -+ case AF_INET: -+ case AF_INET6: -+ sa2addr(&ma->sa, ba); -+ break; -+ case AF_VPNv4: -+ bzero(ba, sizeof(*ba)); -+ ba->aid = AID_VPN_IPv4; -+ ba->vpn4.rd = ma->svpn4.sv_rd; -+ ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr; -+ memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label, -+ sizeof(ba->vpn4.labelstack)); -+ break; -+ } -+} -+ - /* following functions are necessary for imsg framework */ - void - log_warnx(const char *emsg, ...) -@@ -1495,3 +1830,9 @@ fatal(const char *emsg) - { - err(1, emsg); - } -+ -+void -+fatalx(const char *emsg) -+{ -+ errx(1, emsg); -+} Index: net/openbgpd/files/patch-bgpctl_irr_asset.c =================================================================== --- net/openbgpd/files/patch-bgpctl_irr_asset.c +++ /dev/null @@ -1,14 +0,0 @@ -Index: bgpctl/irr_asset.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irr_asset.c,v -retrieving revision 1.1.1.2 -retrieving revision 1.1.1.3 -diff -u -p -r1.1.1.2 -r1.1.1.3 ---- bgpctl/irr_asset.c 9 Jul 2009 16:49:55 -0000 1.1.1.2 -+++ bgpctl/irr_asset.c 13 Oct 2012 18:22:52 -0000 1.1.1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: irr_asset.c,v 1.8 2009/04/14 21:10:54 jj Exp $ */ -+/* $OpenBSD: irr_asset.c,v 1.7 2007/03/31 12:46:55 henning Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer Index: net/openbgpd/files/patch-bgpctl_irr_output.c =================================================================== --- net/openbgpd/files/patch-bgpctl_irr_output.c +++ /dev/null @@ -1,14 +0,0 @@ -Index: bgpctl/irr_output.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irr_output.c,v -retrieving revision 1.1.1.1 -retrieving revision 1.1.1.2 -diff -u -p -r1.1.1.1 -r1.1.1.2 ---- bgpctl/irr_output.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/irr_output.c 13 Oct 2012 18:22:52 -0000 1.1.1.2 -@@ -1,4 +1,4 @@ --/* $OpenBSD: irr_output.c,v 1.13 2007/03/05 17:28:21 henning Exp $ */ -+/* $OpenBSD: irr_output.c,v 1.12 2007/03/05 15:02:05 henning Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer Index: net/openbgpd/files/patch-bgpctl_irr_parser.c =================================================================== --- net/openbgpd/files/patch-bgpctl_irr_parser.c +++ /dev/null @@ -1,48 +0,0 @@ -Index: bgpctl/irr_parser.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irr_parser.c,v -retrieving revision 1.1.1.5 -retrieving revision 1.5 -diff -u -p -r1.1.1.5 -r1.5 ---- bgpctl/irr_parser.c 14 Feb 2010 20:20:14 -0000 1.1.1.5 -+++ bgpctl/irr_parser.c 13 Oct 2012 18:35:56 -0000 1.5 -@@ -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 -@@ -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,11 +408,13 @@ 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 */ -- if (strlen(val) > 0 && val[strlen(val) - 1] == ',') -+ /* route is single-value, but seen trailing , and \r in the wild */ -+ if (strlen(val) > 0 && (val[strlen(val) - 1] == ',' || -+ val[strlen(val) - 1] == '\r')) - val[strlen(val) - 1] = '\0'; - - return (prefixset_addmember(val)); Index: net/openbgpd/files/patch-bgpctl_irr_prefix.c =================================================================== --- net/openbgpd/files/patch-bgpctl_irr_prefix.c +++ /dev/null @@ -1,157 +0,0 @@ -Index: bgpctl/irr_prefix.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irr_prefix.c,v -retrieving revision 1.1.1.5 -retrieving revision 1.1.1.8 -diff -u -p -r1.1.1.5 -r1.1.1.8 ---- bgpctl/irr_prefix.c 14 Feb 2010 20:20:14 -0000 1.1.1.5 -+++ bgpctl/irr_prefix.c 13 Oct 2012 18:22:52 -0000 1.1.1.8 -@@ -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.17 2009/09/08 16:11:36 sthen Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer -@@ -29,6 +29,7 @@ - #include - - #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 *p - 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 - 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); - Index: net/openbgpd/files/patch-bgpctl_irrfilter.h =================================================================== --- net/openbgpd/files/patch-bgpctl_irrfilter.h +++ /dev/null @@ -1,59 +0,0 @@ -Index: bgpctl/irrfilter.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irrfilter.h,v -retrieving revision 1.1.1.5 -retrieving revision 1.4 -diff -u -p -r1.1.1.5 -r1.4 ---- bgpctl/irrfilter.h 14 Feb 2010 20:20:14 -0000 1.1.1.5 -+++ bgpctl/irrfilter.h 13 Oct 2012 18:35:56 -0000 1.4 -@@ -1,4 +1,4 @@ --/* $OpenBSD: irrfilter.h,v 1.7 2007/03/06 16:45:34 henning Exp $ */ -+/* $OpenBSD: irrfilter.h,v 1.8 2009/09/08 15:40:25 claudio Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer -@@ -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 - #include - #include - - #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; Index: net/openbgpd/files/patch-bgpctl_irrfilter.c =================================================================== --- net/openbgpd/files/patch-bgpctl_irrfilter.c +++ /dev/null @@ -1,24 +0,0 @@ -Index: bgpctl/irrfilter.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irrfilter.c,v -retrieving revision 1.1.1.1 -retrieving revision 1.3 -diff -u -p -r1.1.1.1 -r1.3 ---- bgpctl/irrfilter.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/irrfilter.c 13 Oct 2012 18:35:56 -0000 1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: irrfilter.c,v 1.4 2007/05/28 23:31:53 henning Exp $ */ -+/* $OpenBSD: irrfilter.c,v 1.3 2007/03/06 16:45:34 henning Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer -@@ -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 - #include Index: net/openbgpd/files/patch-bgpctl_mrtparser.h =================================================================== --- net/openbgpd/files/patch-bgpctl_mrtparser.h +++ /dev/null @@ -1,122 +0,0 @@ -Index: bgpctl/mrtparser.h -=================================================================== -RCS file: bgpctl/mrtparser.h -diff -N bgpctl/mrtparser.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ bgpctl/mrtparser.h 13 Oct 2012 18:22:53 -0000 1.1.1.1 -@@ -0,0 +1,115 @@ -+/* $OpenBSD$ */ -+/* -+ * Copyright (c) 2011 Claudio Jeker -+ * -+ * 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. -+ */ -+ -+struct sockaddr_vpn4 { -+ u_int8_t sv_len; -+ sa_family_t sv_family; -+ u_int8_t sv_labellen; -+ u_int8_t sv_pad; -+ struct in_addr sv_addr; -+ u_int64_t sv_rd; -+ u_int8_t sv_label[21]; -+ u_int8_t sv_pad2[3]; -+}; -+ -+#define AF_VPNv4 250 /* XXX high enough to not cause issues */ -+ -+union mrt_addr { -+ struct sockaddr_in6 sin6; -+ struct sockaddr_in sin; -+ struct sockaddr_vpn4 svpn4; -+ struct sockaddr sa; -+}; -+ -+/* data structures for the MSG_TABLE_DUMP_V2 format */ -+struct mrt_peer_entry { -+ union mrt_addr addr; -+ u_int32_t bgp_id; -+ u_int32_t asnum; -+}; -+ -+struct mrt_peer { -+ char *view; -+ struct mrt_peer_entry *peers; -+ u_int32_t bgp_id; -+ u_int16_t npeers; -+}; -+ -+struct mrt_attr { -+ void *attr; -+ size_t attr_len; -+}; -+ -+struct mrt_rib_entry { -+ void *aspath; -+ struct mrt_attr *attrs; -+ union mrt_addr nexthop; -+ time_t originated; -+ u_int32_t local_pref; -+ u_int32_t med; -+ u_int16_t peer_idx; -+ u_int16_t aspath_len; -+ u_int16_t nattrs; -+ u_int8_t origin; -+}; -+ -+struct mrt_rib { -+ struct mrt_rib_entry *entries; -+ union mrt_addr prefix; -+ u_int32_t seqnum; -+ u_int16_t nentries; -+ u_int8_t prefixlen; -+}; -+ -+/* data structures for the BGP4MP MESSAGE and STATE types */ -+struct mrt_bgp_state { -+ union mrt_addr src; -+ union mrt_addr dst; -+ u_int32_t src_as; -+ u_int32_t dst_as; -+ u_int16_t old_state; -+ u_int16_t new_state; -+}; -+ -+struct mrt_bgp_msg { -+ union mrt_addr src; -+ union mrt_addr dst; -+ u_int32_t src_as; -+ u_int32_t dst_as; -+ u_int16_t msg_len; -+ void *msg; -+}; -+ -+#define MRT_ATTR_ORIGIN 1 -+#define MRT_ATTR_ASPATH 2 -+#define MRT_ATTR_NEXTHOP 3 -+#define MRT_ATTR_MED 4 -+#define MRT_ATTR_LOCALPREF 5 -+#define MRT_ATTR_MP_REACH_NLRI 14 -+#define MRT_ATTR_AS4PATH 17 -+#define MRT_ATTR_EXTLEN 0x10 -+ -+#define MRT_PREFIX_LEN(x) ((((u_int)x) + 7) / 8) -+ -+struct mrt_parser { -+ void (*dump)(struct mrt_rib *, struct mrt_peer *, void *); -+ void (*state)(struct mrt_bgp_state *, void *); -+ void (*message)(struct mrt_bgp_msg *, void *); -+ void *arg; -+}; -+ -+void mrt_parse(int, struct mrt_parser *, int); Index: net/openbgpd/files/patch-bgpctl_mrtparser.c =================================================================== --- net/openbgpd/files/patch-bgpctl_mrtparser.c +++ /dev/null @@ -1,977 +0,0 @@ -Index: bgpctl/mrtparser.c -=================================================================== -RCS file: bgpctl/mrtparser.c -diff -N bgpctl/mrtparser.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ bgpctl/mrtparser.c 13 Oct 2012 18:22:53 -0000 1.1.1.1 -@@ -0,0 +1,970 @@ -+/* $OpenBSD: mrtparser.c,v 1.2 2012/03/06 07:52:32 claudio Exp $ */ -+/* -+ * Copyright (c) 2011 Claudio Jeker -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mrt.h" -+#include "mrtparser.h" -+ -+void *mrt_read_msg(int, struct mrt_hdr *); -+size_t mrt_read_buf(int, void *, size_t); -+ -+struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, void *); -+struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *); -+int mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **, -+ struct mrt_rib **); -+int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **, -+ struct mrt_rib **); -+int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, sa_family_t, -+ int); -+ -+void mrt_free_peers(struct mrt_peer *); -+void mrt_free_rib(struct mrt_rib *); -+void mrt_free_bgp_state(struct mrt_bgp_state *); -+void mrt_free_bgp_msg(struct mrt_bgp_msg *); -+ -+u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *); -+int mrt_extract_addr(void *, u_int, union mrt_addr *, sa_family_t); -+ -+void * -+mrt_read_msg(int fd, struct mrt_hdr *hdr) -+{ -+ void *buf; -+ -+ bzero(hdr, sizeof(*hdr)); -+ if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) -+ return (NULL); -+ -+ if ((buf = malloc(ntohl(hdr->length))) == NULL) -+ err(1, "malloc(%d)", hdr->length); -+ -+ if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) { -+ free(buf); -+ return (NULL); -+ } -+ return (buf); -+} -+ -+size_t -+mrt_read_buf(int fd, void *buf, size_t len) -+{ -+ char *b = buf; -+ ssize_t n; -+ -+ while (len > 0) { -+ if ((n = read(fd, b, len)) == -1) { -+ if (errno == EINTR) -+ continue; -+ err(1, "read"); -+ } -+ if (n == 0) -+ break; -+ b += n; -+ len -= n; -+ } -+ -+ return (b - (char *)buf); -+} -+ -+void -+mrt_parse(int fd, struct mrt_parser *p, int verbose) -+{ -+ struct mrt_hdr h; -+ struct mrt_peer *pctx = NULL; -+ struct mrt_rib *r; -+ void *msg; -+ -+ while ((msg = mrt_read_msg(fd, &h))) { -+ switch (ntohs(h.type)) { -+ case MSG_NULL: -+ case MSG_START: -+ case MSG_DIE: -+ case MSG_I_AM_DEAD: -+ case MSG_PEER_DOWN: -+ case MSG_PROTOCOL_BGP: -+ case MSG_PROTOCOL_IDRP: -+ case MSG_PROTOCOL_BGP4PLUS: -+ case MSG_PROTOCOL_BGP4PLUS1: -+ if (verbose) -+ printf("deprecated MRT type %d\n", -+ ntohs(h.type)); -+ break; -+ case MSG_PROTOCOL_RIP: -+ case MSG_PROTOCOL_RIPNG: -+ case MSG_PROTOCOL_OSPF: -+ case MSG_PROTOCOL_ISIS_ET: -+ case MSG_PROTOCOL_ISIS: -+ case MSG_PROTOCOL_OSPFV3_ET: -+ case MSG_PROTOCOL_OSPFV3: -+ if (verbose) -+ printf("unsuported MRT type %d\n", -+ ntohs(h.type)); -+ break; -+ case MSG_TABLE_DUMP: -+ switch (ntohs(h.subtype)) { -+ case MRT_DUMP_AFI_IP: -+ case MRT_DUMP_AFI_IPv6: -+ if (p->dump == NULL) -+ break; -+ if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { -+ p->dump(r, pctx, p->arg); -+ mrt_free_rib(r); -+ } -+ break; -+ default: -+ if (verbose) -+ printf("unknown AFI %d in table dump\n", -+ ntohs(h.subtype)); -+ break; -+ } -+ break; -+ case MSG_TABLE_DUMP_V2: -+ switch (ntohs(h.subtype)) { -+ case MRT_DUMP_V2_PEER_INDEX_TABLE: -+ if (p->dump == NULL) -+ break; -+ if (pctx) -+ mrt_free_peers(pctx); -+ pctx = mrt_parse_v2_peer(&h, msg); -+ break; -+ case MRT_DUMP_V2_RIB_IPV4_UNICAST: -+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST: -+ case MRT_DUMP_V2_RIB_IPV6_UNICAST: -+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST: -+ case MRT_DUMP_V2_RIB_GENERIC: -+ if (p->dump == NULL) -+ break; -+ r = mrt_parse_v2_rib(&h, msg); -+ if (r) { -+ p->dump(r, pctx, p->arg); -+ mrt_free_rib(r); -+ } -+ break; -+ default: -+ if (verbose) -+ printf("unhandled BGP4MP subtype %d\n", -+ ntohs(h.subtype)); -+ break; -+ } -+ break; -+ case MSG_PROTOCOL_BGP4MP_ET: -+ /* currently just ignore the microsec field */ -+ msg = (char *)msg + sizeof(u_int32_t); -+ h.length -= sizeof(u_int32_t); -+ /* FALLTHROUGH */ -+ case MSG_PROTOCOL_BGP4MP: -+ switch (ntohs(h.subtype)) { -+ case BGP4MP_STATE_CHANGE: -+ case BGP4MP_STATE_CHANGE_AS4: -+ /* XXX p->state(s, p->arg); */ -+ errx(1, "BGP4MP subtype not yet implemented"); -+ break; -+ case BGP4MP_MESSAGE: -+ case BGP4MP_MESSAGE_AS4: -+ case BGP4MP_MESSAGE_LOCAL: -+ case BGP4MP_MESSAGE_AS4_LOCAL: -+ /* XXX p->message(m, p->arg); */ -+ errx(1, "BGP4MP subtype not yet implemented"); -+ break; -+ case BGP4MP_ENTRY: -+ if (p->dump == NULL) -+ break; -+ if (mrt_parse_dump_mp(&h, msg, &pctx, &r) == -+ 0) { -+ p->dump(r, pctx, p->arg); -+ mrt_free_rib(r); -+ } -+ break; -+ default: -+ if (verbose) -+ printf("unhandled BGP4MP subtype %d\n", -+ ntohs(h.subtype)); -+ break; -+ } -+ break; -+ default: -+ if (verbose) -+ printf("unknown MRT type %d\n", ntohs(h.type)); -+ break; -+ } -+ free(msg); -+ } -+ if (pctx) -+ mrt_free_peers(pctx); -+} -+ -+struct mrt_peer * -+mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg) -+{ -+ struct mrt_peer_entry *peers; -+ struct mrt_peer *p; -+ u_int8_t *b = msg; -+ u_int32_t bid, as4; -+ u_int16_t cnt, i, as2; -+ u_int len = ntohl(hdr->length); -+ -+ if (len < 8) /* min msg size */ -+ return NULL; -+ -+ p = calloc(1, sizeof(struct mrt_peer)); -+ if (p == NULL) -+ err(1, "calloc"); -+ -+ /* collector bgp id */ -+ memcpy(&bid, b, sizeof(bid)); -+ b += sizeof(bid); -+ len -= sizeof(bid); -+ p->bgp_id = ntohl(bid); -+ -+ /* view name length */ -+ memcpy(&cnt, b, sizeof(cnt)); -+ b += sizeof(cnt); -+ len -= sizeof(cnt); -+ cnt = ntohs(cnt); -+ -+ /* view name */ -+ if (cnt > len) -+ goto fail; -+ if (cnt != 0) { -+ if ((p->view = malloc(cnt + 1)) == NULL) -+ err(1, "malloc"); -+ memcpy(p->view, b, cnt); -+ p->view[cnt] = 0; -+ } else -+ if ((p->view = strdup("")) == NULL) -+ err(1, "strdup"); -+ b += cnt; -+ len -= cnt; -+ -+ /* peer_count */ -+ if (len < sizeof(cnt)) -+ goto fail; -+ memcpy(&cnt, b, sizeof(cnt)); -+ b += sizeof(cnt); -+ len -= sizeof(cnt); -+ cnt = ntohs(cnt); -+ -+ /* peer entries */ -+ if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) -+ err(1, "calloc"); -+ for (i = 0; i < cnt; i++) { -+ u_int8_t type; -+ -+ if (len < sizeof(u_int8_t) + sizeof(u_int32_t)) -+ goto fail; -+ type = *b++; -+ len -= 1; -+ memcpy(&bid, b, sizeof(bid)); -+ b += sizeof(bid); -+ len -= sizeof(bid); -+ peers[i].bgp_id = ntohl(bid); -+ -+ if (type & MRT_DUMP_V2_PEER_BIT_I) { -+ if (mrt_extract_addr(b, len, &peers[i].addr, -+ AF_INET6) == -1) -+ goto fail; -+ b += sizeof(struct in6_addr); -+ len -= sizeof(struct in6_addr); -+ } else { -+ if (mrt_extract_addr(b, len, &peers[i].addr, -+ AF_INET) == -1) -+ goto fail; -+ b += sizeof(struct in_addr); -+ len -= sizeof(struct in_addr); -+ } -+ -+ if (type & MRT_DUMP_V2_PEER_BIT_A) { -+ memcpy(&as4, b, sizeof(as4)); -+ b += sizeof(as4); -+ len -= sizeof(as4); -+ as4 = ntohl(as4); -+ } else { -+ memcpy(&as2, b, sizeof(as2)); -+ b += sizeof(as2); -+ len -= sizeof(as2); -+ as4 = ntohs(as2); -+ } -+ peers[i].asnum = as4; -+ } -+ p->peers = peers; -+ p->npeers = cnt; -+ return (p); -+fail: -+ mrt_free_peers(p); -+ return (NULL); -+} -+ -+struct mrt_rib * -+mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg) -+{ -+ struct mrt_rib_entry *entries; -+ struct mrt_rib *r; -+ u_int8_t *b = msg; -+ u_int len = ntohl(hdr->length); -+ u_int32_t snum; -+ u_int16_t cnt, i; -+ u_int8_t plen; -+ -+ if (len < sizeof(snum) + 1) -+ return NULL; -+ -+ r = calloc(1, sizeof(struct mrt_rib)); -+ if (r == NULL) -+ err(1, "calloc"); -+ -+ /* seq_num */ -+ memcpy(&snum, b, sizeof(snum)); -+ b += sizeof(snum); -+ len -= sizeof(snum); -+ r->seqnum = ntohl(snum); -+ -+ switch (ntohs(hdr->subtype)) { -+ case MRT_DUMP_V2_RIB_IPV4_UNICAST: -+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST: -+ plen = *b++; -+ len -= 1; -+ if (len < MRT_PREFIX_LEN(plen)) -+ goto fail; -+ r->prefix.sin.sin_family = AF_INET; -+ r->prefix.sin.sin_len = sizeof(struct sockaddr_in); -+ memcpy(&r->prefix.sin.sin_addr, b, MRT_PREFIX_LEN(plen)); -+ b += MRT_PREFIX_LEN(plen); -+ len -= MRT_PREFIX_LEN(plen); -+ r->prefixlen = plen; -+ break; -+ case MRT_DUMP_V2_RIB_IPV6_UNICAST: -+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST: -+ plen = *b++; -+ len -= 1; -+ if (len < MRT_PREFIX_LEN(plen)) -+ goto fail; -+ r->prefix.sin6.sin6_family = AF_INET6; -+ r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); -+ memcpy(&r->prefix.sin6.sin6_addr, b, MRT_PREFIX_LEN(plen)); -+ b += MRT_PREFIX_LEN(plen); -+ len -= MRT_PREFIX_LEN(plen); -+ r->prefixlen = plen; -+ break; -+ case MRT_DUMP_V2_RIB_GENERIC: -+ /* XXX unhandled */ -+ errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented"); -+ goto fail; -+ } -+ -+ /* entries count */ -+ if (len < sizeof(cnt)) -+ goto fail; -+ memcpy(&cnt, b, sizeof(cnt)); -+ b += sizeof(cnt); -+ len -= sizeof(cnt); -+ cnt = ntohs(cnt); -+ r->nentries = cnt; -+ -+ /* entries */ -+ if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL) -+ err(1, "calloc"); -+ for (i = 0; i < cnt; i++) { -+ u_int32_t otm; -+ u_int16_t pix, alen; -+ if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t)) -+ goto fail; -+ /* peer index */ -+ memcpy(&pix, b, sizeof(pix)); -+ b += sizeof(pix); -+ len -= sizeof(pix); -+ entries[i].peer_idx = ntohs(pix); -+ -+ /* originated */ -+ memcpy(&otm, b, sizeof(otm)); -+ b += sizeof(otm); -+ len -= sizeof(otm); -+ entries[i].originated = ntohl(otm); -+ -+ /* attr_len */ -+ memcpy(&alen, b, sizeof(alen)); -+ b += sizeof(alen); -+ len -= sizeof(alen); -+ alen = ntohs(alen); -+ -+ /* attr */ -+ if (len < alen) -+ goto fail; -+ if (mrt_extract_attr(&entries[i], b, alen, -+ r->prefix.sa.sa_family, 1) == -1) -+ goto fail; -+ b += alen; -+ len -= alen; -+ } -+ r->entries = entries; -+ return (r); -+fail: -+ mrt_free_rib(r); -+ return (NULL); -+} -+ -+int -+mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, -+ struct mrt_rib **rp) -+{ -+ struct mrt_peer *p; -+ struct mrt_rib *r; -+ struct mrt_rib_entry *re; -+ u_int8_t *b = msg; -+ u_int len = ntohl(hdr->length); -+ u_int16_t asnum, alen; -+ -+ if (*pp == NULL) { -+ *pp = calloc(1, sizeof(struct mrt_peer)); -+ if (*pp == NULL) -+ err(1, "calloc"); -+ (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); -+ if ((*pp)->peers == NULL) -+ err(1, "calloc"); -+ (*pp)->npeers = 1; -+ } -+ p = *pp; -+ -+ *rp = r = calloc(1, sizeof(struct mrt_rib)); -+ if (r == NULL) -+ err(1, "calloc"); -+ re = calloc(1, sizeof(struct mrt_rib_entry)); -+ if (re == NULL) -+ err(1, "calloc"); -+ r->nentries = 1; -+ r->entries = re; -+ -+ if (len < 2 * sizeof(u_int16_t)) -+ goto fail; -+ /* view */ -+ b += sizeof(u_int16_t); -+ len -= sizeof(u_int16_t); -+ /* seqnum */ -+ memcpy(&r->seqnum, b, sizeof(u_int16_t)); -+ b += sizeof(u_int16_t); -+ len -= sizeof(u_int16_t); -+ r->seqnum = ntohs(r->seqnum); -+ -+ switch (ntohs(hdr->subtype)) { -+ case MRT_DUMP_AFI_IP: -+ if (mrt_extract_addr(b, len, &r->prefix, AF_INET) == -1) -+ goto fail; -+ b += sizeof(struct in_addr); -+ len -= sizeof(struct in_addr); -+ break; -+ case MRT_DUMP_AFI_IPv6: -+ if (mrt_extract_addr(b, len, &r->prefix, AF_INET6) == -1) -+ goto fail; -+ b += sizeof(struct in6_addr); -+ len -= sizeof(struct in6_addr); -+ break; -+ } -+ if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2) -+ goto fail; -+ r->prefixlen = *b++; -+ len -= 1; -+ /* status */ -+ b += 1; -+ len -= 1; -+ /* originated */ -+ memcpy(&re->originated, b, sizeof(u_int32_t)); -+ b += sizeof(u_int32_t); -+ len -= sizeof(u_int32_t); -+ re->originated = ntohl(re->originated); -+ /* peer ip */ -+ switch (ntohs(hdr->subtype)) { -+ case MRT_DUMP_AFI_IP: -+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) -+ goto fail; -+ b += sizeof(struct in_addr); -+ len -= sizeof(struct in_addr); -+ break; -+ case MRT_DUMP_AFI_IPv6: -+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) -+ goto fail; -+ b += sizeof(struct in6_addr); -+ len -= sizeof(struct in6_addr); -+ break; -+ } -+ memcpy(&asnum, b, sizeof(asnum)); -+ b += sizeof(asnum); -+ len -= sizeof(asnum); -+ p->peers->asnum = ntohs(asnum); -+ -+ memcpy(&alen, b, sizeof(alen)); -+ b += sizeof(alen); -+ len -= sizeof(alen); -+ alen = ntohs(alen); -+ -+ /* attr */ -+ if (len < alen) -+ goto fail; -+ if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) -+ goto fail; -+ b += alen; -+ len -= alen; -+ -+ return (0); -+fail: -+ mrt_free_rib(r); -+ return (-1); -+} -+ -+int -+mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, -+ struct mrt_rib **rp) -+{ -+ struct mrt_peer *p; -+ struct mrt_rib *r; -+ struct mrt_rib_entry *re; -+ u_int8_t *b = msg; -+ u_int len = ntohl(hdr->length); -+ u_int16_t asnum, alen, afi; -+ u_int8_t safi, nhlen; -+ sa_family_t af; -+ -+ if (*pp == NULL) { -+ *pp = calloc(1, sizeof(struct mrt_peer)); -+ if (*pp == NULL) -+ err(1, "calloc"); -+ (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); -+ if ((*pp)->peers == NULL) -+ err(1, "calloc"); -+ (*pp)->npeers = 1; -+ } -+ p = *pp; -+ -+ *rp = r = calloc(1, sizeof(struct mrt_rib)); -+ if (r == NULL) -+ err(1, "calloc"); -+ re = calloc(1, sizeof(struct mrt_rib_entry)); -+ if (re == NULL) -+ err(1, "calloc"); -+ r->nentries = 1; -+ r->entries = re; -+ -+ if (len < 4 * sizeof(u_int16_t)) -+ goto fail; -+ /* source AS */ -+ b += sizeof(u_int16_t); -+ len -= sizeof(u_int16_t); -+ /* dest AS */ -+ memcpy(&asnum, b, sizeof(asnum)); -+ b += sizeof(asnum); -+ len -= sizeof(asnum); -+ p->peers->asnum = ntohs(asnum); -+ /* iface index */ -+ b += sizeof(u_int16_t); -+ len -= sizeof(u_int16_t); -+ /* afi */ -+ memcpy(&afi, b, sizeof(afi)); -+ b += sizeof(afi); -+ len -= sizeof(afi); -+ afi = ntohs(afi); -+ -+ /* source + dest ip */ -+ switch (afi) { -+ case MRT_DUMP_AFI_IP: -+ if (len < 2 * sizeof(struct in_addr)) -+ goto fail; -+ /* source IP */ -+ b += sizeof(struct in_addr); -+ len -= sizeof(struct in_addr); -+ /* dest IP */ -+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET) == -1) -+ goto fail; -+ b += sizeof(struct in_addr); -+ len -= sizeof(struct in_addr); -+ break; -+ case MRT_DUMP_AFI_IPv6: -+ if (len < 2 * sizeof(struct in6_addr)) -+ goto fail; -+ /* source IP */ -+ b += sizeof(struct in6_addr); -+ len -= sizeof(struct in6_addr); -+ /* dest IP */ -+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1) -+ goto fail; -+ b += sizeof(struct in6_addr); -+ len -= sizeof(struct in6_addr); -+ break; -+ } -+ -+ if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t)) -+ goto fail; -+ /* view + status */ -+ b += 2 * sizeof(u_int16_t); -+ len -= 2 * sizeof(u_int16_t); -+ /* originated */ -+ memcpy(&re->originated, b, sizeof(u_int32_t)); -+ b += sizeof(u_int32_t); -+ len -= sizeof(u_int32_t); -+ re->originated = ntohl(re->originated); -+ -+ /* afi */ -+ memcpy(&afi, b, sizeof(afi)); -+ b += sizeof(afi); -+ len -= sizeof(afi); -+ afi = ntohs(afi); -+ -+ /* safi */ -+ safi = *b++; -+ len -= 1; -+ -+ switch (afi) { -+ case MRT_DUMP_AFI_IP: -+ if (safi == 1 || safi == 2) { -+ af = AF_INET; -+ break; -+ } else if (safi == 128) { -+ af = AF_VPNv4; -+ break; -+ } -+ goto fail; -+ case MRT_DUMP_AFI_IPv6: -+ if (safi != 1 && safi != 2) -+ goto fail; -+ af = AF_INET6; -+ break; -+ default: -+ goto fail; -+ } -+ -+ /* nhlen */ -+ nhlen = *b++; -+ len -= 1; -+ -+ /* nexthop */ -+ if (mrt_extract_addr(b, len, &re->nexthop, af) == -1) -+ goto fail; -+ if (len < nhlen) -+ goto fail; -+ b += nhlen; -+ len -= nhlen; -+ -+ if (len < 1) -+ goto fail; -+ r->prefixlen = *b++; -+ len -= 1; -+ -+ /* prefix */ -+ switch (af) { -+ case AF_INET: -+ if (len < MRT_PREFIX_LEN(r->prefixlen)) -+ goto fail; -+ r->prefix.sin.sin_family = AF_INET; -+ r->prefix.sin.sin_len = sizeof(struct sockaddr_in); -+ memcpy(&r->prefix.sin.sin_addr, b, -+ MRT_PREFIX_LEN(r->prefixlen)); -+ b += MRT_PREFIX_LEN(r->prefixlen); -+ len -= MRT_PREFIX_LEN(r->prefixlen); -+ break; -+ case AF_INET6: -+ if (len < MRT_PREFIX_LEN(r->prefixlen)) -+ goto fail; -+ r->prefix.sin6.sin6_family = AF_INET6; -+ r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6); -+ memcpy(&r->prefix.sin6.sin6_addr, b, -+ MRT_PREFIX_LEN(r->prefixlen)); -+ b += MRT_PREFIX_LEN(r->prefixlen); -+ len -= MRT_PREFIX_LEN(r->prefixlen); -+ break; -+ case AF_VPNv4: -+ if (len < MRT_PREFIX_LEN(r->prefixlen)) -+ goto fail; -+ errx(1, "AF_VPNv4 handling not yet implemented"); -+ goto fail; -+ } -+ -+ memcpy(&alen, b, sizeof(alen)); -+ b += sizeof(alen); -+ len -= sizeof(alen); -+ alen = ntohs(alen); -+ -+ /* attr */ -+ if (len < alen) -+ goto fail; -+ if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1) -+ goto fail; -+ b += alen; -+ len -= alen; -+ -+ return (0); -+fail: -+ mrt_free_rib(r); -+ return (-1); -+} -+ -+int -+mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, sa_family_t af, -+ int as4) -+{ -+ struct mrt_attr *ap; -+ u_int32_t tmp; -+ u_int16_t attr_len; -+ u_int8_t type, flags, *attr; -+ -+ do { -+ if (alen < 3) -+ return (-1); -+ attr = a; -+ flags = *a++; -+ alen -= 1; -+ type = *a++; -+ alen -= 1; -+ -+ if (flags & MRT_ATTR_EXTLEN) { -+ if (alen < 2) -+ return (-1); -+ memcpy(&attr_len, a, sizeof(attr_len)); -+ attr_len = ntohs(attr_len); -+ a += sizeof(attr_len); -+ alen -= sizeof(attr_len); -+ } else { -+ attr_len = *a++; -+ alen -= 1; -+ } -+ switch (type) { -+ case MRT_ATTR_ORIGIN: -+ if (attr_len != 1) -+ return (-1); -+ re->origin = *a; -+ break; -+ case MRT_ATTR_ASPATH: -+ if (as4) { -+ re->aspath_len = attr_len; -+ if ((re->aspath = malloc(attr_len)) == NULL) -+ err(1, "malloc"); -+ memcpy(re->aspath, a, attr_len); -+ } else { -+ re->aspath = mrt_aspath_inflate(a, attr_len, -+ &re->aspath_len); -+ if (re->aspath == NULL) -+ return (-1); -+ } -+ break; -+ case MRT_ATTR_NEXTHOP: -+ if (attr_len != 4) -+ return (-1); -+ if (af != AF_INET) -+ break; -+ memcpy(&tmp, a, sizeof(tmp)); -+ re->nexthop.sin.sin_len = sizeof(struct sockaddr_in); -+ re->nexthop.sin.sin_family = AF_INET; -+ re->nexthop.sin.sin_addr.s_addr = tmp; -+ break; -+ case MRT_ATTR_MED: -+ if (attr_len != 4) -+ return (-1); -+ memcpy(&tmp, a, sizeof(tmp)); -+ re->med = ntohl(tmp); -+ break; -+ case MRT_ATTR_LOCALPREF: -+ if (attr_len != 4) -+ return (-1); -+ memcpy(&tmp, a, sizeof(tmp)); -+ re->local_pref = ntohl(tmp); -+ break; -+ case MRT_ATTR_MP_REACH_NLRI: -+ /* -+ * XXX horrible hack: -+ * Once again IETF and the real world differ in the -+ * implementation. In short the abbreviated MP_NLRI -+ * hack in the standard is not used in real life. -+ * Detect the two cases by looking at the first byte -+ * of the payload (either the nexthop addr length (RFC) -+ * or the high byte of the AFI (old form)). If the -+ * first byte matches the expected nexthop length it -+ * is expected to be the RFC 6396 encoding. -+ */ -+ if (*a != attr_len - 1) { -+ a += 3; -+ alen -= 3; -+ attr_len -= 3; -+ } -+ switch (af) { -+ case AF_INET6: -+ if (attr_len < sizeof(struct in6_addr) + 1) -+ return (-1); -+ re->nexthop.sin6.sin6_len = -+ sizeof(struct sockaddr_in6); -+ re->nexthop.sin6.sin6_family = AF_INET6; -+ memcpy(&re->nexthop.sin6.sin6_addr, a + 1, -+ sizeof(struct in6_addr)); -+ break; -+ case AF_VPNv4: -+ if (attr_len < sizeof(u_int64_t) + -+ sizeof(struct in_addr)) -+ return (-1); -+ re->nexthop.svpn4.sv_len = -+ sizeof(struct sockaddr_vpn4); -+ re->nexthop.svpn4.sv_family = AF_VPNv4; -+ memcpy(&tmp, a + 1 + sizeof(u_int64_t), -+ sizeof(tmp)); -+ re->nexthop.svpn4.sv_addr.s_addr = tmp; -+ break; -+ } -+ break; -+ case MRT_ATTR_AS4PATH: -+ if (!as4) { -+ if (re->aspath) -+ free(re->aspath); -+ re->aspath_len = attr_len; -+ if ((re->aspath = malloc(attr_len)) == NULL) -+ err(1, "malloc"); -+ memcpy(re->aspath, a, attr_len); -+ break; -+ } -+ /* FALLTHROUGH */ -+ default: -+ re->nattrs++; -+ if (re->nattrs >= UCHAR_MAX) -+ err(1, "too many attributes"); -+ ap = realloc(re->attrs, -+ re->nattrs * sizeof(struct mrt_attr)); -+ if (ap == NULL) -+ err(1, "realloc"); -+ re->attrs = ap; -+ ap = re->attrs + re->nattrs - 1; -+ ap->attr_len = a + attr_len - attr; -+ if ((ap->attr = malloc(ap->attr_len)) == NULL) -+ err(1, "malloc"); -+ memcpy(ap->attr, attr, ap->attr_len); -+ break; -+ } -+ a += attr_len; -+ alen -= attr_len; -+ } while (alen > 0); -+ -+ return (0); -+} -+ -+void -+mrt_free_peers(struct mrt_peer *p) -+{ -+ free(p->peers); -+ free(p->view); -+ free(p); -+} -+ -+void -+mrt_free_rib(struct mrt_rib *r) -+{ -+ u_int16_t i, j; -+ -+ for (i = 0; i < r->nentries && r->entries; i++) { -+ for (j = 0; j < r->entries[i].nattrs; j++) -+ free(r->entries[i].attrs[j].attr); -+ free(r->entries[i].attrs); -+ free(r->entries[i].aspath); -+ } -+ -+ free(r->entries); -+ free(r); -+} -+ -+void -+mrt_free_bgp_state(struct mrt_bgp_state *s) -+{ -+ free(s); -+} -+ -+void -+mrt_free_bgp_msg(struct mrt_bgp_msg *m) -+{ -+ free(m->msg); -+ free(m); -+} -+ -+u_char * -+mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen) -+{ -+ u_int8_t *seg, *nseg, *ndata; -+ u_int16_t seg_size, olen, nlen; -+ u_int8_t seg_len; -+ -+ /* first calculate the length of the aspath */ -+ seg = data; -+ nlen = 0; -+ for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { -+ seg_len = seg[1]; -+ seg_size = 2 + sizeof(u_int16_t) * seg_len; -+ nlen += 2 + sizeof(u_int32_t) * seg_len; -+ -+ if (seg_size > olen) -+ return NULL; -+ } -+ -+ *newlen = nlen; -+ if ((ndata = malloc(nlen)) == NULL) -+ err(1, "malloc"); -+ -+ /* then copy the aspath */ -+ seg = data; -+ for (nseg = ndata; nseg < ndata + nlen; ) { -+ *nseg++ = *seg++; -+ *nseg++ = seg_len = *seg++; -+ for (; seg_len > 0; seg_len--) { -+ *nseg++ = 0; -+ *nseg++ = 0; -+ *nseg++ = *seg++; -+ *nseg++ = *seg++; -+ } -+ } -+ -+ return (ndata); -+} -+ -+int -+mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af) -+{ -+ u_int8_t *b = msg; -+ -+ switch (af) { -+ case AF_INET: -+ if (len < sizeof(struct in_addr)) -+ return (-1); -+ addr->sin.sin_family = AF_INET; -+ addr->sin.sin_len = sizeof(struct sockaddr_in); -+ memcpy(&addr->sin.sin_addr, b, sizeof(struct in_addr)); -+ return sizeof(struct in_addr); -+ case AF_INET6: -+ if (len < sizeof(struct in6_addr)) -+ return (-1); -+ addr->sin6.sin6_family = AF_INET6; -+ addr->sin6.sin6_len = sizeof(struct sockaddr_in6); -+ memcpy(&addr->sin6.sin6_addr, b, sizeof(struct in6_addr)); -+ return sizeof(struct in6_addr); -+ case AF_VPNv4: -+ if (len < sizeof(u_int64_t) + sizeof(struct in_addr)) -+ return (-1); -+ addr->svpn4.sv_len = sizeof(struct sockaddr_vpn4); -+ addr->svpn4.sv_family = AF_VPNv4; -+ memcpy(&addr->svpn4.sv_addr, b + sizeof(u_int64_t), -+ sizeof(struct in_addr)); -+ return (sizeof(u_int64_t) + sizeof(struct in_addr)); -+ default: -+ return (-1); -+ } -+} Index: net/openbgpd/files/patch-bgpctl_parser.h =================================================================== --- net/openbgpd/files/patch-bgpctl_parser.h +++ /dev/null @@ -1,55 +0,0 @@ -Index: bgpctl/parser.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/parser.h,v -retrieving revision 1.1.1.6 -retrieving revision 1.1.1.9 -diff -u -p -r1.1.1.6 -r1.1.1.9 ---- bgpctl/parser.h 14 Feb 2010 20:20:14 -0000 1.1.1.6 -+++ bgpctl/parser.h 13 Oct 2012 18:22:53 -0000 1.1.1.9 -@@ -1,4 +1,4 @@ --/* $OpenBSD: parser.h,v 1.19 2009/06/06 06:05:41 claudio Exp $ */ -+/* $OpenBSD: parser.h,v 1.23 2011/09/21 10:37:51 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -29,7 +29,9 @@ enum actions { - SHOW_NEIGHBOR_TIMERS, - SHOW_NEIGHBOR_TERSE, - SHOW_FIB, -+ SHOW_FIB_TABLES, - SHOW_RIB, -+ SHOW_MRT, - SHOW_RIB_MEM, - SHOW_NEXTHOP, - SHOW_INTERFACE, -@@ -37,6 +39,8 @@ enum actions { - FIB, - FIB_COUPLE, - FIB_DECOUPLE, -+ LOG_VERBOSE, -+ LOG_BRIEF, - NEIGHBOR, - NEIGHBOR_UP, - NEIGHBOR_DOWN, -@@ -46,6 +50,7 @@ enum actions { - NETWORK_REMOVE, - NETWORK_FLUSH, - NETWORK_SHOW, -+ NETWORK_MRT, - IRRFILTER - }; - -@@ -59,9 +64,11 @@ 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; -+ int mrtfd; - }; - - __dead void usage(void); Index: net/openbgpd/files/patch-bgpctl_parser.c =================================================================== --- net/openbgpd/files/patch-bgpctl_parser.c +++ /dev/null @@ -1,400 +0,0 @@ -Index: bgpctl/parser.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/parser.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.7 -diff -u -p -r1.1.1.6 -r1.7 ---- bgpctl/parser.c 14 Feb 2010 20:20:14 -0000 1.1.1.6 -+++ bgpctl/parser.c 13 Oct 2012 18:35:56 -0000 1.7 -@@ -1,4 +1,4 @@ --/* $OpenBSD: parser.c,v 1.54 2009/06/12 16:44:02 claudio Exp $ */ -+/* $OpenBSD: parser.c,v 1.64 2012/03/27 18:24:11 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -16,11 +16,16 @@ - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -+#if defined(__FreeBSD__) /* compat */ -+#include "openbsd-compat.h" -+#endif /* defined(__FreeBSD__) */ -+ - #include - #include - - #include - #include -+#include - #include - #include - #include -@@ -52,7 +57,9 @@ enum token_type { - PREPSELF, - WEIGHT, - FAMILY, -- GETOPT -+ GETOPT, -+ RTABLE, -+ FILENAME - }; - - enum getopts { -@@ -72,14 +79,18 @@ static const struct token t_show[]; - static const struct token t_show_summary[]; - static const struct token t_show_fib[]; - static const struct token t_show_rib[]; -+static const struct token t_show_mrt[]; -+static const struct token t_show_mrt_file[]; - static const struct token t_show_rib_neigh[]; -+static const struct token t_show_mrt_neigh[]; - static const struct token t_show_rib_rib[]; - static const struct token t_show_neighbor[]; - static const struct token t_show_neighbor_modifiers[]; - static const struct token t_fib[]; - static const struct token t_neighbor[]; - static const struct token t_neighbor_modifiers[]; --static const struct token t_show_as[]; -+static const struct token t_show_rib_as[]; -+static const struct token t_show_mrt_as[]; - static const struct token t_show_prefix[]; - static const struct token t_show_ip[]; - static const struct token t_show_community[]; -@@ -97,6 +108,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 +119,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,8 +131,10 @@ 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}, -+ { KEYWORD, "mrt", SHOW_MRT, t_show_mrt}, - { ENDTOKEN, "", NONE, NULL} - }; - -@@ -128,24 +145,26 @@ 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[] = { - { NOTOKEN, "", NONE, NULL}, -- { ASTYPE, "as", AS_ALL, t_show_as}, -- { ASTYPE, "source-as", AS_SOURCE, t_show_as}, -- { ASTYPE, "transit-as", AS_TRANSIT, t_show_as}, -- { ASTYPE, "peer-as", AS_PEER, t_show_as}, -+ { ASTYPE, "as", AS_ALL, t_show_rib_as}, -+ { ASTYPE, "source-as", AS_SOURCE, t_show_rib_as}, -+ { ASTYPE, "transit-as", AS_TRANSIT, t_show_rib_as}, -+ { ASTYPE, "peer-as", AS_PEER, t_show_rib_as}, - { ASTYPE, "empty-as", AS_EMPTY, t_show_rib}, - { KEYWORD, "community", NONE, t_show_community}, -+ { FLAG, "selected", F_CTL_ACTIVE, t_show_rib}, - { FLAG, "detail", F_CTL_DETAIL, t_show_rib}, - { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, - { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, -@@ -158,12 +177,38 @@ static const struct token t_show_rib[] = - { ENDTOKEN, "", NONE, NULL} - }; - -+ -+static const struct token t_show_mrt[] = { -+ { NOTOKEN, "", NONE, NULL}, -+ { ASTYPE, "as", AS_ALL, t_show_mrt_as}, -+ { ASTYPE, "source-as", AS_SOURCE, t_show_mrt_as}, -+ { ASTYPE, "transit-as", AS_TRANSIT, t_show_mrt_as}, -+ { ASTYPE, "peer-as", AS_PEER, t_show_mrt_as}, -+ { ASTYPE, "empty-as", AS_EMPTY, t_show_mrt}, -+ { FLAG, "detail", F_CTL_DETAIL, t_show_mrt}, -+ { KEYWORD, "neighbor", NONE, t_show_mrt_neigh}, -+ { KEYWORD, "file", NONE, t_show_mrt_file}, -+ { FAMILY, "", NONE, t_show_mrt}, -+ { PREFIX, "", NONE, t_show_prefix}, -+ { ENDTOKEN, "", NONE, NULL} -+}; -+ -+static const struct token t_show_mrt_file[] = { -+ { FILENAME, "", NONE, t_show_mrt}, -+ { ENDTOKEN, "", NONE, NULL} -+}; -+ - static const struct token t_show_rib_neigh[] = { - { PEERADDRESS, "", NONE, t_show_rib}, - { PEERDESC, "", NONE, t_show_rib}, - { ENDTOKEN, "", NONE, NULL} - }; - -+static const struct token t_show_mrt_neigh[] = { -+ { PEERADDRESS, "", NONE, t_show_mrt}, -+ { ENDTOKEN, "", NONE, NULL} -+}; -+ - static const struct token t_show_rib_rib[] = { - { RIBNAME, "", NONE, t_show_rib}, - { ENDTOKEN, "", NONE, NULL} -@@ -187,6 +232,7 @@ static const struct token t_show_neighbo - 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} - }; - -@@ -204,11 +250,16 @@ static const struct token t_neighbor_mod - { ENDTOKEN, "", NONE, NULL} - }; - --static const struct token t_show_as[] = { -+static const struct token t_show_rib_as[] = { - { ASNUM, "", NONE, t_show_rib}, - { ENDTOKEN, "", NONE, NULL} - }; - -+static const struct token t_show_mrt_as[] = { -+ { ASNUM, "", NONE, t_show_mrt}, -+ { ENDTOKEN, "", NONE, NULL} -+}; -+ - static const struct token t_show_prefix[] = { - { NOTOKEN, "", NONE, NULL}, - { FLAG, "all", F_LONGER, NULL}, -@@ -231,6 +282,7 @@ static const struct token t_network[] = - { KEYWORD, "delete", NETWORK_REMOVE, t_prefix}, - { KEYWORD, "flush", NETWORK_FLUSH, NULL}, - { KEYWORD, "show", NETWORK_SHOW, t_network_show}, -+ { KEYWORD, "mrt", NETWORK_MRT, t_show_mrt}, - { ENDTOKEN, "", NONE, NULL} - }; - -@@ -311,6 +363,22 @@ static const struct token t_irrfilter_op - { 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 +472,22 @@ match_token(int *argc, char **argv[], co - 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.af = AF_INET; -+ res.aid = AID_INET; - } -- if (!strcmp(word, "inet6") || !strcmp(word, "IPv6")) { -+ if (!strcmp(word, "inet6") || -+ !strcasecmp(word, "IPv6")) { - match++; - t = &table[i]; -- res.af = AF_INET6; -+ res.aid = AID_INET6; -+ } -+ if (!strcasecmp(word, "VPNv4")) { -+ match++; -+ t = &table[i]; -+ res.aid = AID_VPN_IPv4; - } - break; - case ADDRESS: -@@ -485,6 +560,7 @@ match_token(int *argc, char **argv[], co - case PREPNBR: - case PREPSELF: - case WEIGHT: -+ case RTABLE: - if (word != NULL && strlen(word) > 0 && - parse_number(word, &res, table[i].type)) { - match++; -@@ -518,6 +594,23 @@ match_token(int *argc, char **argv[], co - t = &table[i]; - } - break; -+ case FILENAME: -+ if (word != NULL && strlen(word) > 0) { -+ if ((res.mrtfd = open(word, O_RDONLY)) == -1) { -+ /* -+ * ignore error if path has no / and -+ * does not exist. In hope to print -+ * usage. -+ */ -+ if (errno == ENOENT && -+ !strchr(word, '/')) -+ break; -+ err(1, "mrt open(%s)", word); -+ } -+ match++; -+ t = &table[i]; -+ } -+ break; - case ENDTOKEN: - break; - } -@@ -577,6 +670,9 @@ show_valid_args(const struct token table - case WEIGHT: - fprintf(stderr, " \n"); - break; -+ case RTABLE: -+ fprintf(stderr, " \n"); -+ break; - case NEXTHOP: - fprintf(stderr, "
\n"); - break; -@@ -584,11 +680,14 @@ show_valid_args(const struct token table - fprintf(stderr, " \n"); - break; - case FAMILY: -- fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 ]\n"); -+ fprintf(stderr, " [ inet | inet6 | IPv4 | IPv6 | VPNv4 ]\n"); - break; - case GETOPT: - fprintf(stderr, " \n"); - break; -+ case FILENAME: -+ fprintf(stderr, " \n"); -+ break; - case ENDTOKEN: - break; - } -@@ -608,7 +707,7 @@ parse_addr(const char *word, struct bgpd - 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 +717,7 @@ parse_addr(const char *word, struct bgpd - 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); - } -@@ -647,7 +740,7 @@ parse_prefix(const char *word, struct bg - if ((p = strrchr(word, '/')) != NULL) { - mask = strtonum(p + 1, 0, 128, &errstr); - if (errstr) -- errx(1, "invalid netmask: %s", errstr); -+ errx(1, "netmask %s", errstr); - - if ((ps = malloc(strlen(word) - strlen(p) + 1)) == NULL) - err(1, "parse_prefix: malloc"); -@@ -663,15 +756,15 @@ parse_prefix(const char *word, struct bg - 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 +799,7 @@ parse_asnum(const char *word, u_int32_t - 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 +823,11 @@ parse_number(const char *word, struct pa - 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 +980,14 @@ bgpctl_getopt(int *argc, char **argv[], - 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; Index: net/openbgpd/files/patch-bgpctl_whois.c =================================================================== --- net/openbgpd/files/patch-bgpctl_whois.c +++ /dev/null @@ -1,18 +0,0 @@ -Index: bgpctl/whois.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/whois.c,v -retrieving revision 1.1.1.5 -retrieving revision 1.1.1.7 -diff -u -p -r1.1.1.5 -r1.1.1.7 ---- bgpctl/whois.c 14 Feb 2010 20:20:14 -0000 1.1.1.5 -+++ bgpctl/whois.c 13 Oct 2012 18:22:54 -0000 1.1.1.7 -@@ -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"; Index: net/openbgpd/files/patch-bgpd_Makefile =================================================================== --- net/openbgpd/files/patch-bgpd_Makefile +++ /dev/null @@ -1,30 +0,0 @@ ---- bgpd/Makefile.orig 2013-02-21 19:20:05.000000000 +0000 -+++ bgpd/Makefile 2013-02-21 19:20:54.000000000 +0000 -@@ -1,15 +1,25 @@ - # $OpenBSD: Makefile,v 1.28 2009/06/25 14:14:54 deraadt 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 -+ 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 - Index: net/openbgpd/files/patch-bgpd_bgpd.h =================================================================== --- net/openbgpd/files/patch-bgpd_bgpd.h +++ /dev/null @@ -1,872 +0,0 @@ -Index: bgpd/bgpd.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.h,v -retrieving revision 1.1.1.8 -retrieving revision 1.15 -diff -u -p -r1.1.1.8 -r1.15 ---- bgpd/bgpd.h 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/bgpd.h 16 May 2014 00:36:26 -0000 1.15 -@@ -1,4 +1,4 @@ --/* $OpenBSD: bgpd.h,v 1.241 2009/06/12 16:42:53 claudio Exp $ */ -+/* $OpenBSD: bgpd.h,v 1.273 2012/09/18 10:10:00 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -30,11 +31,16 @@ - #include - #include - --#include -+#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,9 +82,12 @@ - #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 -+#define F_CTL_ACTIVE 0x8000 - - /* - * Limit the number of control messages generated by the RDE and queued in -@@ -109,18 +111,75 @@ 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_MIN 1 /* skip AID_UNSPEC since that is a dummy */ -+ -+#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 +200,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,12 +259,24 @@ 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 */ --}; -+ struct { -+ int16_t timeout; /* graceful restart timeout */ -+ int8_t flags[AID_MAX]; /* graceful restart per AID flags */ -+ int8_t restart; /* graceful restart, RFC 4724 */ -+ } grestart; -+ int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */ -+ int8_t refresh; /* route refresh, RFC 2918 */ -+ int8_t as4byte; /* 4-byte ASnum, RFC 4893 */ -+}; -+ -+#define CAPA_GR_PRESENT 0x01 -+#define CAPA_GR_RESTART 0x02 -+#define CAPA_GR_FORWARD 0x04 -+#define CAPA_GR_RESTARTING 0x08 -+ -+#define CAPA_GR_TIMEMASK 0x0fff -+#define CAPA_GR_R_FLAG 0x8000 -+#define CAPA_GR_F_FLAG 0x80 - - struct peer_config { - struct bgpd_addr remote_addr; -@@ -237,7 +303,7 @@ struct peer_config { - u_int8_t template; - u_int8_t remote_masklen; - u_int8_t cloned; -- u_int8_t ebgp; /* 1 = ebgp, 0 = ibgp */ -+ u_int8_t ebgp; /* 0 = ibgp else ebgp */ - u_int8_t distance; /* 1 = direct, >1 = multihop */ - u_int8_t passive; - u_int8_t down; -@@ -248,21 +314,33 @@ 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, -+ NETWORK_MRTCLONE -+}; -+ - struct network_config { -- struct bgpd_addr prefix; -- struct filter_set_head attrset; -- u_int8_t prefixlen; -+ struct bgpd_addr prefix; -+ struct filter_set_head attrset; -+ struct rde_aspath *asp; -+ 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 +354,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,11 +365,14 @@ 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_ASPATH, -+ IMSG_NETWORK_ATTR, - IMSG_NETWORK_REMOVE, - IMSG_NETWORK_FLUSH, - IMSG_NETWORK_DONE, -@@ -302,19 +382,25 @@ 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, - IMSG_SESSION_ADD, - IMSG_SESSION_UP, - IMSG_SESSION_DOWN, -+ IMSG_SESSION_STALE, -+ IMSG_SESSION_FLUSH, -+ IMSG_SESSION_RESTARTED, - IMSG_MRT_OPEN, - IMSG_MRT_REOPEN, - IMSG_MRT_CLOSE, - IMSG_KROUTE_CHANGE, - IMSG_KROUTE_DELETE, -- IMSG_KROUTE6_CHANGE, -- IMSG_KROUTE6_DELETE, - IMSG_NEXTHOP_ADD, - IMSG_NEXTHOP_REMOVE, - IMSG_NEXTHOP_UPDATE, -@@ -337,6 +423,7 @@ enum ctl_results { - CTL_RES_DENIED, - CTL_RES_NOCAP, - CTL_RES_PARSE_ERROR, -+ CTL_RES_PENDING, - CTL_RES_NOMEM - }; - -@@ -379,9 +466,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 +521,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 +542,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 +555,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 +570,11 @@ 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 -+#define F_PREF_STALE 0x10 - - struct ctl_show_rib { - struct bgpd_addr true_nexthop; -@@ -472,9 +586,7 @@ struct ctl_show_rib { - u_int32_t remote_id; - u_int32_t local_pref; - u_int32_t med; -- u_int32_t prefix_cnt; -- u_int32_t active_cnt; -- u_int32_t rib_cnt; -+ u_int32_t weight; - u_int16_t aspath_len; - u_int16_t flags; - u_int8_t prefixlen; -@@ -482,13 +594,6 @@ struct ctl_show_rib { - /* plus a aspath_len bytes long aspath */ - }; - --struct ctl_show_rib_prefix { -- struct bgpd_addr prefix; -- time_t lastchange; -- u_int16_t flags; -- u_int8_t prefixlen; --}; -- - enum as_spec { - AS_NONE, - AS_ALL, -@@ -498,16 +603,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 +659,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 +726,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 { -@@ -592,18 +755,28 @@ struct filter_prefix { - u_int8_t len; - }; - -+struct filter_nexthop { -+ struct bgpd_addr addr; -+ u_int8_t flags; -+#define FILTER_NEXTHOP_ADDR 1 -+#define FILTER_NEXTHOP_NEIGHBOR 2 -+}; -+ - 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_nexthop nexthop; -+ 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 +808,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 +826,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,82 +883,117 @@ 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; -+/* macros for IPv6 link-local address */ -+#ifdef __KAME__ -+#define IN6_LINKLOCAL_IFINDEX(addr) \ -+ ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) -+ -+#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ -+ do { \ -+ (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ -+ (addr).s6_addr[3] = (index) & 0xff; \ -+ } while (0) -+#endif -+ -+#define MRT_FILE_LEN 512 -+#define MRT2MC(x) ((struct mrt_config *)(x)) -+#define MRT_MAX_TIMEOUT 7200 -+ -+enum mrt_type { -+ MRT_NONE, -+ MRT_TABLE_DUMP, -+ MRT_TABLE_DUMP_MP, -+ MRT_TABLE_DUMP_V2, -+ MRT_ALL_IN, -+ MRT_ALL_OUT, -+ MRT_UPDATE_IN, -+ MRT_UPDATE_OUT -+}; -+ -+enum mrt_state { -+ MRT_STATE_RUNNING, -+ MRT_STATE_OPEN, -+ MRT_STATE_REOPEN, -+ MRT_STATE_REMOVE - }; --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 -- --/* Subsequent Address Family Identifier as per RFC 4760 */ --#define SAFI_NONE 0x00 --#define SAFI_UNICAST 0x01 --#define SAFI_MULTICAST 0x02 --#define SAFI_ALL 0xff -+struct mrt { -+ char rib[PEER_DESCR_LEN]; -+ struct msgbuf wbuf; -+ LIST_ENTRY(mrt) entry; -+ u_int32_t peer_id; -+ u_int32_t group_id; -+ enum mrt_type type; -+ enum mrt_state state; -+ u_int16_t seqnum; -+}; - --/* 4-byte magic AS number */ --#define AS_TRANS 23456 -+struct mrt_config { -+ struct mrt conf; -+ char name[MRT_FILE_LEN]; /* base file name */ -+ char file[MRT_FILE_LEN]; /* actual file name */ -+ time_t ReopenTimer; -+ time_t ReopenTimerInterval; -+}; - - /* 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 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 *, ...); --void log_warn(const char *, ...); --void log_warnx(const char *, ...); --void log_info(const char *, ...); --void log_debug(const char *, ...); --void fatal(const char *) __dead; --void fatalx(const char *) __dead; -- --/* parse.y */ --int cmdline_symset(char *); -+/* control.c */ -+void control_cleanup(const char *); -+int control_imsg_relay(struct imsg *); - - /* config.c */ - 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); - --/* control.c */ --void control_cleanup(const char *); --int control_imsg_relay(struct imsg *); -+/* 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 *, ...); -+void log_warn(const char *, ...); -+void log_warnx(const char *, ...); -+void log_info(const char *, ...); -+void log_debug(const char *, ...); -+void fatal(const char *) __dead; -+void fatalx(const char *) __dead; - --/* pftable.c */ --int pftable_exists(const char *); --int pftable_add(const char *); --int pftable_clear_all(void); --int pftable_addr_add(struct pftable_msg *); --int pftable_addr_remove(struct pftable_msg *); --int pftable_commit(void); -+/* mrt.c */ -+void mrt_clear_seq(void); -+void mrt_write(struct mrt *); -+void mrt_clean(struct mrt *); -+void mrt_init(struct imsgbuf *, struct imsgbuf *); -+int mrt_timeout(struct mrt_head *); -+void mrt_reconfigure(struct mrt_head *); -+void mrt_handler(struct mrt_head *); -+struct mrt *mrt_get(struct mrt_head *, struct mrt *); -+int mrt_mergeconfig(struct mrt_head *, struct mrt_head *); - - /* name2id.c */ - u_int16_t rib_name2id(const char *); -@@ -768,10 +1009,22 @@ const char *pftable_id2name(u_int16_t); - void pftable_unref(u_int16_t); - void pftable_ref(u_int16_t); - -+/* parse.y */ -+int cmdline_symset(char *); -+ -+/* pftable.c */ -+int pftable_exists(const char *); -+int pftable_add(const char *); -+int pftable_clear_all(void); -+int pftable_addr_add(struct pftable_msg *); -+int pftable_addr_remove(struct pftable_msg *); -+int pftable_commit(void); - - /* 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 +1032,24 @@ const char *log_addr(const struct bgpd_a - 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); -+int aspath_match(void *, u_int16_t, enum as_spec, u_int32_t); -+u_int32_t aspath_extract(const void *, int); -+int prefix_compare(const struct bgpd_addr *, -+ const struct bgpd_addr *, int); - 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__ */ Index: net/openbgpd/files/patch-bgpd_bgpd.8 =================================================================== --- net/openbgpd/files/patch-bgpd_bgpd.8 +++ /dev/null @@ -1,348 +0,0 @@ -Index: bgpd/bgpd.8 -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.8,v -retrieving revision 1.1.1.8 -retrieving revision 1.10 -diff -u -p -r1.1.1.8 -r1.10 ---- bgpd/bgpd.8 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/bgpd.8 13 Oct 2012 18:36:00 -0000 1.10 -@@ -1,4 +1,4 @@ --.\" $OpenBSD: bgpd.8,v 1.28 2009/01/13 23:01:36 sthen Exp $ -+.\" $OpenBSD: bgpd.8,v 1.45 2012/08/24 20:13:03 jmc Exp $ - .\" - .\" Copyright (c) 2003, 2004 Henning Brauer - .\" -@@ -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: August 24 2012 $ - .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,106 @@ concerning - with other BGP systems. - .Nm - uses the Border Gateway Protocol, Version 4, --as described in RFC 1771. --Please refer to that document for more information about BGP. -+as described in RFC 4271. -+.Pp -+BGP is an exterior gateway protocol using a multiple step decision process -+to find the best path. -+Advanced filtering can be used to influence the route -+decision for traffic engineering. -+The session engine of -+.Nm -+is responsible for maintaining the TCP session with each neighbor. -+Updates are passed to the Route Decision Engine (RDE) where the paths -+are filtered and used to compute a Routing Information Base (RIB). -+The parent process is responsible for keeping the RIB in sync with -+the kernel routing table. -+.Pp -+The route decision process selects the best path by evaluating all paths to -+the same destination. -+The decision process continues to the next step if paths have equal attributes. -+Paths that are less preferred are taken out of consideration until there is -+only one path left. -+.Bl -enum -width 42 -offset bula -+.It -+All paths with errors or loops are not eligible. -+.It -+Paths with an unreachable nexthop are not eligible. -+After this step all remaining paths are valid. -+.It -+The path with the highest -+.Em LOCAL_PREF -+is selected. -+.It -+The path with the shortest -+.Em AS path -+attribute is selected. -+.It -+The -+.Em ORIGIN -+attribute is compared. -+The order is IGP before EGP before incomplete origins. -+.It -+The path with the lowest -+.Em MULTI_EXIT_DISC -+metric is selected. -+Normally, this value is only considered when choosing between multiple -+routes sent by the same neighbouring AS. -+However, if -+.Dq Li rde med compare always -+is set in the configuration, the metric is compared for routes sent by any AS. -+.It -+Comparison of the BGP session type. -+Paths learned over an external (EBGP) session are preferred over those -+learned via an internal (IBGP) session. -+.It -+The path with the lowest local -+.Em weight -+is selected. -+.It -+If -+.Dq Li rde route-age evaluate -+is set then the oldest path is selected. -+.It -+The path coming from the neighbor with the lowest -+.Em BGP ID -+wins. -+If the -+.Em ORIGINATOR_ID -+attribute is present that value will be used in the comparison instead. -+.It -+The path with the shortest -+.Em CLUSTER_LIST -+attribute is selected. -+If it is not present then a length of 0 is used in the comparison. -+.It -+The path coming from the peer with the lowest IP address is selected. -+IPv4 sessions will be preferred over IPv6 ones. -+.It -+In case of locally announced prefixes -+.Nm -+will prefer statically set prefixes over dynamically inserted ones. -+.El -+.Pp -+Attributes set by filters can be used to tip the decision process to prefer -+particular paths over others. -+This can be achieved by changing the -+.Em localpref , -+.Em med , -+or -+.Em weight -+attributes. -+AS path prepending or changing the -+.Em med -+or -+.Em origin -+attribute can be used to influencing the routing behaviour on remote systems. - .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 +204,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 -@@ -149,55 +227,144 @@ control socket - .Xr bgpctl 8 , - .Xr bgplg 8 , - .Xr bgplgsh 8 -+.Sh STANDARDS - .Rs --.%R RFC 1771 --.%T "A Border Gateway Protocol 4 (BGP-4)" --.%D March 1995 --.Re --.Rs --.%R RFC 1997 --.%T "BGP Communities Attribute" -+.%A R. Chandra -+.%A P. Traina -+.%A "T. Li" - .%D August 1996 -+.%R RFC 1997 -+.%T BGP Communities Attribute - .Re -+.Pp - .Rs --.%R RFC 2385 --.%T "Protection of BGP Sessions via the TCP MD5 Signature Option" -+.%A A. Heffernan - .%D August 1998 -+.%R RFC 2385 -+.%T Protection of BGP Sessions via the TCP MD5 Signature Option - .Re -+.Pp - .Rs --.%R RFC 2796 --.%T "BGP Route Reflection - An Alternative to Full Mesh IBGP" --.%D April 2000 -+.%A P. Marques -+.%A F. Dupont -+.%D March 1999 -+.%R RFC 2545 -+.%T Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing - .Re -+.Pp - .Rs --.%R RFC 2918 --.%T "Route Refresh Capability for BGP-4" -+.%A E. Chen - .%D September 2000 -+.%R RFC 2918 -+.%T Route Refresh Capability for BGP-4 - .Re -+.Pp - .Rs --.%R RFC 3392 --.%T "Capabilities Advertisement with BGP-4" --.%D January 1999 -+.%A G. Huston -+.%D April 2004 -+.%R RFC 3765 -+.%T NOPEER Community for Border Gateway Protocol (BGP) Route Scope Control - .Re -+.Pp - .Rs --.%R RFC 3682 --.%T "The Generalized TTL Security Mechanism (GTSM)" --.%D February 2004 -+.%A Y. Rekhter -+.%A "T. Li" -+.%A S. Hares -+.%D January 2006 -+.%R RFC 4271 -+.%T A Border Gateway Protocol 4 (BGP-4) - .Re -+.Pp - .Rs --.%R RFC 3765 --.%T "NOPEER Community for Border Gateway Protocol" --.%D April 2004 -+.%A S. Sangli -+.%A D. Tappan -+.%A Y. Rekhter -+.%D February 2006 -+.%R RFC 4360 -+.%T BGP Extended Communities Attribute - .Re -+.Pp - .Rs --.%R RFC 4760 --.%T "Multiprotocol Extensions for BGP-4" -+.%A E. Rosen -+.%A Y. Rekhter -+.%D February 2006 -+.%R RFC 4364 -+.%T BGP/MPLS IP Virtual Private Networks (VPNs) -+.Re -+.Pp -+.Rs -+.%A T. Bates -+.%A E. Chen -+.%A R. Chandra -+.%D April 2006 -+.%R RFC 4456 -+.%T "BGP Route Reflection: An Alternative to Full Mesh Internal BGP (IBGP)" -+.Re -+.Pp -+.Rs -+.%A E. Chen -+.%A V. Gillet -+.%D April 2006 -+.%R RFC 4486 -+.%T Subcodes for BGP Cease Notification Message -+.Re -+.Pp -+.Rs -+.%A T. Bates -+.%A R. Chandra -+.%A D. Katz -+.%A Y. Rekhter - .%D January 2007 -+.%R RFC 4760 -+.%T Multiprotocol Extensions for BGP-4 - .Re -+.Pp - .Rs --.%R RFC 4893 --.%T "BGP Support for Four-octet AS Number Space" -+.%A Q. Vohra -+.%A E. Chen - .%D May 2007 -+.%R RFC 4893 -+.%T BGP Support for Four-octet AS Number Space -+.Re -+.Pp -+.Rs -+.%A V. Gill -+.%A J. Heasley -+.%A D. Meyer -+.%A P. Savola -+.%A C. Pignatoro -+.%D October 2007 -+.%R RFC 5082 -+.%T The Generalized TTL Security Mechanism (GTSM) -+.Re -+.Pp -+.Rs -+.%A J. Scudder -+.%A R. Chandra -+.%D February 2009 -+.%R RFC 5492 -+.%T Capabilities Advertisement with BGP-4 -+.Re -+.Pp -+.Rs -+.%D April 2009 -+.%R draft-ietf-idr-optional-transitive-00 -+.%T Error Handling for Optional Transitive BGP Attributes -+.Re -+.Pp -+.Rs -+.%D August 2011 -+.%R draft-ietf-grow-mrt-17 -+.%T MRT routing information export format -+.Re -+.Pp -+.Rs -+.%A J. Dong -+.%A M. Chen -+.%A A. Suryanarayana -+.%D May 2012 -+.%R RFC 6608 -+.%T Subcodes for BGP Finite State Machine Error - .Re - .Sh HISTORY - The Index: net/openbgpd/files/patch-bgpd_bgpd.c =================================================================== --- net/openbgpd/files/patch-bgpd_bgpd.c +++ /dev/null @@ -1,693 +0,0 @@ -Index: bgpd/bgpd.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.1.1.12 -diff -u -p -r1.1.1.7 -r1.1.1.12 ---- bgpd/bgpd.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/bgpd.c 8 Dec 2012 10:37:08 -0000 1.1.1.12 -@@ -1,4 +1,4 @@ --/* $OpenBSD: bgpd.c,v 1.148 2009/06/07 00:30:23 claudio Exp $ */ -+/* $OpenBSD: bgpd.c,v 1.169 2012/09/18 09:45:51 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -32,8 +32,8 @@ - #include - #include - --#include "mrt.h" - #include "bgpd.h" -+#include "mrt.h" - #include "session.h" - - void sighdlr(int); -@@ -42,23 +42,23 @@ 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; -+int reconfpending; - 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 +86,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 +101,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; -@@ -124,18 +119,13 @@ main(int argc, char *argv[]) - bgpd_process = PROC_MAIN; - - log_init(1); /* log to stderr until daemonized */ -- -- if ((rules_l = calloc(1, sizeof(struct filter_head))) == NULL) -- err(1, NULL); -+ log_verbose(1); - - 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 +148,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 +161,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"); -@@ -202,6 +185,7 @@ main(int argc, char *argv[]) - errx(1, "unknown user %s", BGPD_USER); - - log_init(debug); -+ log_verbose(conf.opts & BGPD_OPT_VERBOSE); - - if (!debug) - daemon(1, 0); -@@ -225,13 +209,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 +234,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; -@@ -335,15 +294,16 @@ main(int argc, char *argv[]) - u_int error; - - 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; - case 0: /* all OK */ - error = 0; - break; -+ case 2: -+ error = CTL_RES_PENDING; -+ break; - default: /* parse error */ - error = CTL_RES_PARSE_ERROR; - break; -@@ -389,13 +349,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 +373,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 +414,33 @@ send_filterset(struct imsgbuf *i, struct - - 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 (reconfpending) { -+ log_info("previous reload still running"); -+ return (2); -+ } -+ reconfpending = 2; /* one per child */ -+ -+ log_info("rereading config"); -+ 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); -+ reconfpending = 0; - return (1); - } - - cflags = conf->flags; -- connectset = &conf->connectset; -- staticset = &conf->staticset; -- connectset6 = &conf->connectset6; -- staticset6 = &conf->staticset6; -- - prepare_listeners(conf); - - /* start reconfiguration */ -@@ -483,12 +451,6 @@ reconfigure(char *conffile, struct bgpd_ - 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 +458,104 @@ reconfigure(char *conffile, struct bgpd_ - 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) -- return (-1); -- if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1, -- NULL, 0) == -1) -- return (-1); -- TAILQ_REMOVE(&net_l, n, entry); -- filterset_free(&n->net.attrset); -- free(n); -+ /* 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_RECONF_PEER, p->conf.id, 0, -1, -+ &p->conf, sizeof(struct peer_config)) == -1) -+ return (-1); - } - -- /* 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 +565,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 +588,39 @@ dispatch_imsg(struct imsgbuf *ibuf, int - 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) -@@ -646,26 +654,28 @@ dispatch_imsg(struct imsgbuf *ibuf, int - case IMSG_CTL_RELOAD: - if (idx != PFD_PIPE_SESSION) - log_warnx("reload request not from SE"); -- else -+ else { - reconfig = 1; - reconfpid = imsg.hdr.pid; -+ } - break; - case IMSG_CTL_FIB_COUPLE: - 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 +702,16 @@ dispatch_imsg(struct imsgbuf *ibuf, int - 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; -+ case IMSG_RECONF_DONE: -+ if (reconfpending == 0) -+ log_warnx("unexpected RECONF_DONE received"); -+ reconfpending--; -+ break; - default: - break; - } -@@ -707,7 +727,7 @@ send_nexthop_update(struct kroute_nextho - { - 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 +737,7 @@ send_nexthop_update(struct kroute_nextho - 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 +753,20 @@ send_imsg_session(int type, pid_t pid, v - } - - 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 +794,45 @@ bgpd_filternexthop(struct kroute *kr, st - - 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); -+} Index: net/openbgpd/files/patch-bgpd_bgpd.conf.5 =================================================================== --- net/openbgpd/files/patch-bgpd_bgpd.conf.5 +++ /dev/null @@ -1,746 +0,0 @@ -Index: bgpd/bgpd.conf.5 -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.conf.5,v -retrieving revision 1.1.1.7 -retrieving revision 1.10 -diff -u -p -r1.1.1.7 -r1.10 ---- bgpd/bgpd.conf.5 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/bgpd.conf.5 8 Dec 2012 20:17:59 -0000 1.10 -@@ -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.122 2012/11/13 09:47:20 claudio Exp $ - .\" - .\" Copyright (c) 2004 Claudio Jeker - .\" Copyright (c) 2003, 2004 Henning Brauer -@@ -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: November 13 2012 $ - .Dt BGPD.CONF 5 - .Os - .Sh NAME -@@ -26,11 +26,11 @@ - The - .Xr bgpd 8 - daemon implements the Border Gateway Protocol version 4 as described --in RFC 1771. -+in RFC 4271. - .Sh SECTIONS - The - .Nm --config file is divided into four main sections. -+config file is divided into five main sections. - .Bl -tag -width xxxx - .It Sy Macros - User-defined variables may be defined and used later, simplifying the -@@ -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 -@@ -54,9 +56,16 @@ the sections should be grouped and appea - .Nm - in the order shown above. - .Pp -+The current line can be extended over multiple lines using a backslash -+.Pq Sq \e . - Comments can be put anywhere in the file using a hash mark - .Pq Sq # , - and extend to the end of the current line. -+Care should be taken when commenting out multi-line text: -+the comment is effective until the end of the entire block. -+.Pp -+Argument names not beginning with a letter, digit, or underscore -+must be quoted. - .Pp - Additional configuration files can be included with the - .Ic include -@@ -66,8 +75,8 @@ include "/etc/bgpd/bgpd-10.0.0.1.filter" - .Ed - .Sh MACROS - Macros can be defined that will later be expanded in context. --Macro names must start with a letter, and may contain letters, digits --and underscores. -+Macro names must start with a letter, digit, or underscore, -+and may contain any of those characters. - Macro names may not be reserved words (for example, - .Ic AS , - .Ic neighbor , -@@ -93,7 +102,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,29 +152,33 @@ 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 Ns | Ns Ic table-v2 - .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 - .Em routing information base , - and all BGP messages in Multi-threaded Routing Toolkit (MRT) format. --Dumping the RIB is normally an expensive operation, --but it should not influence the session handling. - It is possible to dump alternate RIB with the use of - .Ar name . - .Pp - For example, the following will dump the entire table to the - .Xr strftime 3 Ns -expanded - filename. --The -+Only the -+.Ic table-v2 -+format is able to dump a multi-protocol RIB correctly. -+Both -+.Ic table -+and - .Ic table-mp --format is multi-protocol capable but often not supported by 3rd-party tools. -+formats are more or less limited when handling multi-protocol entries and -+are only left around to support 3rd party tools not handling the new format. - The timeout is optional: - .Bd -literal -offset indent - dump table "/tmp/rib-dump-%H%M" 300 -@@ -195,7 +208,7 @@ dump updates out "/tmp/updates-out-%H%M" - .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 +255,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 +291,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,38 +308,47 @@ 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 , - the --.Em MED -+.Em MULTI_EXIT_DISC - attributes will always be compared. - The default is - .Ic strict , --where the --.Em MED --is only compared between peers belonging to the same AS. -+where the metric is only compared between peers belonging to the same AS. - .Pp - .It Xo - .Ic rde - .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 +361,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 +383,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 +409,110 @@ to EBGP neighbors are not prepended with - 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 sole purpose of the Route Distinguisher -+.Ic rd -+is to ensure that possible common prefixes are destinct between VPNs. -+The -+.Ic rd -+is neither used to identify the origin of the prefix nor to control into -+which VPNs the prefix is distributed to. -+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. -+.El - .Sh NEIGHBORS AND GROUPS - .Xr bgpd 8 - establishes TCP connections to other BGP speakers called -@@ -470,21 +607,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 +644,29 @@ This can be helpful to connect to old or - 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 +678,7 @@ The demotion counter will be increased a - .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 +722,8 @@ Do not start the session when bgpd comes - .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 +738,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 +763,16 @@ Inherited from the global configuration - 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 +807,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 +819,11 @@ is responsible for managing the session - 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,11 +878,11 @@ Do not attempt to actively open a TCP co - .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 --Act as an RFC 2796 -+Act as an RFC 4456 - .Em route-reflector - for this neighbor. - An optional cluster ID can be specified; otherwise the BGP ID will be used. -@@ -732,8 +912,8 @@ These sets are rewritten into filter rul - .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 +940,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 +952,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 +1029,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 +1101,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 +1154,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 +1162,37 @@ 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 Ic nexthop Ar address -+This rule applies only to -+.Em UPDATES -+where the nexthop is equal to -+.Ar address . -+The -+.Ar address -+can be set to -+.Em neighbor -+in which case the nexthop is compared against the address of the neighbor. -+Nexthop filtering is not supported on locally announced networks and one must -+take into consideration previous rules overwriting nexthops. -+.Pp - .It Xo - .Ic prefix - .Ar address Ns Li / Ns Ar len -@@ -1028,6 +1268,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 +1325,48 @@ Alternately, well-known communities may - 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 +1396,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 +1459,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 +1482,8 @@ For prefixes with equally long paths, th - 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 Index: net/openbgpd/files/patch-bgpd_buffer.c =================================================================== --- net/openbgpd/files/patch-bgpd_buffer.c +++ /dev/null @@ -1,104 +0,0 @@ -Index: bgpd/buffer.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/buffer.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.3 -diff -u -p -r1.1.1.7 -r1.3 ---- bgpd/buffer.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/buffer.c 8 Dec 2012 20:17:59 -0000 1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: buffer.c,v 1.43 2009/06/06 06:33:15 eric Exp $ */ -+/* $OpenBSD: buffer.c,v 1.44 2009/07/23 18:58:42 eric Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -144,7 +144,7 @@ int - buf_write(struct msgbuf *msgbuf) - { - struct iovec iov[IOV_MAX]; -- struct buf *buf, *next; -+ struct buf *buf; - unsigned int i = 0; - ssize_t n; - -@@ -153,7 +153,7 @@ buf_write(struct msgbuf *msgbuf) - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; -- iov[i].iov_len = buf->size - buf->rpos; -+ iov[i].iov_len = buf->wpos - buf->rpos; - i++; - } - -@@ -170,17 +170,7 @@ buf_write(struct msgbuf *msgbuf) - 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; -- } -- } -+ msgbuf_drain(msgbuf, n); - - return (0); - } -@@ -201,6 +191,24 @@ msgbuf_init(struct msgbuf *msgbuf) - } - - void -+msgbuf_drain(struct msgbuf *msgbuf, size_t n) -+{ -+ struct buf *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; -+ buf_dequeue(msgbuf, buf); -+ } else { -+ buf->rpos += n; -+ n = 0; -+ } -+ } -+} -+ -+void - msgbuf_clear(struct msgbuf *msgbuf) - { - struct buf *buf; -@@ -213,7 +221,7 @@ int - msgbuf_write(struct msgbuf *msgbuf) - { - struct iovec iov[IOV_MAX]; -- struct buf *buf, *next; -+ struct buf *buf; - unsigned int i = 0; - ssize_t n; - struct msghdr msg; -@@ -270,17 +278,7 @@ msgbuf_write(struct msgbuf *msgbuf) - 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; -- } -- } -+ msgbuf_drain(msgbuf, n); - - return (0); - } Index: net/openbgpd/files/patch-bgpd_carp.c =================================================================== --- net/openbgpd/files/patch-bgpd_carp.c +++ /dev/null @@ -1,54 +0,0 @@ -Index: bgpd/carp.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/carp.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.4 -diff -u -p -r1.1.1.6 -r1.4 ---- bgpd/carp.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/carp.c 22 Oct 2009 15:10:02 -0000 1.4 -@@ -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 demot - - close(s); - return (res); -+#endif /* defined(__FreeBSD__) */ - } Index: net/openbgpd/files/patch-bgpd_config.c =================================================================== --- net/openbgpd/files/patch-bgpd_config.c +++ /dev/null @@ -1,109 +0,0 @@ -Index: bgpd/config.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/config.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.3 -diff -u -p -r1.1.1.6 -r1.3 ---- bgpd/config.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/config.c 13 Oct 2012 18:36:00 -0000 1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: config.c,v 1.51 2009/01/26 23:10:02 claudio Exp $ */ -+/* $OpenBSD: config.c,v 1.55 2010/09/02 14:03:21 sobrado Exp $ */ - - /* - * Copyright (c) 2003, 2004, 2005 Henning Brauer -@@ -20,6 +20,11 @@ - #include - #include - #include -+#include -+ -+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */ -+#include -+#endif - - #include - #include -@@ -47,8 +52,6 @@ merge_config(struct bgpd_config *xconf, - - /* 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, - 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, - 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 - 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 - 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 *co - } - } - } -+ -+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); -+} Index: net/openbgpd/files/patch-bgpd_control.c =================================================================== --- net/openbgpd/files/patch-bgpd_control.c +++ /dev/null @@ -1,171 +0,0 @@ -Index: bgpd/control.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/control.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.1.1.10 -diff -u -p -r1.1.1.7 -r1.1.1.10 ---- bgpd/control.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/control.c 13 Oct 2012 18:22:41 -0000 1.1.1.10 -@@ -1,4 +1,4 @@ --/* $OpenBSD: control.c,v 1.61 2009/05/05 20:09:19 sthen Exp $ */ -+/* $OpenBSD: control.c,v 1.71 2012/04/12 17:26:09 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -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); - } -@@ -122,15 +122,18 @@ control_accept(int listenfd, int restric - len = sizeof(sun); - if ((connfd = accept(listenfd, - (struct sockaddr *)&sun, &len)) == -1) { -- if (errno != EWOULDBLOCK && errno != EINTR) -- log_warn("session_control_accept"); -+ if (errno == ENFILE || errno == EMFILE) { -+ pauseaccept = getmonotime(); -+ return (0); -+ } else if (errno != EWOULDBLOCK && errno != EINTR) -+ 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); - } -@@ -182,7 +185,7 @@ control_close(int fd) - - close(c->ibuf.fd); - free(c); -- -+ pauseaccept = 0; - return (1); - } - -@@ -191,7 +194,8 @@ control_dispatch_msg(struct pollfd *pfd, - { - 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 +309,8 @@ control_dispatch_msg(struct pollfd *pfd, - 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 +333,19 @@ control_dispatch_msg(struct pollfd *pfd, - 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 +363,19 @@ control_dispatch_msg(struct pollfd *pfd, - "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 +387,7 @@ control_dispatch_msg(struct pollfd *pfd, - 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 +414,7 @@ control_dispatch_msg(struct pollfd *pfd, - 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; -@@ -418,6 +434,8 @@ control_dispatch_msg(struct pollfd *pfd, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - break; - case IMSG_NETWORK_ADD: -+ case IMSG_NETWORK_ASPATH: -+ case IMSG_NETWORK_ATTR: - case IMSG_NETWORK_REMOVE: - case IMSG_NETWORK_FLUSH: - case IMSG_NETWORK_DONE: -@@ -425,6 +443,20 @@ control_dispatch_msg(struct pollfd *pfd, - 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; - } Index: net/openbgpd/files/patch-bgpd_imsg.h =================================================================== --- net/openbgpd/files/patch-bgpd_imsg.h +++ /dev/null @@ -1,115 +0,0 @@ -Index: bgpd/imsg.h -=================================================================== -RCS file: bgpd/imsg.h -diff -N bgpd/imsg.h ---- bgpd/imsg.h 14 Feb 2010 20:19:57 -0000 1.1.1.5 -+++ /dev/null 1 Jan 1970 00:00:00 -0000 -@@ -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 -- * Copyright (c) 2006, 2007, 2008 Reyk Floeter -- * Copyright (c) 2003, 2004 Henning Brauer -- * -- * 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 -- --#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 *); Index: net/openbgpd/files/patch-bgpd_imsg.c =================================================================== --- net/openbgpd/files/patch-bgpd_imsg.c +++ /dev/null @@ -1,275 +0,0 @@ -Index: bgpd/imsg.c -=================================================================== -RCS file: bgpd/imsg.c -diff -N bgpd/imsg.c ---- bgpd/imsg.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ /dev/null 1 Jan 1970 00:00:00 -0000 -@@ -1,268 +0,0 @@ --/* $OpenBSD: imsg.c,v 1.47 2009/06/08 08:30:06 dlg Exp $ */ -- --/* -- * Copyright (c) 2003, 2004 Henning Brauer -- * -- * 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 --#include --#include --#include -- --#include --#include --#include --#include -- --#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); --} Index: net/openbgpd/files/patch-bgpd_kroute.c =================================================================== --- net/openbgpd/files/patch-bgpd_kroute.c +++ /dev/null @@ -1,3140 +0,0 @@ -Index: bgpd/kroute.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/kroute.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.15 -diff -u -p -r1.1.1.7 -r1.15 ---- bgpd/kroute.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/kroute.c 16 May 2014 00:36:26 -0000 1.15 -@@ -1,4 +1,4 @@ --/* $OpenBSD: kroute.c,v 1.169 2009/06/25 15:54:22 claudio Exp $ */ -+/* $OpenBSD: kroute.c,v 1.190 2012/07/13 16:57:35 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -27,6 +27,9 @@ - #include - #include - #include -+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */ -+#include -+#endif - #include - #include - #include -@@ -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); -- --struct knexthop_node *knexthop_find(struct bgpd_addr *); --int knexthop_insert(struct knexthop_node *); --int knexthop_remove(struct knexthop_node *); --void knexthop_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 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,16 @@ int kif_kr6_remove(struct kroute6_nod - 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 *); -+void knexthop_validate(struct ktable *, -+ struct knexthop_node *); -+void knexthop_track(struct ktable *, void *); -+void knexthop_send_update(struct knexthop_node *); -+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(void); -+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 +165,20 @@ void get_rtaddrs(int, 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 +186,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 +224,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 -+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(struct kroute_label *kl) -+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)); - -- rtlabel_unref(kl->kr.labelid); -+ 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; - -- if (kroute_remove(kr) == -1) -+ 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 (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 +759,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,41 +825,18 @@ 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; -- struct kroute6_node *k6; -- -- bzero(&nh, sizeof(nh)); -- memcpy(&nh.nexthop, addr, sizeof(nh.nexthop)); -- nh.valid = 1; -- if (h->kroute != NULL && addr->af == AF_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.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) { -- 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; -- memcpy(&nh.gateway.v6, &k6->r.nexthop, -- sizeof(struct in6_addr)); -- } -- memcpy(&nh.kr.kr6, &k6->r, sizeof(nh.kr.kr6)); -- } -- -- send_nexthop_update(&nh); -+ knexthop_send_update(h); - } else { - if ((h = calloc(1, sizeof(struct knexthop_node))) == NULL) { - log_warn("kr_nexthop_add"); -@@ -492,7 +844,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 +852,26 @@ 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_delete: 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 +880,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 +888,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,41 +994,190 @@ 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; - } -- -- send_imsg_session(IMSG_CTL_END, imsg->hdr.pid, NULL, 0); -+ -+ send_imsg_session(IMSG_CTL_END, imsg->hdr.pid, NULL, 0); -+} -+ -+void -+kr_ifinfo(char *ifname) -+{ -+ struct kif_node *kif; -+ -+ RB_FOREACH(kif, kif_tree, &kit) -+ if (!strcmp(ifname, kif->k.ifname)) { -+ send_imsg_session(IMSG_IFINFO, 0, -+ &kif->k, sizeof(kif->k)); -+ return; -+ } -+} -+ -+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; -+ case NETWORK_MRTCLONE: -+ /* can not happen */ -+ break; -+ } -+ } -+ return (NULL); - } - --void --kr_ifinfo(char *ifname) -+struct network * -+kr_net_match6(struct ktable *kt, struct kroute6 *kr6) - { -- struct kif_node *kif; -+ struct network *xn; - -- RB_FOREACH(kif, kif_tree, &kit) -- if (!strcmp(ifname, kif->k.ifname)) { -- send_imsg_session(IMSG_IFINFO, 0, -- &kif->k, sizeof(kif->k)); -- return; -+ 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; -+ case NETWORK_MRTCLONE: -+ /* can not happen */ -+ break; - } -+ } -+ return (NULL); - } - --struct redist_node { -- LIST_ENTRY(redist_node) entry; -- struct kroute *kr; -- struct kroute6 *kr6; --}; -+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); -+ } -+ } - --LIST_HEAD(, redist_node) redistlist; -+ 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 +1205,40 @@ kr_redistribute(int type, struct kroute - 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; -- -- 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); -- } -- -- return (bgpd_redistribute(type, kr, NULL)); -+ 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; -+ -+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 (send_network(type, &net, match ? &match->net.attrset : NULL)); - } - - int --kr_redistribute6(int type, struct kroute6 *kr6) --{ -- struct redist_node *rn; -+kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6) -+{ -+ 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 +1270,107 @@ kr_redistribute6(int type, struct kroute - * 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); -- } -+ 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 (bgpd_redistribute(type, NULL, kr6)); -+ 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 +1427,28 @@ kroute6_compare(struct kroute6_node *a, - 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 +1466,8 @@ kif_compare(struct kif_node *a, struct k - */ - - 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 +1476,15 @@ kroute_find(in_addr_t prefix, u_int8_t p - 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 +1511,13 @@ kroute_matchgw(struct kroute_node *kr, s - } - - 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; -@@ -941,13 +1525,14 @@ kroute_insert(struct kroute_node *kr) - kr->next = NULL; /* to be sure */ - } - -+ /* XXX this is wrong for nexthop validated via BGP */ - 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 +1540,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 +1560,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); -@@ -1001,14 +1587,14 @@ 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) -+ if (kr->r.flags & F_NEXTHOP) -+ 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 +1607,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 +1626,15 @@ kroute6_find(const struct in6_addr *pref - 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); -@@ -1056,17 +1643,29 @@ kroute6_find(const struct in6_addr *pref - struct kroute6_node * - kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6) - { -- struct in6_addr nexthop; -+ struct sockaddr_in6 nexthop; - - if (sa_in6 == NULL) { - log_warnx("kroute6_matchgw: no nexthop defined"); - return (NULL); - } -- memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop)); -+ memcpy(&nexthop, sa_in6, sizeof(nexthop)); -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+ if (IN6_IS_ADDR_LINKLOCAL(&nexthop.sin6_addr)) { -+ /* Embed scope id and set sin6_scope_id. */ -+ if (nexthop.sin6_scope_id == 0) -+ nexthop.sin6_scope_id = -+ IN6_LINKLOCAL_IFINDEX(nexthop.sin6_addr); -+ else -+ SET_IN6_LINKLOCAL_IFINDEX(nexthop.sin6_addr, -+ nexthop.sin6_scope_id); -+ } -+#endif - - while (kr) { -- if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == NULL) -- return (kr); -+ if (memcmp(&kr->r.nexthop, &nexthop.sin6_addr, -+ sizeof(nexthop.sin6_addr)) == 0) -+ return (kr); - kr = kr->next; - } - -@@ -1074,13 +1673,13 @@ kroute6_matchgw(struct kroute6_node *kr, - } - - 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; -@@ -1088,14 +1687,15 @@ kroute6_insert(struct kroute6_node *kr) - kr->next = NULL; /* to be sure */ - } - -+ /* XXX this is wrong for nexthop validated via BGP */ - 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 +1704,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 +1724,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); -@@ -1151,14 +1752,14 @@ 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) -+ if (kr->r.flags & F_NEXTHOP) -+ 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 +1772,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 +1822,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 +1859,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 +1868,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,113 +2079,109 @@ kroute6_validate(struct kroute6 *kr) - } - - void --knexthop_validate(struct knexthop_node *kn) -+knexthop_validate(struct ktable *kt, struct knexthop_node *kn) - { -+ void *oldk; - 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) -- was_valid = kroute_validate(&kr->r); -- if (kn->nexthop.af == AF_INET6 && (kr6 = kn->kroute) != NULL) -- was_valid = kroute6_validate(&kr6->r); -+ oldk = kn->kroute; -+ kroute_detach_nexthop(kt, kn); - -- bzero(&n, sizeof(n)); -- memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); -- kroute_detach_nexthop(kn); -- -- switch (kn->nexthop.af) { -- case AF_INET: -- if ((kr = kroute_match(kn->nexthop.v4.s_addr, 0)) == NULL) { -- if (was_valid) -- send_nexthop_update(&n); -- } else { /* match */ -- if (kroute_validate(&kr->r)) { /* valid */ -- 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)); -- send_nexthop_update(&n); -- } else /* down */ -- if (was_valid) -- send_nexthop_update(&n); -+ switch (kn->nexthop.aid) { -+ case AID_INET: -+ kr = kroute_match(kt, kn->nexthop.v4.s_addr, 0); - -+ if (kr) { - kn->kroute = kr; - kr->r.flags |= F_NEXTHOP; - } -+ -+ /* -+ * Send update if nexthop route changed under us if -+ * the route remains the same then the NH state has not -+ * changed. State changes are tracked by knexthop_track(). -+ */ -+ if (kr != oldk) -+ knexthop_send_update(kn); - break; -- case AF_INET6: -- if ((kr6 = kroute6_match(&kn->nexthop.v6, 0)) == NULL) { -- if (was_valid) -- send_nexthop_update(&n); -- } else { /* match */ -- if (kroute6_validate(&kr6->r)) { /* valid */ -- 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; -- memcpy(&n.gateway.v6, &kr6->r.nexthop, -- sizeof(struct in6_addr)); -- } -- memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6)); -- send_nexthop_update(&n); -- } else /* down */ -- if (was_valid) -- send_nexthop_update(&n); -+ case AID_INET6: -+ kr6 = kroute6_match(kt, &kn->nexthop.v6, 0); - -+ if (kr6) { - kn->kroute = kr6; - kr6->r.flags |= F_NEXTHOP; - } -+ -+ if (kr6 != oldk) -+ knexthop_send_update(kn); - break; - } - } - - void --knexthop_track(void *krn) -+knexthop_track(struct ktable *kt, void *krp) - { - struct knexthop_node *kn; -+ -+ RB_FOREACH(kn, knexthop_tree, KT2KNT(kt)) -+ if (kn->kroute == krp) -+ knexthop_send_update(kn); -+} -+ -+void -+knexthop_send_update(struct knexthop_node *kn) -+{ -+ struct kroute_nexthop n; - struct kroute_node *kr; - struct kroute6_node *kr6; -- struct kroute_nexthop n; - -- RB_FOREACH(kn, knexthop_tree, &knt) -- if (kn->kroute == krn) { -- bzero(&n, sizeof(n)); -- memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); -+ bzero(&n, sizeof(n)); -+ memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); - -- switch (kn->nexthop.af) { -- case AF_INET: -- kr = krn; -- 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)); -- break; -- case AF_INET6: -- kr6 = krn; -- 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; -- memcpy(&n.gateway.v6, &kr6->r.nexthop, -- sizeof(struct in6_addr)); -- } -- memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6)); -- break; -- } -- send_nexthop_update(&n); -+ if (kn->kroute == NULL) { -+ n.valid = 0; /* NH is not valid */ -+ send_nexthop_update(&n); -+ return; -+ } -+ -+ switch (kn->nexthop.aid) { -+ case AID_INET: -+ kr = kn->kroute; -+ n.valid = kroute_validate(&kr->r); -+ n.connected = kr->r.flags & F_CONNECTED; -+ if ((n.gateway.v4.s_addr = -+ kr->r.nexthop.s_addr) != 0) -+ n.gateway.aid = AID_INET; -+ if (n.connected) { -+ n.net.aid = AID_INET; -+ n.net.v4.s_addr = kr->r.prefix.s_addr; -+ n.netlen = kr->r.prefixlen; - } -+ break; -+ case AID_INET6: -+ kr6 = kn->kroute; -+ n.valid = kroute6_validate(&kr6->r); -+ n.connected = kr6->r.flags & F_CONNECTED; -+ if (memcmp(&kr6->r.nexthop, &in6addr_any, -+ sizeof(struct in6_addr)) != 0) { -+ n.gateway.aid = AID_INET6; -+ memcpy(&n.gateway.v6, &kr6->r.nexthop, -+ sizeof(struct in6_addr)); -+ } -+ if (n.connected) { -+ 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); - } - - 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 +2191,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 +2205,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 +2214,13 @@ kroute6_match(struct in6_addr *key, int - /* 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,31 +2228,30 @@ kroute6_match(struct in6_addr *key, int - } - - 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; - struct kroute6_node *k6; - -+ if (kn->kroute == NULL) -+ return; -+ - /* - * check whether there's another nexthop depending on this kroute - * if not remove the flag - */ -- -- 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)) -- ; /* nothing */ -+ RB_FOREACH(s, knexthop_tree, KT2KNT(kt)) -+ if (s->kroute == kn->kroute && s != kn) -+ break; - - 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 +2266,7 @@ kroute_detach_nexthop(struct knexthop_no - */ - - int --protect_lo(void) -+protect_lo(struct ktable *kt) - { - struct kroute_node *kr; - struct kroute6_node *kr6; -@@ -1675,11 +2276,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 +2290,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 +2327,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 +2365,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_ - case 0x00: - return (l); - default: -- fatalx("non continguous inet6 netmask"); -+ fatalx("non contiguous inet6 netmask"); - } - } - -@@ -1788,7 +2389,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,11 +2409,10 @@ get_rtaddrs(int addrs, struct sockaddr * - 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; -- struct kroute_nexthop nh; -- struct knexthop_node *n; - u_int8_t reachable; - - if ((kif = kif_find(ifindex)) == NULL) { -@@ -1833,28 +2433,18 @@ if_change(u_short ifindex, int flags, st - - 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 (n->kroute == kkr->kr) { -- bzero(&nh, sizeof(nh)); -- memcpy(&nh.nexthop, &n->nexthop, -- sizeof(nh.nexthop)); -- if (kroute_validate(&kkr->kr->r)) { -- nh.valid = 1; -- nh.connected = 1; -- if ((nh.gateway.v4.s_addr = -- kkr->kr->r.nexthop.s_addr) != 0) -- nh.gateway.af = AF_INET; -- } -- memcpy(&nh.kr.kr4, &kkr->kr->r, -- sizeof(nh.kr.kr4)); -- send_nexthop_update(&nh); -- } -+ if (kt == NULL) -+ continue; -+ -+ knexthop_track(kt, kkr->kr); - } - LIST_FOREACH(kkr6, &kif->kroute6_l, entry) { - if (reachable) -@@ -1862,27 +2452,10 @@ if_change(u_short ifindex, int flags, st - else - kkr6->kr->r.flags |= F_DOWN; - -- RB_FOREACH(n, knexthop_tree, &knt) -- if (n->kroute == kkr6->kr) { -- bzero(&nh, sizeof(nh)); -- memcpy(&nh.nexthop, &n->nexthop, -- sizeof(nh.nexthop)); -- if (kroute6_validate(&kkr6->kr->r)) { -- nh.valid = 1; -- nh.connected = 1; -- if (memcmp(&kkr6->kr->r.nexthop, -- &in6addr_any, sizeof(struct -- in6_addr))) { -- nh.gateway.af = AF_INET6; -- memcpy(&nh.gateway.v6, -- &kkr6->kr->r.nexthop, -- sizeof(struct in6_addr)); -- } -- } -- memcpy(&nh.kr.kr6, &kkr6->kr->r, -- sizeof(nh.kr.kr6)); -- send_nexthop_update(&nh); -- } -+ if (kt == NULL) -+ continue; -+ -+ knexthop_track(kt, kkr6->kr); - } - } - -@@ -1917,25 +2490,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 +2570,37 @@ send_rtmsg(int fd, int action, struct kr - 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 +2613,11 @@ send_rtmsg(int fd, int action, struct kr - 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 +2626,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 +2645,23 @@ send_rt6msg(int fd, int action, struct k - 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 +2714,7 @@ send_rt6msg(int fd, int action, struct k - 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 +2727,11 @@ send_rt6msg(int fd, int action, struct k - 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 +2740,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 +2773,35 @@ fetchtable(u_int rtableid, int connected - 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 +2809,11 @@ fetchtable(u_int rtableid, int connected - 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 +2832,11 @@ fetchtable(u_int rtableid, int connected - } - - 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 +2854,12 @@ fetchtable(u_int rtableid, int connected - 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,11 +2873,25 @@ fetchtable(u_int rtableid, int connected - } - - 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, - sizeof(kr6->r.prefix)); -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+ if (IN6_IS_ADDR_LINKLOCAL(&kr6->r.prefix)) { -+ if (((struct sockaddr_in6 *)sa)->sin6_scope_id !=0) -+ SET_IN6_LINKLOCAL_IFINDEX(kr6->r.prefix, -+ ((struct sockaddr_in6 *)sa)->sin6_scope_id); -+ else -+ SET_IN6_LINKLOCAL_IFINDEX(kr6->r.prefix, -+ rtm->rtm_index); -+ } -+#endif - - sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK]; - if (rtm->rtm_flags & RTF_STATIC) -@@ -2257,8 +2906,12 @@ fetchtable(u_int rtableid, int connected - 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; -@@ -2280,6 +2933,13 @@ fetchtable(u_int rtableid, int connected - memcpy(&kr6->r.nexthop, - &((struct sockaddr_in6 *)gw)->sin6_addr, - sizeof(kr6->r.nexthop)); -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+ if (IN6_IS_ADDR_LINKLOCAL(&kr6->r.nexthop) && -+ ((struct sockaddr_in6 *)gw)->sin6_scope_id != 0) { -+ SET_IN6_LINKLOCAL_IFINDEX(kr6->r.nexthop, -+ ((struct sockaddr_in6 *)gw)->sin6_scope_id); -+ } -+#endif - break; - case AF_LINK: - if (sa->sa_family == AF_INET) -@@ -2290,23 +2950,28 @@ fetchtable(u_int rtableid, int connected - } - - 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 +2992,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 +3061,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 +3083,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 +3099,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 +3127,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; -@@ -2468,7 +3135,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - struct kroute_node *kr; - struct kroute6_node *kr6; - struct bgpd_addr prefix; -- int flags, oflags, mpath = 0; -+ int flags, oflags, mpath = 0, changed = 0; - u_int16_t ifindex; - u_int8_t prefixlen; - u_int8_t prio; -@@ -2494,31 +3161,54 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - 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)); -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+ if (IN6_IS_ADDR_LINKLOCAL(&prefix.v6) != 0) { -+ if (((struct sockaddr_in6 *)sa)->sin6_scope_id !=0) -+ SET_IN6_LINKLOCAL_IFINDEX(prefix.v6, -+ ((struct sockaddr_in6 *)sa)->sin6_scope_id); -+ else -+ SET_IN6_LINKLOCAL_IFINDEX(prefix.v6, -+ rtm->rtm_index); -+ } -+#endif - 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 +3227,10 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - } - - 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 +3244,12 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - 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 +3264,23 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - 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 */ -@@ -2605,30 +3292,38 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt - } else if (mpath && rtm->rtm_type == RTM_ADD) - goto add4; - -- if (sa_in != NULL) -+ if (sa_in != NULL) { -+ if (kr->r.nexthop.s_addr != -+ sa_in->sin_addr.s_addr) -+ changed = 1; - kr->r.nexthop.s_addr = - sa_in->sin_addr.s_addr; -- else -+ } else { -+ if (kr->r.nexthop.s_addr != 0) -+ changed = 1; - kr->r.nexthop.s_addr = 0; -+ } - - if (kr->r.flags & F_NEXTHOP) - flags |= F_NEXTHOP; - oflags = kr->r.flags; -+ if (flags != oflags) -+ changed = 1; - kr->r.flags = flags; - if ((oflags & F_CONNECTED) && - !(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); -+ if (kr->r.flags & F_NEXTHOP && changed) -+ knexthop_track(kt, kr); - } - } else if (rtm->rtm_type == RTM_CHANGE) { - log_warnx("change req for %s/%u: not in table", -@@ -2651,50 +3346,62 @@ 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 && - (kr6 = kroute6_matchgw(kr6, sa_in6)) == - NULL) { - log_warnx("dispatch_rtmsg[change] " -- "mpath route not found"); -+ "IPv6 mpath route not found"); - return (-1); - } else if (mpath && rtm->rtm_type == RTM_ADD) - goto add6; - -- if (sa_in6 != NULL) -+ if (sa_in6 != NULL) { -+ if (memcmp(&kr6->r.nexthop, -+ &sa_in6->sin6_addr, -+ sizeof(struct in6_addr))) -+ changed = 1; - memcpy(&kr6->r.nexthop, - &sa_in6->sin6_addr, - sizeof(struct in6_addr)); -- else -+ } else { -+ if (memcmp(&kr6->r.nexthop, -+ &in6addr_any, -+ sizeof(struct in6_addr))) -+ changed = 1; - memcpy(&kr6->r.nexthop, - &in6addr_any, - sizeof(struct in6_addr)); -+ } - - if (kr6->r.flags & F_NEXTHOP) - flags |= F_NEXTHOP; - oflags = kr6->r.flags; -+ if (flags != oflags) -+ changed = 1; - kr6->r.flags = flags; - if ((oflags & F_CONNECTED) && - !(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); -+ if (kr6->r.flags & F_NEXTHOP && changed) -+ knexthop_track(kt, kr6); - } - } else if (rtm->rtm_type == RTM_CHANGE) { - log_warnx("change req for %s/%u: not in table", -@@ -2719,8 +3426,12 @@ add6: - kr6->r.flags = flags; - kr6->r.ifindex = ifindex; - kr6->r.priority = prio; -- -- kroute6_insert(kr6); -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+ if (IN6_IS_ADDR_LINKLOCAL(&kr6->r.nexthop)) -+ SET_IN6_LINKLOCAL_IFINDEX(kr6->r.nexthop, -+ ifindex); -+#endif -+ kroute6_insert(kt, kr6); - } - break; - } Index: net/openbgpd/files/patch-bgpd_log.h =================================================================== --- net/openbgpd/files/patch-bgpd_log.h +++ /dev/null @@ -1,39 +0,0 @@ -Index: bgpd/log.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/log.h,v -retrieving revision 1.1.1.2 -retrieving revision 1.1.1.3 -diff -u -p -r1.1.1.2 -r1.1.1.3 ---- bgpd/log.h 9 Jul 2009 16:49:54 -0000 1.1.1.2 -+++ bgpd/log.h 13 Oct 2012 18:22:43 -0000 1.1.1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: log.h,v 1.11 2008/09/11 14:49:58 henning Exp $ */ -+/* $OpenBSD: log.h,v 1.13 2012/06/10 11:16:08 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -71,6 +71,13 @@ static const char * const suberr_open_na - "unsupported capability" - }; - -+static const char * const suberr_fsm_names[] = { -+ "unspecified error", -+ "received unexpected message in OpenSent", -+ "received unexpected message in OpenConfirm", -+ "received unexpected message in Established" -+}; -+ - static const char * const suberr_update_names[] = { - "none", - "attribute list error", -@@ -109,7 +116,9 @@ static const char * const ctl_res_strerr - "no such neighbor", - "permission denied", - "neighbor does not have this capability", -- "config file has errors, reload failed" -+ "config file has errors, reload failed", -+ "previous reload still running", -+ "out of memory" - }; - - static const char * const timernames[] = { Index: net/openbgpd/files/patch-bgpd_log.c =================================================================== --- net/openbgpd/files/patch-bgpd_log.c +++ /dev/null @@ -1,117 +0,0 @@ -Index: bgpd/log.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/log.c,v -retrieving revision 1.1.1.5 -retrieving revision 1.1.1.8 -diff -u -p -r1.1.1.5 -r1.1.1.8 ---- bgpd/log.c 14 Feb 2010 20:19:57 -0000 1.1.1.5 -+++ bgpd/log.c 13 Oct 2012 18:22:43 -0000 1.1.1.8 -@@ -1,4 +1,4 @@ --/* $OpenBSD: log.c,v 1.50 2007/04/23 13:04:24 claudio Exp $ */ -+/* $OpenBSD: log.c,v 1.55 2011/08/20 19:02:28 sthen Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -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 *p - 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 { -@@ -77,6 +79,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 +201,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 +258,7 @@ log_statechange(struct peer *peer, enum - - 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; -@@ -283,27 +291,31 @@ log_notification(const struct peer *peer - suberrname = suberr_cease_names[subcode]; - break; - case ERR_HOLDTIMEREXPIRED: -- case ERR_FSM: - uk = 1; - break; -+ case ERR_FSM: -+ if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) -+ uk = 1; -+ else -+ suberrname = suberr_fsm_names[subcode]; -+ 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 +330,9 @@ log_conn_attempt(const struct peer *peer - 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]); Index: net/openbgpd/files/patch-bgpd_mrt.h =================================================================== --- net/openbgpd/files/patch-bgpd_mrt.h +++ /dev/null @@ -1,287 +0,0 @@ -Index: bgpd/mrt.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/mrt.h,v -retrieving revision 1.1.1.6 -retrieving revision 1.1.1.9 -diff -u -p -r1.1.1.6 -r1.1.1.9 ---- bgpd/mrt.h 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/mrt.h 13 Oct 2012 18:22:43 -0000 1.1.1.9 -@@ -1,4 +1,4 @@ --/* $OpenBSD: mrt.h,v 1.23 2009/06/29 12:22:16 claudio Exp $ */ -+/* $OpenBSD: mrt.h,v 1.30 2011/09/18 09:31:25 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker -@@ -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 - */ - -@@ -37,11 +35,18 @@ - * | length | length of packet excluding this header - * +--------+--------+--------+--------+ - * -- * ET types include an additional 32bit microsecond field comming after the -- * length field. -+ * ET types include an additional 32bit microsecond field coming after the -+ * length field. Which is accounted in the length field. - */ - #define MRT_HEADER_SIZE 12 - -+struct mrt_hdr { -+ u_int32_t timestamp; -+ u_int16_t type; -+ u_int16_t subtype; -+ u_int32_t length; -+} __packed; -+ - enum MRT_MSG_TYPES { - MSG_NULL, /* 0 empty msg (deprecated) */ - MSG_START, /* 1 sender is starting up */ -@@ -70,13 +75,15 @@ enum MRT_MSG_TYPES { - * that are normaly saved as MSG_TABLE_DUMP. - * In most cases this is the format to choose to dump updates et al. - */ --enum MRT_BGP4MP_TYPES { -+enum MRT_BGP4MP_SUBTYPES { - BGP4MP_STATE_CHANGE, /* state change */ - 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 */ -@@ -104,6 +111,7 @@ enum MRT_BGP4MP_TYPES { - * - * The source_ip and dest_ip are dependant of the afi type. For IPv6 source_ip - * and dest_ip are both 16 bytes long. -+ * For the AS4 types the source_as and dest_as numbers are both 4 bytes long. - * - * Payload of a BGP4MP_STATE_CHANGE packet: - * -@@ -155,6 +163,98 @@ enum MRT_BGP4MP_TYPES { - */ - - /* -+ * New MRT dump format MSG_TABLE_DUMP_V2, the dump is implemented with -+ * sub-tables for peers and NLRI entries just use the index into the peer -+ * table. -+ */ -+enum MRT_DUMP_V2_SUBTYPES { -+ MRT_DUMP_V2_PEER_INDEX_TABLE=1, -+ MRT_DUMP_V2_RIB_IPV4_UNICAST=2, -+ MRT_DUMP_V2_RIB_IPV4_MULTICAST=3, -+ MRT_DUMP_V2_RIB_IPV6_UNICAST=4, -+ MRT_DUMP_V2_RIB_IPV6_MULTICAST=5, -+ MRT_DUMP_V2_RIB_GENERIC=6 -+}; -+ -+/* -+ * Format of the MRT_DUMP_V2_PEER_INDEX_TABLE: -+ * If there is no view_name, view_name_len must be set to 0 -+ * -+ * +--------+--------+--------+--------+ -+ * | collector_bgp_id | -+ * +--------+--------+--------+--------+ -+ * | view_name_len | view_name -+ * +--------+--------+--------+--------+ -+ * view_name (variable) ... | -+ * +--------+--------+--------+--------+ -+ * | peer_count | peer_entries -+ * +--------+--------+--------+--------+ -+ * peer_entries (variable) ... -+ * +--------+--------+--------+--------+ -+ * -+ * The format of a peer_entry is the following: -+ * -+ * +--------+ -+ * | type | -+ * +--------+--------+--------+--------+ -+ * | peer_bgp_id | -+ * +--------+--------+--------+--------+ -+ * | peer_ip_addr (variable) | -+ * +--------+--------+--------+--------+ -+ * | peer_as (variable) | -+ * +--------+--------+--------+--------+ -+ * -+ * The message is packed a bit strangely. The type byte defines what size -+ * the peer addr and peer AS have. -+ * The position of a peer in the PEER_INDEX_TABLE is used as the index for -+ * the other messages. -+ */ -+#define MRT_DUMP_V2_PEER_BIT_I 0x1 /* set for IPv6 addrs */ -+#define MRT_DUMP_V2_PEER_BIT_A 0x2 /* set for 32 bits AS number */ -+ -+/* -+ * AFI/SAFI specific RIB Subtypes are special to save a few bytes. -+ * -+ * +--------+--------+--------+--------+ -+ * | seq_num | -+ * +--------+--------+--------+--------+ -+ * | plen | prefix (variable) -+ * +--------+--------+--------+--------+ -+ * | #entry | rib entries (variable) -+ * +--------+--------+--------+--------+ -+ * -+ * The RIB_GENERIC subtype is needed for the less common AFI/SAFI pairs -+ * -+ * +--------+--------+--------+--------+ -+ * | seq_num | -+ * +--------+--------+--------+--------+ -+ * | AFI | SAFI | NLRI -+ * +--------+--------+--------+--------+ -+ * NLRI (variable) ... -+ * +--------+--------+--------+--------+ -+ * | #entry | rib entries (variable) -+ * +--------+--------+--------+--------+ -+ */ -+ -+/* -+ * The RIB entries have the following form. -+ * -+ * +--------+--------+ -+ * | peer index | -+ * +--------+--------+--------+--------+ -+ * | originated_time | -+ * +--------+--------+--------+--------+ -+ * | attr_len | bgp_attrs -+ * +--------+--------+--------+--------+ -+ * bgp_attrs (variable) ... -+ * +--------+--------+--------+--------+ -+ * -+ * Some BGP path attributes need special encoding: -+ * - the AS_PATH attribute MUST be encoded as 4-Byte AS -+ * - the MP_REACH_NLRI only consists of the nexthop len and nexthop address -+ */ -+ -+/* - * Format for routing table dumps in "old" mrt format. - * Type MSG_TABLE_DUMP and subtype is AFI_IPv4 (1) for IPv4 and AFI_IPv6 (2) - * for IPv6. In the IPv6 case prefix and peer_ip are both 16 bytes long. -@@ -182,8 +282,14 @@ enum MRT_BGP4MP_TYPES { - * The status field is unused and should be set to 1. - */ - -+enum MRT_DUMP_SUBTYPES { -+ MRT_DUMP_AFI_IP=1, -+ MRT_DUMP_AFI_IPv6=2 -+}; -+ - /* 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 -@@ -192,7 +298,7 @@ enum MRT_BGP4MP_TYPES { - * Only for bgp messages (type 5, 9 and 10) - * Nota bene for bgp dumps MSG_PROTOCOL_BGP4MP should be used. - */ --enum MRT_BGP_TYPES { -+enum MRT_BGP_SUBTYPES { - MSG_BGP_NULL, - MSG_BGP_UPDATE, /* raw update packet (contains both withdraws - and announcements) */ -@@ -221,10 +327,8 @@ enum MRT_BGP_TYPES { - * - * For IPv6 the type is MSG_PROTOCOL_BGP4PLUS and the subtype remains - * MSG_BGP_UPDATE. The source_ip and dest_ip are again extended to 16 bytes. -- */ -- --/* -- * For subtype MSG_BGP_STATECHANGE (for all BGP types or just for the -+ * -+ * For subtype MSG_BGP_STATE_CHANGE (for all BGP types or just for the - * MSG_PROTOCOL_BGP4PLUS case? Unclear.) - * - * +--------+--------+--------+--------+ -@@ -235,7 +339,7 @@ enum MRT_BGP_TYPES { - * | new_state | - * +--------+--------+ - * -- * State are defined in RFC 1771. -+ * States are defined in RFC 1771/4271. - */ - - /* -@@ -251,66 +355,4 @@ enum MRT_BGP_TYPES { - * terminated ... | 0 | - * +--------+--------+--------+ - */ -- --#define MRT_FILE_LEN 512 --enum mrt_type { -- MRT_NONE, -- MRT_TABLE_DUMP, -- MRT_TABLE_DUMP_MP, -- MRT_ALL_IN, -- MRT_ALL_OUT, -- MRT_UPDATE_IN, -- MRT_UPDATE_OUT --}; -- --enum mrt_state { -- MRT_STATE_RUNNING, -- MRT_STATE_OPEN, -- MRT_STATE_REOPEN, -- MRT_STATE_REMOVE --}; -- --struct mrt { -- char rib[PEER_DESCR_LEN]; -- struct msgbuf wbuf; -- LIST_ENTRY(mrt) entry; -- u_int32_t peer_id; -- u_int32_t group_id; -- enum mrt_type type; -- enum mrt_state state; -- u_int16_t seqnum; --}; -- --struct mrt_config { -- struct mrt conf; -- char name[MRT_FILE_LEN]; /* base file name */ -- char file[MRT_FILE_LEN]; /* actual file name */ -- time_t ReopenTimer; -- time_t ReopenTimerInterval; --}; -- --#define MRT2MC(x) ((struct mrt_config *)(x)) --#define MRT_MAX_TIMEOUT 7200 -- --struct peer; --struct prefix; --struct rib_entry; -- --/* prototypes */ --void mrt_dump_bgp_msg(struct mrt *, void *, u_int16_t, -- struct peer *); --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_write(struct mrt *); --void mrt_clean(struct mrt *); --void mrt_init(struct imsgbuf *, struct imsgbuf *); --int mrt_timeout(struct mrt_head *); --void mrt_reconfigure(struct mrt_head *); --void mrt_handler(struct mrt_head *); --struct mrt *mrt_get(struct mrt_head *, struct mrt *); --int mrt_mergeconfig(struct mrt_head *, struct mrt_head *); -- - #endif Index: net/openbgpd/files/patch-bgpd_mrt.c =================================================================== --- net/openbgpd/files/patch-bgpd_mrt.c +++ /dev/null @@ -1,864 +0,0 @@ -Index: bgpd/mrt.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/mrt.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.1.1.11 -diff -u -p -r1.1.1.7 -r1.1.1.11 ---- bgpd/mrt.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/mrt.c 8 Dec 2012 10:37:09 -0000 1.1.1.11 -@@ -1,4 +1,4 @@ --/* $OpenBSD: mrt.c,v 1.63 2009/06/29 12:22:16 claudio Exp $ */ -+/* $OpenBSD: mrt.c,v 1.72 2011/11/06 10:29:05 guenther Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker -@@ -21,6 +21,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -32,20 +33,22 @@ - - #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); - 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_entry_v2(struct mrt *, struct rib_entry *, u_int32_t); -+int mrt_dump_peer(struct ibuf *, struct rde_peer *); -+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_warn("mrt_dump1: ibuf_add error"); \ - goto fail; \ - } \ - } while (0) -@@ -54,8 +57,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_warn("mrt_dump2: ibuf_add error"); \ - goto fail; \ - } \ - } while (0) -@@ -64,8 +67,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_warn("mrt_dump3: ibuf_add error"); \ - goto fail; \ - } \ - } while (0) -@@ -73,8 +76,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_warn("mrt_dump4: ibuf_add error"); \ - goto fail; \ - } \ - } while (0) -@@ -83,55 +86,64 @@ 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) { -- log_warnx("mrt_dump_bgp_msg: buf_add error"); -- buf_free(buf); -+ if (ibuf_add(buf, pkg, pkglen) == -1) { -+ log_warn("mrt_dump_bgp_msg: ibuf_add error"); -+ 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, -+ int v2) - { - 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, safi; - - /* origin */ - if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, -@@ -140,12 +152,16 @@ mrt_attr_dump(struct buf *buf, struct rd - - /* 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 (!v2) -+ pdata = aspath_deflate(pdata, &plen, &neednewpath); -+ 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) -@@ -159,7 +175,7 @@ mrt_attr_dump(struct buf *buf, struct rd - return (-1); - } - -- /* local preference, only valid for ibgp */ -+ /* local preference */ - tmp = htonl(a->lpref); - if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) - return (-1); -@@ -173,12 +189,51 @@ mrt_attr_dump(struct buf *buf, struct rd - return (-1); - } - -+ if (nexthop && nexthop->aid != AID_INET) { -+ struct ibuf *nhbuf; -+ -+ if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL) -+ return (-1); -+ if (!v2) { -+ if (aid2afi(nexthop->aid, &afi, &safi)) -+ return (-1); -+ DUMP_SHORT(nhbuf, afi); -+ DUMP_BYTE(nhbuf, safi); -+ } -+ switch (nexthop->aid) { -+ case AID_INET6: -+ DUMP_BYTE(nhbuf, sizeof(struct in6_addr)); -+ if (ibuf_add(nhbuf, &nexthop->v6, -+ sizeof(struct in6_addr)) == -1) { -+ } -+ break; -+ case AID_VPN_IPv4: -+ DUMP_BYTE(nhbuf, sizeof(u_int64_t) + -+ sizeof(struct in_addr)); -+ DUMP_NLONG(nhbuf, 0); /* set RD to 0 */ -+ DUMP_NLONG(nhbuf, 0); -+ DUMP_NLONG(nhbuf, nexthop->v4.s_addr); -+ break; -+ } -+ if (!v2) -+ DUMP_BYTE(nhbuf, 0); -+ if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI, -+ nhbuf->buf, ibuf_size(nhbuf)) == -1) { -+fail: -+ ibuf_free(nhbuf); -+ return (-1); -+ } -+ ibuf_free(nhbuf); -+ } -+ - 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,28 +244,26 @@ 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; -- void *bptr; -+ struct ibuf *buf, *hbuf = NULL, *h2buf = NULL; - 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) { -- log_warn("mrt_dump_entry_mp: buf_dynamic"); -+ if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { -+ log_warn("mrt_dump_entry_mp: ibuf_dynamic"); - return (-1); - } - -- if (mrt_attr_dump(buf, p->aspath, NULL) == -1) { -+ if (mrt_attr_dump(buf, p->aspath, NULL, 0) == -1) { - 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"); -+ log_warn("mrt_dump_entry_mp: ibuf_dynamic"); - goto fail; - } - -@@ -219,25 +272,26 @@ mrt_dump_entry_mp(struct mrt *mrt, struc - 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"); -+ log_warn("mrt_dump_entry_mp: ibuf_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,25 +301,25 @@ mrt_dump_entry_mp(struct mrt *mrt, struc - - 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) { -- log_warnx("mrt_dump_entry_mp: buf_add error"); -+ if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { -+ log_warn("mrt_dump_entry_mp: ibuf_add error"); - goto fail; - } - break; -@@ -274,35 +328,30 @@ mrt_dump_entry_mp(struct mrt *mrt, struc - goto fail; - } - -- p_len = PREFIX_SIZE(p->prefix->prefixlen); -- if ((bptr = buf_reserve(h2buf, p_len)) == NULL) { -- log_warnx("mrt_dump_entry_mp: buf_reserve error"); -- goto fail; -- } -- if (prefix_write(bptr, p_len, &addr, p->prefix->prefixlen) == -1) { -- log_warnx("mrt_dump_entry_mp: prefix_write error"); -+ if (prefix_writebuf(h2buf, &addr, p->prefix->prefixlen) == -1) { -+ log_warn("mrt_dump_entry_mp: prefix_writebuf error"); - goto fail; - } - - 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 +359,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) { -- log_warnx("mrt_dump_entry: buf_dynamic"); -+ if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { -+ log_warn("mrt_dump_entry: ibuf_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) { -+ if (mrt_attr_dump(buf, p->aspath, nh, 0) == -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 +397,241 @@ mrt_dump_entry(struct mrt *mrt, struct p - 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_warn("mrt_dump_entry: ibuf_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_warn("mrt_dump_entry: ibuf_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); -+} -+ -+int -+mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum) -+{ -+ struct ibuf *buf, *hbuf = NULL; -+ struct prefix *p; -+ struct bgpd_addr addr; -+ size_t len, off; -+ u_int16_t subtype, nump; -+ -+ switch (re->prefix->aid) { -+ case AID_INET: -+ subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST; -+ break; -+ case AID_INET6: -+ subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST; -+ break; -+ default: -+ subtype = MRT_DUMP_V2_RIB_GENERIC; -+ break; -+ } -+ -+ if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { -+ log_warn("mrt_dump_entry: ibuf_dynamic"); -+ return (-1); -+ } -+ -+ DUMP_LONG(buf, snum); -+ pt_getaddr(re->prefix, &addr); -+ if (subtype == MRT_DUMP_V2_RIB_GENERIC) { -+ u_int16_t afi; -+ u_int8_t safi; -+ -+ aid2afi(re->prefix->aid, &afi, &safi); -+ DUMP_SHORT(buf, afi); -+ DUMP_BYTE(buf, safi); -+ } -+ if (prefix_writebuf(buf, &addr, re->prefix->prefixlen) == -1) { -+ log_warn("mrt_dump_entry_mp: prefix_writebuf error"); -+ goto fail; -+ } -+ -+ off = ibuf_size(buf); -+ if (ibuf_reserve(buf, sizeof(nump)) == NULL) { -+ log_warn("mrt_dump_v2_hdr: ibuf_reserve error"); -+ goto fail; -+ } -+ nump = 0; -+ LIST_FOREACH(p, &re->prefix_h, rib_l) { -+ struct bgpd_addr *nh; -+ struct ibuf *tbuf; -+ -+ if (p->aspath->nexthop == NULL) { -+ bzero(&addr, sizeof(struct bgpd_addr)); -+ addr.aid = p->prefix->aid; -+ nh = &addr; -+ } else -+ nh = &p->aspath->nexthop->exit_nexthop; -+ -+ DUMP_SHORT(buf, p->aspath->peer->mrt_idx); -+ DUMP_LONG(buf, p->lastchange); /* originated */ -+ -+ if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { -+ log_warn("mrt_dump_entry_v2: ibuf_dynamic"); -+ return (-1); -+ } -+ if (mrt_attr_dump(tbuf, p->aspath, nh, 1) == -1) { -+ log_warnx("mrt_dump_entry_v2: mrt_attr_dump error"); -+ ibuf_free(buf); -+ return (-1); -+ } -+ len = ibuf_size(tbuf); -+ DUMP_SHORT(buf, (u_int16_t)len); -+ if (ibuf_add(buf, tbuf->buf, ibuf_size(tbuf)) == -1) { -+ log_warn("mrt_dump_entry_v2: ibuf_add error"); -+ ibuf_free(tbuf); -+ return (-1); -+ } -+ ibuf_free(tbuf); -+ nump++; -+ } -+ nump = htons(nump); -+ memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); -+ -+ len = ibuf_size(buf); -+ if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, len) == -1) { -+ ibuf_free(buf); -+ return (-1); -+ } -+ -+ ibuf_close(&mrt->wbuf, hbuf); -+ ibuf_close(&mrt->wbuf, buf); -+ -+ return (0); -+fail: -+ if (hbuf) -+ ibuf_free(hbuf); -+ ibuf_free(buf); -+ return (-1); -+} -+ -+int -+mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf, -+ struct rde_peer_head *ph) -+{ -+ struct rde_peer *peer; -+ struct ibuf *buf, *hbuf = NULL; -+ size_t len, off; -+ u_int16_t nlen, nump; -+ -+ if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { -+ log_warn("mrt_dump_v2_hdr: ibuf_dynamic"); -+ return (-1); -+ } -+ -+ DUMP_NLONG(buf, conf->bgpid); -+ nlen = strlen(mrt->rib); -+ if (nlen > 0) -+ nlen += 1; -+ DUMP_SHORT(buf, nlen); -+ if (ibuf_add(buf, mrt->rib, nlen) == -1) { -+ log_warn("mrt_dump_v2_hdr: ibuf_add error"); -+ goto fail; -+ } -+ -+ off = ibuf_size(buf); -+ if (ibuf_reserve(buf, sizeof(nump)) == NULL) { -+ log_warn("mrt_dump_v2_hdr: ibuf_reserve error"); -+ goto fail; -+ } -+ nump = 0; -+ LIST_FOREACH(peer, ph, peer_l) { -+ peer->mrt_idx = nump; -+ if (mrt_dump_peer(buf, peer) == -1) -+ goto fail; -+ nump++; -+ } -+ nump = htons(nump); -+ memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); -+ -+ len = ibuf_size(buf); -+ if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, -+ MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1) -+ goto fail; -+ -+ ibuf_close(&mrt->wbuf, hbuf); -+ ibuf_close(&mrt->wbuf, buf); -+ -+ return (0); -+fail: -+ if (hbuf) -+ ibuf_free(hbuf); -+ ibuf_free(buf); -+ return (-1); -+} -+ -+int -+mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer) -+{ -+ u_int8_t type = 0; -+ -+ if (peer->capa.as4byte) -+ type |= MRT_DUMP_V2_PEER_BIT_A; -+ if (peer->remote_addr.aid == AID_INET6) -+ type |= MRT_DUMP_V2_PEER_BIT_I; -+ -+ DUMP_BYTE(buf, type); -+ DUMP_LONG(buf, peer->remote_bgpid); -+ -+ switch (peer->remote_addr.aid) { -+ case AID_INET: -+ DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); -+ break; -+ case AID_INET6: -+ if (ibuf_add(buf, &peer->remote_addr.v6, -+ sizeof(struct in6_addr)) == -1) { -+ log_warn("mrt_dump_peer: ibuf_add error"); -+ goto fail; -+ } -+ break; -+ case AID_UNSPEC: /* XXX special handling for peer_self? */ -+ DUMP_NLONG(buf, 0); -+ break; -+ default: -+ log_warnx("king bula found new AF in mrt_dump_entry_mp"); -+ goto fail; -+ } -+ -+ if (peer->capa.as4byte) -+ DUMP_LONG(buf, peer->conf.remote_as); -+ else -+ DUMP_SHORT(buf, peer->short_as); -+ -+ return (0); -+fail: - return (-1); - } - -@@ -371,6 +641,11 @@ mrt_dump_upcall(struct rib_entry *re, vo - struct mrt *mrtbuf = ptr; - struct prefix *p; - -+ if (mrtbuf->type == MRT_TABLE_DUMP_V2) { -+ mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++); -+ return; -+ } -+ - /* - * dump all prefixes even the inactive ones. That is the way zebra - * dumps the table so we do the same. If only the active route should -@@ -387,7 +662,7 @@ mrt_dump_upcall(struct rib_entry *re, vo - } - - void --mrt_dump_done(void *ptr) -+mrt_done(void *ptr) - { - struct mrt *mrtbuf = ptr; - -@@ -395,14 +670,14 @@ 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"); -+ log_warn("mrt_dump_hdr_se: ibuf_dynamic error"); - return (-1); - } - -@@ -468,23 +743,23 @@ mrt_dump_hdr_se(struct buf ** bp, struct - 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"); -+ log_warn("mrt_dump_hdr_se: ibuf_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"); -+ log_warn("mrt_dump_hdr_se: ibuf_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"); -+ log_warn("mrt_dump_hdr_se: ibuf_add error"); - goto fail; - } - break; -@@ -493,20 +768,20 @@ mrt_dump_hdr_se(struct buf ** bp, struct - 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"); -+ log_warn("mrt_dump_hdr_rde: ibuf_dynamic error"); - return (-1); - } - -@@ -517,19 +792,28 @@ mrt_dump_hdr_rde(struct buf **bp, u_int1 - - 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: -+ case MSG_TABLE_DUMP_V2: - DUMP_LONG(*bp, len); - break; - default: - log_warnx("mrt_dump_hdr_rde: unsupported type"); - goto fail; -- } -+ } - return (0); - - fail: -- buf_free(*bp); -+ ibuf_free(*bp); - return (-1); - } - -@@ -538,21 +822,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; - } -@@ -590,7 +875,8 @@ mrt_open(struct mrt *mrt, time_t now) - else - type = IMSG_MRT_REOPEN; - -- if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP) -+ if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP || -+ mrt->type == MRT_TABLE_DUMP_V2) - i = 0; - - if (imsg_compose(mrt_imsgbuf[i], type, 0, 0, fd, -@@ -659,7 +945,9 @@ mrt_handler(struct mrt_head *mrt) - LIST_FOREACH(m, mrt, entry) { - if (m->state == MRT_STATE_RUNNING && - (MRT2MC(m)->ReopenTimerInterval != 0 || -- m->type == MRT_TABLE_DUMP)) { -+ m->type == MRT_TABLE_DUMP || -+ m->type == MRT_TABLE_DUMP_MP || -+ m->type == MRT_TABLE_DUMP_V2)) { - if (mrt_open(m, now) == -1) - continue; - MRT2MC(m)->ReopenTimer = Index: net/openbgpd/files/patch-bgpd_name2id.c =================================================================== --- net/openbgpd/files/patch-bgpd_name2id.c +++ /dev/null @@ -1,14 +0,0 @@ -Index: bgpd/name2id.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/name2id.c,v -retrieving revision 1.1.1.2 -retrieving revision 1.1.1.3 -diff -u -p -r1.1.1.2 -r1.1.1.3 ---- bgpd/name2id.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 -+++ bgpd/name2id.c 13 Oct 2012 18:22:43 -0000 1.1.1.3 -@@ -1,4 +1,4 @@ --/* $OpenBSD: name2id.c,v 1.9 2009/06/04 04:46:42 claudio Exp $ */ -+/* $OpenBSD: name2id.c,v 1.8 2009/05/17 12:25:15 claudio Exp $ */ - - /* - * Copyright (c) 2004, 2005 Henning Brauer Index: net/openbgpd/files/patch-bgpd_parse.y =================================================================== --- net/openbgpd/files/patch-bgpd_parse.y +++ /dev/null @@ -1,1626 +0,0 @@ -Index: bgpd/parse.y -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/parse.y,v -retrieving revision 1.1.1.8 -retrieving revision 1.12 -diff -u -p -r1.1.1.8 -r1.12 ---- bgpd/parse.y 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/parse.y 8 Dec 2012 20:17:59 -0000 1.12 -@@ -1,4 +1,4 @@ --/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: parse.y,v 1.264 2012/09/23 09:39:17 claudio Exp $ */ - - /* - * Copyright (c) 2002, 2003, 2004 Henning Brauer -@@ -25,7 +25,10 @@ - #include - #include - #include -- -+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */ -+#include -+#endif -+ - #include - #include - #include -@@ -33,6 +36,9 @@ - #include - #include - #include -+#if defined(__FreeBSD__) -+#include -+#endif - #include - #include - -@@ -74,10 +80,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 +113,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 +121,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 +131,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 +169,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 STRING - %token NUMBER --%type asnumber as4number optnumber yesno inout --%type espah family restart -+%type asnumber as4number optnumber -+%type espah family restart origincode nettype -+%type yesno inout restricted - %type string filter_rib - %type address - %type prefix addrspec -@@ -204,6 +218,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 +226,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 +293,8 @@ yesno : STRING { - else if (!strcmp($1, "no")) - $$ = 0; - else { -+ yyerror("syntax error, " -+ "either yes or no expected"); - free($1); - YYERROR; - } -@@ -318,7 +339,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 +363,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 +390,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 +399,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 +440,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; - -@@ -484,6 +454,8 @@ conf_main : AS as4number { - action = MRT_TABLE_DUMP; - else if (!strcmp($2, "table-mp")) - action = MRT_TABLE_DUMP_MP; -+ else if (!strcmp($2, "table-v2")) -+ action = MRT_TABLE_DUMP_V2; - else { - yyerror("unknown mrt dump type"); - free($2); -@@ -511,6 +483,8 @@ conf_main : AS as4number { - action = MRT_TABLE_DUMP; - else if (!strcmp($4, "table-mp")) - action = MRT_TABLE_DUMP_MP; -+ else if (!strcmp($4, "table-v2")) -+ action = MRT_TABLE_DUMP_V2; - else { - yyerror("unknown mrt dump type"); - free($3); -@@ -575,11 +549,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 +571,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 +612,47 @@ mrtdump : DUMP STRING inout STRING optn - } - ; - -+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 +664,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 +682,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 +701,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 +715,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 +734,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 +967,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 +1028,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 +1046,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.grestart.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 +1269,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 +1343,10 @@ family : IPV4 { $$ = AFI_IPv4; } - | IPV6 { $$ = AFI_IPv6; } - ; - -+nettype : STATIC { $$ = 1; }, -+ | CONNECTED { $$ = 0; } -+ ; -+ - espah : ESP { $$ = 1; } - | AH { $$ = 0; } - ; -@@ -1336,12 +1526,12 @@ filter_prefix_l : filter_prefix { $$ - ; - - 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 +1600,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 +1633,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 +1653,93 @@ 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; -+ } -+ | NEXTHOP address { -+ if (fmopts.m.nexthop.flags) { -+ yyerror("nexthop already specified"); -+ YYERROR; -+ } -+ if (fmopts.aid && fmopts.aid != $2.aid) { -+ yyerror("nexthop address family doesn't match " -+ "rule address family"); -+ YYERROR; -+ } -+ fmopts.m.nexthop.addr = $2; -+ fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; -+ } -+ | NEXTHOP NEIGHBOR { -+ if (fmopts.m.nexthop.flags) { -+ yyerror("nexthop already specified"); -+ YYERROR; -+ } -+ fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; - } - ; - -@@ -1588,7 +1845,7 @@ filter_set_opt : LOCALPREF NUMBER { - } - if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) - fatal(NULL); -- if ($2 > 0) { -+ if ($2 >= 0) { - $$->type = ACTION_SET_MED; - $$->action.metric = $2; - } else { -@@ -1623,7 +1880,7 @@ filter_set_opt : LOCALPREF NUMBER { - } - if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) - fatal(NULL); -- if ($2 > 0) { -+ if ($2 >= 0) { - $$->type = ACTION_SET_MED; - $$->action.metric = $2; - } else { -@@ -1782,8 +2039,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 +2052,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 +2151,7 @@ lookup(char *s) - { "allow", ALLOW}, - { "announce", ANNOUNCE}, - { "any", ANY}, -+ { "as-4byte", AS4BYTE }, - { "blackhole", BLACKHOLE}, - { "capabilities", CAPABILITIES}, - { "community", COMMUNITY}, -@@ -1889,16 +2168,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 +2191,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 +2205,7 @@ lookup(char *s) - { "nexthop", NEXTHOP}, - { "no-modify", NOMODIFY}, - { "on", ON}, -+ { "origin", ORIGIN}, - { "out", OUT}, - { "passive", PASSIVE}, - { "password", PASSWORD}, -@@ -1929,10 +2217,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 +2233,7 @@ lookup(char *s) - { "rtlabel", RTLABEL}, - { "self", SELF}, - { "set", SET}, -+ { "socket", SOCKET }, - { "softreconfig", SOFTRECONFIG}, - { "source-as", SOURCEAS}, - { "spi", SPI}, -@@ -2117,9 +2410,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 +2429,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 +2588,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 +2633,15 @@ parse_config(char *filename, struct bgpd - 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 +2663,9 @@ parse_config(char *filename, struct bgpd - - 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 +2679,44 @@ parse_config(char *filename, struct bgpd - - 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 +2848,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 +2880,176 @@ parsecommunity(char *s, int *as, int *ty - - 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 +3060,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.grestart.restart = 1; -+ 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 +3088,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 +3173,52 @@ add_mrtconfig(enum mrt_type type, char * - } - - 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 +3227,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 +3368,11 @@ str2key(char *s, char *dest, size_t max_ - 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 +3383,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,18 +3403,14 @@ 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) -- p->conf.announce_type = p->conf.ebgp == 0 ? -- ANNOUNCE_ALL : ANNOUNCE_SELF; -+ p->conf.announce_type = p->conf.ebgp ? -+ ANNOUNCE_SELF : ANNOUNCE_ALL; - if (p->conf.enforce_as == ENFORCE_AS_UNDEF) -- p->conf.enforce_as = p->conf.ebgp == 0 ? -- ENFORCE_AS_OFF : ENFORCE_AS_ON; -+ p->conf.enforce_as = p->conf.ebgp ? -+ ENFORCE_AS_ON : ENFORCE_AS_OFF; - - /* EBGP neighbors are not allowed in route reflector clusters */ - if (p->conf.reflector_client && p->conf.ebgp) { -@@ -2909,6 +3419,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 +3442,11 @@ merge_filterset(struct filter_set_head * - 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 +3473,18 @@ merge_filterset(struct filter_set_head * - 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 +3514,6 @@ copy_filterset(struct filter_set_head *s - } - } - --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) - { Index: net/openbgpd/files/patch-bgpd_pfkey.c =================================================================== --- net/openbgpd/files/patch-bgpd_pfkey.c +++ /dev/null @@ -1,471 +0,0 @@ -diff -ur bgpd.orig/pfkey.c bgpd/pfkey.c ---- bgpd.orig/pfkey.c 2013-03-15 12:07:16.000000000 +0000 -+++ bgpd/pfkey.c 2013-03-15 12:07:47.000000000 +0000 -@@ -1,4 +1,4 @@ --/* $OpenBSD: pfkey.c,v 1.37 2009/04/21 15:25:52 henning Exp $ */ -+/* $OpenBSD: pfkey.c,v 1.40 2009/12/14 17:38:18 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -21,7 +21,7 @@ - #include - #include - #include --#include -+//#include - #include - #include - #include -@@ -65,15 +65,15 @@ - { - struct sadb_msg smsg; - struct sadb_sa sa; -- struct sadb_address sa_src, sa_dst, sa_peer, sa_smask, sa_dmask; -+ struct sadb_address sa_src, sa_dst; - struct sadb_key sa_akey, sa_ekey; - struct sadb_spirange sa_spirange; -- struct sadb_protocol sa_flowtype, sa_protocol; - struct iovec iov[IOV_CNT]; - ssize_t n; - int len = 0; - int iov_cnt; -- struct sockaddr_storage ssrc, sdst, speer, smask, dmask; -+ struct sockaddr_storage ssrc, sdst, smask, dmask; -+ struct sockaddr *saptr; - - if (!pid) - pid = getpid(); -@@ -81,22 +81,17 @@ - /* 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 +102,17 @@ - - 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: -@@ -135,7 +125,7 @@ - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = pid; -- smsg.sadb_msg_len = sizeof(smsg) / 8; -+ smsg.sadb_msg_len = PFKEY_UNIT64(sizeof(smsg)); - smsg.sadb_msg_type = mtype; - smsg.sadb_msg_satype = satype; - -@@ -143,7 +133,7 @@ - case SADB_GETSPI: - bzero(&sa_spirange, sizeof(sa_spirange)); - sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; -- sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; -+ sa_spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(sa_spirange)); - sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = 0xffffffff; - sa_spirange.sadb_spirange_reserved = 0; -@@ -153,11 +143,12 @@ - case SADB_DELETE: - bzero(&sa, sizeof(sa)); - sa.sadb_sa_exttype = SADB_EXT_SA; -- sa.sadb_sa_len = sizeof(sa) / 8; -+ sa.sadb_sa_len = PFKEY_UNIT64(sizeof(sa)); - sa.sadb_sa_replay = 0; - sa.sadb_sa_spi = spi; - sa.sadb_sa_state = SADB_SASTATE_MATURE; - break; -+#if 0 - case SADB_X_ADDFLOW: - case SADB_X_DELFLOW: - bzero(&sa_flowtype, sizeof(sa_flowtype)); -@@ -172,35 +163,37 @@ - sa_protocol.sadb_protocol_direction = 0; - sa_protocol.sadb_protocol_proto = 6; - break; -+#endif - } - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; -- sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; -+ sa_src.sadb_address_len = PFKEY_UNIT64(sizeof(sa_src) + ROUNDUP(ssrc.ss_len)); - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; -- sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; -+ sa_dst.sadb_address_len = PFKEY_UNIT64(sizeof(sa_dst) + ROUNDUP(sdst.ss_len)); - - sa.sadb_sa_auth = aalg; -- sa.sadb_sa_encrypt = SADB_X_EALG_AES; /* XXX */ -+ sa.sadb_sa_encrypt = ealg; /* XXX */ - - switch (mtype) { - case SADB_ADD: - case SADB_UPDATE: - bzero(&sa_akey, sizeof(sa_akey)); - sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH; -- sa_akey.sadb_key_len = (sizeof(sa_akey) + -- ((alen + 7) / 8) * 8) / 8; -+ sa_akey.sadb_key_len = PFKEY_UNIT64(sizeof(sa_akey) + -+ (PFKEY_ALIGN8(alen))); - sa_akey.sadb_key_bits = 8 * alen; - - bzero(&sa_ekey, sizeof(sa_ekey)); - sa_ekey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; -- sa_ekey.sadb_key_len = (sizeof(sa_ekey) + -- ((elen + 7) / 8) * 8) / 8; -+ sa_ekey.sadb_key_len = PFKEY_UNIT64(sizeof(sa_ekey) + -+ (PFKEY_ALIGN8(elen))); - sa_ekey.sadb_key_bits = 8 * elen; - - break; -+#if 0 - case SADB_X_ADDFLOW: - case SADB_X_DELFLOW: - /* sa_peer always points to the remote machine */ -@@ -220,8 +213,8 @@ - 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 +226,7 @@ - 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 +240,8 @@ - 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 +253,7 @@ - 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, -@@ -284,6 +277,7 @@ - sa_dmask.sadb_address_len = - (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; - break; -+#endif - } - - iov_cnt = 0; -@@ -310,6 +304,7 @@ - smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; - iov_cnt++; - break; -+#if 0 - case SADB_X_ADDFLOW: - /* sa_peer always points to the remote machine */ - iov[iov_cnt].iov_base = &sa_peer; -@@ -351,6 +346,7 @@ - smsg.sadb_msg_len += sa_dmask.sadb_address_len; - iov_cnt++; - break; -+#endif - } - - /* dest addr */ -@@ -380,7 +376,7 @@ - iov[iov_cnt].iov_len = sizeof(sa_akey); - iov_cnt++; - iov[iov_cnt].iov_base = akey; -- iov[iov_cnt].iov_len = ((alen + 7) / 8) * 8; -+ iov[iov_cnt].iov_len = PFKEY_ALIGN8(alen); - smsg.sadb_msg_len += sa_akey.sadb_key_len; - iov_cnt++; - } -@@ -390,14 +386,14 @@ - iov[iov_cnt].iov_len = sizeof(sa_ekey); - iov_cnt++; - iov[iov_cnt].iov_base = ekey; -- iov[iov_cnt].iov_len = ((elen + 7) / 8) * 8; -+ iov[iov_cnt].iov_len = PFKEY_ALIGN8(elen); - smsg.sadb_msg_len += sa_ekey.sadb_key_len; - iov_cnt++; - } - break; - } - -- len = smsg.sadb_msg_len * 8; -+ len = PFKEY_UNUNIT64(smsg.sadb_msg_len); - do { - n = writev(sd, iov, iov_cnt); - } while (n == -1 && (errno == EAGAIN || errno == EINTR)); -@@ -411,6 +407,33 @@ - } - - 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,27 +441,17 @@ - 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"); -- 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"); -+ do { -+ rv = pfkey_read(sd, &hdr); -+ if (rv == -1) - return (-1); -- } -- } -+ } while (rv); - - if (hdr.sadb_msg_errno != 0) { - errno = hdr.sadb_msg_errno; -- if (errno == ESRCH) -+ if (errno == ESRCH || errno == EEXIST) - return (0); - else { - log_warn("pfkey"); -@@ -486,13 +499,8 @@ - pfkey_sa_add(struct bgpd_addr *src, struct bgpd_addr *dst, u_int8_t keylen, - char *key, u_int32_t *spi) - { -- if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0, -- src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) -- return (-1); -- if (pfkey_reply(fd, spi) < 0) -- return (-1); -- if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_UPDATE, 0, -- src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0) -+ if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_ADD, 0, -+ src, dst, *spi, SADB_X_AALG_TCP_MD5, keylen, key, SADB_EALG_NONE, 0, NULL, 0, 0) < 0) - return (-1); - if (pfkey_reply(fd, NULL) < 0) - return (-1); -@@ -503,7 +511,7 @@ - pfkey_sa_remove(struct bgpd_addr *src, struct bgpd_addr *dst, u_int32_t *spi) - { - if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0, -- src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0) -+ src, dst, *spi, SADB_X_AALG_TCP_MD5, 0, NULL, 0, 0, NULL, 0, 0) < 0) - return (-1); - if (pfkey_reply(fd, NULL) < 0) - return (-1); -@@ -511,37 +519,37 @@ - return (0); - } - -+#define TCP_SIG_SPI 0x1000 - int - pfkey_md5sig_establish(struct peer *p) - { - sleep(1); - -- if (!p->auth.spi_out) -- if (pfkey_sa_add(&p->auth.local_addr, &p->conf.remote_addr, -- p->conf.auth.md5key_len, p->conf.auth.md5key, -- &p->auth.spi_out) == -1) -- return (-1); -- if (!p->auth.spi_in) -- if (pfkey_sa_add(&p->conf.remote_addr, &p->auth.local_addr, -- p->conf.auth.md5key_len, p->conf.auth.md5key, -- &p->auth.spi_in) == -1) -- return (-1); -+ p->auth.spi_out = htonl(TCP_SIG_SPI); -+ if (pfkey_sa_add(&p->auth.local_addr, &p->conf.remote_addr, -+ p->conf.auth.md5key_len, p->conf.auth.md5key, -+ &p->auth.spi_out) == -1) -+ return (-1); -+ p->auth.spi_in = htonl(TCP_SIG_SPI); -+ if (pfkey_sa_add(&p->conf.remote_addr, &p->auth.local_addr, -+ p->conf.auth.md5key_len, p->conf.auth.md5key, -+ &p->auth.spi_out) == -1) -+ return (-1); - - p->auth.established = 1; - return (0); - } -+#undef TCP_SIG_SPI - - int - pfkey_md5sig_remove(struct peer *p) - { -- if (p->auth.spi_out) -- if (pfkey_sa_remove(&p->auth.local_addr, &p->conf.remote_addr, -- &p->auth.spi_out) == -1) -- return (-1); -- if (p->auth.spi_in) -- if (pfkey_sa_remove(&p->conf.remote_addr, &p->auth.local_addr, -- &p->auth.spi_in) == -1) -- return (-1); -+ if (pfkey_sa_remove(&p->auth.local_addr, &p->conf.remote_addr, -+ &p->auth.spi_out) == -1) -+ return (-1); -+ if (pfkey_sa_remove(&p->conf.remote_addr, &p->auth.local_addr, -+ &p->auth.spi_in) == -1) -+ return (-1); - - p->auth.established = 0; - return (0); -@@ -550,6 +558,7 @@ - int - pfkey_ipsec_establish(struct peer *p) - { -+#if 0 - uint8_t satype = SADB_SATYPE_ESP; - - switch (p->auth.method) { -@@ -621,6 +630,9 @@ - - p->auth.established = 1; - return (0); -+#else -+ return (-1); -+#endif - } - - int -@@ -660,6 +672,7 @@ - break; - } - -+#if 0 - if (pfkey_flow(fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_OUT, - &p->auth.local_addr, &p->conf.remote_addr, 0, BGP_PORT) < 0) - return (-1); -@@ -681,6 +694,7 @@ - if (pfkey_flow(fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_IN, - &p->conf.remote_addr, &p->auth.local_addr, BGP_PORT, 0) < 0) - return (-1); -+#endif - if (pfkey_reply(fd, NULL) < 0) - return (-1); - -@@ -715,9 +729,7 @@ - int - pfkey_remove(struct peer *p) - { -- if (!p->auth.established) -- return (0); -- else if (p->auth.method == AUTH_MD5SIG) -+ if (p->auth.method == AUTH_MD5SIG) - return (pfkey_md5sig_remove(p)); - else - return (pfkey_ipsec_remove(p)); -@@ -730,11 +742,9 @@ - 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); - } Index: net/openbgpd/files/patch-bgpd_pftable.c =================================================================== --- net/openbgpd/files/patch-bgpd_pftable.c +++ /dev/null @@ -1,17 +0,0 @@ -Index: bgpd/pftable.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/pftable.c,v -retrieving revision 1.1.1.5 -retrieving revision 1.1.1.7 -diff -u -p -r1.1.1.5 -r1.1.1.7 ---- bgpd/pftable.c 14 Feb 2010 20:19:57 -0000 1.1.1.5 -+++ bgpd/pftable.c 13 Oct 2012 18:22:44 -0000 1.1.1.7 -@@ -214,7 +214,7 @@ pftable_add_work(const char *table, stru - - 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++; Index: net/openbgpd/files/patch-bgpd_printconf.c =================================================================== --- net/openbgpd/files/patch-bgpd_printconf.c +++ /dev/null @@ -1,439 +0,0 @@ -Index: bgpd/printconf.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/printconf.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.11 -diff -u -p -r1.1.1.7 -r1.11 ---- bgpd/printconf.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/printconf.c 16 May 2014 00:36:26 -0000 1.11 -@@ -1,4 +1,4 @@ --/* $OpenBSD: printconf.c,v 1.70 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: printconf.c,v 1.88 2012/09/23 09:39:18 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -16,9 +16,13 @@ - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -+#include - #include - #include - #include -+#if defined(__FreeBSD__) /* limits.h */ -+#include -+#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 - 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 - 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 - 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.grestart.restart == 0) -+ printf("%s\tannounce restart no\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 - 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 - 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 f - } 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 "); - } - -@@ -479,6 +568,13 @@ print_rule(struct peer *peer_l, struct f - } - } - -+ if (r->match.nexthop.flags) { -+ if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR) -+ printf("nexthop neighbor "); -+ else -+ printf("nexthop %s ", log_addr(&r->match.nexthop.addr)); -+ } -+ - if (r->match.as.type) { - if (r->match.as.type == AS_ALL) - printf("AS %s ", log_as(r->match.as.as)); -@@ -492,11 +588,20 @@ print_rule(struct peer *peer_l, struct f - 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); - -@@ -513,6 +618,8 @@ mrt_type(enum mrt_type t) - return "table"; - case MRT_TABLE_DUMP_MP: - return "table-mp"; -+ case MRT_TABLE_DUMP_V2: -+ return "table-v2"; - case MRT_ALL_IN: - return "all in"; - case MRT_ALL_OUT: -@@ -541,12 +648,12 @@ print_mrt(u_int32_t pid, u_int32_t gid, - printf("%s%sdump ", prep, prep2); - if (m->rib[0]) - printf("rib %s ", m->rib); -+ printf("%s \"%s\"", mrt_type(m->type), -+ MRT2MC(m)->name); - if (MRT2MC(m)->ReopenTimerInterval == 0) -- printf("%s %s\n", mrt_type(m->type), -- MRT2MC(m)->name); -+ printf("\n"); - else -- printf("%s %s %d\n", mrt_type(m->type), -- MRT2MC(m)->name, -+ printf(" %ld\n", - MRT2MC(m)->ReopenTimerInterval); - } - } -@@ -612,26 +719,34 @@ peer_compare(const void *aa, const void - 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); Index: net/openbgpd/files/patch-bgpd_rde.h =================================================================== --- net/openbgpd/files/patch-bgpd_rde.h +++ /dev/null @@ -1,361 +0,0 @@ -Index: bgpd/rde.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.h,v -retrieving revision 1.1.1.8 -retrieving revision 1.1.1.13 -diff -u -p -r1.1.1.8 -r1.1.1.13 ---- bgpd/rde.h 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/rde.h 8 Dec 2012 10:37:09 -0000 1.1.1.13 -@@ -1,8 +1,8 @@ --/* $OpenBSD: rde.h,v 1.120 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: rde.h,v 1.144 2012/09/12 05:56:22 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker and -- * Andre Oppermann -+ * Andre Oppermann - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above -@@ -56,16 +56,16 @@ 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; -+ time_t staletime[AID_MAX]; - u_int64_t prefix_rcvd_update; - u_int64_t prefix_rcvd_withdraw; -+ u_int64_t prefix_rcvd_eor; - u_int64_t prefix_sent_update; - u_int64_t prefix_sent_withdraw; -+ u_int64_t prefix_sent_eor; - u_int32_t prefix_cnt; /* # of prefixes */ - u_int32_t remote_bgpid; /* host byte order! */ - u_int32_t up_pcnt; -@@ -75,12 +75,16 @@ struct rde_peer { - enum peer_state state; - u_int16_t ribid; - u_int16_t short_as; -+ u_int16_t mrt_idx; - 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); -@@ -117,6 +121,9 @@ enum attrtypes { - #define ATTR_PARTIAL 0x20 - #define ATTR_TRANSITIVE 0x40 - #define ATTR_OPTIONAL 0x80 -+#define ATTR_RESERVED 0x0f -+/* by default mask the reserved bits and the ext len bit */ -+#define ATTR_DEFMASK (ATTR_RESERVED | ATTR_EXTLEN) - - /* default attribute flags for well known attributes */ - #define ATTR_WELL_KNOWN ATTR_TRANSITIVE -@@ -163,6 +170,8 @@ LIST_HEAD(prefix_head, prefix); - #define F_NEXTHOP_REJECT 0x02000 - #define F_NEXTHOP_BLACKHOLE 0x04000 - #define F_NEXTHOP_NOMODIFY 0x08000 -+#define F_NEXTHOP_MASK 0x0f000 -+#define F_ATTR_PARSE_ERR 0x10000 - #define F_ATTR_LINKED 0x20000 - - -@@ -220,14 +229,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 +244,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 +272,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 +284,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 { -@@ -292,8 +306,14 @@ struct prefix { - extern struct rde_memstats rdemem; - - /* prototypes */ -+/* mrt.c */ -+int mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *, -+ struct rde_peer_head *); -+void mrt_dump_upcall(struct rib_entry *, void *); -+void mrt_done(void *); -+ - /* 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 +329,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 +347,7 @@ int aspath_verify(void *, u_int16_t, i - #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); -@@ -341,22 +362,66 @@ u_int32_t aspath_neighbor(struct aspath - 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_decide.c */ -+void prefix_evaluate(struct prefix *, struct rib_entry *); -+ -+/* rde_filter.c */ -+enum filter_actions rde_filter(u_int16_t, struct rde_aspath **, -+ struct filter_head *, struct rde_peer *, -+ 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 *, -+ u_int8_t, struct rde_peer *, struct rde_peer *); -+int rde_filter_equal(struct filter_head *, struct filter_head *, -+ struct rde_peer *, enum directions); -+ -+/* rde_prefix.c */ -+#define pt_empty(pt) ((pt)->refcnt == 0) -+#define pt_ref(pt) do { \ -+ ++(pt)->refcnt; \ -+ if ((pt)->refcnt == 0) \ -+ fatalx("pt_ref: overflow"); \ -+} while(0) -+#define pt_unref(pt) do { \ -+ if ((pt)->refcnt == 0) \ -+ fatalx("pt_unref: underflow"); \ -+ --(pt)->refcnt; \ -+} while(0) -+ -+void pt_init(void); -+void pt_shutdown(void); -+void pt_getaddr(struct pt_entry *, struct bgpd_addr *); -+struct pt_entry *pt_fill(struct bgpd_addr *, int); -+struct pt_entry *pt_get(struct bgpd_addr *, int); -+struct pt_entry *pt_add(struct bgpd_addr *, int); -+void pt_remove(struct pt_entry *); -+struct pt_entry *pt_lookup(struct bgpd_addr *); -+int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); - - /* 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); -@@ -368,6 +433,7 @@ int path_update(struct rib *, struct r - int path_compare(struct rde_aspath *, struct rde_aspath *); - struct rde_aspath *path_lookup(struct rde_aspath *, struct rde_peer *); - void path_remove(struct rde_aspath *); -+void path_remove_stale(struct rde_aspath *, u_int8_t); - void path_destroy(struct rde_aspath *); - int path_empty(struct rde_aspath *); - struct rde_aspath *path_copy(struct rde_aspath *); -@@ -375,8 +441,6 @@ struct rde_aspath *path_get(void); - void path_put(struct rde_aspath *); - - #define PREFIX_SIZE(x) (((x) + 7) / 8 + 1) --int prefix_compare(const struct bgpd_addr *, -- const struct bgpd_addr *, int); - struct prefix *prefix_get(struct rib *, struct rde_peer *, - struct bgpd_addr *, int, u_int32_t); - int prefix_add(struct rib *, struct rde_aspath *, -@@ -385,6 +449,7 @@ void prefix_move(struct rde_aspath *, - int prefix_remove(struct rib *, struct rde_peer *, - struct bgpd_addr *, int, u_int32_t); - int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t); -+int prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t); - struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *, - u_int32_t); - void prefix_updateall(struct rde_aspath *, enum nexthop_state, -@@ -395,7 +460,7 @@ void prefix_network_clean(struct rde_p - 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 *); -@@ -403,9 +468,6 @@ void nexthop_update(struct kroute_next - struct nexthop *nexthop_get(struct bgpd_addr *); - int nexthop_compare(struct nexthop *, struct nexthop *); - --/* rde_decide.c */ --void prefix_evaluate(struct prefix *, struct rib_entry *); -- - /* rde_update.c */ - void up_init(struct rde_peer *); - void up_down(struct rde_peer *); -@@ -415,49 +477,14 @@ int up_generate(struct rde_peer *, str - 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 *); -- --/* rde_prefix.c */ --#define pt_empty(pt) ((pt)->refcnt == 0) --#define pt_ref(pt) do { \ -- ++(pt)->refcnt; \ -- if ((pt)->refcnt == 0) \ -- fatalx("pt_ref: overflow"); \ --} while(0) --#define pt_unref(pt) do { \ -- if ((pt)->refcnt == 0) \ -- fatalx("pt_unref: underflow"); \ -- --(pt)->refcnt; \ --} while(0) -- --void pt_init(void); --void pt_shutdown(void); --void pt_getaddr(struct pt_entry *, struct bgpd_addr *); --struct pt_entry *pt_fill(struct bgpd_addr *, int); --struct pt_entry *pt_get(struct bgpd_addr *, int); --struct pt_entry *pt_add(struct bgpd_addr *, int); --void pt_remove(struct pt_entry *); --struct pt_entry *pt_lookup(struct bgpd_addr *); --int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); -- -- --/* rde_filter.c */ --enum filter_actions rde_filter(u_int16_t, struct rde_aspath **, -- struct filter_head *, struct rde_peer *, -- 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); --int rde_filter_equal(struct filter_head *, struct filter_head *, -- struct rde_peer *, enum directions); -- --/* util.c */ --u_int32_t aspath_extract(const void *, int); -+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); - - #endif /* __RDE_H__ */ Index: net/openbgpd/files/patch-bgpd_rde.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde.c +++ /dev/null @@ -1,2614 +0,0 @@ -Index: bgpd/rde.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v -retrieving revision 1.1.1.8 -retrieving revision 1.12 -diff -u -p -r1.1.1.8 -r1.12 ---- bgpd/rde.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/rde.c 16 May 2014 00:36:26 -0000 1.12 -@@ -1,4 +1,4 @@ --/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */ -+/* $OpenBSD: rde.c,v 1.320 2012/09/18 09:45:51 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -18,10 +18,11 @@ - - #include - #include -+#include -+#include - - #include - #include --#include - #include - #include - #include -@@ -50,13 +51,18 @@ void rde_update_withdraw(struct rde_pe - u_int8_t); - int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *, - struct rde_aspath *, struct mpattr *); -+int rde_attr_add(struct rde_aspath *, u_char *, u_int16_t); - 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_ - 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,12 @@ struct rde_peer *peer_add(u_int32_t, str - 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_flush(struct rde_peer *, u_int8_t); -+void peer_stale(u_int32_t, u_int8_t); -+void peer_recv_eor(struct rde_peer *, u_int8_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 +120,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 +133,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 +158,17 @@ 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) - { - 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 +179,6 @@ rde_main(struct bgpd_config *config, str - return (pid); - } - -- conf = config; -- - if ((pw = getpwnam(BGPD_USER)) == NULL) - fatal("getpwnam"); - -@@ -194,6 +199,8 @@ rde_main(struct bgpd_config *config, str - 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 +217,25 @@ rde_main(struct bgpd_config *config, str - 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 +269,18 @@ rde_main(struct bgpd_config *config, str - 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 +314,17 @@ rde_main(struct bgpd_config *config, str - 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 +333,12 @@ rde_main(struct bgpd_config *config, str - 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 +361,18 @@ rde_dispatch_imsg_session(struct imsgbuf - 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 csr; - struct ctl_show_rib_request req; -+ struct rde_peer *peer; -+ struct rde_aspath *asp; - struct filter_set *s; - struct nexthop *nh; -- int n; -+ u_int8_t *asdata; -+ ssize_t n; -+ int verbose; -+ u_int16_t len; -+ u_int8_t aid; - - if ((n = imsg_read(ibuf)) == -1) - fatal("rde_dispatch_imsg_session: imsg_read error"); -@@ -422,13 +410,56 @@ rde_dispatch_imsg_session(struct imsgbuf - case IMSG_SESSION_DOWN: - peer_down(imsg.hdr.peerid); - break; -+ case IMSG_SESSION_STALE: -+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { -+ log_warnx("rde_dispatch: wrong imsg len"); -+ break; -+ } -+ memcpy(&aid, imsg.data, sizeof(aid)); -+ if (aid >= AID_MAX) -+ fatalx("IMSG_SESSION_STALE: bad AID"); -+ peer_stale(imsg.hdr.peerid, aid); -+ break; -+ case IMSG_SESSION_FLUSH: -+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { -+ log_warnx("rde_dispatch: wrong imsg len"); -+ break; -+ } -+ memcpy(&aid, imsg.data, sizeof(aid)); -+ if (aid >= AID_MAX) -+ fatalx("IMSG_SESSION_FLUSH: bad AID"); -+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL) { -+ log_warnx("rde_dispatch: unknown peer id %d", -+ imsg.hdr.peerid); -+ break; -+ } -+ peer_flush(peer, aid); -+ break; -+ case IMSG_SESSION_RESTARTED: -+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { -+ log_warnx("rde_dispatch: wrong imsg len"); -+ break; -+ } -+ memcpy(&aid, imsg.data, sizeof(aid)); -+ if (aid >= AID_MAX) -+ fatalx("IMSG_SESSION_RESTARTED: bad AID"); -+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL) { -+ log_warnx("rde_dispatch: unknown peer id %d", -+ imsg.hdr.peerid); -+ break; -+ } -+ if (peer->staletime[aid]) -+ peer_flush(peer, aid); -+ 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 != -@@ -440,23 +471,68 @@ rde_dispatch_imsg_session(struct imsgbuf - TAILQ_INIT(&netconf_s.attrset); - session_set = &netconf_s.attrset; - break; -+ case IMSG_NETWORK_ASPATH: -+ if (imsg.hdr.len - IMSG_HEADER_SIZE < -+ sizeof(struct ctl_show_rib)) { -+ log_warnx("rde_dispatch: wrong imsg len"); -+ bzero(&netconf_s, sizeof(netconf_s)); -+ break; -+ } -+ asdata = imsg.data; -+ asdata += sizeof(struct ctl_show_rib); -+ memcpy(&csr, imsg.data, sizeof(csr)); -+ if (csr.aspath_len + sizeof(csr) > imsg.hdr.len - -+ IMSG_HEADER_SIZE) { -+ log_warnx("rde_dispatch: wrong aspath len"); -+ bzero(&netconf_s, sizeof(netconf_s)); -+ break; -+ } -+ asp = path_get(); -+ asp->lpref = csr.local_pref; -+ asp->med = csr.med; -+ asp->weight = csr.weight; -+ asp->flags = csr.flags; -+ asp->origin = csr.origin; -+ asp->flags |= F_PREFIX_ANNOUNCED | F_ANN_DYNAMIC; -+ asp->aspath = aspath_get(asdata, csr.aspath_len); -+ netconf_s.asp = asp; -+ break; -+ case IMSG_NETWORK_ATTR: -+ if (imsg.hdr.len <= IMSG_HEADER_SIZE) { -+ log_warnx("rde_dispatch: wrong imsg len"); -+ break; -+ } -+ /* parse path attributes */ -+ len = imsg.hdr.len - IMSG_HEADER_SIZE; -+ asp = netconf_s.asp; -+ if (rde_attr_add(asp, imsg.data, len) == -1) { -+ log_warnx("rde_dispatch: bad network " -+ "attribute"); -+ path_put(asp); -+ bzero(&netconf_s, sizeof(netconf_s)); -+ break; -+ } -+ break; - case IMSG_NETWORK_DONE: - if (imsg.hdr.len != IMSG_HEADER_SIZE) { - log_warnx("rde_dispatch: wrong imsg len"); - 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); - break; -+ case 0: -+ /* something failed beforehands */ -+ break; - default: - badnet: - log_warnx("rde_dispatch: bad network"); -@@ -528,10 +604,14 @@ badnet: - peer->prefix_rcvd_update; - p.stats.prefix_rcvd_withdraw = - peer->prefix_rcvd_withdraw; -+ p.stats.prefix_rcvd_eor = -+ peer->prefix_rcvd_eor; - p.stats.prefix_sent_update = - peer->prefix_sent_update; - p.stats.prefix_sent_withdraw = - peer->prefix_sent_withdraw; -+ p.stats.prefix_sent_eor = -+ peer->prefix_sent_eor; - } - imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NEIGHBOR, 0, - imsg.hdr.pid, -1, &p, sizeof(struct peer)); -@@ -544,6 +624,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 +639,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 +664,12 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +688,26 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +715,26 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +748,42 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +791,27 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +819,59 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +881,18 @@ rde_dispatch_imsg_parent(struct imsgbuf - } - 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"); -+ imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, -+ -1, NULL, 0); - 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"); -@@ -725,7 +920,8 @@ rde_dispatch_imsg_parent(struct imsgbuf - log_warnx("expected to receive fd for mrt dump " - "but didn't receive any"); - else if (xmrt.type == MRT_TABLE_DUMP || -- xmrt.type == MRT_TABLE_DUMP_MP) { -+ xmrt.type == MRT_TABLE_DUMP_MP || -+ xmrt.type == MRT_TABLE_DUMP_V2) { - rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd); - } else - close(fd); -@@ -744,6 +940,8 @@ rde_dispatch_imsg_parent(struct imsgbuf - 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 +950,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 +1007,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 +1052,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; -@@ -879,6 +1071,10 @@ rde_update_dispatch(struct imsg *imsg) - ERR_UPD_ATTRLIST, NULL, 0); - return (-1); - } -+ if (withdrawn_len == 0) { -+ /* EoR marker */ -+ peer_recv_eor(peer, AID_INET); -+ } - return (0); - } - -@@ -892,15 +1088,30 @@ 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; -+ } -+ -+ if ((asp->flags & ~F_ATTR_MP_UNREACH) == 0 && mplen == 0) { -+ /* EoR marker */ -+ peer_recv_eor(peer, aid); -+ } -+ -+ switch (aid) { -+ case AID_INET6: - while (mplen > 0) { - if ((pos = rde_update_get_prefix6(mpp, mplen, - &prefix, &prefixlen)) == -1) { -@@ -926,6 +1137,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 +1200,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 +1232,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 +1257,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 +1266,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 +1303,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 +1366,8 @@ rde_update_update(struct rde_peer *peer, - 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 +1377,24 @@ rde_update_update(struct rde_peer *peer, - - 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 +1402,8 @@ done: - - if (r) - peer->prefix_cnt++; -+ else if (f) -+ peer->prefix_cnt--; - } - - void -@@ -1152,7 +1442,7 @@ rde_update_withdraw(struct rde_peer *pee - } while (0) - - #define CHECK_FLAGS(s, t, m) \ -- (((s) & ~(ATTR_EXTLEN | (m))) == (t)) -+ (((s) & ~(ATTR_DEFMASK | (m))) == (t)) - - int - rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer, -@@ -1161,6 +1451,7 @@ rde_attr_parse(u_char *p, u_int16_t len, - 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 +1486,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 +1512,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 +1550,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 +1607,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 +1637,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 +1677,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 +1711,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,20 +1729,31 @@ 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; -- } -- a->flags |= F_ATTR_AS4BYTE_NEW; -- 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; - default: - if ((flags & ATTR_OPTIONAL) == 0) { - rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNKNWN_WK_ATTR, -@@ -1415,6 +1774,42 @@ bad_list: - - return (plen); - } -+ -+int -+rde_attr_add(struct rde_aspath *a, u_char *p, u_int16_t len) -+{ -+ u_int16_t attr_len; -+ u_int16_t plen = 0; -+ u_int8_t flags; -+ u_int8_t type; -+ u_int8_t tmp8; -+ -+ if (a == NULL) /* no aspath, nothing to do */ -+ return (0); -+ if (len < 3) -+ return (-1); -+ -+ UPD_READ(&flags, p, plen, 1); -+ UPD_READ(&type, p, plen, 1); -+ -+ if (flags & ATTR_EXTLEN) { -+ if (len - plen < 2) -+ return (-1); -+ UPD_READ(&attr_len, p, plen, 2); -+ attr_len = ntohs(attr_len); -+ } else { -+ UPD_READ(&tmp8, p, plen, 1); -+ attr_len = tmp8; -+ } -+ -+ if (len - plen < attr_len) -+ return (-1); -+ -+ if (attr_optadd(a, flags, type, p, attr_len) == -1) -+ return (-1); -+ return (0); -+} -+ - #undef UPD_READ - #undef CHECK_FLAGS - -@@ -1440,8 +1835,8 @@ rde_attr_missing(struct rde_aspath *a, i - } - - 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 +1852,9 @@ rde_get_mp_nexthop(u_char *data, u_int16 - 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 +1867,144 @@ rde_get_mp_nexthop(u_char *data, u_int16 - 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); -+ nexthop.scope_id = 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 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 +2014,50 @@ rde_update_get_prefix6(u_char *p, u_int1 - 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 +2109,30 @@ rde_as4byte_fixup(struct rde_peer *peer, - 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 +2176,10 @@ rde_reflector(struct rde_peer *peer, str - 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) { -@@ -1677,10 +2188,10 @@ rde_reflector(struct rde_peer *peer, str - return; - } - } else if (conf->flags & BGPD_FLAG_REFLECTOR) { -- if (peer->conf.ebgp == 0) -- id = htonl(peer->remote_bgpid); -- else -+ if (peer->conf.ebgp) - id = conf->bgpid; -+ else -+ id = htonl(peer->remote_bgpid); - if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID, - &id, sizeof(u_int32_t)) == -1) - fatalx("attr_optadd failed but impossible"); -@@ -1724,17 +2235,17 @@ 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; -+ time_t staletime; - u_int8_t l; - - bzero(&rib, sizeof(rib)); - rib.lastchange = p->lastchange; - rib.local_pref = asp->lpref; - rib.med = asp->med; -- rib.prefix_cnt = asp->prefix_cnt; -- rib.active_cnt = asp->active_cnt; -+ rib.weight = asp->weight; - strlcpy(rib.descr, asp->peer->conf.descr, sizeof(rib.descr)); - memcpy(&rib.remote_addr, &asp->peer->remote_addr, - sizeof(rib.remote_addr)); -@@ -1748,23 +2259,26 @@ rde_dump_rib_as(struct prefix *p, struct - /* 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; -- if (asp->peer->conf.ebgp == 0) -- rib.flags |= F_RIB_INTERNAL; -+ rib.flags |= F_PREF_ACTIVE; -+ if (!asp->peer->conf.ebgp) -+ 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; -+ staletime = asp->peer->staletime[p->prefix->aid]; -+ if (staletime && p->lastchange <= staletime) -+ rib.flags |= F_PREF_STALE; - rib.aspath_len = aspath_length(asp->aspath); - - if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid, -@@ -1784,13 +2298,13 @@ rde_dump_rib_as(struct prefix *p, struct - 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,17 +2342,20 @@ rde_dump_filter(struct prefix *p, struct - { - 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 && -- !aspath_match(p->aspath->aspath, req->as.type, req->as.as)) -+ if (req->type == IMSG_CTL_SHOW_RIB_AS && -+ !aspath_match(p->aspath->aspath->data, -+ p->aspath->aspath->len, 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; -+ if ((req->flags & F_CTL_ACTIVE) && p->rib->active != p) -+ return; - rde_dump_rib_as(p, p->aspath, req->pid, req->flags); - } else if (req->flags & F_CTL_ADJ_OUT) { - if (p->rib->active != p) -@@ -1872,7 +2389,7 @@ rde_dump_prefix_upcall(struct rib_entry - - 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 +2406,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req - 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 +2420,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req - error = CTL_RES_NOSUCHPEER; - imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error, - sizeof(error)); -+ free(ctx); - return; - } - -@@ -1924,7 +2443,18 @@ rde_dump_ctx_new(struct ctl_show_rib_req - 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 +2467,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req - } - 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); - } - -@@ -1971,13 +2501,17 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t - free(ctx); - return; - } -+ -+ if (ctx->mrt.type == MRT_TABLE_DUMP_V2) -+ mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist); -+ - 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 +2519,25 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t - /* - * 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 +2557,43 @@ rde_send_kroute(struct prefix *new, stru - } - - 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 (!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 +2644,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 +2651,6 @@ rde_send_nexthop(struct bgpd_addr *next, - 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 +2744,10 @@ rde_softreconfig_in(struct rib_entry *re - 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 +2775,7 @@ rde_softreconfig_in(struct rib_entry *re - 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 +2788,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 +2897,7 @@ rde_up_dump_upcall(struct rib_entry *re, - 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 +2910,7 @@ rde_generate_updates(u_int16_t ribid, st - - /* - * 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 +2931,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 +2945,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 +2955,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 +3009,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 +3032,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 +3082,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 +3100,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 +3115,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 +3200,10 @@ peer_localaddrs(struct rde_peer *peer, s - 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 +3221,7 @@ peer_localaddrs(struct rde_peer *peer, s - &((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,23 +3233,22 @@ 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) { -- log_warnx("peer_up: peer id %d already exists", id); -+ log_warnx("peer_up: unknown peer id %d", id); - return; - } - -- if (peer->state != PEER_DOWN && peer->state != PEER_NONE) -+ if (peer->state != PEER_DOWN && peer->state != PEER_NONE && -+ peer->state != PEER_UP) - fatalx("peer_up: bad state"); - peer->remote_bgpid = ntohl(sup->remote_bgpid); - 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 +3262,10 @@ peer_up(u_int32_t id, struct session_up - */ - 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 -@@ -2641,43 +3299,90 @@ peer_down(u_int32_t id) - free(peer); - } - -+/* -+ * Flush all routes older then staletime. If staletime is 0 all routes will -+ * be flushed. -+ */ -+void -+peer_flush(struct rde_peer *peer, u_int8_t aid) -+{ -+ struct rde_aspath *asp, *nasp; -+ -+ /* walk through per peer RIB list and remove all stale prefixes. */ -+ for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) { -+ nasp = LIST_NEXT(asp, peer_l); -+ path_remove_stale(asp, aid); -+ } -+ -+ /* Deletions are performed in path_remove() */ -+ rde_send_pftable_commit(); -+ -+ /* flushed no need to keep staletime */ -+ peer->staletime[aid] = 0; -+} -+ - void --peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi) -+peer_stale(u_int32_t id, u_int8_t aid) - { - struct rde_peer *peer; -+ time_t now; - - peer = peer_get(id); - if (peer == NULL) { -- log_warnx("peer_down: unknown peer id %d", id); -+ log_warnx("peer_stale: 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->staletime[aid]) -+ peer_flush(peer, aid); -+ peer->staletime[aid] = now = time(NULL); - -- if (peer->capa_received.restart && peer->capa_announced.restart) -- peer_send_eor(peer, afi, safi); -+ /* make sure new prefixes start on a higher timestamp */ -+ do { -+ sleep(1); -+ } while (now >= time(NULL)); - } - --/* End-of-RIB marker, draft-ietf-idr-restart-13.txt */ - void --peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi) -+peer_dump(u_int32_t id, u_int8_t aid) - { -- if (afi == AFI_IPv4 && safi == SAFI_UNICAST) { -+ struct rde_peer *peer; -+ -+ peer = peer_get(id); -+ if (peer == NULL) { -+ log_warnx("peer_dump: unknown peer id %d", id); -+ return; -+ } -+ -+ 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.grestart.restart) -+ up_generate_marker(peer, aid); -+} -+ -+/* End-of-RIB marker, RFC 4724 */ -+void -+peer_recv_eor(struct rde_peer *peer, u_int8_t aid) -+{ -+ peer->prefix_rcvd_eor++; -+ -+ /* First notify SE to remove possible race with the timeout. */ -+ if (imsg_compose(ibuf_se, IMSG_SESSION_RESTARTED, peer->conf.id, -+ 0, -1, &aid, sizeof(aid)) == -1) -+ fatal("imsg_compose error"); -+} -+ -+void -+peer_send_eor(struct rde_peer *peer, u_int8_t aid) -+{ -+ u_int16_t afi; -+ u_int8_t safi; -+ -+ peer->prefix_sent_eor++; -+ -+ if (aid == AID_INET) { - u_char null[4]; - - bzero(&null, 4); -@@ -2688,6 +3393,9 @@ peer_send_eor(struct rde_peer *peer, u_i - 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,39 +3417,61 @@ peer_send_eor(struct rde_peer *peer, u_i - * 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; - -- asp = path_get(); -- asp->aspath = aspath_get(NULL, 0); -- asp->origin = ORIGIN_IGP; -- asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH | -- F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED; -- /* the nexthop is unset unless a default set overrides it */ -+ 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; -+ } -+ } -+ } -+ -+ if (nc->type == NETWORK_MRTCLONE) { -+ asp = nc->asp; -+ } else { -+ asp = path_get(); -+ asp->aspath = aspath_get(NULL, 0); -+ asp->origin = ORIGIN_IGP; -+ asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH | -+ F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED; -+ /* the nexthop is unset unless a default set overrides it */ -+ } - 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); -- - path_put(asp); - filterset_free(&nc->attrset); - } -@@ -2749,12 +3479,41 @@ network_add(struct network_config *nc, i - 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 +3523,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 +3593,10 @@ sa_cmp(struct bgpd_addr *a, struct socka - 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) -@@ -2855,10 +3607,11 @@ sa_cmp(struct bgpd_addr *a, struct socka - #ifdef __KAME__ - /* directly stolen from sbin/ifconfig/ifconfig.c */ - if (IN6_IS_ADDR_LINKLOCAL(&in6_b->sin6_addr)) { -- in6_b->sin6_scope_id = -- ntohs(*(u_int16_t *)&in6_b->sin6_addr.s6_addr[2]); -- in6_b->sin6_addr.s6_addr[2] = -- in6_b->sin6_addr.s6_addr[3] = 0; -+ if (in6_b->sin6_scope_id == 0) { -+ in6_b->sin6_scope_id = -+ IN6_LINKLOCAL_IFINDEX(in6_b->sin6_addr); -+ } -+ SET_IN6_LINKLOCAL_IFINDEX(in6_b->sin6_addr, 0); - } - #endif - if (bcmp(&a->v6, &in6_b->sin6_addr, Index: net/openbgpd/files/patch-bgpd_rde_attr.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_attr.c +++ /dev/null @@ -1,562 +0,0 @@ -Index: bgpd/rde_attr.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_attr.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.7 -diff -u -p -r1.1.1.6 -r1.7 ---- bgpd/rde_attr.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/rde_attr.c 13 Oct 2012 18:36:00 -0000 1.7 -@@ -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.90 2012/04/12 17:27:20 claudio Exp $ */ - - /* - * Copyright (c) 2004 Claudio Jeker -@@ -17,14 +17,22 @@ - */ - - #include -+#if defined(__FreeBSD__) /* sys/hash.h */ -+#include "hash.h" -+#else - #include -+#endif /* defined(__FreeBSD__) */ - #include - - #include - -+#include - #include - #include - #include -+#if defined(__FreeBSD__) /* limits.h */ -+#include -+#endif /* defined(__FreeBSD__) */ - - #include "bgpd.h" - #include "rde.h" -@@ -36,12 +44,12 @@ attr_write(void *p, u_int16_t p_len, u_i - u_char *b = p; - u_int16_t tmp, tot_len = 2; /* attribute header (without len) */ - -+ flags &= ~ATTR_DEFMASK; - if (data_len > 255) { - tot_len += 2 + data_len; - flags |= ATTR_EXTLEN; - } else { - tot_len += 1 + data_len; -- flags &= ~ATTR_EXTLEN; - } - - if (tot_len > p_len) -@@ -63,26 +71,26 @@ attr_write(void *p, u_int16_t p_len, u_i - } - - 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]; - -+ flags &= ~ATTR_DEFMASK; - if (data_len > 255) { - flags |= ATTR_EXTLEN; - hdr[2] = (data_len >> 8) & 0xff; - hdr[3] = data_len & 0xff; - } else { -- flags &= ~ATTR_EXTLEN; - hdr[2] = data_len & 0xff; - } - - 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_in - 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 */ -@@ -318,6 +329,7 @@ attr_alloc(u_int8_t flags, u_int8_t type - fatal("attr_optadd"); - rdemem.attr_cnt++; - -+ flags &= ~ATTR_DEFMASK; /* normalize mask */ - a->flags = flags; - a->hash = hash32_buf(&flags, sizeof(flags), HASHINIT); - a->type = type; -@@ -347,6 +359,7 @@ attr_lookup(u_int8_t flags, u_int8_t typ - struct attr *a; - u_int32_t hash; - -+ flags &= ~ATTR_DEFMASK; /* normalize mask */ - hash = hash32_buf(&flags, sizeof(flags), HASHINIT); - hash = hash32_buf(&type, sizeof(type), hash); - hash = hash32_buf(&len, sizeof(len), hash); -@@ -405,6 +418,7 @@ aspath_verify(void *data, u_int16_t len, - 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 +433,15 @@ aspath_verify(void *data, u_int16_t len, - 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 +453,7 @@ aspath_verify(void *data, u_int16_t len, - /* 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 -@@ -762,15 +784,9 @@ aspath_countcopy(struct aspath *aspath, - u_int32_t - aspath_neighbor(struct aspath *aspath) - { -- /* -- * Empty aspath is OK -- internal as route. -- * But what is the neighbor? For now let's return 0. -- * That should not break anything. -- */ -- -+ /* Empty aspath is OK -- internal AS route. */ - if (aspath->len == 0) -- return (0); -- -+ return (rde_local_as()); - return (aspath_extract(aspath->data, 0)); - } - -@@ -910,76 +926,63 @@ aspath_prepend(struct aspath *asp, u_int - return (p); - } - --/* we need to be able to search more than one as */ - int --aspath_match(struct aspath *a, enum as_spec type, u_int32_t as) -+aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen) - { - u_int8_t *seg; -- int final; -+ 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 == AS_EMPTY) { -- if (a->len == 0) -+ if (type == ASLEN_MAX) { -+ if (aslen < aspath_count(a->data, a->len)) - return (1); - else - return (0); - } - -- final = 0; -+ /* 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; - -- final = (len == seg_size); -- -- /* just check the first (leftmost) AS */ -- if (type == AS_PEER) { -- if (as == aspath_extract(seg, 0)) -- return (1); -- else -- return (0); -- } -- /* just check the final (rightmost) AS */ -- if (type == AS_SOURCE) { -- /* not yet in the final segment */ -- if (!final) -- continue; -- -- if (as == aspath_extract(seg, seg_len - 1)) -- return (1); -- else -- return (0); -- } -- -- /* AS_TRANSIT or AS_ALL */ - for (i = 0; i < seg_len; i++) { -- if (as == aspath_extract(seg, i)) { -- /* -- * the source (rightmost) AS is excluded from -- * AS_TRANSIT matches. -- */ -- if (final && i == seg_len - 1 && -- type == AS_TRANSIT) -- return (0); -- return (1); -- } -+ /* 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(void *data, u_int16_t len, int as, int type) -+community_match(struct rde_aspath *asp, int as, int type) - { -- u_int8_t *p = data; -- u_int16_t eas, etype; -+ struct attr *a; -+ u_int8_t *p; -+ u_int16_t eas, etype, len; - -- len >>= 2; /* divide by four */ -+ a = attr_optget(asp, ATTR_COMMUNITIES); -+ if (a == NULL) -+ /* no communities, no match */ -+ return (0); - -- for (; len > 0; len--) { -+ p = a->data; -+ for (len = a->len / 4; len > 0; len--) { - eas = *p++; - eas <<= 8; - eas |= *p++; -@@ -1000,7 +1003,6 @@ community_set(struct rde_aspath *asp, in - 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 +1019,7 @@ community_set(struct rde_aspath *asp, in - p += 4; - } - -- if (ncommunities++ >= 0x3fff) -+ if (ncommunities++ >= USHRT_MAX / 4) - /* overflow */ - return (0); - -@@ -1032,11 +1034,10 @@ community_set(struct rde_aspath *asp, in - 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 +1050,7 @@ community_delete(struct rde_aspath *asp, - 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 +1101,250 @@ community_delete(struct rde_aspath *asp, - } - - 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); -+} Index: net/openbgpd/files/patch-bgpd_rde_decide.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_decide.c +++ /dev/null @@ -1,133 +0,0 @@ -Index: bgpd/rde_decide.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_decide.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.4 -diff -u -p -r1.1.1.6 -r1.4 ---- bgpd/rde_decide.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/rde_decide.c 13 Oct 2012 18:36:00 -0000 1.4 -@@ -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.61 2012/04/12 17:31:05 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker -@@ -109,6 +109,9 @@ int - prefix_cmp(struct prefix *p1, struct prefix *p2) - { - struct rde_aspath *asp1, *asp2; -+ struct attr *a; -+ u_int32_t p1id, p2id; -+ int p1cnt, p2cnt; - - if (p1 == NULL) - return (-1); -@@ -118,6 +121,12 @@ prefix_cmp(struct prefix *p1, struct pre - 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); -@@ -130,7 +139,7 @@ prefix_cmp(struct prefix *p1, struct pre - if (asp1->nexthop != NULL && asp1->nexthop->state != NEXTHOP_REACH) - return (-1); - -- /* 2. preference of prefix, bigger is better */ -+ /* 2. local preference of prefix, bigger is better */ - if ((asp1->lpref - asp2->lpref) != 0) - return (asp1->lpref - asp2->lpref); - -@@ -154,10 +163,10 @@ prefix_cmp(struct prefix *p1, struct pre - * It is absolutely important that the ebgp value in peer_config.ebgp - * is bigger than all other ones (IBGP, confederations) - */ -- if ((asp1->peer->conf.ebgp - asp2->peer->conf.ebgp) != 0) { -- if (asp1->peer->conf.ebgp == 1) /* p1 is EBGP other is lower */ -+ if (asp1->peer->conf.ebgp != asp2->peer->conf.ebgp) { -+ if (asp1->peer->conf.ebgp) /* p1 is EBGP other is lower */ - return 1; -- else if (asp2->peer->conf.ebgp == 1) /* p2 is EBGP */ -+ else if (asp2->peer->conf.ebgp) /* p2 is EBGP */ - return -1; - } - -@@ -181,13 +190,30 @@ prefix_cmp(struct prefix *p1, struct pre - if ((p2->lastchange - p1->lastchange) != 0) - return (p2->lastchange - p1->lastchange); - -- /* 10. lowest BGP Id wins */ -- if ((p2->aspath->peer->remote_bgpid - -- p1->aspath->peer->remote_bgpid) != 0) -- return (p2->aspath->peer->remote_bgpid - -- p1->aspath->peer->remote_bgpid); -+ /* 10. lowest BGP Id wins, use ORIGINATOR_ID if present */ -+ if ((a = attr_optget(asp1, ATTR_ORIGINATOR_ID)) != NULL) { -+ memcpy(&p1id, a->data, sizeof(p1id)); -+ p1id = ntohl(p1id); -+ } else -+ p1id = asp1->peer->remote_bgpid; -+ if ((a = attr_optget(asp2, ATTR_ORIGINATOR_ID)) != NULL) { -+ memcpy(&p2id, a->data, sizeof(p2id)); -+ p2id = ntohl(p2id); -+ } else -+ p2id = asp2->peer->remote_bgpid; -+ if ((p2id - p1id) != 0) -+ return (p2id - p1id); -+ -+ /* 11. compare CLUSTER_LIST length, shorter is better */ -+ p1cnt = p2cnt = 0; -+ if ((a = attr_optget(asp1, ATTR_CLUSTER_LIST)) != NULL) -+ p1cnt = a->len / sizeof(u_int32_t); -+ if ((a = attr_optget(asp2, ATTR_CLUSTER_LIST)) != NULL) -+ p2cnt = a->len / sizeof(u_int32_t); -+ if ((p2cnt - p1cnt) != 0) -+ return (p2cnt - p1cnt); - -- /* 11. lowest peer address wins (IPv4 is better than IPv6) */ -+ /* 12. lowest peer address wins (IPv4 is better than IPv6) */ - if (memcmp(&p1->aspath->peer->remote_addr, - &p2->aspath->peer->remote_addr, - sizeof(p1->aspath->peer->remote_addr)) != 0) -@@ -195,7 +221,7 @@ prefix_cmp(struct prefix *p1, struct pre - &p2->aspath->peer->remote_addr, - sizeof(p1->aspath->peer->remote_addr))); - -- /* 12. for announced prefixes prefer dynamic routes */ -+ /* 13. for announced prefixes prefer dynamic routes */ - if ((asp1->flags & F_ANN_DYNAMIC) != (asp2->flags & F_ANN_DYNAMIC)) { - if (asp1->flags & F_ANN_DYNAMIC) - return (1); -@@ -204,7 +230,7 @@ prefix_cmp(struct prefix *p1, struct pre - } - - fatalx("Uh, oh a politician in the decision process"); -- /* NOTREACHED */ -+ return(0); /* NOTREACHED */ - } - - /* -@@ -245,7 +271,7 @@ prefix_evaluate(struct prefix *p, struct - } - - 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 +289,7 @@ prefix_evaluate(struct prefix *p, struct - */ - 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) Index: net/openbgpd/files/patch-bgpd_rde_filter.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_filter.c +++ /dev/null @@ -1,297 +0,0 @@ -Index: bgpd/rde_filter.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_filter.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.9 -diff -u -p -r1.1.1.7 -r1.9 ---- bgpd/rde_filter.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/rde_filter.c 8 Dec 2012 20:17:59 -0000 1.9 -@@ -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.67 2011/09/20 21:19:06 claudio Exp $ */ - - /* - * Copyright (c) 2004 Claudio Jeker -@@ -26,7 +26,7 @@ - #include "rde.h" - - int rde_filter_match(struct filter_rule *, struct rde_aspath *, -- struct bgpd_addr *, u_int8_t, struct rde_peer *); -+ struct bgpd_addr *, u_int8_t, struct rde_peer *, struct rde_peer *); - int filterset_equal(struct filter_set_head *, struct filter_set_head *); - - enum filter_actions -@@ -40,6 +40,13 @@ rde_filter(u_int16_t ribid, struct rde_a - 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; -@@ -51,7 +58,7 @@ rde_filter(u_int16_t ribid, struct rde_a - if (f->peer.peerid != 0 && - f->peer.peerid != peer->conf.id) - continue; -- if (rde_filter_match(f, asp, prefix, prefixlen, peer)) { -+ if (rde_filter_match(f, asp, prefix, prefixlen, peer, from)) { - if (asp != NULL && new != NULL) { - /* asp may get modified so create a copy */ - if (*new == NULL) { -@@ -59,7 +66,7 @@ rde_filter(u_int16_t ribid, struct rde_a - /* ... 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_a - - 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, st - 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,19 +250,42 @@ rde_apply_set(struct rde_aspath *asp, st - 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; - } - } - } - - int - rde_filter_match(struct filter_rule *f, struct rde_aspath *asp, -- struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer) -+ struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer, -+ struct rde_peer *from) - { -- int as, type; -+ u_int32_t pas; -+ int cas, type; - -- 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.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->data, asp->aspath->len, -+ f->match.as.type, pas) == 0) -+ return (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 +293,10 @@ rde_filter_match(struct filter_rule *f, - 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 +311,17 @@ rde_filter_match(struct filter_rule *f, - 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 +357,7 @@ rde_filter_match(struct filter_rule *f, - } 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); - -@@ -350,25 +385,40 @@ rde_filter_match(struct filter_rule *f, - } - /* NOTREACHED */ - } -+ if (f->match.nexthop.flags != 0) { -+ struct bgpd_addr *nexthop, *cmpaddr; -+ if (asp->nexthop == NULL) -+ /* no nexthop, skip */ -+ return (0); -+ nexthop = &asp->nexthop->exit_nexthop; -+ if (f->match.nexthop.flags == FILTER_NEXTHOP_ADDR) -+ cmpaddr = &f->match.nexthop.addr; -+ else -+ cmpaddr = &from->remote_addr; -+ if (cmpaddr->aid != nexthop->aid) -+ /* don't use IPv4 rules for IPv6 and vice versa */ -+ return (0); -+ -+ switch (cmpaddr->aid) { -+ case AID_INET: -+ if (cmpaddr->v4.s_addr != nexthop->v4.s_addr) -+ return (0); -+ break; -+ case AID_INET6: -+ if (memcmp(&cmpaddr->v6, &nexthop->v6, -+ sizeof(struct in6_addr))) -+ return (0); -+ break; -+ default: -+ fatalx("King Bula lost in address space"); -+ } -+ } - - /* matched somewhen or is anymatch rule */ - return (1); - } - - 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 +526,12 @@ filterset_cmp(struct filter_set *a, stru - 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 +539,29 @@ filterset_cmp(struct filter_set *a, stru - * 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 +646,19 @@ filterset_equal(struct filter_set_head * - 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 +701,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 */ - } Index: net/openbgpd/files/patch-bgpd_rde_prefix.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_prefix.c +++ /dev/null @@ -1,301 +0,0 @@ -Index: bgpd/rde_prefix.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_prefix.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.6 -diff -u -p -r1.1.1.6 -r1.6 ---- bgpd/rde_prefix.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/rde_prefix.c 13 Oct 2012 18:36:00 -0000 1.6 -@@ -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.31 2010/01/13 06:02:37 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker -@@ -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 - 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"); -- } - -- if (RB_INSERT(pt_tree, &pttable, p) != NULL) { -- log_warnx("pt_add: insert failed"); -- return (NULL); -- } -+ p = pt_fill(prefix, prefixlen); -+ p = pt_alloc(p); -+ -+ 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, - 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, - 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); - } Index: net/openbgpd/files/patch-bgpd_rde_rib.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_rib.c +++ /dev/null @@ -1,513 +0,0 @@ -Index: bgpd/rde_rib.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_rib.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.8 -diff -u -p -r1.1.1.7 -r1.8 ---- bgpd/rde_rib.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/rde_rib.c 13 Oct 2012 18:36:00 -0000 1.8 -@@ -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.133 2012/07/01 11:55:13 sthen Exp $ */ - - /* - * Copyright (c) 2003, 2004 Claudio Jeker -@@ -18,7 +18,11 @@ - - #include - #include -+#if defined(__FreeBSD__) /* sys/hash.h */ -+#include "hash.h" -+#else - #include -+#endif /* defined(__FreeBSD__) */ - - #include - #include -@@ -50,16 +54,15 @@ RB_GENERATE(rib_tree, rib_entry, rib_e, - - /* 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 fl - 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_ - 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_add - - 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) - 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 */ -@@ -502,6 +509,36 @@ path_remove(struct rde_aspath *asp) - } - } - -+/* remove all stale routes or if staletime is 0 remove all routes for -+ a specified AID. */ -+void -+path_remove_stale(struct rde_aspath *asp, u_int8_t aid) -+{ -+ struct prefix *p, *np; -+ time_t staletime; -+ -+ staletime = asp->peer->staletime[aid]; -+ for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = np) { -+ np = LIST_NEXT(p, path_l); -+ if (p->prefix->aid != aid) -+ continue; -+ -+ if (staletime && p->lastchange > staletime) -+ continue; -+ -+ if (asp->pftableid) { -+ struct bgpd_addr addr; -+ -+ pt_getaddr(p->prefix, &addr); -+ /* Commit is done in peer_flush() */ -+ rde_send_pftable(p->aspath->pftableid, &addr, -+ p->prefix->prefixlen, 1); -+ } -+ prefix_destroy(p); -+ } -+} -+ -+ - /* this function is only called by prefix_remove and path_remove */ - void - path_destroy(struct rde_aspath *asp) -@@ -624,48 +661,6 @@ static void prefix_link(struct prefix - struct rde_aspath *); - static void prefix_unlink(struct prefix *); - --int --prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, -- int prefixlen) --{ -- in_addr_t mask, aa, ba; -- int i; -- u_int8_t m; -- -- if (a->af != b->af) -- return (a->af - b->af); -- -- switch (a->af) { -- case AF_INET: -- if (prefixlen > 32) -- fatalx("prefix_cmp: bad IPv4 prefixlen"); -- mask = htonl(prefixlen2mask(prefixlen)); -- aa = ntohl(a->v4.s_addr & mask); -- ba = ntohl(b->v4.s_addr & mask); -- if (aa != ba) -- return (aa - ba); -- return (0); -- case AF_INET6: -- if (prefixlen > 128) -- fatalx("prefix_cmp: bad IPv6 prefixlen"); -- for (i = 0; i < prefixlen / 8; i++) -- if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) -- return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); -- i = prefixlen % 8; -- if (i) { -- m = 0xff00 >> i; -- if ((a->v6.s6_addr[prefixlen / 8] & m) != -- (b->v6.s6_addr[prefixlen / 8] & m)) -- return ((a->v6.s6_addr[prefixlen / 8] & m) - -- (b->v6.s6_addr[prefixlen / 8] & m)); -- } -- return (0); -- default: -- fatalx("prefix_cmp: unknown af"); -- } -- return (-1); --} -- - /* - * search for specified prefix of a peer. Returns NULL if not found. - */ -@@ -806,16 +801,58 @@ prefix_write(u_char *buf, int len, struc - { - int totlen; - -- if (prefix->af != AF_INET && prefix->af != AF_INET6) -+ switch (prefix->aid) { -+ case AID_INET: -+ case AID_INET6: -+ totlen = PREFIX_SIZE(plen); -+ -+ 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); -+ } -+} - -- totlen = PREFIX_SIZE(plen); -+int -+prefix_writebuf(struct ibuf *buf, struct bgpd_addr *prefix, u_int8_t plen) -+{ -+ int totlen; -+ void *bptr; - -- if (totlen > len) -+ switch (prefix->aid) { -+ case AID_INET: -+ case AID_INET6: -+ totlen = PREFIX_SIZE(plen); -+ break; -+ case AID_VPN_IPv4: -+ totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd) + -+ prefix->vpn4.labellen; -+ default: - return (-1); -- *buf++ = plen; -- memcpy(buf, &prefix->ba, totlen - 1); -- return (totlen); -+ } -+ -+ if ((bptr = ibuf_reserve(buf, totlen)) == NULL) -+ return (-1); -+ if (prefix_write(bptr, totlen, prefix, plen) == -1) -+ return (-1); -+ return (0); - } - - /* -@@ -861,7 +898,7 @@ prefix_updateall(struct rde_aspath *asp, - */ - 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; - } - -@@ -871,7 +908,7 @@ prefix_updateall(struct rde_aspath *asp, - * If the prefix is the active one remove it first, - * this has to be done because we can not detect when - * the active prefix changes its state. In this case -- * we know that this is a withdrawl and so the second -+ * we know that this is a withdrawal and so the second - * prefix_evaluate() will generate no update because - * the nexthop is unreachable or ineligible. - */ -@@ -885,16 +922,12 @@ prefix_updateall(struct rde_aspath *asp, - 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,21 +940,16 @@ prefix_network_clean(struct rde_peer *pe - { - 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); -- if ((asp->flags & F_ANN_DYNAMIC) == flags) -+ if ((asp->flags & F_ANN_DYNAMIC) != flags) - continue; - 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 +982,11 @@ prefix_link(struct prefix *pref, struct - 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 +994,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 +1003,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 +1100,6 @@ nexthop_update(struct kroute_nexthop *ms - return; - } - -- if (nexthop_delete(nh)) -- /* nexthop no longer used */ -- return; -- - oldstate = nh->state; - if (msg->valid) - nh->state = NEXTHOP_REACH; -@@ -1088,21 +1114,13 @@ nexthop_update(struct kroute_nexthop *ms - 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,35 +1136,38 @@ nexthop_update(struct kroute_nexthop *ms - - 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; - -- if (type == ACTION_SET_NEXTHOP_REJECT) { -- asp->flags |= F_NEXTHOP_REJECT; -+ if (type == ACTION_SET_NEXTHOP && aid != nexthop->aid) - return; -- } -- if (type == ACTION_SET_NEXTHOP_BLACKHOLE) { -+ -+ asp->flags &= ~F_NEXTHOP_MASK; -+ switch (type) { -+ case ACTION_SET_NEXTHOP_REJECT: -+ asp->flags |= F_NEXTHOP_REJECT; -+ break; -+ case ACTION_SET_NEXTHOP_BLACKHOLE: - asp->flags |= F_NEXTHOP_BLACKHOLE; -- return; -- } -- if (type == ACTION_SET_NEXTHOP_NOMODIFY) { -+ break; -+ case ACTION_SET_NEXTHOP_NOMODIFY: - asp->flags |= F_NEXTHOP_NOMODIFY; -- return; -- } -- if (type == ACTION_SET_NEXTHOP_SELF) { -+ break; -+ case ACTION_SET_NEXTHOP_SELF: - asp->flags |= F_NEXTHOP_SELF; -- return; -+ break; -+ case ACTION_SET_NEXTHOP: -+ nh = nexthop_get(nexthop); -+ if (asp->flags & F_ATTR_LINKED) -+ nexthop_unlink(asp); -+ asp->nexthop = nh; -+ if (asp->flags & F_ATTR_LINKED) -+ nexthop_link(asp); -+ break; -+ default: -+ break; - } -- if (af != nexthop->af) -- return; -- -- nh = nexthop_get(nexthop); -- if (asp->flags & F_ATTR_LINKED) -- nexthop_unlink(asp); -- asp->nexthop = nh; -- if (asp->flags & F_ATTR_LINKED) -- nexthop_link(asp); - } - - void -@@ -1233,17 +1254,17 @@ nexthop_compare(struct nexthop *na, stru - 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 +1290,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: Index: net/openbgpd/files/patch-bgpd_rde_update.c =================================================================== --- net/openbgpd/files/patch-bgpd_rde_update.c +++ /dev/null @@ -1,644 +0,0 @@ -Index: bgpd/rde_update.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_update.c,v -retrieving revision 1.1.1.7 -retrieving revision 1.8 -diff -u -p -r1.1.1.7 -r1.8 ---- bgpd/rde_update.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/rde_update.c 13 Oct 2012 18:36:00 -0000 1.8 -@@ -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 -@@ -17,19 +17,27 @@ - */ - #include - #include -+#if defined(__FreeBSD__) /* sys/hash.h */ -+#include "hash.h" -+#else - #include -+#endif /* defined(__FreeBSD__) */ - -+#include - #include - #include -+#if defined(__FreeBSD__) /* limits.h */ -+#include -+#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, en - 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, st - 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, s - { - 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, s - 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 upd - 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,23 +291,16 @@ up_test_update(struct rde_peer *peer, st - /* 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) { -+ if (!p->aspath->peer->conf.ebgp && !peer->conf.ebgp) { - /* - * route reflector redistribution rules: - * 1. if announce is set -> announce -@@ -325,13 +339,13 @@ up_test_update(struct rde_peer *peer, st - } - - /* 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, struc - 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 * - /* 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 * - - /* 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 * - 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, st - - 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 *pe - 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 *pe - - 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, - 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, - /* - * 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)) { -+ if (a->flags & F_ATTR_MED && (!peer->conf.ebgp || -+ 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) -@@ -669,7 +791,7 @@ up_generate_attr(struct rde_peer *peer, - wlen += r; len -= r; - } - -- if (peer->conf.ebgp == 0) { -+ if (!peer->conf.ebgp) { - /* local preference, only valid for ibgp */ - tmp32 = htonl(a->lpref); - if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN, -@@ -704,7 +826,7 @@ up_generate_attr(struct rde_peer *peer, - u_int16_t tas; - - if ((!(oa->flags & ATTR_TRANSITIVE)) && -- peer->conf.ebgp != 0) { -+ peer->conf.ebgp) { - r = 0; - break; - } -@@ -730,7 +852,7 @@ up_generate_attr(struct rde_peer *peer, - case ATTR_ORIGINATOR_ID: - case ATTR_CLUSTER_LIST: - if ((!(oa->flags & ATTR_TRANSITIVE)) && -- peer->conf.ebgp != 0) { -+ peer->conf.ebgp) { - r = 0; - break; - } -@@ -791,7 +913,7 @@ up_generate_attr(struct rde_peer *peer, - - /* 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, str - { - 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, str - 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, s - * 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, s - 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, s - } - - 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_ - 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_ - - /* 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_ - 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 - */ - 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 - 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 = datalen + 4; -- return (buf + wpos); -+ return (wpos); - } -- Index: net/openbgpd/files/patch-bgpd_session.h =================================================================== --- net/openbgpd/files/patch-bgpd_session.h +++ /dev/null @@ -1,188 +0,0 @@ -Index: bgpd/session.h -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.h,v -retrieving revision 1.1.1.7 -retrieving revision 1.1.1.10 -diff -u -p -r1.1.1.7 -r1.1.1.10 ---- bgpd/session.h 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/session.h 13 Oct 2012 18:22:50 -0000 1.1.1.10 -@@ -1,4 +1,4 @@ --/* $OpenBSD: session.h,v 1.101 2009/06/05 20:26:38 claudio Exp $ */ -+/* $OpenBSD: session.h,v 1.113 2012/04/12 17:26:09 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004 Henning Brauer -@@ -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; - }; -@@ -155,8 +162,10 @@ struct peer_stats { - u_int64_t msg_sent_rrefresh; - u_int64_t prefix_rcvd_update; - u_int64_t prefix_rcvd_withdraw; -+ u_int64_t prefix_rcvd_eor; - u_int64_t prefix_sent_update; - u_int64_t prefix_sent_withdraw; -+ u_int64_t prefix_sent_eor; - time_t last_updown; - time_t last_read; - u_int32_t prefix_cnt; -@@ -172,6 +181,7 @@ enum Timer { - Timer_IdleHold, - Timer_IdleHoldReset, - Timer_CarpUndemote, -+ Timer_RestartTimeout, - Timer_Max - }; - -@@ -189,6 +199,7 @@ struct peer { - struct { - struct capabilities ann; - struct capabilities peer; -+ struct capabilities neg; - } capa; - struct { - struct bgpd_addr local_addr; -@@ -201,7 +212,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,47 +228,25 @@ struct peer { - u_int8_t passive; - }; - --struct peer *peers; -+extern struct peer *peers; -+extern time_t pauseaccept; - - struct ctl_timer { - enum Timer type; - time_t val; - }; - --/* 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]); --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_rde(int, pid_t, void *, u_int16_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); --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 *); -+/* carp.c */ -+int carp_demote_init(char *, int); -+void carp_demote_shutdown(void); -+int carp_demote_get(char *); -+int carp_demote_set(char *, int); - - /* config.c */ - int merge_config(struct bgpd_config *, struct bgpd_config *, - struct peer *, struct listen_addrs *); - void prepare_listeners(struct bgpd_config *); -- --/* 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); -+int get_mpe_label(struct rdomain *); - - /* control.c */ - int control_init(int, char *); -@@ -266,7 +255,27 @@ void control_shutdown(int); - int control_dispatch_msg(struct pollfd *, u_int *); - unsigned int control_accept(int, int); - -+/* 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, const char *); -+void log_conn_attempt(const struct peer *, struct sockaddr *); -+ -+/* mrt.c */ -+void mrt_dump_bgp_msg(struct mrt *, void *, u_int16_t, -+ struct peer *); -+void mrt_dump_state(struct mrt *, u_int16_t, u_int16_t, -+ struct peer *); -+ -+/* parse.y */ -+int parse_config(char *, struct bgpd_config *, struct mrt_head *, -+ struct peer **, struct network_head *, struct filter_head *, -+ struct rdomain_head *); -+ - /* 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,15 +283,24 @@ 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); --void carp_demote_shutdown(void); --int carp_demote_get(char *); --int carp_demote_set(char *, int); -+/* rde.c */ -+pid_t rde_main(int[2], int[2], int[2], int[2], int); -+ -+/* session.c */ -+void session_socket_blockmode(int, enum blockmodes); -+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, 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); - - /* timer.c */ -+time_t getmonotime(void); - struct peer_timer *timer_get(struct peer *, enum Timer); - struct peer_timer *timer_nextisdue(struct peer *); - time_t timer_nextduein(struct peer *); Index: net/openbgpd/files/patch-bgpd_session.c =================================================================== --- net/openbgpd/files/patch-bgpd_session.c +++ /dev/null @@ -1,2075 +0,0 @@ -Index: bgpd/session.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.c,v -retrieving revision 1.1.1.8 -retrieving revision 1.13 -diff -u -p -r1.1.1.8 -r1.13 ---- bgpd/session.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/session.c 8 Dec 2012 20:17:59 -0000 1.13 -@@ -1,4 +1,4 @@ --/* $OpenBSD: session.c,v 1.293 2009/06/07 05:56:24 eric Exp $ */ -+/* $OpenBSD: session.c,v 1.325 2012/09/18 09:45:50 claudio Exp $ */ - - /* - * Copyright (c) 2003, 2004, 2005 Henning Brauer -@@ -21,18 +21,21 @@ - - #include - #include -+#include -+#include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - - #include - #include - #include --#include - #include - #include - #include -@@ -50,7 +53,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 +73,9 @@ 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); -+int session_capa_add_gr(struct peer *, 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,30 +83,34 @@ 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_graceful_restart(struct peer *); -+int session_graceful_is_restarting(struct peer *); -+int session_graceful_stop(struct peer *); - int session_dispatch_msg(struct pollfd *, struct peer *); -+int session_process_msg(struct peer *); - int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *); - int parse_open(struct peer *); - 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; -@@ -106,6 +118,7 @@ struct imsgbuf *ibuf_rde_ctl; - struct imsgbuf *ibuf_main; - - struct mrt_head mrthead; -+time_t pauseaccept; - - void - session_sighdlr(int sig) -@@ -125,6 +138,22 @@ setup_listeners(u_int *la_cnt) - int opt; - struct listen_addr *la; - u_int cnt = 0; -+#if defined(__FreeBSD__) -+ int s; -+ -+ /* Check if TCP_MD5SIG is supported. */ -+ s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); -+ if (s < 0) -+ fatal("socket open for TCP_MD5SIG check"); -+ opt = TF_SIGNATURE; -+ if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, &opt, sizeof(opt)) == -1) { -+ if (errno == ENOPROTOOPT || errno == EINVAL) -+ sysdep.no_md5sig = 1; -+ else -+ fatal("setsockopt TCP_MD5SIG"); -+ } -+ close(s); -+#endif /* defined(__FreeBSD__) */ - - TAILQ_FOREACH(la, conf->listen_addrs, entry) { - la->reconf = RECONF_NONE; -@@ -140,6 +169,7 @@ setup_listeners(u_int *la_cnt) - } - - opt = 1; -+#if !defined(__FreeBSD__) - if (setsockopt(la->fd, IPPROTO_TCP, TCP_MD5SIG, - &opt, sizeof(opt)) == -1) { - if (errno == ENOPROTOOPT) { /* system w/o md5sig */ -@@ -148,6 +178,7 @@ setup_listeners(u_int *la_cnt) - } else - fatal("setsockopt TCP_MD5SIG"); - } -+#endif /* !defined(__FreeBSD__) */ - - /* set ttl to 255 so that ttl-security works */ - if (la->sa.ss_family == AF_INET && setsockopt(la->fd, -@@ -175,12 +206,10 @@ 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; -+ 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 +218,13 @@ session_main(struct bgpd_config *config, - 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 +234,6 @@ session_main(struct bgpd_config *config, - 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); - -@@ -228,29 +244,25 @@ session_main(struct bgpd_config *config, - - setproctitle("session engine"); - bgpd_process = PROC_SE; -- -- if (pfkey_init(&sysdep) == -1) -- fatalx("pfkey setup failed"); -+ 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 +270,21 @@ session_main(struct bgpd_config *config, - 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 +304,9 @@ session_main(struct bgpd_config *config, - - /* 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 +314,7 @@ session_main(struct bgpd_config *config, - 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 +343,17 @@ session_main(struct bgpd_config *config, - } - - 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,18 +399,31 @@ session_main(struct bgpd_config *config, - 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; -- -+ if (pauseaccept == 0) { -+ pfd[PFD_SOCK_CTL].fd = csock; -+ pfd[PFD_SOCK_CTL].events = POLLIN; -+ pfd[PFD_SOCK_RCTL].fd = rcsock; -+ pfd[PFD_SOCK_RCTL].events = POLLIN; -+ } else { -+ pfd[PFD_SOCK_CTL].fd = -1; -+ pfd[PFD_SOCK_RCTL].fd = -1; -+ } -+ 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; -- pfd[i].events = POLLIN; -+ if (pauseaccept == 0) { -+ pfd[i].fd = la->fd; -+ pfd[i].events = POLLIN; -+ } else -+ pfd[i].fd = -1; - i++; - } - idx_listeners = i; -@@ -450,6 +468,10 @@ session_main(struct bgpd_config *config, - p->state == STATE_ESTABLISHED) - session_demote(p, -1); - break; -+ case Timer_RestartTimeout: -+ timer_stop(p, Timer_RestartTimeout); -+ session_graceful_stop(p); -+ break; - default: - fatalx("King Bula lost in time"); - } -@@ -462,6 +484,9 @@ session_main(struct bgpd_config *config, - events = POLLIN; - if (p->wbuf.queued > 0 || p->state == STATE_CONNECT) - events |= POLLOUT; -+ /* is there still work to do? */ -+ if (p->rbuf && p->rbuf->wpos) -+ timeout = 0; - - /* poll events */ - if (p->fd != -1 && events != 0) { -@@ -492,12 +517,21 @@ session_main(struct bgpd_config *config, - i++; - } - -+ if (pauseaccept && timeout > 1) -+ timeout = 1; - if (timeout < 0) - timeout = 0; - if ((nfds = poll(pfd, i, timeout * 1000)) == -1) - if (errno != EINTR) - fatal("poll error"); - -+ /* -+ * If we previously saw fd exhaustion, we stop accept() -+ * for 1 second to throttle the accept() loop. -+ */ -+ if (pauseaccept && getmonotime() > pauseaccept + 1) -+ pauseaccept = 0; -+ - if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & POLLOUT) - if (msgbuf_write(&ibuf_main->w) < 0) - fatal("pipe write error"); -@@ -534,6 +568,14 @@ session_main(struct bgpd_config *config, - 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) { -@@ -545,6 +587,10 @@ session_main(struct bgpd_config *config, - nfds -= session_dispatch_msg(&pfd[j], - peer_l[j - idx_listeners]); - -+ for (p = peers; p != NULL; p = p->next) -+ if (p->rbuf && p->rbuf->wpos) -+ session_process_msg(p); -+ - for (; nfds > 0 && j < idx_mrts; j++) - if (pfd[j].revents & POLLOUT) { - nfds--; -@@ -557,7 +603,7 @@ session_main(struct bgpd_config *config, - - 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 +689,9 @@ bgp_fsm(struct peer *peer, enum session_ - 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 +791,6 @@ bgp_fsm(struct peer *peer, enum session_ - /* 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 +824,8 @@ bgp_fsm(struct peer *peer, enum session_ - 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 +836,6 @@ bgp_fsm(struct peer *peer, enum session_ - /* 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 +859,8 @@ bgp_fsm(struct peer *peer, enum session_ - 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 +871,6 @@ bgp_fsm(struct peer *peer, enum session_ - /* 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 +900,8 @@ bgp_fsm(struct peer *peer, enum session_ - 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; - } -@@ -885,9 +930,10 @@ start_timer_keepalive(struct peer *peer) - void - session_close_connection(struct peer *peer) - { -- if (peer->fd != -1) -+ if (peer->fd != -1) { - close(peer->fd); -- -+ pauseaccept = 0; -+ } - peer->fd = peer->wbuf.fd = -1; - } - -@@ -923,20 +969,31 @@ change_state(struct peer *peer, enum ses - 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); - free(peer->rbuf); - peer->rbuf = NULL; - bzero(&peer->capa.peer, sizeof(peer->capa.peer)); -- if (peer->state == STATE_ESTABLISHED) -- session_down(peer); -+ - if (event != EVNT_STOP) { - timer_set(peer, Timer_IdleHold, peer->IdleHoldTime); - if (event != EVNT_NONE && - peer->IdleHoldTime < MAX_IDLE_HOLD/2) - peer->IdleHoldTime *= 2; - } -+ if (peer->state == STATE_ESTABLISHED) { -+ if (peer->capa.neg.grestart.restart == 2 && -+ (event == EVNT_CON_CLOSED || -+ event == EVNT_CON_FATAL)) { -+ /* don't punish graceful restart */ -+ timer_set(peer, Timer_IdleHold, 0); -+ peer->IdleHoldTime /= 2; -+ session_graceful_restart(peer); -+ } else -+ session_down(peer); -+ } - if (peer->state == STATE_NONE || - peer->state == STATE_ESTABLISHED) { - /* initialize capability negotiation structures */ -@@ -947,6 +1004,20 @@ change_state(struct peer *peer, enum ses - } - break; - case STATE_CONNECT: -+ if (peer->state == STATE_ESTABLISHED && -+ peer->capa.neg.grestart.restart == 2) { -+ /* do the graceful restart dance */ -+ session_graceful_restart(peer); -+ peer->holdtime = INTERVAL_HOLD_INITIAL; -+ 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); -+ bzero(&peer->capa.peer, sizeof(peer->capa.peer)); -+ } - break; - case STATE_ACTIVE: - break; -@@ -990,7 +1061,10 @@ session_accept(int listenfd) - len = sizeof(cliaddr); - if ((connfd = accept(listenfd, - (struct sockaddr *)&cliaddr, &len)) == -1) { -- if (errno == EWOULDBLOCK || errno == EINTR) -+ if (errno == ENFILE || errno == EMFILE) { -+ pauseaccept = getmonotime(); -+ return; -+ } else if (errno == EWOULDBLOCK || errno == EINTR) - return; - else - log_warn("accept"); -@@ -1017,6 +1091,7 @@ session_accept(int listenfd) - } - } - -+open: - if (p->conf.auth.method != AUTH_NONE && sysdep.no_pfkey) { - log_peer_warnx(&p->conf, - "ipsec or md5sig configured but not available"); -@@ -1049,6 +1124,13 @@ session_accept(int listenfd) - } - session_socket_blockmode(connfd, BM_NONBLOCK); - bgp_fsm(p, EVNT_CON_OPEN); -+ return; -+ } else if (p != NULL && p->state == STATE_ESTABLISHED && -+ p->capa.neg.grestart.restart == 2) { -+ /* first do the graceful restart dance */ -+ change_state(p, STATE_CONNECT, EVNT_CON_CLOSED); -+ /* then do part of the open dance */ -+ goto open; - } else { - log_conn_attempt(p, (struct sockaddr *)&cliaddr); - close(connfd); -@@ -1069,7 +1151,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 +1182,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 +1220,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,24 +1274,18 @@ 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 */ - bsize = 65535; -- while (setsockopt(p->fd, SOL_SOCKET, SO_RCVBUF, &bsize, -- sizeof(bsize)) == -1) -+ while (bsize > 8192 && -+ setsockopt(p->fd, SOL_SOCKET, SO_RCVBUF, &bsize, -+ sizeof(bsize)) == -1 && errno != EINVAL) - bsize /= 2; - bsize = 65535; -- while (setsockopt(p->fd, SOL_SOCKET, SO_SNDBUF, &bsize, -- sizeof(bsize)) == -1) -+ while (bsize > 8192 && -+ setsockopt(p->fd, SOL_SOCKET, SO_SNDBUF, &bsize, -+ sizeof(bsize)) == -1 && errno != EINVAL) - bsize /= 2; - } - -@@ -1244,40 +1327,56 @@ session_tcp_established(struct peer *pee - 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) --{ -- 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; -+session_capa_add(struct ibuf *opb, u_int8_t capa_code, u_int8_t capa_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 += ibuf_add(buf, &afi, sizeof(afi)); -+ errs += ibuf_add(buf, &pad, sizeof(pad)); -+ errs += ibuf_add(buf, &safi, sizeof(safi)); -+ -+ return (errs); -+} -+ -+int -+session_capa_add_gr(struct peer *p, struct ibuf *b, u_int8_t aid) -+{ -+ u_int errs = 0; -+ u_int16_t afi; -+ u_int8_t flags, safi; -+ -+ if (aid2afi(aid, &afi, &safi)) { -+ log_warn("session_capa_add_gr: bad AID"); -+ return (1); -+ } -+ if (p->capa.neg.grestart.flags[aid] & CAPA_GR_RESTARTING) -+ flags = CAPA_GR_F_FLAG; -+ else -+ flags = 0; -+ - 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(b, &afi, sizeof(afi)); -+ errs += ibuf_add(b, &safi, sizeof(safi)); -+ errs += ibuf_add(b, &flags, sizeof(flags)); - - return (errs); - } -@@ -1287,23 +1386,22 @@ session_newmsg(enum msg_type msgtype, u_ - { - 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)); -- -- if (errs > 0 || -- (msg = calloc(1, sizeof(*msg))) == NULL) { -- buf_free(buf); -+ 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 || (msg = calloc(1, sizeof(*msg))) == NULL) { -+ ibuf_free(buf); - return (NULL); - } - -@@ -1329,7 +1427,7 @@ session_sendmsg(struct bgp_msg *msg, str - 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 +1436,70 @@ 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; -+ int mpcapa = 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); -+ mpcapa++; -+ } - - /* 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); -+ /* graceful restart and End-of-RIB marker, RFC 4724 */ -+ if (p->capa.ann.grestart.restart) { -+ int rst = 0; -+ u_int16_t hdr; -+ u_int8_t grlen; -+ -+ if (mpcapa) { -+ grlen = 2 + 4 * mpcapa; -+ for (i = 0; i < AID_MAX; i++) { -+ if (p->capa.neg.grestart.flags[i] & -+ CAPA_GR_RESTARTING) -+ rst++; -+ } -+ } else { /* AID_INET */ -+ grlen = 2 + 4; -+ if (p->capa.neg.grestart.flags[AID_INET] & -+ CAPA_GR_RESTARTING) -+ rst++; -+ } -+ -+ hdr = conf->holdtime; /* default timeout */ -+ /* if client does graceful restart don't set R flag */ -+ if (!rst) -+ hdr |= CAPA_GR_R_FLAG; -+ hdr = htons(hdr); -+ -+ errs += session_capa_add(opb, CAPA_RESTART, grlen); -+ errs += ibuf_add(opb, &hdr, sizeof(hdr)); -+ -+ if (mpcapa) { -+ for (i = 0; i < AID_MAX; i++) { -+ if (p->capa.ann.mp[i]) { -+ errs += session_capa_add_gr(p, opb, i); -+ } -+ } -+ } else { /* AID_INET */ -+ errs += session_capa_add_gr(p, opb, AID_INET); -+ } - } - - /* 4-bytes AS numbers, draft-ietf-idr-as4bytes-13 */ -@@ -1379,13 +1507,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 +1531,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)); -- -- if (optparamlen) -- errs += buf_add(buf->buf, opb->buf, 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) { -+ 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 +1596,8 @@ session_update(u_int32_t peerid, void *d - 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 +1617,27 @@ session_notification(struct peer *p, u_i - 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 +1656,29 @@ session_notification(struct peer *p, u_i - 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 +1686,12 @@ session_rrefresh(struct peer *p, u_int16 - } - - 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; -@@ -1565,13 +1706,74 @@ session_rrefresh(struct peer *p, u_int16 - } - - int -+session_graceful_restart(struct peer *p) -+{ -+ u_int8_t i; -+ -+ timer_set(p, Timer_RestartTimeout, p->capa.neg.grestart.timeout); -+ -+ for (i = 0; i < AID_MAX; i++) { -+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_PRESENT) { -+ if (imsg_compose(ibuf_rde, IMSG_SESSION_STALE, -+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) -+ return (-1); -+ log_peer_warnx(&p->conf, -+ "graceful restart of %s, keeping routes", -+ aid2str(i)); -+ p->capa.neg.grestart.flags[i] |= CAPA_GR_RESTARTING; -+ } else if (p->capa.neg.mp[i]) { -+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, -+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) -+ return (-1); -+ log_peer_warnx(&p->conf, -+ "graceful restart of %s, flushing routes", -+ aid2str(i)); -+ } -+ } -+ return (0); -+} -+ -+int -+session_graceful_is_restarting(struct peer *p) -+{ -+ u_int8_t i; -+ -+ for (i = 0; i < AID_MAX; i++) -+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING) -+ return (1); -+ return (0); -+} -+ -+int -+session_graceful_stop(struct peer *p) -+{ -+ u_int8_t i; -+ -+ for (i = 0; i < AID_MAX; i++) { -+ /* -+ * Only flush if the peer is restarting and the peer indicated -+ * it hold the forwarding state. In all other cases the -+ * session was already flushed when the session came up. -+ */ -+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING && -+ p->capa.neg.grestart.flags[i] & CAPA_GR_FORWARD) { -+ log_peer_warnx(&p->conf, "graceful restart of %s, " -+ "time-out, flushing", aid2str(i)); -+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, -+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) -+ return (-1); -+ } -+ p->capa.neg.grestart.flags[i] &= ~CAPA_GR_RESTARTING; -+ } -+ return (0); -+} -+ -+int - session_dispatch_msg(struct pollfd *pfd, struct peer *p) - { -- ssize_t n, rpos, av, left; -+ ssize_t n; - socklen_t len; -- int error, processed = 0; -- u_int16_t msglen; -- u_int8_t msgtype; -+ int error; - - if (p->state == STATE_CONNECT) { - if (pfd->revents & POLLOUT) { -@@ -1641,71 +1843,83 @@ session_dispatch_msg(struct pollfd *pfd, - return (1); - } - -- rpos = 0; -- av = p->rbuf->wpos + n; -+ p->rbuf->wpos += n; - p->stats.last_read = time(NULL); -+ return (1); -+ } -+ return (0); -+} - -- /* -- * session might drop to IDLE -> buffers deallocated -- * we MUST check rbuf != NULL before use -- */ -- for (;;) { -- if (rpos + MSGSIZE_HEADER > av) -- break; -- if (p->rbuf == NULL) -- break; -- if (parse_header(p, p->rbuf->buf + rpos, &msglen, -- &msgtype) == -1) -- return (0); -- if (rpos + msglen > av) -- break; -- p->rbuf->rptr = p->rbuf->buf + rpos; -- -- switch (msgtype) { -- case OPEN: -- bgp_fsm(p, EVNT_RCVD_OPEN); -- p->stats.msg_rcvd_open++; -- break; -- case UPDATE: -- bgp_fsm(p, EVNT_RCVD_UPDATE); -- p->stats.msg_rcvd_update++; -- break; -- case NOTIFICATION: -- bgp_fsm(p, EVNT_RCVD_NOTIFICATION); -- p->stats.msg_rcvd_notification++; -- break; -- case KEEPALIVE: -- bgp_fsm(p, EVNT_RCVD_KEEPALIVE); -- p->stats.msg_rcvd_keepalive++; -- break; -- case RREFRESH: -- parse_refresh(p); -- p->stats.msg_rcvd_rrefresh++; -- break; -- default: /* cannot happen */ -- session_notification(p, ERR_HEADER, -- ERR_HDR_TYPE, &msgtype, 1); -- log_warnx("received message with " -- "unknown type %u", msgtype); -- bgp_fsm(p, EVNT_CON_FATAL); -- } -- rpos += msglen; -- if (++processed > MSG_PROCESS_LIMIT) -- break; -- } -- if (p->rbuf == NULL) -- return (1); -+int -+session_process_msg(struct peer *p) -+{ -+ ssize_t rpos, av, left; -+ int processed = 0; -+ u_int16_t msglen; -+ u_int8_t msgtype; - -- if (rpos < av) { -- left = av - rpos; -- memcpy(&p->rbuf->buf, p->rbuf->buf + rpos, left); -- p->rbuf->wpos = left; -- } else -- p->rbuf->wpos = 0; -+ rpos = 0; -+ av = p->rbuf->wpos; - -- return (1); -+ /* -+ * session might drop to IDLE -> buffers deallocated -+ * we MUST check rbuf != NULL before use -+ */ -+ for (;;) { -+ if (rpos + MSGSIZE_HEADER > av) -+ break; -+ if (p->rbuf == NULL) -+ break; -+ if (parse_header(p, p->rbuf->buf + rpos, &msglen, -+ &msgtype) == -1) -+ return (0); -+ if (rpos + msglen > av) -+ break; -+ p->rbuf->rptr = p->rbuf->buf + rpos; -+ -+ switch (msgtype) { -+ case OPEN: -+ bgp_fsm(p, EVNT_RCVD_OPEN); -+ p->stats.msg_rcvd_open++; -+ break; -+ case UPDATE: -+ bgp_fsm(p, EVNT_RCVD_UPDATE); -+ p->stats.msg_rcvd_update++; -+ break; -+ case NOTIFICATION: -+ bgp_fsm(p, EVNT_RCVD_NOTIFICATION); -+ p->stats.msg_rcvd_notification++; -+ break; -+ case KEEPALIVE: -+ bgp_fsm(p, EVNT_RCVD_KEEPALIVE); -+ p->stats.msg_rcvd_keepalive++; -+ break; -+ case RREFRESH: -+ parse_refresh(p); -+ p->stats.msg_rcvd_rrefresh++; -+ break; -+ default: /* cannot happen */ -+ session_notification(p, ERR_HEADER, ERR_HDR_TYPE, -+ &msgtype, 1); -+ log_warnx("received message with unknown type %u", -+ msgtype); -+ bgp_fsm(p, EVNT_CON_FATAL); -+ } -+ rpos += msglen; -+ if (++processed > MSG_PROCESS_LIMIT) -+ break; - } -- return (0); -+ if (p->rbuf == NULL) -+ return (1); -+ -+ if (rpos < av) { -+ left = av - rpos; -+ memcpy(&p->rbuf->buf, p->rbuf->buf + rpos, left); -+ p->rbuf->wpos = left; -+ } else -+ p->rbuf->wpos = 0; -+ -+ return (1); - } - - int -@@ -1853,12 +2067,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 +2174,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 +2191,14 @@ parse_open(struct peer *peer) - return (-1); - } - -+ if (capa_neg_calc(peer) == -1) { -+ log_peer_warnx(&peer->conf, -+ "capability 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 +2233,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 +2271,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 +2296,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 +2331,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; -@@ -2105,7 +2342,7 @@ parse_notification(struct peer *peer) - "disabling route refresh capability"); - break; - case CAPA_RESTART: -- peer->capa.ann.restart = 0; -+ peer->capa.ann.grestart.restart = 0; - log_peer_warnx(&peer->conf, - "disabling restart capability"); - break; -@@ -2139,19 +2376,23 @@ 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_int16_t gr_header; -+ u_int8_t safi; -+ u_int8_t aid; -+ u_int8_t gr_flags; - 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; -+ u_int8_t i; - - len = dlen; - while (len > 0) { - if (len < 2) { -- log_peer_warnx(&peer->conf, "parse_capabilities: " -- "expect len >= 2, len is %u", len); -+ log_peer_warnx(&peer->conf, "Bad capabilities attr " -+ "length: %u, too short", len); - return (-1); - } - memcpy(&capa_code, d, sizeof(capa_code)); -@@ -2163,7 +2404,7 @@ parse_capabilities(struct peer *peer, u_ - if (capa_len > 0) { - if (len < capa_len) { - log_peer_warnx(&peer->conf, -- "parse_capabilities: " -+ "Bad capabilities attr length: " - "len %u smaller than capa_len %u", - len, capa_len); - return (-1); -@@ -2178,47 +2419,82 @@ parse_capabilities(struct peer *peer, u_ - case CAPA_MP: /* RFC 4760 */ - if (capa_len != 4) { - log_peer_warnx(&peer->conf, -- "parse_capabilities: " -- "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; -+ "Bad multi protocol capability length: " -+ "%u", capa_len); - 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, -+ "Received multi protocol capability: " -+ " unknown AFI %u, safi %u pair", -+ afi, safi); - break; - } -+ peer->capa.peer.mp[aid] = 1; - break; - case CAPA_REFRESH: - peer->capa.peer.refresh = 1; - break; - case CAPA_RESTART: -- peer->capa.peer.restart = 1; -- /* we don't care about the further restart capas yet */ -+ if (capa_len == 2) { -+ /* peer only supports EoR marker */ -+ peer->capa.peer.grestart.restart = 1; -+ peer->capa.peer.grestart.timeout = 0; -+ break; -+ } else if (capa_len % 4 != 2) { -+ log_peer_warnx(&peer->conf, -+ "Bad graceful restart capability length: " -+ "%u", capa_len); -+ peer->capa.peer.grestart.restart = 0; -+ peer->capa.peer.grestart.timeout = 0; -+ break; -+ } -+ -+ memcpy(&gr_header, capa_val, sizeof(gr_header)); -+ gr_header = ntohs(gr_header); -+ peer->capa.peer.grestart.timeout = -+ gr_header & CAPA_GR_TIMEMASK; -+ if (peer->capa.peer.grestart.timeout == 0) { -+ log_peer_warnx(&peer->conf, "Received " -+ "graceful restart timeout is zero"); -+ peer->capa.peer.grestart.restart = 0; -+ break; -+ } -+ -+ for (i = 2; i <= capa_len - 4; i += 4) { -+ memcpy(&afi, capa_val + i, sizeof(afi)); -+ afi = ntohs(afi); -+ memcpy(&safi, capa_val + i + 2, sizeof(safi)); -+ if (afi2aid(afi, safi, &aid) == -1) { -+ log_peer_warnx(&peer->conf, -+ "Received graceful restart capa: " -+ " unknown AFI %u, safi %u pair", -+ afi, safi); -+ continue; -+ } -+ memcpy(&gr_flags, capa_val + i + 3, -+ sizeof(gr_flags)); -+ peer->capa.peer.grestart.flags[aid] |= -+ CAPA_GR_PRESENT; -+ if (gr_flags & CAPA_GR_F_FLAG) -+ peer->capa.peer.grestart.flags[aid] |= -+ CAPA_GR_FORWARD; -+ if (gr_header & CAPA_GR_R_FLAG) -+ peer->capa.peer.grestart.flags[aid] |= -+ CAPA_GR_RESTART; -+ peer->capa.peer.grestart.restart = 2; -+ } - break; - case CAPA_AS4BYTE: - if (capa_len != 4) { - log_peer_warnx(&peer->conf, -- "parse_capabilities: " -- "expect len 4, len is %u", capa_len); -- return (-1); -+ "Bad AS4BYTE capability length: " -+ "%u", capa_len); -+ peer->capa.peer.as4byte = 0; -+ break; - } - memcpy(&remote_as, capa_val, sizeof(remote_as)); - *as = ntohl(remote_as); -@@ -2232,6 +2508,66 @@ parse_capabilities(struct peer *peer, u_ - 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 default to IPv4 unicast mode */ -+ if (!hasmp) -+ p->capa.neg.mp[AID_INET] = 1; -+ -+ /* -+ * graceful restart: only the peer capabilities are of interest here. -+ * It is necessary to compare the new values with the previous ones -+ * and act acordingly. AFI/SAFI that are not part in the MP capability -+ * are treated as not being present. -+ */ -+ -+ for (i = 0; i < AID_MAX; i++) { -+ /* disable GR if the AFI/SAFI is not present */ -+ if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT && -+ p->capa.neg.mp[i] == 0) -+ p->capa.peer.grestart.flags[i] = 0; /* disable */ -+ /* look at current GR state and decide what to do */ -+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING) { -+ if (!(p->capa.peer.grestart.flags[i] & -+ CAPA_GR_FORWARD)) { -+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, -+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) -+ return (-1); -+ log_peer_warnx(&p->conf, "graceful restart of " -+ "%s, not restarted, flushing", aid2str(i)); -+ } -+ p->capa.neg.grestart.flags[i] = -+ p->capa.peer.grestart.flags[i] | CAPA_GR_RESTARTING; -+ } else -+ p->capa.neg.grestart.flags[i] = -+ p->capa.peer.grestart.flags[i]; -+ } -+ p->capa.neg.grestart.timeout = p->capa.peer.grestart.timeout; -+ p->capa.neg.grestart.restart = p->capa.peer.grestart.restart; -+ -+ return (0); -+} -+ - void - session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) - { -@@ -2244,8 +2580,8 @@ session_dispatch_imsg(struct imsgbuf *ib - struct kif *kif; - u_char *data; - enum reconf_action reconf; -- int n, depend_ok; -- u_int8_t errcode, subcode; -+ int n, depend_ok, restricted; -+ u_int8_t aid, errcode, subcode; - - if ((n = imsg_read(ibuf)) == -1) - fatal("session_dispatch_imsg: imsg_read error"); -@@ -2332,15 +2668,42 @@ session_dispatch_imsg(struct imsgbuf *ib - } - - 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) { -@@ -2388,6 +2751,8 @@ session_dispatch_imsg(struct imsgbuf *ib - nconf = NULL; - pending_reconf = 0; - log_info("SE reconfigured"); -+ imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, -+ -1, NULL, 0); - break; - case IMSG_IFINFO: - if (idx != PFD_PIPE_MAIN) -@@ -2397,9 +2762,7 @@ session_dispatch_imsg(struct imsgbuf *ib - fatalx("IFINFO imsg with wrong len"); - kif = imsg.data; - depend_ok = (kif->flags & IFF_UP) && -- (LINK_STATE_IS_UP(kif->link_state) || -- (kif->link_state == LINK_STATE_UNKNOWN && -- kif->media_type != IFT_CARP)); -+ LINK_STATE_IS_UP(kif->link_state); - - for (p = peers; p != NULL; p = p->next) - if (!strcmp(p->conf.if_depend, kif->ifname)) { -@@ -2408,7 +2771,8 @@ session_dispatch_imsg(struct imsgbuf *ib - 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 +2820,10 @@ session_dispatch_imsg(struct imsgbuf *ib - } - 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 +2833,6 @@ session_dispatch_imsg(struct imsgbuf *ib - 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"); -@@ -2531,6 +2894,40 @@ session_dispatch_imsg(struct imsgbuf *ib - break; - } - break; -+ case IMSG_SESSION_RESTARTED: -+ if (idx != PFD_PIPE_ROUTE) -+ fatalx("update request not from RDE"); -+ if (imsg.hdr.len < IMSG_HEADER_SIZE + sizeof(aid)) { -+ log_warnx("RDE sent invalid restart msg"); -+ break; -+ } -+ if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) { -+ log_warnx("no such peer: id=%u", -+ imsg.hdr.peerid); -+ break; -+ } -+ memcpy(&aid, imsg.data, sizeof(aid)); -+ if (aid >= AID_MAX) -+ fatalx("IMSG_SESSION_RESTARTED: bad AID"); -+ if (p->capa.neg.grestart.flags[aid] & -+ CAPA_GR_RESTARTING && -+ p->capa.neg.grestart.flags[aid] & -+ CAPA_GR_FORWARD) { -+ log_peer_warnx(&p->conf, -+ "graceful restart of %s finished", -+ aid2str(aid)); -+ p->capa.neg.grestart.flags[aid] &= -+ ~CAPA_GR_RESTARTING; -+ timer_stop(p, Timer_RestartTimeout); -+ -+ /* signal back to RDE to cleanup stale routes */ -+ if (imsg_compose(ibuf_rde, -+ IMSG_SESSION_RESTARTED, imsg.hdr.peerid, 0, -+ -1, &aid, sizeof(aid)) == -1) -+ fatal("imsg_compose: " -+ "IMSG_SESSION_RESTARTED"); -+ } -+ break; - default: - break; - } -@@ -2612,29 +3009,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 +3044,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 +3069,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 +3106,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) -@@ -2744,39 +3118,17 @@ session_up(struct peer *p) - { - struct session_up sup; - -- if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1, -- &p->conf, sizeof(p->conf)) == -1) -- fatalx("imsg_compose error"); -+ if (!session_graceful_is_restarting(p)) -+ if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1, -+ &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 +3136,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 +3148,6 @@ imsg_compose_rde(int type, pid_t pid, vo - 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 +3162,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); -+} Index: net/openbgpd/files/patch-bgpd_timer.c =================================================================== --- net/openbgpd/files/patch-bgpd_timer.c +++ /dev/null @@ -1,32 +0,0 @@ -Index: bgpd/timer.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/timer.c,v -retrieving revision 1.1.1.2 -retrieving revision 1.1.1.4 -diff -u -p -r1.1.1.2 -r1.1.1.4 ---- bgpd/timer.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 -+++ bgpd/timer.c 13 Oct 2012 18:22:50 -0000 1.1.1.4 -@@ -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 -@@ -23,8 +23,6 @@ - #include "bgpd.h" - #include "session.h" - --time_t getmonotime(void); -- - time_t - getmonotime(void) - { -@@ -43,7 +41,7 @@ timer_get(struct peer *p, enum Timer tim - - TAILQ_FOREACH(pt, &p->timers, entry) - if (pt->type == timer) -- break; -+ break; - - return (pt); - } Index: net/openbgpd/files/patch-bgpd_util.c =================================================================== --- net/openbgpd/files/patch-bgpd_util.c +++ /dev/null @@ -1,440 +0,0 @@ -Index: bgpd/util.c -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/util.c,v -retrieving revision 1.1.1.6 -retrieving revision 1.7 -diff -u -p -r1.1.1.6 -r1.7 ---- bgpd/util.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/util.c 13 Oct 2012 18:36:00 -0000 1.7 -@@ -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 -@@ -18,6 +18,9 @@ - */ - #include - #include -+#if defined(__FreeBSD__) /* sys/limits.h */ -+#include -+#endif /* defined(__FreeBSD__) */ - #include - #include - #include -@@ -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, v - 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, v - 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) -@@ -235,6 +335,67 @@ aspath_strlen(void *data, u_int16_t len) - return (total_size); - } - -+/* we need to be able to search more than one as */ -+int -+aspath_match(void *data, u_int16_t len, enum as_spec type, u_int32_t as) -+{ -+ u_int8_t *seg; -+ int final; -+ u_int16_t seg_size; -+ u_int8_t i, seg_type, seg_len; -+ -+ if (type == AS_EMPTY) { -+ if (len == 0) -+ return (1); -+ else -+ return (0); -+ } -+ -+ final = 0; -+ seg = data; -+ for (; 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; -+ -+ final = (len == seg_size); -+ -+ /* just check the first (leftmost) AS */ -+ if (type == AS_PEER) { -+ if (as == aspath_extract(seg, 0)) -+ return (1); -+ else -+ return (0); -+ } -+ /* just check the final (rightmost) AS */ -+ if (type == AS_SOURCE) { -+ /* not yet in the final segment */ -+ if (!final) -+ continue; -+ -+ if (as == aspath_extract(seg, seg_len - 1)) -+ return (1); -+ else -+ return (0); -+ } -+ -+ /* AS_TRANSIT or AS_ALL */ -+ for (i = 0; i < seg_len; i++) { -+ if (as == aspath_extract(seg, i)) { -+ /* -+ * the source (rightmost) AS is excluded from -+ * AS_TRANSIT matches. -+ */ -+ if (final && i == seg_len - 1 && -+ type == AS_TRANSIT) -+ return (0); -+ return (1); -+ } -+ } -+ } -+ return (0); -+} -+ - /* - * Extract the asnum out of the as segment at the specified position. - * Direct access is not possible because of non-aligned reads. -@@ -251,6 +412,66 @@ aspath_extract(const void *seg, int pos) - return (ntohl(as)); - } - -+int -+prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, -+ int prefixlen) -+{ -+ in_addr_t mask, aa, ba; -+ int i; -+ u_int8_t m; -+ -+ if (a->aid != b->aid) -+ return (a->aid - b->aid); -+ -+ switch (a->aid) { -+ case AID_INET: -+ if (prefixlen > 32) -+ fatalx("prefix_cmp: bad IPv4 prefixlen"); -+ mask = htonl(prefixlen2mask(prefixlen)); -+ aa = ntohl(a->v4.s_addr & mask); -+ ba = ntohl(b->v4.s_addr & mask); -+ if (aa != ba) -+ return (aa - ba); -+ return (0); -+ case AID_INET6: -+ if (prefixlen > 128) -+ fatalx("prefix_cmp: bad IPv6 prefixlen"); -+ for (i = 0; i < prefixlen / 8; i++) -+ if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) -+ return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); -+ i = prefixlen % 8; -+ if (i) { -+ m = 0xff00 >> i; -+ if ((a->v6.s6_addr[prefixlen / 8] & m) != -+ (b->v6.s6_addr[prefixlen / 8] & m)) -+ return ((a->v6.s6_addr[prefixlen / 8] & m) - -+ (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"); -+ } -+ return (-1); -+} -+ - in_addr_t - prefixlen2mask(u_int8_t prefixlen) - { -@@ -276,3 +497,115 @@ inet6applymask(struct in6_addr *dest, co - 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; -+ } -+} Index: net/openbgpd/files/patch-openbsd-compat_fmt_scaled.c =================================================================== --- net/openbgpd/files/patch-openbsd-compat_fmt_scaled.c +++ /dev/null @@ -1,275 +0,0 @@ -Index: openbsd-compat/fmt_scaled.c -=================================================================== -RCS file: openbsd-compat/fmt_scaled.c -diff -N openbsd-compat/fmt_scaled.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/fmt_scaled.c 30 Jun 2009 06:40:07 -0000 1.1 -@@ -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 -+#include -+#include -+#include -+#include -+#include -+ -+#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 Index: net/openbgpd/files/patch-openbsd-compat_hash.h =================================================================== --- net/openbgpd/files/patch-openbsd-compat_hash.h +++ /dev/null @@ -1,134 +0,0 @@ -Index: openbsd-compat/hash.h -=================================================================== -RCS file: openbsd-compat/hash.h -diff -N openbsd-compat/hash.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/hash.h 30 Jun 2009 05:48:11 -0000 1.1 -@@ -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 -+ -+/* -+ * 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_ */ Index: net/openbgpd/files/patch-openbsd-compat_if_media.h =================================================================== --- net/openbgpd/files/patch-openbsd-compat_if_media.h +++ /dev/null @@ -1,619 +0,0 @@ -Index: openbsd-compat/if_media.h -=================================================================== -RCS file: openbsd-compat/if_media.h -diff -N openbsd-compat/if_media.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/if_media.h 30 Jun 2009 05:48:11 -0000 1.1 -@@ -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 -+ -+/* -+ * 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_ */ Index: net/openbgpd/files/patch-openbsd-compat_imsg-buffer.c =================================================================== --- net/openbgpd/files/patch-openbsd-compat_imsg-buffer.c +++ /dev/null @@ -1,312 +0,0 @@ -Index: openbsd-compat/imsg-buffer.c -=================================================================== -RCS file: openbsd-compat/imsg-buffer.c -diff -N openbsd-compat/imsg-buffer.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/imsg-buffer.c 8 Dec 2012 20:17:59 -0000 1.2 -@@ -0,0 +1,305 @@ -+/* $OpenBSD: imsg-buffer.c,v 1.1 2010/05/26 16:44:32 nicm Exp $ */ -+ -+/* -+ * Copyright (c) 2003, 2004 Henning Brauer -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#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++; -+ } -+ -+again: -+ if ((n = writev(msgbuf->fd, iov, i)) == -1) { -+ if (errno == EAGAIN || errno == EINTR) -+ goto again; -+ if (errno == ENOBUFS) -+ errno = EAGAIN; -+ return (-1); -+ } -+ -+ if (n == 0) { /* connection closed */ -+ errno = 0; -+ return (0); -+ } -+ -+ msgbuf_drain(msgbuf, n); -+ -+ return (1); -+} -+ -+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; -+ } -+ -+again: -+ if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { -+ if (errno == EAGAIN || errno == EINTR) -+ goto again; -+ if (errno == ENOBUFS) -+ errno = EAGAIN; -+ return (-1); -+ } -+ -+ if (n == 0) { /* connection closed */ -+ errno = 0; -+ return (0); -+ } -+ -+ /* -+ * 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 (1); -+} -+ -+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); -+} Index: net/openbgpd/files/patch-openbsd-compat_imsg.h =================================================================== --- net/openbgpd/files/patch-openbsd-compat_imsg.h +++ /dev/null @@ -1,119 +0,0 @@ -Index: openbsd-compat/imsg.h -=================================================================== -RCS file: openbsd-compat/imsg.h -diff -N openbsd-compat/imsg.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/imsg.h 8 Dec 2012 20:17:59 -0000 1.2 -@@ -0,0 +1,112 @@ -+/* $OpenBSD: imsg.h,v 1.1 2010/05/26 16:44:32 nicm Exp $ */ -+ -+/* -+ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard -+ * Copyright (c) 2006, 2007, 2008 Reyk Floeter -+ * Copyright (c) 2003, 2004 Henning Brauer -+ * -+ * 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 Index: net/openbgpd/files/patch-openbsd-compat_imsg.c =================================================================== --- net/openbgpd/files/patch-openbsd-compat_imsg.c +++ /dev/null @@ -1,312 +0,0 @@ -Index: openbsd-compat/imsg.c -=================================================================== -RCS file: openbsd-compat/imsg.c -diff -N openbsd-compat/imsg.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/imsg.c 8 Dec 2012 20:17:59 -0000 1.2 -@@ -0,0 +1,305 @@ -+/* $OpenBSD: imsg.c,v 1.1 2010/05/26 16:44:32 nicm Exp $ */ -+ -+/* -+ * Copyright (c) 2003, 2004 Henning Brauer -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "imsg.h" -+ -+int imsg_fd_overhead = 0; -+ -+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) * 1)]; -+ } cmsgbuf; -+ struct iovec iov; -+ ssize_t n = -1; -+ 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 ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) -+ return (-1); -+ -+again: -+#if defined(__FreeBSD__) -+ if (imsg_fd_overhead + -+#else -+ if (getdtablecount() + imsg_fd_overhead + -+#endif -+ (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int) -+ >= getdtablesize()) { -+ errno = EAGAIN; -+ return (-1); -+ } -+ -+ if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { -+ if (errno == EMSGSIZE) -+ goto fail; -+ if (errno != EINTR && errno != EAGAIN) -+ goto fail; -+ goto again; -+ } -+ -+ 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) { -+ int i; -+ int j; -+ -+ /* -+ * We only accept one file descriptor. Due to C -+ * padding rules, our control buffer might contain -+ * more than one fd, and we must close them. -+ */ -+ j = ((char *)cmsg + cmsg->cmsg_len - -+ (char *)CMSG_DATA(cmsg)) / sizeof(int); -+ for (i = 0; i < j; i++) { -+ fd = ((int *)CMSG_DATA(cmsg))[i]; -+ if (i == 0) { -+ ifd->fd = fd; -+ TAILQ_INSERT_TAIL(&ibuf->fds, ifd, -+ entry); -+ ifd = NULL; -+ } else -+ close(fd); -+ } -+ } -+ /* we do not handle other ctl data level */ -+ } -+ -+fail: -+ if (ifd) -+ free(ifd); -+ 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); -+} Index: net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h =================================================================== --- net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h +++ /dev/null @@ -1,98 +0,0 @@ -Index: openbsd-compat/openbsd-compat.h -=================================================================== -RCS file: openbsd-compat/openbsd-compat.h -diff -N openbsd-compat/openbsd-compat.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/openbsd-compat.h 13 Oct 2012 18:50:10 -0000 1.8 -@@ -0,0 +1,91 @@ -+/* -+ * $hrs: openbgpd/openbsd-compat/openbsd-compat.h,v 1.8 2012/10/13 18:50:10 hrs Exp $ -+ */ -+ -+#ifndef _OPENBSD_COMPAT_H -+#define _OPENBSD_COMPAT_H -+ -+#define __dead -+ -+/* bgpctl/bgpctl.c */ -+#include -+#include -+#define betoh64(x) (be64toh(x)) -+#ifndef IFT_CARP -+#define IFT_CARP 0xf8 -+#endif -+ -+/* 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 */ Index: net/openbgpd/files/patch-openbsd-compat_util.h =================================================================== --- net/openbgpd/files/patch-openbsd-compat_util.h +++ /dev/null @@ -1,126 +0,0 @@ -Index: openbsd-compat/util.h -=================================================================== -RCS file: openbsd-compat/util.h -diff -N openbsd-compat/util.h ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ openbsd-compat/util.h 30 Jun 2009 06:40:07 -0000 1.1 -@@ -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 -+#include -+ -+/* -+ * 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_ */ Index: net/openbgpd/pkg-plist =================================================================== --- /dev/null +++ net/openbgpd/pkg-plist @@ -0,0 +1,6 @@ +sbin/bgpctl +sbin/bgpd +man/man5/bgpd.conf.5.gz +man/man8/bgpctl.8.gz +man/man8/bgpd.8.gz +@sample etc/bgpd.conf.sample Index: sysutils/rsyslog8/Makefile =================================================================== --- sysutils/rsyslog8/Makefile +++ sysutils/rsyslog8/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PORTNAME= rsyslog -PORTVERSION= 8.40.0 +PORTVERSION= 8.1905.0 CATEGORIES= sysutils MASTER_SITES= http://www.rsyslog.com/files/download/rsyslog/ Index: sysutils/rsyslog8/distinfo =================================================================== --- sysutils/rsyslog8/distinfo +++ sysutils/rsyslog8/distinfo @@ -1,3 +1,3 @@ -TIMESTAMP = 1544620533 -SHA256 (rsyslog-8.40.0.tar.gz) = 414abbdd27b65d3cd513e1a8a7ccbd110d06160759189e818ea93aca962fc194 -SIZE (rsyslog-8.40.0.tar.gz) = 2726022 +TIMESTAMP = 1559113281 +SHA256 (rsyslog-8.1905.0.tar.gz) = 96bd4fab8d768fd6ad22d45e10b83e159b93df9bafcde1d582e1224f647116e4 +SIZE (rsyslog-8.1905.0.tar.gz) = 2911703 Index: sysutils/rsyslog8/files/patch-configure.ac =================================================================== --- sysutils/rsyslog8/files/patch-configure.ac +++ sysutils/rsyslog8/files/patch-configure.ac @@ -1,6 +1,6 @@ ---- configure.ac.orig 2018-04-03 09:47:39 UTC +--- configure.ac.orig 2019-05-29 07:03:26 UTC +++ configure.ac -@@ -1520,6 +1520,19 @@ if test "x$enable_imfile" = "xyes"; then +@@ -1661,6 +1661,20 @@ if test "x$enable_imfile" = "xyes"; then fi AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes) @@ -17,14 +17,15 @@ + [enable_imuxsock_rfc5424=no] +) +AM_CONDITIONAL(ENABLE_IMUXSOCK_RFC5424, test x$enable_imuxsock_rfc5424 = xyes) - - # settings for the door input module (under solaris, thus default off) - AC_ARG_ENABLE(imsolaris, -@@ -2312,6 +2325,7 @@ echo " imdiag enabled: - echo " file input module enabled: $enable_imfile" ++ + # settings for the docker log input module + AC_ARG_ENABLE(imdocker, + [AS_HELP_STRING([--enable-imdocker],[input docker module enabled @<:@default=no@:>@])], +@@ -2529,6 +2543,7 @@ echo " file input module enabled: $e + echo " docker log input module enabled: $enable_imdocker" echo " Solaris input module enabled: $enable_imsolaris" echo " periodic statistics module enabled: $enable_impstats" -+echo " syslog(3) unix socket uses RFC5424: $enable_imuxsock_rfc5424" - echo " imzmq3 input module enabled: $enable_imzmq3" ++echo " syslog(3) unix socket uses RFC5424: $enable_imuxsock_rfc5424" echo " imczmq input module enabled: $enable_imczmq" echo " imjournal input module enabled: $enable_imjournal" + echo " imbatchreport input module enabled: $enable_imbatchreport"