Index: head/net/openbgpd/Makefile =================================================================== --- head/net/openbgpd/Makefile (revision 305847) +++ head/net/openbgpd/Makefile (revision 305848) @@ -1,56 +1,52 @@ -# New ports collection makefile for: openbgpd -# Date created: May 10 2005 -# Whom: Florent Thoumie -# +# Created by: Florent Thoumie # $FreeBSD$ -# PORTNAME= openbgpd -PORTVERSION= 4.9.20110612 -PORTREVISION= 1 +PORTVERSION= 5.2.20121014 CATEGORIES= net MASTER_SITES= ${MASTER_SITE_OPENBSD} MASTER_SITE_SUBDIR= OpenBGPD DISTNAME= ${PORTNAME}-4.6 EXTRACT_SUFX= .tgz DIST_SUBDIR= ${PORTNAME} MAINTAINER= hrs@FreeBSD.org COMMENT= Free implementation of the Border Gateway Protocol, Version 4 CONFLICTS= zebra-[0-9]* quagga-[0-9]* -OPTIONS= IPV6LLPEER \ - "Support nexthop using IPv6 link-local address" on +OPTIONS_DEFINE= IPV6LLPEER +OPTIONS_DEFAULT=IPV6LLPEER +IPV6LLPEER_DESC=Support nexthop using IPv6 link-local address .include .if ${OSVERSION} < 700000 BROKEN= does not build .endif WRKSRC= ${WRKDIR} MANCOMPRESSED= yes USE_RC_SUBR= ${PORTNAME} PLIST_FILES= sbin/bgpctl sbin/bgpd SUB_FILES= pkg-message USERS= _bgpd GROUPS= _bgpd MAN5= bgpd.conf.5 MAN8= bgpctl.8 bgpd.8 .if !defined(WITHOUT_IPV6LLPEER) MAKE_ARGS= -DIPV6_LINKLOCAL_PEER .endif post-patch: @${REINPLACE_CMD} -e "s|%%PREFIX%%|${PREFIX}|g" \ ${WRKSRC}/bgpd/bgpd.8 \ ${WRKSRC}/bgpd/bgpd.conf.5 \ ${WRKSRC}/bgpctl/bgpctl.8 post-install: @${CAT} ${PKGMESSAGE} .include Index: head/net/openbgpd/files/patch-bgpctl_Makefile =================================================================== --- head/net/openbgpd/files/patch-bgpctl_Makefile (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_Makefile (revision 305848) @@ -1,30 +1,31 @@ Index: bgpctl/Makefile =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/Makefile,v retrieving revision 1.1.1.1 -retrieving revision 1.3 -diff -u -p -r1.1.1.1 -r1.3 +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 2 Jul 2011 16:06:35 -0000 1.3 ++++ 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 ++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: head/net/openbgpd/files/patch-bgpctl_bgpctl.8 =================================================================== --- head/net/openbgpd/files/patch-bgpctl_bgpctl.8 (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_bgpctl.8 (revision 305848) @@ -1,123 +1,287 @@ Index: bgpctl/bgpctl.8 =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.8,v retrieving revision 1.1.1.6 -retrieving revision 1.5 -diff -u -p -r1.1.1.6 -r1.5 +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 2 Jul 2011 16:06:35 -0000 1.5 ++++ 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.52 2009/11/03 08:09:15 jmc 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 3 2010 $ ++.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,8 +113,10 @@ Note that the neighbor is not obliged to +@@ -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 -@@ -122,7 +139,7 @@ view of the Forwarding Information Base. + 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,6 +150,14 @@ Show only routes originating from +@@ -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. -@@ -243,10 +268,12 @@ and message counters. ++.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 Property changes on: head/net/openbgpd/files/patch-bgpctl_bgpctl.8 ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpctl_bgpctl.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_bgpctl.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_bgpctl.c (revision 305848) @@ -1,819 +1,1518 @@ Index: bgpctl/bgpctl.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.c,v retrieving revision 1.1.1.7 -retrieving revision 1.8 -diff -u -p -r1.1.1.7 -r1.8 +diff -u -p -r1.1.1.7 bgpctl.c --- bgpctl/bgpctl.c 14 Feb 2010 20:20:14 -0000 1.1.1.7 -+++ bgpctl/bgpctl.c 2 Jul 2011 16:06:35 -0000 1.8 ++++ bgpctl/bgpctl.c 13 Oct 2012 18:49:31 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.c,v 1.142 2009/06/06 06:33:15 eric Exp $ */ -+/* $OpenBSD: bgpctl.c,v 1.157 2010/03/08 17:02:19 claudio Exp $ */ ++/* $OpenBSD: bgpctl.c,v 1.165 2012/09/12 05:57:10 claudio 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" -@@ -38,6 +50,10 @@ +@@ -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, - NV_TIMERS -@@ -50,12 +66,13 @@ int show_summary_msg(struct imsg *, in +@@ -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 +82,7 @@ void show_interface_head(void); +@@ -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); -@@ -74,7 +91,6 @@ void print_flags(u_int8_t, int); +@@ -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 *); -@@ -98,7 +114,7 @@ int + 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 +144,11 @@ main(int argc, char *argv[]) +@@ -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)); -@@ -164,24 +183,32 @@ main(int argc, char *argv[]) +@@ -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 +219,7 @@ main(int argc, char *argv[]) +@@ -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 +233,7 @@ main(int argc, char *argv[]) +@@ -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; -@@ -220,7 +247,7 @@ main(int argc, char *argv[]) - memcpy(&ribreq.neighbor, &neighbor, - sizeof(ribreq.neighbor)); +@@ -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)) -@@ -237,12 +264,14 @@ main(int argc, char *argv[]) + 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 +319,21 @@ main(int argc, char *argv[]) +@@ -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 +342,13 @@ main(int argc, char *argv[]) +@@ -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 +367,8 @@ main(int argc, char *argv[]) +@@ -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 +396,6 @@ main(int argc, char *argv[]) +@@ -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 +410,8 @@ main(int argc, char *argv[]) +@@ -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 +437,8 @@ fmt_peer(const char *descr, const struct +@@ -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 { -@@ -521,13 +560,15 @@ show_neighbor_msg(struct imsg *imsg, enu +@@ -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,6 +590,10 @@ show_neighbor_msg(struct imsg *imsg, enu +@@ -549,6 +643,10 @@ 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); -@@ -563,17 +608,16 @@ show_neighbor_msg(struct imsg *imsg, enu +@@ -563,22 +661,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.restart || p->capa.peer.as4byte) { ++ 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"); -@@ -633,20 +677,16 @@ show_neighbor_msg(struct imsg *imsg, enu +- 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 +733,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 -@@ -680,7 +720,7 @@ print_neighbor_msgstats(struct peer *p) +@@ -654,17 +772,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 +791,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 +785,12 @@ show_fib_head(void) +@@ -745,6 +865,12 @@ show_fib_head(void) } void +show_fib_tables_head(void) +{ + printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); +} + +void show_network_head(void) { printf("flags: S = Static\n"); -@@ -788,56 +834,44 @@ show_fib_flags(u_int16_t flags) +@@ -788,56 +914,44 @@ show_fib_flags(u_int16_t flags) int show_fib_msg(struct imsg *imsg) { - struct kroute *k; - struct kroute6 *k6; + struct kroute_full *kf; + struct ktable *kt; char *p; switch (imsg->hdr.type) { case IMSG_CTL_KROUTE: case IMSG_CTL_SHOW_NETWORK: - if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) + if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf)) errx(1, "wrong imsg len"); - k = imsg->data; + kf = imsg->data; - show_fib_flags(k->flags); + show_fib_flags(kf->flags); - if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) == - -1) + if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), + kf->prefixlen) == -1) err(1, NULL); - printf("%4i %-20s ", k->priority, p); + printf("%4i %-20s ", kf->priority, p); free(p); - if (k->nexthop.s_addr) - printf("%s", inet_ntoa(k->nexthop)); - else if (k->flags & F_CONNECTED) - printf("link#%u", k->ifindex); + if (kf->flags & F_CONNECTED) + printf("link#%u", kf->ifindex); + else + printf("%s", log_addr(&kf->nexthop)); printf("\n"); break; - case IMSG_CTL_KROUTE6: - case IMSG_CTL_SHOW_NETWORK6: - if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute6)) + case IMSG_CTL_SHOW_FIB_TABLES: + if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt)) errx(1, "wrong imsg len"); - k6 = imsg->data; + kt = imsg->data; - show_fib_flags(k6->flags); - - if (asprintf(&p, "%s/%u", log_in6addr(&k6->prefix), - k6->prefixlen) == -1) - err(1, NULL); - printf("%4i %-20s ", k6->priority, p); - free(p); - - if (!IN6_IS_ADDR_UNSPECIFIED(&k6->nexthop)) - printf("%s", log_in6addr(&k6->nexthop)); - else if (k6->flags & F_CONNECTED) - printf("link#%u", k6->ifindex); - printf("\n"); + printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, + kt->fib_sync ? "coupled" : "decoupled", + kt->fib_sync != kt->fib_conf ? "*" : ""); break; case IMSG_CTL_END: return (1); - break; default: break; } -@@ -848,35 +882,70 @@ show_fib_msg(struct imsg *imsg) +@@ -848,35 +962,70 @@ show_fib_msg(struct imsg *imsg) void show_nexthop_head(void) { - printf("%-20s %-10s\n", "Nexthop", "State"); + printf("Flags: * = nexthop valid\n"); + printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", + "Prio", "Gateway", "Iface"); } int show_nexthop_msg(struct imsg *imsg) { struct ctl_show_nexthop *p; - int ifms_type; + struct kroute *k; + struct kroute6 *k6; + char *s; switch (imsg->hdr.type) { case IMSG_CTL_SHOW_NEXTHOP: p = imsg->data; - printf("%-20s %-10s", log_addr(&p->addr), - p->valid ? "valid" : "invalid"); + printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr)); + if (!p->krvalid) { + printf("\n"); + return (0); + } + switch (p->addr.aid) { + case AID_INET: + k = &p->kr.kr4; + if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), + k->prefixlen) == -1) + err(1, NULL); + printf("%-20s", s); + free(s); + printf("%3i %-15s ", k->priority, + k->flags & F_CONNECTED ? "connected" : + inet_ntoa(k->nexthop)); + break; + case AID_INET6: + k6 = &p->kr.kr6; + if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), + k6->prefixlen) == -1) + err(1, NULL); + printf("%-20s", s); + free(s); + printf("%3i %-15s ", k6->priority, + k6->flags & F_CONNECTED ? "connected" : + log_in6addr(&k6->nexthop)); + break; + default: + printf("unknown address family\n"); + return (0); + } if (p->kif.ifname[0]) { - printf("%-8s", p->kif.ifname); - if (p->kif.flags & IFF_UP) { - printf("UP"); - ifms_type = ift2ifm(p->kif.media_type); - if (ifms_type != 0) - printf(", %s, %s", - get_media_descr(ifms_type), - get_linkstate(ifms_type, - p->kif.link_state)); - if (p->kif.baudrate) { - printf(", "); - print_baudrate(p->kif.baudrate); - } - } + char *s1; + if (p->kif.baudrate) { + if (asprintf(&s1, ", %s", + get_baudrate(p->kif.baudrate, + "bps")) == -1) + err(1, NULL); + } else if (asprintf(&s1, ", %s", get_linkstate( + p->kif.media_type, p->kif.link_state)) == -1) + err(1, NULL); + if (asprintf(&s, "%s (%s%s)", p->kif.ifname, + p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1) + err(1, NULL); + printf("%-15s", s); + free(s1); + free(s); } printf("\n"); break; -@@ -898,9 +967,8 @@ show_interface_head(void) +@@ -898,9 +1047,8 @@ show_interface_head(void) "Link state"); } -const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; -const struct ifmedia_status_description - ifm_status_descriptions[] = IFM_STATUS_DESCRIPTIONS; +const struct if_status_description + if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; const struct ifmedia_description ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; -@@ -936,36 +1004,36 @@ get_media_descr(int media_type) +@@ -936,36 +1084,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"); -+ const struct if_status_description *p; -+ static char buf[8]; - +- - for (i = 0; ifm_status_valid_list[i] != 0; i++) - for (p = ifm_status_descriptions; p->ifms_valid != 0; p++) { - if (p->ifms_type != media_type || - p->ifms_valid != ifm_status_valid_list[i]) - continue; - if (LINK_STATE_IS_UP(link_state)) - return (p->ifms_string[1]); - return (p->ifms_string[0]); - } -- ++ const struct if_status_description *p; ++ static char buf[8]; + - return ("unknown link state"); + for (p = if_status_descriptions; p->ifs_string != NULL; p++) { + if (LINK_STATE_DESC_MATCH(p, media_type, link_state)) + return (p->ifs_string); + } + snprintf(buf, sizeof(buf), "[#%d]", link_state); + return (buf); } -void -print_baudrate(u_int64_t baudrate) +const char * +get_baudrate(u_int64_t baudrate, char *unit) { + static char bbuf[16]; + if (baudrate > IF_Gbps(1)) - printf("%llu GBit/s", baudrate / IF_Gbps(1)); -+ snprintf(bbuf, sizeof(bbuf), "%llu G%s", ++ 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), "%llu M%s", ++ 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), "%llu K%s", ++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " K%s", + baudrate / IF_Kbps(1), unit); else - printf("%llu Bit/s", baudrate); -+ snprintf(bbuf, sizeof(bbuf), "%llu %s", ++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " %s", + baudrate, unit); + + return (bbuf); } int -@@ -982,17 +1050,12 @@ show_interface_msg(struct imsg *imsg) +@@ -982,17 +1130,12 @@ show_interface_msg(struct imsg *imsg) printf("%-15s", k->flags & IFF_UP ? "UP" : ""); if ((ifms_type = ift2ifm(k->media_type)) != 0) - printf("%s, %s", get_media_descr(ifms_type), - get_linkstate(ifms_type, k->link_state)); - else if (k->link_state == LINK_STATE_UNKNOWN) - printf("unknown"); - else - printf("link state %u", k->link_state); + printf("%s, ", get_media_descr(ifms_type)); - if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { - printf(", "); - print_baudrate(k->baudrate); - } + printf("%s", get_linkstate(k->media_type, k->link_state)); + + if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) + printf(", %s", get_baudrate(k->baudrate, "Bit/s")); printf("\n"); break; case IMSG_CTL_END: -@@ -1011,7 +1074,7 @@ show_rib_summary_head(void) - printf( - "flags: * = Valid, > = Selected, I = via IBGP, A = Announced\n"); +@@ -1008,10 +1151,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 +1112,26 @@ print_flags(u_int8_t flags, int sum) +@@ -1049,26 +1192,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"); } } -@@ -1085,7 +1148,7 @@ show_rib_summary_msg(struct imsg *imsg) - memcpy(&rib, imsg->data, sizeof(rib)); +@@ -1077,27 +1224,14 @@ int + show_rib_summary_msg(struct imsg *imsg) + { + struct ctl_show_rib rib; +- char *aspath; + u_char *asdata; - print_prefix(&rib.prefix, rib.prefixlen, rib.flags); + 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(" %-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 +1246,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; - printf(" %5u %5u ", rib.local_pref, rib.med); - -@@ -1189,8 +1252,8 @@ show_rib_detail_msg(struct imsg *imsg, i - case ATTR_AGGREGATOR: - memcpy(&as, data, sizeof(as)); - memcpy(&id, data + sizeof(as), sizeof(id)); + 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)); -+ printf(" Aggregator: %s [%s]\n", -+ log_as(ntohl(as)), inet_ntoa(id)); - break; - case ATTR_ORIGINATOR_ID: - memcpy(&id, data, sizeof(id)); -@@ -1236,22 +1299,27 @@ fmt_mem(int64_t num) - return (buf); +- 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 +1272,128 @@ show_rib_detail_msg(struct imsg *imsg, i + return (0); } -+size_t pt_sizes[AID_MAX] = AID_PTSIZE; +-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); + - int - show_rib_memory_msg(struct imsg *imsg) ++ 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; -+ size_t pts = 0; -+ int i; +- 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"); +- switch (imsg->hdr.type) { +- case IMSG_CTL_SHOW_RIB_MEM: +- memcpy(&stats, imsg->data, sizeof(stats)); +- printf("RDE memory statistics\n"); - printf("%10lld IPv4 network entries using %s of memory\n", - (long long)stats.pt4_cnt, fmt_mem(stats.pt4_cnt * - sizeof(struct pt_entry4))); - if (stats.pt6_cnt != 0) - printf("%10lld IPv6 network entries using " - "%s of memory\n", (long long)stats.pt6_cnt, - fmt_mem(stats.pt6_cnt * sizeof(struct pt_entry6))); -+ for (i = 0; i < AID_MAX; i++) { -+ if (stats.pt_cnt[i] == 0) -+ continue; -+ pts += stats.pt_cnt[i] * pt_sizes[i]; -+ printf("%10lld %s network entries using %s of memory\n", -+ (long long)stats.pt_cnt[i], aid_vals[i].name, -+ fmt_mem(stats.pt_cnt[i] * pt_sizes[i])); -+ } - printf("%10lld rib entries using %s of memory\n", - (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt * - sizeof(struct rib_entry))); -@@ -1272,9 +1340,7 @@ show_rib_memory_msg(struct imsg *imsg) - (long long)stats.attr_refs); - printf("%10lld BGP attributes using %s of memory\n", - (long long)stats.attr_dcnt, fmt_mem(stats.attr_data)); +- printf("%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) + -+ printf("RIB using %s of memory\n", fmt_mem(pts + - stats.prefix_cnt * sizeof(struct prefix) + - stats.rib_cnt * sizeof(struct rib_entry) + - stats.path_cnt * sizeof(struct rde_aspath) + -@@ -1328,30 +1394,6 @@ show_community(u_char *data, u_int16_t l +- 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 +1436,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,28 +1414,29 @@ show_ext_community(u_char *data, u_int16 +@@ -1372,34 +1456,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%llx", log_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%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 +1620,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 +1823,9 @@ fatal(const char *emsg) + { + err(1, emsg); + } ++ ++void ++fatalx(const char *emsg) ++{ ++ errx(1, emsg); ++} Index: head/net/openbgpd/files/patch-bgpctl_irr_asset.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irr_asset.c (nonexistent) +++ head/net/openbgpd/files/patch-bgpctl_irr_asset.c (revision 305848) @@ -0,0 +1,14 @@ +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 Property changes on: head/net/openbgpd/files/patch-bgpctl_irr_asset.c ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpctl_irr_output.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irr_output.c (nonexistent) +++ head/net/openbgpd/files/patch-bgpctl_irr_output.c (revision 305848) @@ -0,0 +1,14 @@ +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 Property changes on: head/net/openbgpd/files/patch-bgpctl_irr_output.c ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpctl_irr_parser.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irr_parser.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_irr_parser.c (revision 305848) @@ -1,41 +1,48 @@ 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.4 -diff -u -p -r1.1.1.5 -r1.4 +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 4 Feb 2010 16:22:26 -0000 1.4 ++++ 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,7 +408,8 @@ parse_asset(char *key, char *val) +@@ -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 */ +- /* 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: head/net/openbgpd/files/patch-bgpctl_irr_prefix.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irr_prefix.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_irr_prefix.c (revision 305848) @@ -1,157 +1,157 @@ 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.7 -diff -u -p -r1.1.1.5 -r1.1.1.7 +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 12 Jun 2011 10:44:54 -0000 1.1.1.7 ++++ 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.18 2010/05/10 02:00:50 krw 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: head/net/openbgpd/files/patch-bgpctl_irrfilter.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irrfilter.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_irrfilter.c (revision 305848) @@ -1,18 +1,24 @@ Index: bgpctl/irrfilter.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irrfilter.c,v retrieving revision 1.1.1.1 -retrieving revision 1.2 -diff -u -p -r1.1.1.1 -r1.2 +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 30 Jun 2009 06:40:06 -0000 1.2 ++++ 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: head/net/openbgpd/files/patch-bgpctl_irrfilter.h =================================================================== --- head/net/openbgpd/files/patch-bgpctl_irrfilter.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_irrfilter.h (revision 305848) @@ -1,59 +1,59 @@ Index: bgpctl/irrfilter.h =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irrfilter.h,v retrieving revision 1.1.1.5 -retrieving revision 1.3 -diff -u -p -r1.1.1.5 -r1.3 +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 4 Feb 2010 16:22:26 -0000 1.3 ++++ 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.9 2009/09/08 16:11:36 sthen 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: head/net/openbgpd/files/patch-bgpctl_mrtparser.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_mrtparser.c (nonexistent) +++ head/net/openbgpd/files/patch-bgpctl_mrtparser.c (revision 305848) @@ -0,0 +1,977 @@ +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); ++ } ++} Property changes on: head/net/openbgpd/files/patch-bgpctl_mrtparser.c ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpctl_mrtparser.h =================================================================== --- head/net/openbgpd/files/patch-bgpctl_mrtparser.h (nonexistent) +++ head/net/openbgpd/files/patch-bgpctl_mrtparser.h (revision 305848) @@ -0,0 +1,122 @@ +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); Property changes on: head/net/openbgpd/files/patch-bgpctl_mrtparser.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpctl_parser.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_parser.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_parser.c (revision 305848) @@ -1,250 +1,400 @@ Index: bgpctl/parser.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/parser.c,v retrieving revision 1.1.1.6 -retrieving revision 1.6 -diff -u -p -r1.1.1.6 -r1.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 2 Jul 2011 16:06:35 -0000 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.61 2010/03/08 17:02:19 claudio Exp $ */ ++/* $OpenBSD: parser.c,v 1.64 2012/03/27 18:24:11 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer -@@ -16,6 +16,10 @@ +@@ -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 -@@ -52,7 +56,8 @@ enum token_type { + #include + #include ++#include + #include + #include + #include +@@ -52,7 +57,9 @@ enum token_type { PREPSELF, WEIGHT, FAMILY, - GETOPT + GETOPT, -+ RTABLE ++ RTABLE, ++ FILENAME }; enum getopts { -@@ -97,6 +102,9 @@ static const struct token t_prepself[]; +@@ -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 +113,7 @@ static const struct token t_main[] = { +@@ -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,6 +125,7 @@ static const struct token t_show[] = { +@@ -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,14 +138,15 @@ static const struct token t_show_summary }; +@@ -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[] = { -@@ -187,6 +198,7 @@ static const struct token t_show_neighbo + { 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} }; -@@ -311,6 +323,22 @@ static const struct token t_irrfilter_op +@@ -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 +432,22 @@ match_token(int *argc, char **argv[], co +@@ -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.aid = AID_INET; -+ } -+ if (!strcmp(word, "inet6") || -+ !strcasecmp(word, "IPv6")) { match++; t = &table[i]; - res.af = AF_INET; -+ res.aid = AID_INET6; ++ res.aid = AID_INET; } - if (!strcmp(word, "inet6") || !strcmp(word, "IPv6")) { -+ if (!strcasecmp(word, "VPNv4")) { ++ 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 +520,7 @@ match_token(int *argc, char **argv[], co +@@ -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++; -@@ -577,6 +613,9 @@ show_valid_args(const struct token table +@@ -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,7 +623,7 @@ show_valid_args(const struct token table +@@ -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"); -@@ -608,7 +647,7 @@ parse_addr(const char *word, struct bgpd + 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 +657,7 @@ parse_addr(const char *word, struct bgpd +@@ -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); } -@@ -663,15 +696,15 @@ parse_prefix(const char *word, struct bg +@@ -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 +739,7 @@ parse_asnum(const char *word, u_int32_t +@@ -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 +763,11 @@ parse_number(const char *word, struct pa +@@ -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 +920,14 @@ bgpctl_getopt(int *argc, char **argv[], +@@ -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: head/net/openbgpd/files/patch-bgpctl_parser.h =================================================================== --- head/net/openbgpd/files/patch-bgpctl_parser.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_parser.h (revision 305848) @@ -1,44 +1,55 @@ 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.8 -diff -u -p -r1.1.1.6 -r1.1.1.8 +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 12 Jun 2011 10:44:54 -0000 1.1.1.8 ++++ 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.22 2010/05/03 13:11:41 claudio Exp $ */ ++/* $OpenBSD: parser.h,v 1.23 2011/09/21 10:37:51 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer -@@ -29,6 +29,7 @@ enum actions { +@@ -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, -@@ -37,6 +38,8 @@ enum actions { + SHOW_INTERFACE, +@@ -37,6 +39,8 @@ enum actions { FIB, FIB_COUPLE, FIB_DECOUPLE, + LOG_VERBOSE, + LOG_BRIEF, NEIGHBOR, NEIGHBOR_UP, NEIGHBOR_DOWN, -@@ -59,9 +62,10 @@ struct parse_result { +@@ -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: head/net/openbgpd/files/patch-bgpctl_whois.c =================================================================== --- head/net/openbgpd/files/patch-bgpctl_whois.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpctl_whois.c (revision 305848) @@ -1,24 +1,18 @@ 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.6 -diff -u -p -r1.1.1.5 -r1.1.1.6 +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 14 Feb 2010 20:27:21 -0000 1.1.1.6 -@@ -1,4 +1,4 @@ --/* $OpenBSD: whois.c,v 1.3 2007/03/05 16:43:24 henning Exp $ */ -+/* $OpenBSD: whois.c,v 1.4 2009/09/08 15:40:25 claudio Exp $ */ - - /* - * Copyright (c) 2007 Henning Brauer ++++ 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: head/net/openbgpd/files/patch-bgpd_Makefile =================================================================== --- head/net/openbgpd/files/patch-bgpd_Makefile (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_Makefile (revision 305848) @@ -1,38 +1,37 @@ Index: bgpd/Makefile =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/Makefile,v retrieving revision 1.1.1.2 -retrieving revision 1.8 -diff -u -p -r1.1.1.2 -r1.8 +retrieving revision 1.9 +diff -u -p -r1.1.1.2 -r1.9 --- bgpd/Makefile 9 Jul 2009 16:49:54 -0000 1.1.1.2 -+++ bgpd/Makefile 3 Jul 2011 04:46:36 -0000 1.8 ++++ bgpd/Makefile 13 Oct 2012 18:36:00 -0000 1.9 @@ -1,15 +1,25 @@ --# $OpenBSD: Makefile,v 1.28 2009/06/25 14:14:54 deraadt Exp $ -+# $OpenBSD: Makefile,v 1.29 2010/05/26 16:44:32 nicm Exp $ -+ + # $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 + control.c pfkey_compat.c rde_update.c rde_attr.c printconf.c \ + rde_filter.c pftable.c name2id.c util.c carp.c timer.c \ + imsg.c imsg-buffer.c CFLAGS+= -Wall -I${.CURDIR} +CFLAGS+= -I${.CURDIR}/../openbsd-compat CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wsign-compare +CFLAGS+= -DCONFFILE=\"${CONFFILE}\" +.if defined(IPV6_LINKLOCAL_PEER) +CFLAGS+= -DIPV6_LINKLOCAL_PEER +.endif YFLAGS= MAN= bgpd.8 bgpd.conf.5 Property changes on: head/net/openbgpd/files/patch-bgpd_Makefile ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_bgpd.8 =================================================================== --- head/net/openbgpd/files/patch-bgpd_bgpd.8 (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_bgpd.8 (revision 305848) @@ -1,164 +1,348 @@ Index: bgpd/bgpd.8 =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.8,v retrieving revision 1.1.1.8 -retrieving revision 1.9 -diff -u -p -r1.1.1.8 -r1.9 +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 2 Jul 2011 16:06:38 -0000 1.9 ++++ 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.33 2009/12/16 15:40:55 claudio 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: June 27 2010 $ ++.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,15 @@ concerning +@@ -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. - Please refer to that document for more information about BGP. ++.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 +113,16 @@ Use +@@ -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 -@@ -150,9 +137,9 @@ control socket +@@ -149,55 +227,144 @@ control socket + .Xr bgpctl 8 , .Xr bgplg 8 , .Xr bgplgsh 8 ++.Sh STANDARDS .Rs -.%R RFC 1771 -+.%R RFC 4271 - .%T "A Border Gateway Protocol 4 (BGP-4)" +-.%T "A Border Gateway Protocol 4 (BGP-4)" -.%D March 1995 -+.%D January 2006 +-.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 1997 -@@ -165,6 +152,11 @@ control socket +-.%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 2545 -+.%T "Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing" +-.%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 -+.Re -+.Rs - .%R RFC 2796 - .%T "BGP Route Reflection - An Alternative to Full Mesh IBGP" - .%D April 2000 -@@ -175,11 +167,6 @@ control socket ++.%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 --.Re --.Rs - .%R RFC 3682 - .%T "The Generalized TTL Security Mechanism (GTSM)" - .%D February 2004 -@@ -190,6 +177,21 @@ control socket - .%D April 2004 ++.%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" ++.%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 -+.%R RFC 4364 -+.%T "BGP/MPLS IP Virtual Private Networks (VPNs)" -+.%D February 2006 ++.%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 -+.%R RFC 4486 -+.%T "BGP Cease Notification Message Subcodes" ++.%A E. Chen ++.%A V. Gillet +.%D April 2006 ++.%R RFC 4486 ++.%T Subcodes for BGP Cease Notification Message +.Re ++.Pp +.Rs - .%R RFC 4760 - .%T "Multiprotocol Extensions for BGP-4" ++.%A T. Bates ++.%A R. Chandra ++.%A D. Katz ++.%A Y. Rekhter .%D January 2007 -@@ -199,6 +201,21 @@ control socket - .%T "BGP Support for Four-octet AS Number Space" - .%D May 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 -+.%R RFC 5492 -+.%T "Capabilities Advertisement with BGP-4" ++.%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 -+.%R draft-ietf-idr-optional-transitive-00 -+.%T "Error Handling for Optional Transitive BGP Attributes" +.%D April 2009 ++.%R draft-ietf-idr-optional-transitive-00 ++.%T Error Handling for Optional Transitive BGP Attributes +.Re ++.Pp +.Rs -+.%R draft-ietf-idr-fsm-subcode-00 -+.%T "Subcodes for BGP Finite State Machine Error" -+.%D September 2010 ++.%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 - .Nm Property changes on: head/net/openbgpd/files/patch-bgpd_bgpd.8 ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_bgpd.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_bgpd.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_bgpd.c (revision 305848) @@ -1,648 +1,692 @@ Index: bgpd/bgpd.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.c,v retrieving revision 1.1.1.7 -diff -u -p -r1.1.1.7 bgpd.c +retrieving revision 1.1.1.11 +diff -u -p -r1.1.1.7 -r1.1.1.11 --- bgpd/bgpd.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/bgpd.c 3 Jul 2011 04:34:14 -0000 ++++ bgpd/bgpd.c 13 Oct 2012 18:22:38 -0000 1.1.1.11 @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.148 2009/06/07 00:30:23 claudio Exp $ */ -+/* $OpenBSD: bgpd.c,v 1.167 2011/05/01 10:42:28 claudio Exp $ */ ++/* $OpenBSD: bgpd.c,v 1.168 2011/08/20 19:02:28 sthen 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,22 @@ int main(int, char *[]); +@@ -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 +85,8 @@ usage(void) +@@ -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 +100,10 @@ int +@@ -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; -@@ -125,17 +119,11 @@ main(int argc, char *argv[]) +@@ -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 +146,7 @@ main(int argc, char *argv[]) +@@ -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 +159,22 @@ main(int argc, char *argv[]) +@@ -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"); -@@ -225,13 +206,9 @@ main(int argc, char *argv[]) +@@ -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 +231,12 @@ main(int argc, char *argv[]) +@@ -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; -@@ -336,8 +292,7 @@ main(int argc, char *argv[]) +@@ -335,15 +294,16 @@ main(int argc, char *argv[]) + u_int error; reconfig = 0; - log_info("rereading config"); +- log_info("rereading config"); - switch (reconfigure(conffile, &conf, &mrt_l, &peer_l, - rules_l)) { + switch (reconfigure(conffile, &conf, &mrt_l, &peer_l)) { case -1: /* fatal error */ quit = 1; break; -@@ -389,13 +344,13 @@ main(int argc, char *argv[]) + 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 +368,8 @@ main(int argc, char *argv[]) +@@ -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 +409,25 @@ send_filterset(struct imsgbuf *i, struct +@@ -452,27 +414,32 @@ 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); return (1); } cflags = conf->flags; - connectset = &conf->connectset; - staticset = &conf->staticset; - connectset6 = &conf->connectset6; - staticset6 = &conf->staticset6; - prepare_listeners(conf); /* start reconfiguration */ -@@ -483,12 +438,6 @@ reconfigure(char *conffile, struct bgpd_ +@@ -483,12 +450,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 +445,104 @@ reconfigure(char *conffile, struct bgpd_ +@@ -496,51 +457,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 +552,8 @@ int +@@ -550,8 +564,8 @@ int dispatch_imsg(struct imsgbuf *ibuf, int idx) { struct imsg imsg; - int n; - int rv; + ssize_t n; + int rv, verbose; if ((n = imsg_read(ibuf)) == -1) return (-1); -@@ -573,46 +575,39 @@ dispatch_imsg(struct imsgbuf *ibuf, int +@@ -573,46 +587,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) -@@ -654,18 +649,19 @@ dispatch_imsg(struct imsgbuf *ibuf, int +@@ -646,26 +653,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 +688,11 @@ dispatch_imsg(struct imsgbuf *ibuf, int +@@ -692,6 +701,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 +708,7 @@ send_nexthop_update(struct kroute_nextho +@@ -707,7 +726,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 +718,7 @@ send_nexthop_update(struct kroute_nextho +@@ -717,7 +736,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 +734,20 @@ send_imsg_session(int type, pid_t pid, v +@@ -733,56 +752,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 +775,45 @@ bgpd_filternexthop(struct kroute *kr, st +@@ -810,3 +793,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: head/net/openbgpd/files/patch-bgpd_bgpd.conf.5 =================================================================== --- head/net/openbgpd/files/patch-bgpd_bgpd.conf.5 (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_bgpd.conf.5 (revision 305848) @@ -1,660 +1,734 @@ 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.8 -diff -u -p -r1.1.1.7 -r1.8 +retrieving revision 1.9 +diff -u -p -r1.1.1.7 -r1.9 --- bgpd/bgpd.conf.5 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/bgpd.conf.5 2 Jul 2011 16:06:38 -0000 1.8 ++++ bgpd/bgpd.conf.5 13 Oct 2012 18:36:00 -0000 1.9 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bgpd.conf.5,v 1.94 2009/06/07 00:31:22 claudio Exp $ -+.\" $OpenBSD: bgpd.conf.5,v 1.104 2010/03/05 15:25:00 claudio Exp $ ++.\" $OpenBSD: bgpd.conf.5,v 1.120 2012/07/07 08:22:57 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: October 23 2010 $ ++.Dd $Mdocdate: July 7 2012 $ .Dt BGPD.CONF 5 .Os .Sh NAME -@@ -26,7 +26,7 @@ +@@ -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 -@@ -93,7 +95,7 @@ Set the local +@@ -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,13 +145,13 @@ The default is 120 seconds. +@@ -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 ++.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 -@@ -195,7 +197,7 @@ dump updates out "/tmp/updates-out-%H%M" + .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 +244,12 @@ Log received and sent updates. +@@ -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 +280,7 @@ section. +@@ -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,7 +297,7 @@ daemons like +@@ -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 , -@@ -313,20 +315,31 @@ is only compared between peers belonging + 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 +352,7 @@ The default is +@@ -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 +374,24 @@ to the local machine. +@@ -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 +400,111 @@ to EBGP neighbors are not prepended with +@@ -376,6 +409,111 @@ 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 Route Distinguishers uniquely identifies a set of VPN prefixes. -+Only prefixes matching the ++The sole purpose of the Route Distinguisher +.Ic rd -+will be imported into the routing domain. -+The purpose of the ++is to ensure that possible common prefixes are destinct between VPNs. ++The +.Ic rd -+is solely to allow one to create distinct routes to a common address prefix. ++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. +.Pp +.El .Sh NEIGHBORS AND GROUPS .Xr bgpd 8 establishes TCP connections to other BGP speakers called -@@ -470,21 +599,35 @@ The default for IBGP peers is +@@ -470,21 +608,35 @@ The default for IBGP peers is .Pp .It Xo .Ic announce -.Pq Ic IPv4 Ns \&| Ns Ic IPv6 -.Pq Ic none Ns \&| Ns Ic unicast +.Pq Ic IPv4 Ns | Ns Ic IPv6 +.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn .Xc For the given address family, control which subsequent address families (at the moment, only .Em none , -which disables the announcement of that address family, and -.Em unicast -are supported) are announced during the capabilities negotiation. +which disables the announcement of that address family, +.Em unicast , +and +.Em vpn , +which allows the distribution of BGP MPLS VPNs, are supported) are announced +during the capabilities negotiation. Only routes for that address family and subsequent address family will be announced and processed. .Pp .It Xo +.Ic announce as-4byte +.Pq Ic yes Ns | Ns Ic no +.Xc +If set to +.Ic no , +the 4-byte AS capability is not announced and so native 4-byte AS support is +disabled. +The default is +.Ic yes . +.Pp +.It Xo .Ic announce capabilities -.Pq Ic yes Ns \&| Ns Ic no +.Pq Ic yes Ns | Ns Ic no .Xc If set to .Ic no , -@@ -493,6 +636,29 @@ This can be helpful to connect to old or +@@ -493,6 +645,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 +670,7 @@ The demotion counter will be increased a +@@ -504,7 +679,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 +714,8 @@ Do not start the session when bgpd comes +@@ -548,8 +723,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 +730,7 @@ section in +@@ -564,7 +739,7 @@ section in .Pp .It Xo .Ic enforce neighbor-as -.Pq Ic yes Ns \&| Ns Ic no +.Pq Ic yes Ns | Ns Ic no .Xc If set to .Ic yes , -@@ -589,10 +755,16 @@ Inherited from the global configuration +@@ -589,10 +764,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 +799,7 @@ Keys must be given in hexadecimal format +@@ -627,7 +808,7 @@ Keys must be given in hexadecimal format .Pp .It Xo .Ic ipsec -.Pq Ic ah Ns \&| Ns Ic esp +.Pq Ic ah Ns | Ns Ic esp .Ic ike .Xc Enable IPsec with dynamic keying. -@@ -639,11 +811,11 @@ is responsible for managing the session +@@ -639,11 +820,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,7 +870,7 @@ Do not attempt to actively open a TCP co +@@ -698,11 +879,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 -@@ -732,8 +904,8 @@ These sets are rewritten into filter rul +-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 +913,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 +932,7 @@ tcp md5sig key deadbeef +@@ -760,7 +941,7 @@ tcp md5sig key deadbeef .Pp .It Xo .Ic transparent-as -.Pq Ic yes Ns \&| Ns Ic no +.Pq Ic yes Ns | Ns Ic no .Xc If set to .Ic yes , -@@ -772,7 +944,7 @@ setting. +@@ -772,7 +953,7 @@ setting. .Pp .It Xo .Ic ttl-security -.Pq Ic yes Ns \&| Ns Ic no +.Pq Ic yes Ns | Ns Ic no .Xc Enable or disable ttl-security. When enabled, -@@ -849,6 +1021,10 @@ is matched against a part of the +@@ -849,6 +1030,10 @@ is matched against a part of the .Em AS path specified by the .Ar as-type . +.Ar as-number +may be set to +.Ic neighbor-as , +which is expanded to the current neighbor remote AS number. .Ar as-type is one of the following operators: .Pp -@@ -917,7 +1093,32 @@ may be set to +@@ -917,7 +1102,32 @@ may be set to which is expanded to the current neighbor remote AS number. .Pp .It Xo -.Pq Ic from Ns \&| Ns Ic to +.Ic ext-community +.Ar subtype Ar as-number Ns Li : Ns Ar local +.Xc +.It Xo +.Ic ext-community +.Ar subtype Ar IP Ns Li : Ns Ar local +.Xc +.It Xo +.Ic ext-community +.Ar subtype Ar numvalue +.Xc +This rule applies only to +.Em UPDATES +where the +.Em extended community +path attribute is present and matches. +Extended Communities are specified by a +.Ar subtype +and normally two values, a globally unique part (e.g. the AS number) and a +local part. +See also the +.Sx ATTRIBUTE SET +section for further information about the encoding. +.Pp +.It Xo +.Pq Ic from Ns | Ns Ic to .Ar peer .Xc This rule applies only to -@@ -945,7 +1146,7 @@ if enclosed in curly brackets: +@@ -945,7 +1155,7 @@ if enclosed in curly brackets: deny from { 128.251.16.1, 251.128.16.2, group hojo } .Ed .Pp -.It Pq Ic inet Ns \&| Ns Ic inet6 +.It Pq Ic inet Ns | Ns Ic inet6 This rule applies only to routes matching the stated address family. The address family needs to be set only in rules that use .Ic prefixlen -@@ -953,6 +1154,24 @@ without specifying a +@@ -953,6 +1163,24 @@ without specifying a .Ic prefix beforehand. .Pp +.It Ic max-as-len Ar len +This rule applies only to +.Em UPDATES +where the +.Em AS path +has more than +.Ar len +elements. +.Pp +.It Ic max-as-seq Ar len +This rule applies only to +.Em UPDATES +where a single +.Em AS number +is repeated more than +.Ar len +times. +.Pp .It Xo .Ic prefix .Ar address Ns Li / Ns Ar len -@@ -1028,6 +1247,12 @@ matches a rule which has the +@@ -1028,6 +1256,12 @@ matches a rule which has the option set, this rule is considered the last matching rule, and evaluation of subsequent rules is skipped. .Pp +.It Ic rib Ar name +Apply rule only to the specified RIB. +This only applies for received updates, so not for rules using the +.Ar to peer +parameter. +.Pp .It Ic set Ar attribute ... All matching rules can set the .Em AS path attributes -@@ -1079,6 +1304,48 @@ Alternately, well-known communities may +@@ -1079,6 +1313,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 +1375,20 @@ otherwise it will be set to +@@ -1108,6 +1384,20 @@ otherwise it will be set to .Ar number . .Pp .It Xo +.Ic origin +.Sm off +.Po Ic igp \*(Ba +.Ic egp \*(Ba +.Ic incomplete Pc +.Sm on +.Xc +Set the +.Em ORIGIN +AS path attribute to mark the source of this +route as being injected from an igp protocol, an egp protocol +or being an aggregated route. +.Pp +.It Xo .Ic nexthop .Sm off .Po Ar address \*(Ba -@@ -1157,9 +1438,8 @@ times to the +@@ -1157,9 +1447,8 @@ times to the .Em AS path . .Pp .It Ic rtlabel Ar label -Add the prefix with the specified -.Ar label -to the kernel routing table. +Add the prefix to the kernel routing table with the specified +.Ar label . .Pp .It Ic weight Ar number The -@@ -1181,8 +1461,8 @@ For prefixes with equally long paths, th +@@ -1181,8 +1470,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 Property changes on: head/net/openbgpd/files/patch-bgpd_bgpd.conf.5 ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_bgpd.h =================================================================== --- head/net/openbgpd/files/patch-bgpd_bgpd.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_bgpd.h (revision 305848) @@ -1,680 +1,862 @@ Index: bgpd/bgpd.h =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.h,v retrieving revision 1.1.1.8 -retrieving revision 1.12 -diff -u -p -r1.1.1.8 -r1.12 +retrieving revision 1.13 +diff -u -p -r1.1.1.8 -r1.13 --- bgpd/bgpd.h 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/bgpd.h 2 Jul 2011 16:06:38 -0000 1.12 ++++ bgpd/bgpd.h 13 Oct 2012 18:36:00 -0000 1.13 @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.241 2009/06/12 16:42:53 claudio Exp $ */ -+/* $OpenBSD: bgpd.h,v 1.255 2010/04/06 13:25:08 claudio Exp $ */ ++/* $OpenBSD: bgpd.h,v 1.272 2012/09/18 09:45:51 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,6 +82,8 @@ +@@ -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 -@@ -109,18 +110,74 @@ enum reconf_action { ++#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 +198,12 @@ TAILQ_HEAD(listen_addrs, listen_addr); +@@ -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,11 +257,10 @@ struct peer_auth { +@@ -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 */ -+ int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */ -+ int8_t refresh; /* route refresh, RFC 2918 */ -+ int8_t restart; /* graceful restart, RFC 4724 */ -+ int8_t as4byte; /* draft-ietf-idr-as4bytes-13 */ - }; +-}; ++ struct { ++ 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 { -@@ -248,21 +299,31 @@ 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_CONNECTED, ++ NETWORK_MRTCLONE +}; + struct network_config { - struct bgpd_addr prefix; - struct filter_set_head attrset; -+ u_int rtableid; -+ enum network_type type; - u_int8_t prefixlen; -+ u_int8_t old; /* used for reloading */ +- 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 +337,6 @@ 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,10 +348,11 @@ enum imsg_type { +@@ -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, -@@ -302,6 +363,11 @@ enum imsg_type { + 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, -@@ -313,8 +379,6 @@ enum imsg_type { + 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, -@@ -379,9 +443,43 @@ enum suberr_cease { +@@ -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 +498,12 @@ struct kroute6 { +@@ -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 +519,7 @@ 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 +532,13 @@ struct pftable_msg { +@@ -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 +547,10 @@ 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; -@@ -498,16 +588,52 @@ enum as_spec { +@@ -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 +644,8 @@ struct ctl_show_rib_request { +@@ -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 +711,28 @@ struct filter_peers { +@@ -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 { -@@ -594,16 +742,18 @@ struct filter_prefix { +@@ -594,16 +757,18 @@ struct filter_prefix { struct filter_prefixlen { enum comp_ops op; - sa_family_t af; + u_int8_t aid; u_int8_t len_min; u_int8_t len_max; }; struct filter_match { - struct filter_prefix prefix; - struct filter_prefixlen prefixlen; - struct filter_as as; - struct filter_community community; + struct filter_prefix prefix; + struct filter_prefixlen prefixlen; + struct filter_as as; + struct filter_aslen aslen; + struct filter_community community; + struct filter_extcommunity ext_community; }; TAILQ_HEAD(filter_head, filter_rule); -@@ -635,10 +785,13 @@ enum action_types { +@@ -635,10 +800,13 @@ enum action_types { ACTION_SET_NEXTHOP_SELF, ACTION_SET_COMMUNITY, ACTION_DEL_COMMUNITY, + ACTION_SET_EXT_COMMUNITY, + ACTION_DEL_EXT_COMMUNITY, ACTION_PFTABLE, ACTION_PFTABLE_ID, ACTION_RTLABEL, - ACTION_RTLABEL_ID + ACTION_RTLABEL_ID, + ACTION_SET_ORIGIN }; struct filter_set { -@@ -650,23 +803,53 @@ struct filter_set { +@@ -650,23 +818,53 @@ struct filter_set { int32_t relative; struct bgpd_addr nexthop; struct filter_community community; + struct filter_extcommunity ext_community; char pftable[PFTABLE_LEN]; char rtlabel[RTLABEL_LEN]; + u_int8_t origin; } action; enum action_types type; }; -struct rrefresh { - u_int16_t afi; - u_int8_t safi; +struct rdomain { + SIMPLEQ_ENTRY(rdomain) entry; + char descr[PEER_DESCR_LEN]; + char ifmpe[IFNAMSIZ]; + struct filter_set_head import; + struct filter_set_head export; + struct network_head net_l; + u_int64_t rd; + u_int rtableid; + u_int label; + int flags; -+}; + }; +SIMPLEQ_HEAD(rdomain_head, rdomain); + +struct rde_rib { + SIMPLEQ_ENTRY(rde_rib) entry; + char name[PEER_DESCR_LEN]; + u_int rtableid; + u_int16_t id; + u_int16_t flags; - }; ++}; +SIMPLEQ_HEAD(rib_names, rde_rib); +extern struct rib_names ribnames; + +/* rde_rib flags */ +#define F_RIB_ENTRYLOCK 0x0001 +#define F_RIB_NOEVALUATE 0x0002 +#define F_RIB_NOFIB 0x0004 +#define F_RIB_NOFIBSYNC 0x0008 +#define F_RIB_HASNOFIB (F_RIB_NOFIB | F_RIB_NOEVALUATE) + +/* 4-byte magic AS number */ +#define AS_TRANS 23456 struct rde_memstats { int64_t path_cnt; int64_t prefix_cnt; int64_t rib_cnt; - int64_t pt4_cnt; - int64_t pt6_cnt; + int64_t pt_cnt[AID_MAX]; int64_t nexthop_cnt; int64_t aspath_cnt; int64_t aspath_size; -@@ -677,38 +860,29 @@ struct rde_memstats { +@@ -677,82 +875,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 */ ++#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) ++#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 -+/* macros for IPv6 link-local address */ -+#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) -+#define IN6_LINKLOCAL_IFINDEX(addr) \ -+ ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) -+ -+#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ -+ do { \ -+ (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ -+ (addr).s6_addr[3] = (index) & 0xff; \ -+ } while (0) -+#endif ++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 log_verbose(int); - void vlog(int, const char *, va_list); - void log_peer_warn(const struct peer_config *, const char *, ...); - void log_peer_warnx(const struct peer_config *, const char *, ...); -@@ -726,19 +900,22 @@ int cmdline_symset(char *); +-/* 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); -@@ -772,6 +949,8 @@ void pftable_ref(u_int16_t); +-/* 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 +1001,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 +958,20 @@ const char *log_addr(const struct bgpd_a +@@ -779,11 +1024,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__ */ Property changes on: head/net/openbgpd/files/patch-bgpd_bgpd.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_carp.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_carp.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_carp.c (revision 305848) @@ -1,54 +1,53 @@ 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 +diff -u -p -r1.1.1.6 carp.c --- 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 ++++ bgpd/carp.c 13 Oct 2012 18:23:46 -0000 @@ -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: head/net/openbgpd/files/patch-bgpd_config.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_config.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_config.c (revision 305848) @@ -1,109 +1,109 @@ Index: bgpd/config.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/config.c,v retrieving revision 1.1.1.6 -retrieving revision 1.2 -diff -u -p -r1.1.1.6 -r1.2 +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 2 Jul 2011 16:06:38 -0000 1.2 ++++ 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.56 2010/10/24 17:20:08 deraadt 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: head/net/openbgpd/files/patch-bgpd_control.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_control.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_control.c (revision 305848) @@ -1,148 +1,171 @@ 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.9 -diff -u -p -r1.1.1.7 -r1.1.1.9 +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 12 Jun 2011 10:44:24 -0000 1.1.1.9 ++++ 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.70 2010/10/29 12:51:53 henning 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); } -@@ -123,14 +123,14 @@ control_accept(int listenfd, int restric +@@ -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) +- 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); } -@@ -191,7 +191,8 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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 +306,8 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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 +330,19 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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 +360,19 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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 +384,7 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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 +411,7 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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; -@@ -425,6 +438,20 @@ control_dispatch_msg(struct pollfd *pfd, +@@ -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: head/net/openbgpd/files/patch-bgpd_kroute.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_kroute.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_kroute.c (revision 305848) @@ -1,2901 +1,3043 @@ Index: bgpd/kroute.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/kroute.c,v retrieving revision 1.1.1.7 -retrieving revision 1.12 -diff -u -p -r1.1.1.7 -r1.12 +retrieving revision 1.13 +diff -u -p -r1.1.1.7 -r1.13 --- bgpd/kroute.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/kroute.c 3 Jul 2011 04:46:36 -0000 1.12 ++++ bgpd/kroute.c 13 Oct 2012 18:36:00 -0000 1.13 @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.169 2009/06/25 15:54:22 claudio Exp $ */ -+/* $OpenBSD: kroute.c,v 1.176 2010/04/06 13:25:08 claudio Exp $ */ ++/* $OpenBSD: kroute.c,v 1.189 2012/05/27 18:52:07 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,15 @@ int kif_kr6_remove(struct kroute6_nod +@@ -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 +164,20 @@ void get_rtaddrs(int, struct sockaddr * +@@ -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 +185,21 @@ RB_HEAD(kif_tree, kif_node) kit; +@@ -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 +223,533 @@ kr_init(int fs, u_int rtableid) +@@ -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 + } + + int +-kr_change(struct kroute_label *kl) +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) ++} ++ ++int +kr_change(u_int rtableid, struct kroute_full *kl) +{ + struct ktable *kt; + + if ((kt = ktable_get(rtableid)) == NULL) + /* too noisy during reloads, just ignore */ + return (0); + switch (kl->prefix.aid) { + case AID_INET: + return (kr4_change(kt, kl)); + case AID_INET6: + return (kr6_change(kt, kl)); + case AID_VPN_IPv4: + return (krVPN4_change(kt, kl)); + } + log_warnx("kr_change: not handled AID"); + return (-1); +} + +int +kr4_change(struct ktable *kt, struct kroute_full *kl) { struct kroute_node *kr; int action = RTM_ADD; + u_int16_t labelid; - if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) - != NULL) + if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen, + RTP_BGP)) != NULL) action = RTM_CHANGE; /* nexthop within 127/8 -> ignore silently */ - if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) == + if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) == htonl(INADDR_LOOPBACK & IN_CLASSA_NET)) return (0); - if (kr) - rtlabel_unref(kr->r.labelid); - kl->kr.labelid = rtlabel_name2id(kl->label); + labelid = rtlabel_name2id(kl->label); /* for blackhole and reject routes nexthop needs to be 127.0.0.1 */ - if (kl->kr.flags & (F_BLACKHOLE|F_REJECT)) - kl->kr.nexthop.s_addr = htonl(INADDR_LOOPBACK); - - if (send_rtmsg(kr_state.fd, action, &kl->kr) == -1) - return (-1); + if (kl->flags & (F_BLACKHOLE|F_REJECT)) + kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK); if (action == RTM_ADD) { if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { log_warn("kr_change"); return (-1); } - kr->r.prefix.s_addr = kl->kr.prefix.s_addr; - kr->r.prefixlen = kl->kr.prefixlen; - kr->r.nexthop.s_addr = kl->kr.nexthop.s_addr; - kr->r.flags = kl->kr.flags | F_BGPD_INSERTED; + kr->r.prefix.s_addr = kl->prefix.v4.s_addr; + kr->r.prefixlen = kl->prefixlen; + kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr; + kr->r.flags = kl->flags | F_BGPD_INSERTED; kr->r.priority = RTP_BGP; - kr->r.labelid = kl->kr.labelid; + kr->r.labelid = labelid; - if (kroute_insert(kr) == -1) + if (kroute_insert(kt, kr) == -1) free(kr); } else { - kr->r.nexthop.s_addr = kl->kr.nexthop.s_addr; - kr->r.labelid = kl->kr.labelid; - if (kl->kr.flags & F_BLACKHOLE) + kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr; + rtlabel_unref(kr->r.labelid); + kr->r.labelid = labelid; + if (kl->flags & F_BLACKHOLE) kr->r.flags |= F_BLACKHOLE; else kr->r.flags &= ~F_BLACKHOLE; - if (kl->kr.flags & F_REJECT) + if (kl->flags & F_REJECT) kr->r.flags |= F_REJECT; else kr->r.flags &= ~F_REJECT; } + if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1) + return (-1); + return (0); } int -kr_delete(struct kroute_label *kl) +kr6_change(struct ktable *kt, struct kroute_full *kl) { - struct kroute_node *kr; + struct kroute6_node *kr6; + struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; + int action = RTM_ADD; + u_int16_t labelid; - if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) - == NULL) - return (0); + if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) != + NULL) + action = RTM_CHANGE; - if (!(kr->r.flags & F_BGPD_INSERTED)) + /* nexthop to loopback -> ignore silently */ + if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6)) return (0); - /* nexthop within 127/8 -> ignore silently */ - if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) == - htonl(INADDR_LOOPBACK & IN_CLASSA_NET)) - return (0); + labelid = rtlabel_name2id(kl->label); - if (send_rtmsg(kr_state.fd, RTM_DELETE, &kl->kr) == -1) - return (-1); + /* for blackhole and reject routes nexthop needs to be ::1 */ + if (kl->flags & (F_BLACKHOLE|F_REJECT)) + bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6)); -+ + +- 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; - -- rtlabel_unref(kl->kr.labelid); ++ + if (kroute6_insert(kt, kr6) == -1) + free(kr6); + } else { + memcpy(&kr6->r.nexthop, &kl->nexthop.v6, + sizeof(struct in6_addr)); + rtlabel_unref(kr6->r.labelid); + kr6->r.labelid = labelid; + if (kl->flags & F_BLACKHOLE) + kr6->r.flags |= F_BLACKHOLE; + else + kr6->r.flags &= ~F_BLACKHOLE; + if (kl->flags & F_REJECT) + kr6->r.flags |= F_REJECT; + else + kr6->r.flags &= ~F_REJECT; + } - if (kroute_remove(kr) == -1) + if (send_rt6msg(kr_state.fd, action, kt, &kr6->r) == -1) return (-1); return (0); } int -kr6_change(struct kroute6_label *kl) +krVPN4_change(struct ktable *kt, struct kroute_full *kl) { - struct kroute6_node *kr6; + struct kroute_node *kr; int action = RTM_ADD; - struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; + u_int32_t mplslabel = 0; + u_int16_t labelid; - if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) - != NULL) + if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen, + RTP_BGP)) != NULL) action = RTM_CHANGE; - /* nexthop to loopback -> ignore silently */ - if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop)) + /* nexthop within 127/8 -> ignore silently */ + if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) == + htonl(INADDR_LOOPBACK & IN_CLASSA_NET)) return (0); - if (kr6) - rtlabel_unref(kr6->r.labelid); - kl->kr.labelid = rtlabel_name2id(kl->label); + /* only single MPLS label are supported for now */ + if (kl->prefix.vpn4.labellen != 3) { + log_warnx("krVPN4_change: %s/%u has not a single label", + log_addr(&kl->prefix), kl->prefixlen); + return (0); + } + mplslabel = (kl->prefix.vpn4.labelstack[0] << 24) | + (kl->prefix.vpn4.labelstack[1] << 16) | + (kl->prefix.vpn4.labelstack[2] << 8); + mplslabel = htonl(mplslabel); - /* for blackhole and reject routes nexthop needs to be ::1 */ - if (kl->kr.flags & (F_BLACKHOLE|F_REJECT)) - bcopy(&lo6, &kl->kr.nexthop, sizeof(kl->kr.nexthop)); + labelid = rtlabel_name2id(kl->label); - if (send_rt6msg(kr_state.fd, action, &kl->kr) == -1) - return (-1); + /* for blackhole and reject routes nexthop needs to be 127.0.0.1 */ + if (kl->flags & (F_BLACKHOLE|F_REJECT)) + kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK); if (action == RTM_ADD) { - if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) { + if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { log_warn("kr_change"); return (-1); } - memcpy(&kr6->r.prefix, &kl->kr.prefix, - sizeof(struct in6_addr)); - kr6->r.prefixlen = kl->kr.prefixlen; - memcpy(&kr6->r.nexthop, &kl->kr.nexthop, - sizeof(struct in6_addr)); - kr6->r.flags = kl->kr.flags | F_BGPD_INSERTED; - kr6->r.priority = RTP_BGP; - kr6->r.labelid = kl->kr.labelid; + kr->r.prefix.s_addr = kl->prefix.vpn4.addr.s_addr; + kr->r.prefixlen = kl->prefixlen; + kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr; + kr->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS; + kr->r.priority = RTP_BGP; + kr->r.labelid = labelid; + kr->r.mplslabel = mplslabel; - if (kroute6_insert(kr6) == -1) - free(kr6); + if (kroute_insert(kt, kr) == -1) + free(kr); } else { - memcpy(&kr6->r.nexthop, &kl->kr.nexthop, - sizeof(struct in6_addr)); - kr6->r.labelid = kl->kr.labelid; - if (kl->kr.flags & F_BLACKHOLE) - kr6->r.flags |= F_BLACKHOLE; + kr->r.mplslabel = mplslabel; + kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr; + rtlabel_unref(kr->r.labelid); + kr->r.labelid = labelid; + if (kl->flags & F_BLACKHOLE) + kr->r.flags |= F_BLACKHOLE; else - kr6->r.flags &= ~F_BLACKHOLE; - if (kl->kr.flags & F_REJECT) - kr6->r.flags |= F_REJECT; + kr->r.flags &= ~F_BLACKHOLE; + if (kl->flags & F_REJECT) + kr->r.flags |= F_REJECT; else - kr6->r.flags &= ~F_REJECT; + kr->r.flags &= ~F_REJECT; -+ } -+ + } + + if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1) + return (-1); + -+ return (0); -+} -+ -+int + 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 kroute6_label *kl) ++ ++ return (0); ++} ++ ++int +kr6_delete(struct ktable *kt, struct kroute_full *kl) { struct kroute6_node *kr6; - if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) - == NULL) + if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) == + NULL) return (0); if (!(kr6->r.flags & F_BGPD_INSERTED)) return (0); - /* nexthop to loopback -> ignore silently */ - if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop)) + if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r) == -1) + return (-1); + + rtlabel_unref(kr6->r.labelid); + + if (kroute6_remove(kt, kr6) == -1) + return (-1); + + return (0); +} + +int +krVPN4_delete(struct ktable *kt, struct kroute_full *kl) +{ + struct kroute_node *kr; + + if ((kr = kroute_find(kt, kl->prefix.vpn4.addr.s_addr, kl->prefixlen, + RTP_BGP)) == NULL) return (0); - if (send_rt6msg(kr_state.fd, RTM_DELETE, &kl->kr) == -1) + if (!(kr->r.flags & F_BGPD_INSERTED)) + return (0); + + if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r) == -1) return (-1); - rtlabel_unref(kl->kr.labelid); + rtlabel_unref(kr->r.labelid); - if (kroute6_remove(kr6) == -1) + if (kroute_remove(kt, kr) == -1) return (-1); return (0); -@@ -394,53 +758,63 @@ kr6_delete(struct kroute6_label *kl) +@@ -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; + + kt->fib_sync = 1; - 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_ADD, &kr->r); - RB_FOREACH(kr6, kroute6_tree, &krt6) + send_rtmsg(kr_state.fd, RTM_ADD, kt, &kr->r); + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) if ((kr6->r.flags & F_BGPD_INSERTED)) - send_rt6msg(kr_state.fd, RTM_ADD, &kr6->r); + send_rt6msg(kr_state.fd, RTM_ADD, kt, &kr6->r); - log_info("kernel routing table coupled"); + log_info("kernel routing table %u (%s) coupled", kt->rtableid, + kt->descr); } void -kr_fib_decouple(void) +kr_fib_decouple(u_int rtableid) { + struct ktable *kt; struct kroute_node *kr; struct kroute6_node *kr6; - if (kr_state.fib_sync == 0) /* already decoupled */ + if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */ + return; + + if (!kt->fib_sync) /* already decoupled */ return; - RB_FOREACH(kr, kroute_tree, &krt) + RB_FOREACH(kr, kroute_tree, &kt->krt) if ((kr->r.flags & F_BGPD_INSERTED)) - send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); - RB_FOREACH(kr6, kroute6_tree, &krt6) + send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r); + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) if ((kr6->r.flags & F_BGPD_INSERTED)) - send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r); + send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r); - kr_state.fib_sync = 0; + kt->fib_sync = 0; - log_info("kernel routing table decoupled"); + log_info("kernel routing table %u (%s) decoupled", kt->rtableid, + kt->descr); } int -@@ -450,11 +824,16 @@ kr_dispatch_msg(void) +@@ -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; -@@ -463,25 +842,30 @@ kr_nexthop_add(struct bgpd_addr *addr) - bzero(&nh, sizeof(nh)); - memcpy(&nh.nexthop, addr, sizeof(nh.nexthop)); - nh.valid = 1; +- 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) { -+ if (h->kroute != NULL && addr->aid == AID_INET) { - k = h->kroute; - nh.connected = k->r.flags & F_CONNECTED; - if (k->r.nexthop.s_addr != 0) { +- k = h->kroute; +- nh.connected = k->r.flags & F_CONNECTED; +- if (k->r.nexthop.s_addr != 0) { - nh.gateway.af = AF_INET; -+ nh.gateway.aid = AID_INET; - nh.gateway.v4.s_addr = - k->r.nexthop.s_addr; - } +- nh.gateway.v4.s_addr = +- k->r.nexthop.s_addr; +- } - memcpy(&nh.kr.kr4, &k->r, sizeof(nh.kr.kr4)); - } else if (h->kroute != NULL && addr->af == AF_INET6) { -+ nh.net.aid = AID_INET; -+ nh.net.v4.s_addr = k->r.prefix.s_addr; -+ nh.netlen = k->r.prefixlen; -+ } else if (h->kroute != NULL && addr->aid == AID_INET6) { - k6 = h->kroute; - nh.connected = k6->r.flags & F_CONNECTED; - if (memcmp(&k6->r.nexthop, &in6addr_any, - sizeof(struct in6_addr)) != 0) { +- k6 = h->kroute; +- nh.connected = k6->r.flags & F_CONNECTED; +- if (memcmp(&k6->r.nexthop, &in6addr_any, +- sizeof(struct in6_addr)) != 0) { - nh.gateway.af = AF_INET6; -+ nh.gateway.aid = AID_INET6; - memcpy(&nh.gateway.v6, &k6->r.nexthop, - sizeof(struct in6_addr)); - } +- memcpy(&nh.gateway.v6, &k6->r.nexthop, +- sizeof(struct in6_addr)); +- } - memcpy(&nh.kr.kr6, &k6->r, sizeof(nh.kr.kr6)); -+ nh.net.aid = AID_INET6; -+ memcpy(&nh.net.v6, &k6->r.nexthop, -+ sizeof(struct in6_addr)); -+ nh.netlen = k6->r.prefixlen; +- } +- +- send_nexthop_update(&nh); ++ 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) } - - send_nexthop_update(&nh); -@@ -492,7 +876,7 @@ kr_nexthop_add(struct bgpd_addr *addr) - } memcpy(&h->nexthop, addr, sizeof(h->nexthop)); - if (knexthop_insert(h) == -1) + if (knexthop_insert(kt, h) == -1) return (-1); } -@@ -500,19 +884,25 @@ kr_nexthop_add(struct bgpd_addr *addr) +@@ -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_add: non-existent rtableid %d", rtableid); ++ 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 +911,7 @@ kr_show_route(struct imsg *imsg) +@@ -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 +919,96 @@ kr_show_route(struct imsg *imsg) +@@ -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,6 +1025,24 @@ kr_show_route(struct imsg *imsg) +@@ -608,6 +994,24 @@ kr_show_route(struct imsg *imsg) send_imsg_session(IMSG_CTL_SHOW_INTERFACE, imsg->hdr.pid, &kif->k, sizeof(kif->k)); break; + case IMSG_CTL_SHOW_FIB_TABLES: + for (i = 0; i < krt_size; i++) { + struct ktable ktab; + + if ((kt = ktable_get(i)) == NULL) + continue; + + ktab = *kt; + /* do not leak internal information */ + RB_INIT(&ktab.krt); + RB_INIT(&ktab.krt6); + RB_INIT(&ktab.knt); + TAILQ_INIT(&ktab.krn); + + send_imsg_session(IMSG_CTL_SHOW_FIB_TABLES, + imsg->hdr.pid, &ktab, sizeof(ktab)); + } + break; default: /* nada */ break; } -@@ -628,21 +1063,146 @@ kr_ifinfo(char *ifname) +@@ -628,21 +1032,152 @@ kr_ifinfo(char *ifname) } } -struct redist_node { - LIST_ENTRY(redist_node) entry; - struct kroute *kr; - struct kroute6 *kr6; -}; +void +kr_net_delete(struct network *n) +{ + filterset_free(&n->net.attrset); + free(n); +} + +struct network * +kr_net_match(struct ktable *kt, struct kroute *kr) +{ + struct network *xn; + + TAILQ_FOREACH(xn, &kt->krn, entry) { + if (xn->net.prefix.aid != AID_INET) + continue; + switch (xn->net.type) { + case NETWORK_DEFAULT: + if (xn->net.prefixlen == kr->prefixlen && + xn->net.prefix.v4.s_addr == kr->prefix.s_addr) + /* static match already redistributed */ + return (NULL); + break; + case NETWORK_STATIC: + if (kr->flags & F_STATIC) + return (xn); + break; + case NETWORK_CONNECTED: + if (kr->flags & F_CONNECTED) + return (xn); + break; ++ case NETWORK_MRTCLONE: ++ /* can not happen */ ++ break; + } + } + return (NULL); +} -+ + +struct network * +kr_net_match6(struct ktable *kt, struct kroute6 *kr6) +{ + struct network *xn; + + TAILQ_FOREACH(xn, &kt->krn, entry) { + if (xn->net.prefix.aid != AID_INET6) + continue; + switch (xn->net.type) { + case NETWORK_DEFAULT: + if (xn->net.prefixlen == kr6->prefixlen && + memcmp(&xn->net.prefix.v6, &kr6->prefix, + sizeof(struct in6_addr)) == 0) + /* static match already redistributed */ + return (NULL); + break; + case NETWORK_STATIC: + if (kr6->flags & F_STATIC) + return (xn); + break; + case NETWORK_CONNECTED: + if (kr6->flags & F_CONNECTED) + return (xn); + break; ++ case NETWORK_MRTCLONE: ++ /* can not happen */ ++ break; + } + } + return (NULL); +} -+ + +-LIST_HEAD(, redist_node) redistlist; +struct network * +kr_net_find(struct ktable *kt, struct network *n) +{ + struct network *xn; + + TAILQ_FOREACH(xn, &kt->krn, entry) { + if (n->net.type != xn->net.type || + n->net.prefixlen != xn->net.prefixlen || + n->net.rtableid != xn->net.rtableid) + continue; + if (memcmp(&n->net.prefix, &xn->net.prefix, + sizeof(n->net.prefix)) == 0) + return (xn); + } + return (NULL); +} -+ -+int + + int +-kr_redistribute(int type, struct kroute *kr) +kr_net_reload(u_int rtableid, struct network_head *nh) -+{ + { +- struct redist_node *rn; + 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) ++ ++int +kr_redistribute(int type, struct ktable *kt, struct kroute *kr) - { -- struct redist_node *rn; ++{ + struct network *match; + struct network_config net; u_int32_t a; + /* shortcut for removals */ + if (type == IMSG_NETWORK_REMOVE) { + if (!(kr->flags & F_REDISTRIBUTED)) + return (0); /* no match, don't redistribute */ + kr->flags &= ~F_REDISTRIBUTED; + match = NULL; + goto sendit; + } + if (!(kr->flags & F_KERNEL)) return (0); -@@ -670,41 +1230,40 @@ kr_redistribute(int type, struct kroute +@@ -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 +1295,107 @@ kr_redistribute6(int type, struct kroute +@@ -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, KT2KNT(kt)) ++ knexthop_validate(kt, nh); - RB_FOREACH(nh, knexthop_tree, &knt) - knexthop_validate(nh); -+ RB_FOREACH(nh, knexthop_tree, KT2KNT(kt)) -+ knexthop_validate(kt, nh); -+ + TAILQ_FOREACH(n, &kt->krn, entry) + if (n->net.type == NETWORK_DEFAULT) { + if (send_network(IMSG_NETWORK_ADD, &n->net, + &n->net.attrset)) + return (-1); + } else + hasdyn = 1; + + if (hasdyn) { + /* only evaluate the full tree if we need */ + RB_FOREACH(kr, kroute_tree, &kt->krt) + kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r); + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) + kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr6->r); + } + } return (0); } +struct kroute_full * +kr_tofull(struct kroute *kr) +{ + static struct kroute_full kf; + + bzero(&kf, sizeof(kf)); + + kf.prefix.aid = AID_INET; + kf.prefix.v4.s_addr = kr->prefix.s_addr; + kf.nexthop.aid = AID_INET; + kf.nexthop.v4.s_addr = kr->nexthop.s_addr; + strlcpy(kf.label, rtlabel_id2name(kr->labelid), sizeof(kf.label)); + kf.flags = kr->flags; + kf.ifindex = kr->ifindex; + kf.prefixlen = kr->prefixlen; + kf.priority = kr->priority; + + return (&kf); +} + +struct kroute_full * +kr6_tofull(struct kroute6 *kr6) +{ + static struct kroute_full kf; + + bzero(&kf, sizeof(kf)); + + kf.prefix.aid = AID_INET6; + memcpy(&kf.prefix.v6, &kr6->prefix, sizeof(struct in6_addr)); + kf.nexthop.aid = AID_INET6; + memcpy(&kf.nexthop.v6, &kr6->nexthop, sizeof(struct in6_addr)); + strlcpy(kf.label, rtlabel_id2name(kr6->labelid), sizeof(kf.label)); + kf.flags = kr6->flags; + kf.ifindex = kr6->ifindex; + kf.prefixlen = kr6->prefixlen; + kf.priority = kr6->priority; + + return (&kf); +} + /* * RB-tree compare functions */ -@@ -846,26 +1452,28 @@ kroute6_compare(struct kroute6_node *a, +@@ -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 +1491,8 @@ kif_compare(struct kif_node *a, struct k +@@ -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 +1501,15 @@ kroute_find(in_addr_t prefix, u_int8_t p +@@ -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 +1536,13 @@ kroute_matchgw(struct kroute_node *kr, s +@@ -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; -@@ -944,10 +1553,10 @@ kroute_insert(struct kroute_node *kr) +@@ -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 +1564,19 @@ kroute_insert(struct kroute_node *kr) +@@ -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 +1584,14 @@ kroute_remove(struct kroute_node *kr) +@@ -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); -@@ -1002,13 +1612,13 @@ kroute_remove(struct kroute_node *kr) +@@ -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)) +- 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 +1631,17 @@ kroute_remove(struct kroute_node *kr) +@@ -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 +1650,15 @@ kroute6_find(const struct in6_addr *pref +@@ -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); -@@ -1065,7 +1676,7 @@ kroute6_matchgw(struct kroute6_node *kr, +@@ -1065,7 +1652,7 @@ kroute6_matchgw(struct kroute6_node *kr, memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop)); while (kr) { - if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == NULL) + if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0) return (kr); kr = kr->next; } -@@ -1074,13 +1685,13 @@ kroute6_matchgw(struct kroute6_node *kr, +@@ -1074,13 +1661,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; -@@ -1090,12 +1701,12 @@ kroute6_insert(struct kroute6_node *kr) +@@ -1088,14 +1675,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 +1715,19 @@ kroute6_insert(struct kroute6_node *kr) +@@ -1104,19 +1692,19 @@ kroute6_insert(struct kroute6_node *kr) if (krm == NULL) /* redistribute multipath routes only once */ - kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); + kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr->r); } return (0); } int -kroute6_remove(struct kroute6_node *kr) +kroute6_remove(struct ktable *kt, struct kroute6_node *kr) { struct kroute6_node *krm; struct knexthop_node *s; - if ((krm = RB_FIND(kroute6_tree, &krt6, kr)) == NULL) { + if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) { log_warnx("kroute6_remove failed for %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); return (-1); -@@ -1124,13 +1735,14 @@ kroute6_remove(struct kroute6_node *kr) +@@ -1124,13 +1712,14 @@ kroute6_remove(struct kroute6_node *kr) if (krm == kr) { /* head element */ - if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) { + if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) { log_warnx("kroute6_remove failed for %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); return (-1); } if (kr->next != NULL) { - if (RB_INSERT(kroute6_tree, &krt6, kr->next) != NULL) { + if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) != + NULL) { log_warnx("kroute6_remove failed to add %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); -@@ -1152,13 +1764,13 @@ kroute6_remove(struct kroute6_node *kr) +@@ -1151,14 +1740,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)) +- 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 +1783,46 @@ kroute6_remove(struct kroute6_node *kr) +@@ -1171,45 +1760,46 @@ kroute6_remove(struct kroute6_node *kr) } void -kroute6_clear(void) +kroute6_clear(struct ktable *kt) { struct kroute6_node *kr; - while ((kr = RB_MIN(kroute6_tree, &krt6)) != NULL) - kroute6_remove(kr); + while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL) + kroute6_remove(kt, kr); } struct knexthop_node * -knexthop_find(struct bgpd_addr *addr) +knexthop_find(struct ktable *kt, struct bgpd_addr *addr) { struct knexthop_node s; + bzero(&s, sizeof(s)); memcpy(&s.nexthop, addr, sizeof(s.nexthop)); - return (RB_FIND(knexthop_tree, &knt, &s)); + return (RB_FIND(knexthop_tree, KT2KNT(kt), &s)); } int -knexthop_insert(struct knexthop_node *kn) +knexthop_insert(struct ktable *kt, struct knexthop_node *kn) { - if (RB_INSERT(knexthop_tree, &knt, kn) != NULL) { + if (RB_INSERT(knexthop_tree, KT2KNT(kt), kn) != NULL) { log_warnx("knexthop_tree insert failed for %s", log_addr(&kn->nexthop)); free(kn); return (-1); } - knexthop_validate(kn); + knexthop_validate(kt, kn); return (0); } int -knexthop_remove(struct knexthop_node *kn) +knexthop_remove(struct ktable *kt, struct knexthop_node *kn) { - kroute_detach_nexthop(kn); + kroute_detach_nexthop(kt, kn); - if (RB_REMOVE(knexthop_tree, &knt, kn) == NULL) { + if (RB_REMOVE(knexthop_tree, KT2KNT(kt), kn) == NULL) { log_warnx("knexthop_remove failed for %s", log_addr(&kn->nexthop)); return (-1); -@@ -1220,12 +1833,12 @@ knexthop_remove(struct knexthop_node *kn +@@ -1220,12 +1810,12 @@ knexthop_remove(struct knexthop_node *kn } void -knexthop_clear(void) +knexthop_clear(struct ktable *kt) { struct knexthop_node *kn; - while ((kn = RB_MIN(knexthop_tree, &knt)) != NULL) - knexthop_remove(kn); + while ((kn = RB_MIN(knexthop_tree, KT2KNT(kt))) != NULL) + knexthop_remove(kt, kn); } struct kif_node * -@@ -1257,6 +1870,7 @@ kif_insert(struct kif_node *kif) +@@ -1257,6 +1847,7 @@ kif_insert(struct kif_node *kif) int kif_remove(struct kif_node *kif) { + struct ktable *kt; struct kif_kr *kkr; struct kif_kr6 *kkr6; -@@ -1265,20 +1879,23 @@ kif_remove(struct kif_node *kif) +@@ -1265,20 +1856,23 @@ kif_remove(struct kif_node *kif) return (-1); } + if ((kt = ktable_get(/* XXX */ 0)) == NULL) + goto done; + while ((kkr = LIST_FIRST(&kif->kroute_l)) != NULL) { LIST_REMOVE(kkr, entry); kkr->kr->r.flags &= ~F_NEXTHOP; - kroute_remove(kkr->kr); + kroute_remove(kt, kkr->kr); free(kkr); } while ((kkr6 = LIST_FIRST(&kif->kroute6_l)) != NULL) { LIST_REMOVE(kkr6, entry); kkr6->kr->r.flags &= ~F_NEXTHOP; - kroute6_remove(kkr6->kr); + kroute6_remove(kt, kkr6->kr); free(kkr6); } - +done: free(kif); return (0); } -@@ -1473,25 +2090,25 @@ kroute6_validate(struct kroute6 *kr) +@@ -1473,113 +2067,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; +- struct kroute_nexthop n; +- int was_valid = 0; - if (kn->nexthop.af == AF_INET && (kr = kn->kroute) != NULL) -+ if (kn->nexthop.aid == AID_INET && (kr = kn->kroute) != NULL) - was_valid = kroute_validate(&kr->r); +- was_valid = kroute_validate(&kr->r); - if (kn->nexthop.af == AF_INET6 && (kr6 = kn->kroute) != NULL) -+ if (kn->nexthop.aid == AID_INET6 && (kr6 = kn->kroute) != NULL) - was_valid = kroute6_validate(&kr6->r); - - bzero(&n, sizeof(n)); - memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); -- kroute_detach_nexthop(kn); +- 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) { -+ switch (kn->nexthop.aid) { -+ case AID_INET: -+ if ((kr = kroute_match(kt, kn->nexthop.v4.s_addr, 0)) == NULL) { - if (was_valid) - send_nexthop_update(&n); - } else { /* match */ -@@ -1500,8 +2117,10 @@ knexthop_validate(struct knexthop_node * - n.connected = kr->r.flags & F_CONNECTED; - if ((n.gateway.v4.s_addr = - kr->r.nexthop.s_addr) != 0) +- 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)); -+ n.gateway.aid = AID_INET; -+ n.net.aid = AID_INET; -+ n.net.v4.s_addr = kr->r.prefix.s_addr; -+ n.netlen = kr->r.prefixlen; - send_nexthop_update(&n); - } else /* down */ - if (was_valid) -@@ -1511,8 +2130,8 @@ knexthop_validate(struct knexthop_node * +- 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) { -+ case AID_INET6: -+ if ((kr6 = kroute6_match(kt, &kn->nexthop.v6, 0)) == NULL) { - if (was_valid) - send_nexthop_update(&n); - } else { /* match */ -@@ -1521,11 +2140,14 @@ knexthop_validate(struct knexthop_node * - n.connected = kr6->r.flags & F_CONNECTED; - if (memcmp(&kr6->r.nexthop, &in6addr_any, - sizeof(struct in6_addr)) != 0) { +- 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; -+ n.gateway.aid = AID_INET6; - memcpy(&n.gateway.v6, &kr6->r.nexthop, - sizeof(struct in6_addr)); - } +- memcpy(&n.gateway.v6, &kr6->r.nexthop, +- sizeof(struct in6_addr)); +- } - memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6)); -+ n.net.aid = AID_INET6; -+ memcpy(&n.net.v6, &kr6->r.nexthop, -+ sizeof(struct in6_addr)); -+ n.netlen = kr6->r.prefixlen; - send_nexthop_update(&n); - } else /* down */ - if (was_valid) -@@ -1539,39 +2161,44 @@ knexthop_validate(struct knexthop_node * +- 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; +- struct kroute_nexthop n; - RB_FOREACH(kn, knexthop_tree, &knt) - if (kn->kroute == krn) { -+ RB_FOREACH(kn, knexthop_tree, KT2KNT(kt)) -+ if (kn->kroute == krp) { - bzero(&n, sizeof(n)); - memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); +- 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; -+ switch (kn->nexthop.aid) { -+ case AID_INET: -+ kr = krp; - n.valid = 1; - n.connected = kr->r.flags & F_CONNECTED; - if ((n.gateway.v4.s_addr = - kr->r.nexthop.s_addr) != 0) +- n.valid = 1; +- n.connected = kr->r.flags & F_CONNECTED; +- if ((n.gateway.v4.s_addr = +- kr->r.nexthop.s_addr) != 0) - n.gateway.af = AF_INET; - memcpy(&n.kr.kr4, &kr->r, sizeof(n.kr.kr4)); -+ n.gateway.aid = AID_INET; -+ n.net.aid = AID_INET; -+ n.net.v4.s_addr = kr->r.prefix.s_addr; -+ n.netlen = kr->r.prefixlen; - break; +- break; - case AF_INET6: - kr6 = krn; -+ case AID_INET6: -+ kr6 = krp; - n.valid = 1; - n.connected = kr6->r.flags & F_CONNECTED; - if (memcmp(&kr6->r.nexthop, &in6addr_any, - sizeof(struct in6_addr)) != 0) { +- n.valid = 1; +- n.connected = kr6->r.flags & F_CONNECTED; +- if (memcmp(&kr6->r.nexthop, &in6addr_any, +- sizeof(struct in6_addr)) != 0) { - n.gateway.af = AF_INET6; -+ n.gateway.aid = AID_INET6; - memcpy(&n.gateway.v6, &kr6->r.nexthop, - sizeof(struct in6_addr)); - } +- memcpy(&n.gateway.v6, &kr6->r.nexthop, +- sizeof(struct in6_addr)); +- } - memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6)); -+ n.net.aid = AID_INET6; -+ memcpy(&n.net.v6, &kr6->r.nexthop, -+ sizeof(struct in6_addr)); -+ n.netlen = kr6->r.prefixlen; - break; - } - send_nexthop_update(&n); -@@ -1579,7 +2206,7 @@ knexthop_track(void *krn) +- 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 +2216,13 @@ kroute_match(in_addr_t key, int matchall +@@ -1589,13 +2179,13 @@ kroute_match(in_addr_t key, int matchall /* we will never match the default route */ for (i = 32; i > 0; i--) - if ((kr = kroute_find(htonl(ina & prefixlen2mask(i)), i, + if ((kr = kroute_find(kt, htonl(ina & prefixlen2mask(i)), i, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); /* if we don't have a match yet, try to find a default route */ - if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL) + if ((kr = kroute_find(kt, 0, 0, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); -@@ -1603,7 +2230,7 @@ kroute_match(in_addr_t key, int matchall +@@ -1603,7 +2193,7 @@ kroute_match(in_addr_t key, int matchall } struct kroute6_node * -kroute6_match(struct in6_addr *key, int matchall) +kroute6_match(struct ktable *kt, struct in6_addr *key, int matchall) { int i; struct kroute6_node *kr6; -@@ -1612,13 +2239,13 @@ kroute6_match(struct in6_addr *key, int +@@ -1612,13 +2202,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,7 +2253,7 @@ kroute6_match(struct in6_addr *key, int +@@ -1626,31 +2216,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; -@@ -1640,17 +2267,17 @@ kroute_detach_nexthop(struct knexthop_no - if (kn->kroute == NULL) - return; + 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)) -+ for (s = RB_MIN(knexthop_tree, KT2KNT(kt)); s != NULL && -+ s->kroute != kn->kroute; s = RB_NEXT(knexthop_tree, KT2KNT(kt), s)) - ; /* nothing */ +- ; /* 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 +2292,7 @@ kroute_detach_nexthop(struct knexthop_no +@@ -1665,7 +2254,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 +2302,11 @@ protect_lo(void) +@@ -1675,11 +2264,11 @@ protect_lo(void) log_warn("protect_lo"); return (-1); } - kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK); + kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); kr->r.prefixlen = 8; kr->r.flags = F_KERNEL|F_CONNECTED; - if (RB_INSERT(kroute_tree, &krt, kr) != NULL) + if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL) free(kr); /* kernel route already there, no problem */ /* special protection for loopback */ -@@ -1689,9 +2316,9 @@ protect_lo(void) +@@ -1689,9 +2278,9 @@ protect_lo(void) } memcpy(&kr6->r.prefix, &in6addr_loopback, sizeof(kr6->r.prefix)); kr6->r.prefixlen = 128; - kr->r.flags = F_KERNEL|F_CONNECTED; + kr6->r.flags = F_KERNEL|F_CONNECTED; - if (RB_INSERT(kroute6_tree, &krt6, kr6) != NULL) + if (RB_INSERT(kroute6_tree, &kt->krt6, kr6) != NULL) free(kr6); /* kernel route already there, no problem */ return (0); -@@ -1726,17 +2353,17 @@ mask2prefixlen(in_addr_t ina) +@@ -1726,17 +2315,17 @@ mask2prefixlen(in_addr_t ina) u_int8_t mask2prefixlen6(struct sockaddr_in6 *sa_in6) { - u_int8_t l = 0, i, len; + u_int8_t l = 0, *ap, *ep; /* * sin6_len is the size of the sockaddr so substract the offset of * the possibly truncated sin6_addr struct. */ - len = sa_in6->sin6_len - - (u_int8_t)(&((struct sockaddr_in6 *)NULL)->sin6_addr); - for (i = 0; i < len; i++) { + ap = (u_int8_t *)&sa_in6->sin6_addr; + ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; + for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ - switch (sa_in6->sin6_addr.s6_addr[i]) { + switch (*ap) { case 0xff: l += 8; break; -@@ -1764,7 +2391,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_ +@@ -1764,7 +2353,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_ case 0x00: return (l); default: - fatalx("non continguous inet6 netmask"); + fatalx("non contiguous inet6 netmask"); } } -@@ -1788,7 +2415,7 @@ prefixlen2mask6(u_int8_t prefixlen) +@@ -1788,7 +2377,7 @@ prefixlen2mask6(u_int8_t prefixlen) } #define ROUNDUP(a) \ - (((a) & ((sizeof(long)) - 1)) ? (1 + ((a) | ((sizeof(long)) - 1))) : (a)) + (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) -@@ -1808,6 +2435,7 @@ get_rtaddrs(int addrs, struct sockaddr * +@@ -1808,11 +2397,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; -@@ -1833,13 +2461,18 @@ if_change(u_short ifindex, int flags, st +- struct kroute_nexthop nh; +- struct knexthop_node *n; + u_int8_t reachable; + if ((kif = kif_find(ifindex)) == NULL) { +@@ -1833,28 +2421,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 (kt == NULL) -+ continue; -+ -+ RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) - if (n->kroute == kkr->kr) { - bzero(&nh, sizeof(nh)); - memcpy(&nh.nexthop, &n->nexthop, -@@ -1849,10 +2482,11 @@ if_change(u_short ifindex, int flags, st - nh.connected = 1; - if ((nh.gateway.v4.s_addr = - kkr->kr->r.nexthop.s_addr) != 0) +- 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; -+ nh.gateway.aid = AID_INET; - } +- } - memcpy(&nh.kr.kr4, &kkr->kr->r, - sizeof(nh.kr.kr4)); -+ nh.net.aid = AID_INET; -+ nh.net.v4.s_addr = kkr->kr->r.prefix.s_addr; -+ nh.netlen = kkr->kr->r.prefixlen; - send_nexthop_update(&nh); - } +- send_nexthop_update(&nh); +- } ++ if (kt == NULL) ++ continue; ++ ++ knexthop_track(kt, kkr->kr); } -@@ -1862,7 +2496,9 @@ if_change(u_short ifindex, int flags, st + LIST_FOREACH(kkr6, &kif->kroute6_l, entry) { + if (reachable) +@@ -1862,27 +2440,10 @@ if_change(u_short ifindex, int flags, st else kkr6->kr->r.flags |= F_DOWN; - RB_FOREACH(n, knexthop_tree, &knt) -+ if (kt == NULL) -+ continue; -+ RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) - if (n->kroute == kkr6->kr) { - bzero(&nh, sizeof(nh)); - memcpy(&nh.nexthop, &n->nexthop, -@@ -1873,14 +2509,16 @@ if_change(u_short ifindex, int flags, st - if (memcmp(&kkr6->kr->r.nexthop, - &in6addr_any, sizeof(struct - in6_addr))) { +- 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; -+ nh.gateway.aid = AID_INET6; - memcpy(&nh.gateway.v6, - &kkr6->kr->r.nexthop, - sizeof(struct in6_addr)); - } - } +- memcpy(&nh.gateway.v6, +- &kkr6->kr->r.nexthop, +- sizeof(struct in6_addr)); +- } +- } - memcpy(&nh.kr.kr6, &kkr6->kr->r, - sizeof(nh.kr.kr6)); -+ nh.net.aid = AID_INET6; -+ memcpy(&nh.net.v6, &kkr6->kr->r.nexthop, -+ sizeof(struct in6_addr)); -+ nh.netlen = kkr6->kr->r.prefixlen; - send_nexthop_update(&nh); - } +- send_nexthop_update(&nh); +- } ++ if (kt == NULL) ++ continue; ++ ++ knexthop_track(kt, kkr6->kr); } -@@ -1917,25 +2555,38 @@ if_announce(void *msg) + } + +@@ -1917,25 +2478,38 @@ if_announce(void *msg) */ int -send_rtmsg(int fd, int action, struct kroute *kroute) +send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute) { - struct iovec iov[5]; + struct iovec iov[7]; struct rt_msghdr hdr; struct sockaddr_in prefix; struct sockaddr_in nexthop; struct sockaddr_in mask; + struct { + struct sockaddr_dl dl; + char pad[sizeof(long)]; + } ifp; +#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */ + struct sockaddr_mpls mpls; struct sockaddr_rtlabel label; +#endif /* !defined(__FreeBSD__) */ int iovcnt = 0; - if (kr_state.fib_sync == 0) + if (!kt->fib_sync) return (0); /* initialize header */ bzero(&hdr, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; - hdr.rtm_tableid = kr_state.rtableid; +#if !defined(__FreeBSD__) /* XXX: FreeBSD has no multiple routing tables */ + hdr.rtm_tableid = kt->rtableid; +#endif /* !defined(__FreeBSD__) */ +#if !defined(__FreeBSD__) /* XXX: FreeBSD has no rtm_priority */ hdr.rtm_priority = RTP_BGP; +#else + hdr.rtm_flags = RTF_PROTO1; +#endif /* !defined(__FreeBSD__) */ if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; if (kroute->flags & F_REJECT) -@@ -1984,6 +2635,37 @@ send_rtmsg(int fd, int action, struct kr +@@ -1984,6 +2558,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 +2678,11 @@ send_rtmsg(int fd, int action, struct kr +@@ -1996,11 +2601,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 +2691,18 @@ retry: +@@ -2009,27 +2614,18 @@ retry: inet_ntoa(kroute->prefix), kroute->prefixlen); return (0); - } else { - log_warnx("send_rtmsg: action %u, " - "prefix %s/%u: %s", hdr.rtm_type, - inet_ntoa(kroute->prefix), - kroute->prefixlen, strerror(errno)); - return (0); } - break; - default: - log_warnx("send_rtmsg: action %u, prefix %s/%u: %s", - hdr.rtm_type, inet_ntoa(kroute->prefix), - kroute->prefixlen, strerror(errno)); - return (0); } + log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type, + inet_ntoa(kroute->prefix), kroute->prefixlen); + return (0); } return (0); } int -send_rt6msg(int fd, int action, struct kroute6 *kroute) +send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute) { struct iovec iov[5]; struct rt_msghdr hdr; -@@ -2037,17 +2710,23 @@ send_rt6msg(int fd, int action, struct k +@@ -2037,17 +2633,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 +2779,7 @@ send_rt6msg(int fd, int action, struct k +@@ -2100,6 +2702,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 +2792,11 @@ send_rt6msg(int fd, int action, struct k +@@ -2112,11 +2715,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 +2805,26 @@ retry: +@@ -2125,31 +2728,26 @@ retry: log_in6addr(&kroute->prefix), kroute->prefixlen); return (0); - } else { - log_warnx("send_rt6msg: action %u, " - "prefix %s/%u: %s", hdr.rtm_type, - log_in6addr(&kroute->prefix), - kroute->prefixlen, strerror(errno)); - return (0); } - break; - default: - log_warnx("send_rt6msg: action %u, prefix %s/%u: %s", - hdr.rtm_type, log_in6addr(&kroute->prefix), - kroute->prefixlen, strerror(errno)); - return (0); } + log_warn("send_rt6msg: action %u, prefix %s/%u", hdr.rtm_type, + log_in6addr(&kroute->prefix), kroute->prefixlen); + return (0); } return (0); } int -fetchtable(u_int rtableid, int connected_only) +fetchtable(struct ktable *kt) { size_t len; +#if !defined(__FreeBSD__) /* FreeBSD has no table id. */ int mib[7]; - char *buf, *next, *lim; +#else + int mib[6]; +#endif + char *buf = NULL, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa, *gw, *rti_info[RTAX_MAX]; struct sockaddr_in *sa_in; -@@ -2163,22 +2838,35 @@ fetchtable(u_int rtableid, int connected +@@ -2163,22 +2761,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 +2874,11 @@ fetchtable(u_int rtableid, int connected +@@ -2186,7 +2797,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 +2897,11 @@ fetchtable(u_int rtableid, int connected +@@ -2205,7 +2820,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 +2919,12 @@ fetchtable(u_int rtableid, int connected +@@ -2223,8 +2842,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,7 +2938,11 @@ fetchtable(u_int rtableid, int connected +@@ -2238,7 +2861,11 @@ 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, -@@ -2257,8 +2961,12 @@ fetchtable(u_int rtableid, int connected +@@ -2257,8 +2884,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; -@@ -2290,23 +2998,28 @@ fetchtable(u_int rtableid, int connected +@@ -2290,23 +2921,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 +3040,7 @@ fetchifs(int ifindex) +@@ -2327,7 +2963,7 @@ fetchifs(int ifindex) mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; - mib[3] = AF_INET; + mib[3] = AF_INET; /* AF does not matter but AF_INET is shorter */ mib[4] = NET_RT_IFLIST; mib[5] = ifindex; -@@ -2396,7 +3109,7 @@ dispatch_rtmsg(void) +@@ -2396,7 +3032,7 @@ dispatch_rtmsg(void) struct rt_msghdr *rtm; struct if_msghdr ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; - int connected_only; + struct ktable *kt; if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { log_warn("dispatch_rtmsg: read error"); -@@ -2418,7 +3131,11 @@ dispatch_rtmsg(void) +@@ -2418,7 +3054,11 @@ dispatch_rtmsg(void) case RTM_ADD: case RTM_CHANGE: case RTM_DELETE: +#if !defined(__FreeBSD__) sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); +#else + sa = (struct sockaddr *)(next + sizeof(struct rt_msghdr)); +#endif get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if (rtm->rtm_pid == kr_state.pid) /* cause by us */ -@@ -2430,16 +3147,14 @@ dispatch_rtmsg(void) +@@ -2430,16 +3070,14 @@ dispatch_rtmsg(void) if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ continue; - connected_only = 0; - if (rtm->rtm_tableid != kr_state.rtableid) { - if (rtm->rtm_tableid == 0) - connected_only = 1; - else - continue; - } +#if !defined(__FreeBSD__) /* FreeBSD has no rtm_tableid. */ + if ((kt = ktable_get(rtm->rtm_tableid)) == NULL) +#else + if ((kt = ktable_get(0)) == NULL) +#endif + continue; - if (dispatch_rtmsg_addr(rtm, rti_info, - connected_only) == -1) + if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1) return (-1); break; case RTM_IFINFO: -@@ -2460,7 +3175,7 @@ dispatch_rtmsg(void) +@@ -2460,7 +3098,7 @@ dispatch_rtmsg(void) int dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], - int connected_only) + struct ktable *kt) { struct sockaddr *sa; struct sockaddr_in *sa_in; -@@ -2494,31 +3209,44 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt +@@ -2468,7 +3106,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 +3132,44 @@ 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)); sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK]; if (sa_in6 != NULL) { if (sa_in6->sin6_len != 0) prefixlen = mask2prefixlen6(sa_in6); - } else if (rtm->rtm_flags & RTF_HOST) + } else if (rtm->rtm_flags & RTF_HOST) { prefixlen = 128; +#if defined(__FreeBSD__) /* RTF_HOST means connected route */ + flags |= F_CONNECTED; +#endif + } else fatalx("in6 net addr without netmask"); break; -@@ -2537,10 +3265,10 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt +@@ -2537,10 +3188,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 +3282,12 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt +@@ -2554,12 +3205,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 +3302,23 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt +@@ -2574,26 +3225,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 */ -@@ -2619,16 +3344,16 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt +@@ -2605,30 +3253,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) +- 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,12 +3376,13 @@ add4: +@@ -2651,12 +3307,13 @@ add4: kr->r.ifindex = ifindex; kr->r.priority = prio; - kroute_insert(kr); + kroute_insert(kt, kr); } break; - case AF_INET6: + case AID_INET6: sa_in6 = (struct sockaddr_in6 *)sa; - if ((kr6 = kroute6_find(&prefix.v6, prefixlen, prio)) != NULL) { + if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) != + NULL) { if (kr6->r.flags & F_KERNEL) { /* get the correct route */ if (mpath && rtm->rtm_type == RTM_CHANGE && -@@ -2685,16 +3411,16 @@ add4: +@@ -2668,33 +3325,44 @@ add4: + } 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) +- 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", -@@ -2720,7 +3446,7 @@ add6: +@@ -2720,7 +3388,7 @@ add6: kr6->r.ifindex = ifindex; kr6->r.priority = prio; - kroute6_insert(kr6); + kroute6_insert(kt, kr6); } break; } Index: head/net/openbgpd/files/patch-bgpd_log.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_log.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_log.c (revision 305848) @@ -1,115 +1,117 @@ 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.7 -diff -u -p -r1.1.1.5 -r1.1.1.7 +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 12 Jun 2011 10:44:25 -0000 1.1.1.7 ++++ 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.54 2010/11/18 12:51: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 { -@@ -69,6 +71,7 @@ log_init(int n_debug) - extern char *__progname; - - debug = n_debug; -+ verbose = n_debug; - - if (!debug) - openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); -@@ -77,6 +80,12 @@ log_init(int n_debug) +@@ -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 +202,7 @@ log_debug(const char *emsg, ...) +@@ -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 +259,7 @@ log_statechange(struct peer *peer, enum +@@ -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; -@@ -287,23 +296,22 @@ log_notification(const struct peer *peer +@@ -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 +326,9 @@ log_conn_attempt(const struct peer *peer +@@ -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: head/net/openbgpd/files/patch-bgpd_log.h =================================================================== --- head/net/openbgpd/files/patch-bgpd_log.h (nonexistent) +++ head/net/openbgpd/files/patch-bgpd_log.h (revision 305848) @@ -0,0 +1,39 @@ +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[] = { Property changes on: head/net/openbgpd/files/patch-bgpd_log.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_mrt.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_mrt.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_mrt.c (revision 305848) @@ -1,556 +1,859 @@ 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.9 -diff -u -p -r1.1.1.7 -r1.1.1.9 +retrieving revision 1.1.1.10 +diff -u -p -r1.1.1.7 -r1.1.1.10 --- bgpd/mrt.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/mrt.c 12 Jun 2011 10:44:25 -0000 1.1.1.9 ++++ bgpd/mrt.c 13 Oct 2012 18:22:43 -0000 1.1.1.10 @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.63 2009/06/29 12:22:16 claudio Exp $ */ -+/* $OpenBSD: mrt.c,v 1.70 2010/09/02 14:03:21 sobrado Exp $ */ ++/* $OpenBSD: mrt.c,v 1.71 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker -@@ -32,20 +32,20 @@ +@@ -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 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_warnx("mrt_dump1: ibuf_add error"); \ ++ log_warn("mrt_dump1: ibuf_add error"); \ goto fail; \ } \ } while (0) -@@ -54,8 +54,8 @@ int mrt_open(struct mrt *, time_t); +@@ -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_warnx("mrt_dump2: ibuf_add error"); \ ++ log_warn("mrt_dump2: ibuf_add error"); \ goto fail; \ } \ } while (0) -@@ -64,8 +64,8 @@ int mrt_open(struct mrt *, time_t); +@@ -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_warnx("mrt_dump3: ibuf_add error"); \ ++ log_warn("mrt_dump3: ibuf_add error"); \ goto fail; \ } \ } while (0) -@@ -73,8 +73,8 @@ int mrt_open(struct mrt *, time_t); +@@ -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_warnx("mrt_dump4: ibuf_add error"); \ ++ log_warn("mrt_dump4: ibuf_add error"); \ goto fail; \ } \ } while (0) -@@ -83,55 +83,63 @@ void +@@ -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) { -+ if (ibuf_add(buf, pkg, pkglen) == -1) { - log_warnx("mrt_dump_bgp_msg: buf_add error"); +- 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: buf_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) ++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, mpattr[21]; ++ u_int8_t l, safi; /* origin */ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, -@@ -141,11 +149,14 @@ mrt_attr_dump(struct buf *buf, struct rd +@@ -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); +- 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) -@@ -173,12 +184,27 @@ mrt_attr_dump(struct buf *buf, struct rd +@@ -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) { -+ if (aid2afi(nexthop->aid, &afi, &mpattr[2])) ++ struct ibuf *nhbuf; ++ ++ if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL) + return (-1); -+ afi = htons(afi); -+ memcpy(mpattr, &afi, sizeof(afi)); -+ mpattr[3] = sizeof(struct in6_addr); -+ memcpy(&mpattr[4], &nexthop->v6, sizeof(struct in6_addr)); -+ mpattr[20] = 0; /* Reserved must be 0 */ ++ if (!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, -+ mpattr, sizeof(mpattr)) == -1) ++ 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,14 +215,14 @@ int +@@ -189,25 +244,23 @@ 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; - void *bptr; struct bgpd_addr addr, nexthop, *nh; u_int16_t len; - u_int8_t p_len; +- u_int8_t p_len; - sa_family_t af; + u_int8_t aid; - if ((buf = buf_dynamic(0, MAX_PKTSIZE)) == NULL) { + if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { log_warn("mrt_dump_entry_mp: buf_dynamic"); return (-1); } -@@ -205,9 +231,9 @@ mrt_dump_entry_mp(struct mrt *mrt, struc + +- 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"); -@@ -219,25 +245,26 @@ mrt_dump_entry_mp(struct mrt *mrt, struc +@@ -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_warnx("mrt_dump_entry_mp: buf_add error"); ++ log_warn("mrt_dump_entry_mp: buf_add error"); goto fail; } break; default: - log_warnx("king bula found new AF %d in mrt_dump_entry_mp", af); + log_warnx("king bula found new AF in mrt_dump_entry_mp"); goto fail; } -@@ -247,24 +274,24 @@ mrt_dump_entry_mp(struct mrt *mrt, struc +@@ -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_warnx("mrt_dump_entry_mp: buf_add error"); ++ log_warn("mrt_dump_entry_mp: buf_add error"); goto fail; } -@@ -275,7 +302,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struc + break; +@@ -274,35 +328,30 @@ mrt_dump_entry_mp(struct mrt *mrt, struc + goto fail; } - p_len = PREFIX_SIZE(p->prefix->prefixlen); +- p_len = PREFIX_SIZE(p->prefix->prefixlen); - if ((bptr = buf_reserve(h2buf, p_len)) == NULL) { -+ if ((bptr = ibuf_reserve(h2buf, p_len)) == NULL) { - log_warnx("mrt_dump_entry_mp: buf_reserve error"); +- 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; } -@@ -285,24 +312,24 @@ mrt_dump_entry_mp(struct mrt *mrt, struc - } DUMP_SHORT(h2buf, len); - len += buf_size(h2buf); + len += ibuf_size(h2buf); if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, len) == -1) goto fail; - buf_close(&mrt->wbuf, hbuf); - buf_close(&mrt->wbuf, h2buf); - buf_close(&mrt->wbuf, buf); + ibuf_close(&mrt->wbuf, hbuf); + ibuf_close(&mrt->wbuf, h2buf); + ibuf_close(&mrt->wbuf, buf); return (len + MRT_HEADER_SIZE); fail: if (hbuf) - buf_free(hbuf); - if (h2buf); - buf_free(h2buf); - buf_free(buf); + ibuf_free(hbuf); + if (h2buf) + ibuf_free(h2buf); + ibuf_free(buf); return (-1); } -@@ -310,34 +337,37 @@ int +@@ -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_warnx("mrt_dump_entry: buf_dynamic"); ++ log_warn("mrt_dump_entry: buf_dynamic"); return (-1); } if (p->aspath->nexthop == NULL) { bzero(&addr, sizeof(struct bgpd_addr)); - addr.af = AF_INET; + addr.aid = p->prefix->aid; nh = &addr; } else nh = &p->aspath->nexthop->exit_nexthop; - if (mrt_attr_dump(buf, p->aspath, nh) == -1) { +- 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 +375,44 @@ mrt_dump_entry(struct mrt *mrt, struct p +@@ -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_warnx("mrt_dump_entry: buf_add error"); ++ log_warn("mrt_dump_entry: buf_add error"); + goto fail; + } + break; + } DUMP_BYTE(hbuf, p->prefix->prefixlen); DUMP_BYTE(hbuf, 1); /* state */ DUMP_LONG(hbuf, p->lastchange); /* originated */ - DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); + switch (p->prefix->aid) { + case AID_INET: + DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); + break; + case AID_INET6: + if (ibuf_add(hbuf, &peer->remote_addr.v6, + sizeof(struct in6_addr)) == -1) { -+ log_warnx("mrt_dump_entry: buf_add error"); ++ log_warn("mrt_dump_entry: buf_add error"); + goto fail; + } + break; + } DUMP_SHORT(hbuf, peer->short_as); DUMP_SHORT(hbuf, len); - buf_close(&mrt->wbuf, hbuf); - buf_close(&mrt->wbuf, buf); + ibuf_close(&mrt->wbuf, hbuf); + ibuf_close(&mrt->wbuf, buf); return (len + MRT_HEADER_SIZE); fail: - buf_free(hbuf); - buf_free(buf); + ibuf_free(hbuf); + ibuf_free(buf); ++ return (-1); ++} ++ ++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: buf_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: buf_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: buf_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: buf_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: buf_add error"); ++ goto fail; ++ } ++ ++ off = ibuf_size(buf); ++ if (ibuf_reserve(buf, sizeof(nump)) == NULL) { ++ log_warn("mrt_dump_v2_hdr: buf_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: buf_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); } -@@ -387,7 +438,7 @@ mrt_dump_upcall(struct rib_entry *re, vo +@@ -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,12 +446,12 @@ mrt_dump_done(void *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_warnx("mrt_dump_hdr_se: buf_open error"); ++ log_warn("mrt_dump_hdr_se: buf_open error"); return (-1); -@@ -468,20 +519,20 @@ mrt_dump_hdr_se(struct buf ** bp, struct + } + +@@ -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_warnx("mrt_dump_hdr_se: buf_add error"); ++ log_warn("mrt_dump_hdr_se: buf_add error"); goto fail; } - if (buf_add(*bp, + if (ibuf_add(*bp, &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, sizeof(struct in6_addr)) == -1) { - log_warnx("mrt_dump_hdr_se: buf_add error"); +- log_warnx("mrt_dump_hdr_se: buf_add error"); ++ log_warn("mrt_dump_hdr_se: buf_add error"); goto fail; } if (swap) - if (buf_add(*bp, &((struct sockaddr_in6 *) + if (ibuf_add(*bp, &((struct sockaddr_in6 *) &peer->sa_local)->sin6_addr, sizeof(struct in6_addr)) == -1) { - log_warnx("mrt_dump_hdr_se: buf_add error"); -@@ -493,17 +544,17 @@ mrt_dump_hdr_se(struct buf ** bp, struct +- log_warnx("mrt_dump_hdr_se: buf_add error"); ++ log_warn("mrt_dump_hdr_se: buf_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"); -@@ -517,7 +568,15 @@ mrt_dump_hdr_rde(struct buf **bp, u_int1 +- log_warnx("mrt_dump_hdr_rde: buf_dynamic error"); ++ log_warn("mrt_dump_hdr_rde: buf_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); -@@ -525,11 +584,11 @@ mrt_dump_hdr_rde(struct buf **bp, u_int1 + 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 +597,22 @@ mrt_write(struct mrt *mrt) +@@ -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: head/net/openbgpd/files/patch-bgpd_mrt.h =================================================================== --- head/net/openbgpd/files/patch-bgpd_mrt.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_mrt.h (revision 305848) @@ -1,66 +1,287 @@ 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.8 -diff -u -p -r1.1.1.6 -r1.1.1.8 +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 12 Jun 2011 10:44:25 -0000 1.1.1.8 ++++ 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.27 2010/06/04 10:13:00 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 */ -@@ -75,8 +73,10 @@ enum MRT_BGP4MP_TYPES { +@@ -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 */ -@@ -184,6 +184,7 @@ enum MRT_BGP4MP_TYPES { +@@ -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 -@@ -235,7 +236,7 @@ enum MRT_BGP_TYPES { +@@ -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. -+ * State are defined in RFC 1771/4271. ++ * States are defined in RFC 1771/4271. */ /* -@@ -303,7 +304,7 @@ void mrt_dump_state(struct mrt *, u_in - struct peer *); - void mrt_clear_seq(void); - void mrt_dump_upcall(struct rib_entry *, void *); +@@ -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_done(void *); - void mrt_write(struct mrt *); - void mrt_clean(struct mrt *); - void mrt_init(struct imsgbuf *, struct imsgbuf *); +-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: head/net/openbgpd/files/patch-bgpd_name2id.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_name2id.c (nonexistent) +++ head/net/openbgpd/files/patch-bgpd_name2id.c (revision 305848) @@ -0,0 +1,14 @@ +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 Property changes on: head/net/openbgpd/files/patch-bgpd_name2id.c ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: head/net/openbgpd/files/patch-bgpd_parse.y =================================================================== --- head/net/openbgpd/files/patch-bgpd_parse.y (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_parse.y (revision 305848) @@ -1,1546 +1,1606 @@ Index: bgpd/parse.y =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/parse.y,v retrieving revision 1.1.1.8 -diff -u -p -r1.1.1.8 parse.y +retrieving revision 1.11 +diff -u -p -r1.1.1.8 -r1.11 --- bgpd/parse.y 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/parse.y 3 Jul 2011 04:43:32 -0000 ++++ bgpd/parse.y 13 Oct 2012 18:50:07 -0000 1.11 @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: parse.y,v 1.250 2010/03/31 18:53:23 claudio Exp $ */ ++/* $OpenBSD: parse.y,v 1.263 2012/09/12 05:56:22 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 -@@ -74,10 +77,12 @@ char *symget(const char *); +@@ -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 +110,7 @@ struct filter_match_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 +118,8 @@ struct peer *new_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 +128,14 @@ int neighbor_consistent(struct peer *) +@@ -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 +166,33 @@ typedef struct { +@@ -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 +215,7 @@ grammar : /* empty */ +@@ -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 +223,12 @@ grammar : /* empty */ +@@ -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 +290,8 @@ yesno : STRING { +@@ -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 +336,7 @@ conf_main : AS as4number { +@@ -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 +360,25 @@ conf_main : AS as4number { +@@ -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 +387,7 @@ conf_main : AS as4number { +@@ -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 +396,27 @@ conf_main : AS as4number { +@@ -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 +437,7 @@ conf_main : AS as4number { +@@ -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; -@@ -575,11 +542,20 @@ conf_main : AS as4number { +@@ -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 +564,15 @@ conf_main : AS as4number { +@@ -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 +605,47 @@ mrtdump : DUMP STRING inout STRING optn +@@ -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 +657,11 @@ address : STRING { +@@ -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 +675,7 @@ prefix : STRING '/' NUMBER { +@@ -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 +694,7 @@ prefix : STRING '/' NUMBER { +@@ -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 +708,7 @@ prefix : STRING '/' NUMBER { +@@ -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 +727,150 @@ optnumber : /* empty */ { $$ = 0; } +@@ -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 +960,17 @@ peeropts : REMOTEAS as4number { +@@ -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 +1021,17 @@ peeropts : REMOTEAS as4number { +@@ -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 +1039,31 @@ peeropts : REMOTEAS as4number { +@@ -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.restart = $3; ++ 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 +1262,7 @@ peeropts : REMOTEAS as4number { +@@ -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 +1336,10 @@ family : IPV4 { $$ = AFI_IPv4; } +@@ -1157,6 +1343,10 @@ family : IPV4 { $$ = AFI_IPv4; } | IPV6 { $$ = AFI_IPv6; } ; +nettype : STATIC { $$ = 1; }, + | CONNECTED { $$ = 0; } + ; + espah : ESP { $$ = 1; } | AH { $$ = 0; } ; -@@ -1336,12 +1519,12 @@ filter_prefix_l : filter_prefix { $$ +@@ -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 +1593,12 @@ filter_as : as4number { +@@ -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 +1626,18 @@ filter_elm : filter_prefix_h { +@@ -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 +1646,73 @@ filter_elm : filter_prefix_h { +@@ -1457,32 +1653,73 @@ filter_elm : filter_prefix_h { } fmopts.as_l = $1; } + | MAXASLEN NUMBER { + if (fmopts.m.aslen.type != ASLEN_NONE) { + yyerror("AS length filters already specified"); + YYERROR; + } + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("bad max-as-len %lld", $2); + YYERROR; + } + fmopts.m.aslen.type = ASLEN_MAX; + fmopts.m.aslen.aslen = $2; + } + | MAXASSEQ NUMBER { + if (fmopts.m.aslen.type != ASLEN_NONE) { + yyerror("AS length filters already specified"); + YYERROR; + } + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("bad max-as-seq %lld", $2); + YYERROR; + } + fmopts.m.aslen.type = ASLEN_SEQ; + fmopts.m.aslen.aslen = $2; + } | COMMUNITY STRING { if (fmopts.m.community.as != COMMUNITY_UNSET) { yyerror("\"community\" already specified"); free($2); YYERROR; } - if (parsecommunity($2, &fmopts.m.community.as, - &fmopts.m.community.type) == -1) { + if (parsecommunity(&fmopts.m.community, $2) == -1) { - free($2); - YYERROR; - } - free($2); - } ++ 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($2); + free($3); -+ YYERROR; -+ } -+ free($2); + YYERROR; + } + free($2); + free($3); -+ } + } | IPV4 { - if (fmopts.af) { + if (fmopts.aid) { yyerror("address family already specified"); YYERROR; } - fmopts.af = AF_INET; + fmopts.aid = AID_INET; } | IPV6 { - if (fmopts.af) { + if (fmopts.aid) { yyerror("address family already specified"); YYERROR; } - fmopts.af = AF_INET6; + fmopts.aid = AID_INET6; } ; -@@ -1782,8 +2012,7 @@ filter_set_opt : LOCALPREF NUMBER { +@@ -1588,7 +1825,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 +1860,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 +2019,7 @@ filter_set_opt : LOCALPREF NUMBER { else $$->type = ACTION_SET_COMMUNITY; - if (parsecommunity($3, &$$->action.community.as, - &$$->action.community.type) == -1) { + if (parsecommunity(&$$->action.community, $3) == -1) { free($3); free($$); YYERROR; -@@ -1796,40 +2025,62 @@ filter_set_opt : LOCALPREF NUMBER { +@@ -1796,40 +2032,62 @@ filter_set_opt : LOCALPREF NUMBER { free($$); YYERROR; } - /* Don't allow setting of unknown well-known types */ - if ($$->action.community.as == COMMUNITY_WELLKNOWN) { - switch ($$->action.community.type) { - case COMMUNITY_NO_EXPORT: - case COMMUNITY_NO_ADVERTISE: - case COMMUNITY_NO_EXPSUBCONFED: - case COMMUNITY_NO_PEER: - /* valid */ - break; - default: - /* unknown */ - yyerror("Invalid well-known community"); - free($$); - YYERROR; - break; - } + } + | EXTCOMMUNITY delete STRING STRING { + if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) + fatal(NULL); + if ($2) + $$->type = ACTION_DEL_EXT_COMMUNITY; + else + $$->type = ACTION_SET_EXT_COMMUNITY; + + if (parseextcommunity(&$$->action.ext_community, + $3, $4) == -1) { + free($3); + free($4); + free($$); + YYERROR; } + free($3); + free($4); + } + | ORIGIN origincode { + if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) + fatal(NULL); + $$->type = ACTION_SET_ORIGIN; + $$->action.origin = $2; } ; +origincode : string { + if (!strcmp($1, "egp")) + $$ = ORIGIN_EGP; + else if (!strcmp($1, "igp")) + $$ = ORIGIN_IGP; + else if (!strcmp($1, "incomplete")) + $$ = ORIGIN_INCOMPLETE; + else { + yyerror("unknown origin \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + }; + comma : "," | /* empty */ ; unaryop : '=' { $$ = OP_EQ; } - | '!' '=' { $$ = OP_NE; } - | '<' '=' { $$ = OP_LE; } + | NE { $$ = OP_NE; } + | LE { $$ = OP_LE; } | '<' { $$ = OP_LT; } - | '>' '=' { $$ = OP_GE; } + | GE { $$ = OP_GE; } | '>' { $$ = OP_GT; } ; binaryop : '-' { $$ = OP_RANGE; } - | '>' '<' { $$ = OP_XRANGE; } + | XRANGE { $$ = OP_XRANGE; } ; %% -@@ -1873,6 +2124,7 @@ lookup(char *s) +@@ -1873,6 +2131,7 @@ lookup(char *s) { "allow", ALLOW}, { "announce", ANNOUNCE}, { "any", ANY}, + { "as-4byte", AS4BYTE }, { "blackhole", BLACKHOLE}, { "capabilities", CAPABILITIES}, { "community", COMMUNITY}, -@@ -1889,16 +2141,22 @@ lookup(char *s) +@@ -1889,16 +2148,22 @@ lookup(char *s) { "enforce", ENFORCE}, { "esp", ESP}, { "evaluate", EVALUATE}, + { "export-target", EXPORTTRGT}, + { "ext-community", EXTCOMMUNITY}, { "fib-update", FIBUPDATE}, { "from", FROM}, { "group", GROUP}, { "holdtime", HOLDTIME}, { "ignore", IGNORE}, { "ike", IKE}, + { "import-target", IMPORTTRGT}, { "in", IN}, { "include", INCLUDE}, { "inet", IPV4}, { "inet6", IPV6}, +#if defined(IPV6_LINKLOCAL_PEER) + { "interface", LLIFACE}, +#endif { "ipsec", IPSEC}, { "key", KEY}, { "listen", LISTEN}, -@@ -1906,6 +2164,8 @@ lookup(char *s) +@@ -1906,6 +2171,8 @@ lookup(char *s) { "localpref", LOCALPREF}, { "log", LOG}, { "match", MATCH}, + { "max-as-len", MAXASLEN}, + { "max-as-seq", MAXASSEQ}, { "max-prefix", MAXPREFIX}, { "md5sig", MD5SIG}, { "med", MED}, -@@ -1918,6 +2178,7 @@ lookup(char *s) +@@ -1918,6 +2185,7 @@ lookup(char *s) { "nexthop", NEXTHOP}, { "no-modify", NOMODIFY}, { "on", ON}, + { "origin", ORIGIN}, { "out", OUT}, { "passive", PASSIVE}, { "password", PASSWORD}, -@@ -1929,10 +2190,14 @@ lookup(char *s) +@@ -1929,10 +2197,14 @@ lookup(char *s) { "prepend-self", PREPEND_SELF}, { "qualify", QUALIFY}, { "quick", QUICK}, + { "rd", RD}, { "rde", RDE}, + { "rdomain", RDOMAIN}, + { "refresh", REFRESH }, { "reject", REJECT}, { "remote-as", REMOTEAS}, { "restart", RESTART}, + { "restricted", RESTRICTED}, { "rib", RIB}, { "route-collector", ROUTECOLL}, { "route-reflector", REFLECTOR}, -@@ -1941,6 +2206,7 @@ lookup(char *s) +@@ -1941,6 +2213,7 @@ lookup(char *s) { "rtlabel", RTLABEL}, { "self", SELF}, { "set", SET}, + { "socket", SOCKET }, { "softreconfig", SOFTRECONFIG}, { "source-as", SOURCEAS}, { "spi", SPI}, -@@ -2117,9 +2383,10 @@ top: +@@ -2117,9 +2390,10 @@ top: return (0); if (next == quotec || c == ' ' || c == '\t') c = next; - else if (next == '\n') + else if (next == '\n') { + file->lineno++; continue; - else + } else lungetc(next); } else if (c == quotec) { *p = '\0'; -@@ -2135,6 +2402,26 @@ top: +@@ -2135,6 +2409,26 @@ top: if (yylval.v.string == NULL) fatal("yylex: strdup"); return (STRING); + case '!': + next = lgetc(0); + if (next == '=') + return (NE); + lungetc(next); + break; + case '<': + next = lgetc(0); + if (next == '=') + return (LE); + lungetc(next); + break; + case '>': + next = lgetc(0); + if (next == '<') + return (XRANGE); + else if (next == '=') + return (GE); + lungetc(next); + break; } #define allowed_to_end_number(x) \ -@@ -2274,18 +2561,21 @@ popfile(void) +@@ -2274,18 +2568,21 @@ popfile(void) int parse_config(char *filename, struct bgpd_config *xconf, struct mrt_head *xmconf, struct peer **xpeers, struct network_head *nc, - struct filter_head *xfilter_l) + struct filter_head *xfilter_l, struct rdomain_head *xrdom_l) { struct sym *sym, *next; struct peer *p, *pnext; struct listen_addr *la; struct network *n; struct filter_rule *r; + struct rde_rib *rr; + struct rdomain *rd; int errors = 0; if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) fatal(NULL); conf->opts = xconf->opts; + conf->csock = strdup(SOCKET_NAME); if ((file = pushfile(filename, 1)) == NULL) { free(conf); -@@ -2316,13 +2606,15 @@ parse_config(char *filename, struct bgpd +@@ -2316,13 +2613,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 +2636,9 @@ parse_config(char *filename, struct bgpd +@@ -2344,6 +2643,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 +2652,44 @@ parse_config(char *filename, struct bgpd +@@ -2357,23 +2659,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 +2821,27 @@ getcommunity(char *s) +@@ -2505,27 +2828,27 @@ getcommunity(char *s) } int -parsecommunity(char *s, int *as, int *type) +parsecommunity(struct filter_community *c, char *s) { char *p; - int i; + int i, as; /* Well-known communities */ if (strcasecmp(s, "NO_EXPORT") == 0) { - *as = COMMUNITY_WELLKNOWN; - *type = COMMUNITY_NO_EXPORT; + c->as = COMMUNITY_WELLKNOWN; + c->type = COMMUNITY_NO_EXPORT; return (0); } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { - *as = COMMUNITY_WELLKNOWN; - *type = COMMUNITY_NO_ADVERTISE; + c->as = COMMUNITY_WELLKNOWN; + c->type = COMMUNITY_NO_ADVERTISE; return (0); } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { - *as = COMMUNITY_WELLKNOWN; - *type = COMMUNITY_NO_EXPSUBCONFED; + c->as = COMMUNITY_WELLKNOWN; + c->type = COMMUNITY_NO_EXPSUBCONFED; return (0); } else if (strcasecmp(s, "NO_PEER") == 0) { - *as = COMMUNITY_WELLKNOWN; - *type = COMMUNITY_NO_PEER; + c->as = COMMUNITY_WELLKNOWN; + c->type = COMMUNITY_NO_PEER; return (0); } -@@ -2537,23 +2853,176 @@ parsecommunity(char *s, int *as, int *ty +@@ -2537,23 +2860,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 +3033,11 @@ alloc_peer(void) +@@ -2564,11 +3040,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.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 +3061,9 @@ new_peer(void) +@@ -2592,6 +3068,9 @@ new_peer(void) if (strlcpy(p->conf.descr, curgroup->conf.descr, sizeof(p->conf.descr)) >= sizeof(p->conf.descr)) fatalx("new_peer descr strlcpy"); + if (strlcpy(p->conf.lliface, curgroup->conf.lliface, + sizeof(p->conf.lliface)) >= sizeof(p->conf.lliface)) + fatalx("new_peer lliface strlcpy"); p->conf.groupid = curgroup->conf.id; p->conf.local_as = curgroup->conf.local_as; p->conf.local_short_as = curgroup->conf.local_short_as; -@@ -2674,39 +3146,52 @@ add_mrtconfig(enum mrt_type type, char * +@@ -2674,39 +3153,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 +3200,7 @@ get_id(struct peer *newpeer) +@@ -2715,7 +3207,7 @@ get_id(struct peer *newpeer) struct peer *p; for (p = peer_l_old; p != NULL; p = p->next) - if (newpeer->conf.remote_addr.af) { + if (newpeer->conf.remote_addr.aid) { if (!memcmp(&p->conf.remote_addr, &newpeer->conf.remote_addr, sizeof(p->conf.remote_addr))) { -@@ -2856,9 +3341,11 @@ str2key(char *s, char *dest, size_t max_ +@@ -2856,9 +3348,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 +3356,7 @@ neighbor_consistent(struct peer *p) +@@ -2869,7 +3363,7 @@ neighbor_consistent(struct peer *p) p->conf.auth.method == AUTH_IPSEC_IKE_AH || p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && - !p->conf.local_addr.af) { + !p->conf.local_addr.aid) { yyerror("neighbors with any form of IPsec configured " "need local-address to be specified"); return (-1); -@@ -2889,10 +3376,6 @@ neighbor_consistent(struct peer *p) +@@ -2889,18 +3383,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) -@@ -2909,6 +3392,11 @@ neighbor_consistent(struct peer *p) +- 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 +3399,11 @@ neighbor_consistent(struct peer *p) return (-1); } + /* the default MP capability is NONE */ + for (i = 0; i < AID_MAX; i++) + if (p->conf.capabilities.mp[i] == -1) + p->conf.capabilities.mp[i] = 0; + return (0); } -@@ -2927,6 +3415,11 @@ merge_filterset(struct filter_set_head * +@@ -2927,6 +3422,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 +3446,18 @@ merge_filterset(struct filter_set_head * +@@ -2953,9 +3453,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 +3487,6 @@ copy_filterset(struct filter_set_head *s +@@ -2985,22 +3494,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: head/net/openbgpd/files/patch-bgpd_pfkey.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_pfkey.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_pfkey.c (revision 305848) @@ -1,198 +1,198 @@ Index: bgpd/pfkey.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/pfkey.c,v retrieving revision 1.1.1.6 -retrieving revision 1.1.1.8 -diff -u -p -r1.1.1.6 -r1.1.1.8 +retrieving revision 1.1.1.9 +diff -u -p -r1.1.1.6 -r1.1.1.9 --- bgpd/pfkey.c 14 Feb 2010 20:19:57 -0000 1.1.1.6 -+++ bgpd/pfkey.c 12 Jun 2011 10:44:25 -0000 1.1.1.8 ++++ bgpd/pfkey.c 13 Oct 2012 18:22:44 -0000 1.1.1.9 @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.37 2009/04/21 15:25:52 henning Exp $ */ -+/* $OpenBSD: pfkey.c,v 1.41 2010/12/09 13:50:41 claudio Exp $ */ ++/* $OpenBSD: pfkey.c,v 1.40 2009/12/14 17:38:18 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -74,6 +74,7 @@ pfkey_send(int sd, uint8_t satype, uint8 int len = 0; int iov_cnt; struct sockaddr_storage ssrc, sdst, speer, smask, dmask; + struct sockaddr *saptr; if (!pid) pid = getpid(); @@ -81,22 +82,17 @@ pfkey_send(int sd, uint8_t satype, uint8 /* we need clean sockaddr... no ports set */ bzero(&ssrc, sizeof(ssrc)); bzero(&smask, sizeof(smask)); - switch (src->af) { - case AF_INET: - ((struct sockaddr_in *)&ssrc)->sin_addr = src->v4; - ssrc.ss_len = sizeof(struct sockaddr_in); - ssrc.ss_family = AF_INET; + if ((saptr = addr2sa(src, 0))) + memcpy(&ssrc, saptr, sizeof(ssrc)); + switch (src->aid) { + case AID_INET: memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8); break; - case AF_INET6: - memcpy(&((struct sockaddr_in6 *)&ssrc)->sin6_addr, - &src->v6, sizeof(struct in6_addr)); - ssrc.ss_len = sizeof(struct sockaddr_in6); - ssrc.ss_family = AF_INET6; + case AID_INET6: memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff, 128/8); break; - case 0: + case AID_UNSPEC: ssrc.ss_len = sizeof(struct sockaddr); break; default: @@ -107,22 +103,17 @@ pfkey_send(int sd, uint8_t satype, uint8 bzero(&sdst, sizeof(sdst)); bzero(&dmask, sizeof(dmask)); - switch (dst->af) { - case AF_INET: - ((struct sockaddr_in *)&sdst)->sin_addr = dst->v4; - sdst.ss_len = sizeof(struct sockaddr_in); - sdst.ss_family = AF_INET; + if ((saptr = addr2sa(dst, 0))) + memcpy(&sdst, saptr, sizeof(sdst)); + switch (dst->aid) { + case AID_INET: memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8); break; - case AF_INET6: - memcpy(&((struct sockaddr_in6 *)&sdst)->sin6_addr, - &dst->v6, sizeof(struct in6_addr)); - sdst.ss_len = sizeof(struct sockaddr_in6); - sdst.ss_family = AF_INET6; + case AID_INET6: memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff, 128/8); break; - case 0: + case AID_UNSPEC: sdst.ss_len = sizeof(struct sockaddr); break; default: @@ -220,8 +211,8 @@ pfkey_send(int sd, uint8_t satype, uint8 sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; bzero(&smask, sizeof(smask)); - switch (src->af) { - case AF_INET: + switch (src->aid) { + case AID_INET: smask.ss_len = sizeof(struct sockaddr_in); smask.ss_family = AF_INET; memset(&((struct sockaddr_in *)&smask)->sin_addr, @@ -233,7 +224,7 @@ pfkey_send(int sd, uint8_t satype, uint8 htons(0xffff); } break; - case AF_INET6: + case AID_INET6: smask.ss_len = sizeof(struct sockaddr_in6); smask.ss_family = AF_INET6; memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, @@ -247,8 +238,8 @@ pfkey_send(int sd, uint8_t satype, uint8 break; } bzero(&dmask, sizeof(dmask)); - switch (dst->af) { - case AF_INET: + switch (dst->aid) { + case AID_INET: dmask.ss_len = sizeof(struct sockaddr_in); dmask.ss_family = AF_INET; memset(&((struct sockaddr_in *)&dmask)->sin_addr, @@ -260,7 +251,7 @@ pfkey_send(int sd, uint8_t satype, uint8 htons(0xffff); } break; - case AF_INET6: + case AID_INET6: dmask.ss_len = sizeof(struct sockaddr_in6); dmask.ss_family = AF_INET6; memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, @@ -411,6 +402,33 @@ pfkey_send(int sd, uint8_t satype, uint8 } int +pfkey_read(int sd, struct sadb_msg *h) +{ + struct sadb_msg hdr; + + if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { + log_warn("pfkey peek"); + return (-1); + } + + /* XXX: Only one message can be outstanding. */ + if (hdr.sadb_msg_seq == sadb_msg_seq && + hdr.sadb_msg_pid == pid) { + if (h) + bcopy(&hdr, h, sizeof(hdr)); + return (0); + } + + /* not ours, discard */ + if (read(sd, &hdr, sizeof(hdr)) == -1) { + log_warn("pfkey read"); + return (-1); + } + + return (1); +} + +int pfkey_reply(int sd, u_int32_t *spip) { struct sadb_msg hdr, *msg; @@ -418,23 +436,13 @@ pfkey_reply(int sd, u_int32_t *spip) struct sadb_sa *sa; u_int8_t *data; ssize_t len; + int rv; - for (;;) { - if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { - log_warn("pfkey peek"); + do { + rv = pfkey_read(sd, &hdr); + if (rv == -1) return (-1); - } - - if (hdr.sadb_msg_seq == sadb_msg_seq && - hdr.sadb_msg_pid == pid) - break; - - /* not ours, discard */ - if (read(sd, &hdr, sizeof(hdr)) == -1) { - log_warn("pfkey read"); - return (-1); - } - } + } while (rv); if (hdr.sadb_msg_errno != 0) { errno = hdr.sadb_msg_errno; @@ -730,11 +738,9 @@ pfkey_init(struct bgpd_sysdep *sysdep) if (errno == EPROTONOSUPPORT) { log_warnx("PF_KEY not available, disabling ipsec"); sysdep->no_pfkey = 1; - return (0); - } else { - log_warn("PF_KEY socket"); return (-1); - } + } else + fatal("pfkey setup failed"); } - return (0); + return (fd); } Index: head/net/openbgpd/files/patch-bgpd_pftable.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_pftable.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_pftable.c (revision 305848) @@ -1,23 +1,17 @@ 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.6 -diff -u -p -r1.1.1.5 -r1.1.1.6 +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 14 Feb 2010 20:27:06 -0000 1.1.1.6 -@@ -1,4 +1,4 @@ --/* $OpenBSD: pftable.c,v 1.5 2005/07/01 09:19:24 claudio Exp $ */ -+/* $OpenBSD: pftable.c,v 1.6 2009/12/01 14:28:05 claudio Exp $ */ - - /* - * Copyright (c) 2004 Damien Miller ++++ 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: head/net/openbgpd/files/patch-bgpd_printconf.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_printconf.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_printconf.c (revision 305848) @@ -1,408 +1,426 @@ Index: bgpd/printconf.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/printconf.c,v retrieving revision 1.1.1.7 -retrieving revision 1.8 -diff -u -p -r1.1.1.7 -r1.8 +retrieving revision 1.9 +diff -u -p -r1.1.1.7 -r1.9 --- bgpd/printconf.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/printconf.c 2 Jul 2011 16:06:38 -0000 1.8 ++++ bgpd/printconf.c 13 Oct 2012 18:36:00 -0000 1.9 @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.70 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: printconf.c,v 1.79 2010/03/05 15:25:00 claudio Exp $ */ ++/* $OpenBSD: printconf.c,v 1.87 2012/09/12 05:56:22 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.restart == 1) -+ printf("%s\tannounce restart yes\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 "); } @@ -492,11 +581,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); -@@ -547,7 +645,7 @@ print_mrt(u_int32_t pid, u_int32_t gid, +@@ -513,6 +611,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,13 +641,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("%s %s %d\n", mrt_type(m->type), +- MRT2MC(m)->name, - MRT2MC(m)->ReopenTimerInterval); -+ (int)MRT2MC(m)->ReopenTimerInterval); ++ printf(" %d\n", MRT2MC(m)->ReopenTimerInterval); } } -@@ -612,26 +710,34 @@ peer_compare(const void *aa, const void +@@ -612,26 +711,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: head/net/openbgpd/files/patch-bgpd_rde.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde.c (revision 305848) @@ -1,2275 +1,2595 @@ Index: bgpd/rde.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v retrieving revision 1.1.1.8 -diff -u -p -r1.1.1.8 rde.c +retrieving revision 1.11 +diff -u -p -r1.1.1.8 -r1.11 --- bgpd/rde.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/rde.c 3 Jul 2011 04:43:59 -0000 ++++ bgpd/rde.c 13 Oct 2012 18:36:00 -0000 1.11 @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */ -+/* $OpenBSD: rde.c,v 1.290 2010/03/30 15:43:30 claudio Exp $ */ ++/* $OpenBSD: rde.c,v 1.320 2012/09/18 09:45:51 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer -@@ -18,6 +18,8 @@ +@@ -18,10 +18,11 @@ #include #include +#include +#include #include #include -@@ -51,12 +53,16 @@ void rde_update_withdraw(struct rde_pe +-#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,9 @@ struct rde_peer *peer_add(u_int32_t, str +@@ -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 +117,7 @@ time_t reloadtime; +@@ -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 +130,12 @@ struct rde_dump_ctx { +@@ -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 +155,18 @@ u_int32_t attrhashsize = 512; +@@ -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) { -+ struct rlimit rl; pid_t pid; struct passwd *pw; - struct peer *p; - struct listen_addr *la; struct pollfd *pfd = NULL; - struct filter_rule *f; - struct filter_set *set; - struct nexthop *nh; - struct rde_rib *rr; - struct mrt *mrt, *xmrt; + struct rde_mrt_ctx *mctx, *xmctx; void *newp; u_int pfd_elms = 0, i, j; int timeout; + u_int8_t aid; switch (pid = fork()) { case -1: -@@ -172,8 +177,6 @@ rde_main(struct bgpd_config *config, str +@@ -172,8 +179,6 @@ rde_main(struct bgpd_config *config, str return (pid); } - conf = config; - if ((pw = getpwnam(BGPD_USER)) == NULL) fatal("getpwnam"); -@@ -185,6 +188,12 @@ rde_main(struct bgpd_config *config, str - setproctitle("route decision engine"); - bgpd_process = PROC_RDE; - -+ if (getrlimit(RLIMIT_DATA, &rl) == -1) -+ fatal("getrlimit"); -+ rl.rlim_cur = rl.rlim_max; -+ if (setrlimit(RLIMIT_DATA, &rl) == -1) -+ fatal("setrlimit"); -+ - if (setgroups(1, &pw->pw_gid) || - setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) -@@ -194,6 +203,8 @@ rde_main(struct bgpd_config *config, str +@@ -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 +221,25 @@ rde_main(struct bgpd_config *config, str +@@ -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 +273,18 @@ rde_main(struct bgpd_config *config, str +@@ -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 +318,17 @@ rde_main(struct bgpd_config *config, str +@@ -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 +337,12 @@ rde_main(struct bgpd_config *config, str +@@ -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 +365,14 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -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 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"); -@@ -423,12 +411,14 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -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 != -@@ -446,13 +436,13 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -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); -@@ -544,6 +534,11 @@ badnet: + 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 +549,17 @@ badnet: +@@ -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 +574,12 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +598,26 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +625,26 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +658,42 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +701,27 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +729,59 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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); -+ } + } +- /* XXX this needs rework anyway */ +- /* sync local-RIB first */ + /* sync local-RIBs first */ if (reconf_in) rib_dump(&ribs[0], rde_softreconfig_in, NULL, - AF_UNSPEC); + AID_UNSPEC); /* then sync peers */ if (reconf_out) { int i; - for (i = 1; i < rib_size; i++) + for (i = 1; i < rib_size; i++) { + if (ribs[i].state == RECONF_REINIT) + /* already synced by _load */ + continue; rib_dump(&ribs[i], rde_softreconfig_out, - NULL, AF_UNSPEC); + NULL, AID_UNSPEC); + } + } + if (reconf_rib) { + LIST_FOREACH(peer, &peerlist, peer_l) { + rib_dump(&ribs[peer->ribid], + rde_softreconfig_load_peer, + peer, AID_UNSPEC); + } } while ((r = TAILQ_FIRST(rules_l)) != NULL) { -@@ -688,16 +791,16 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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"); -@@ -744,6 +847,8 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -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 +857,8 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +914,21 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +959,9 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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; -@@ -892,15 +991,25 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1035,32 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1098,9 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1130,22 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1155,8 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1164,8 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1201,42 @@ rde_update_dispatch(struct imsg *imsg) +@@ -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 +1264,8 @@ rde_update_update(struct rde_peer *peer, +@@ -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 +1275,24 @@ rde_update_update(struct rde_peer *peer, +@@ -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 +1300,8 @@ done: +@@ -1114,6 +1402,8 @@ done: if (r) peer->prefix_cnt++; + else if (f) + peer->prefix_cnt--; } void -@@ -1161,6 +1349,7 @@ rde_attr_parse(u_char *p, u_int16_t len, +@@ -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 +1384,7 @@ bad_len: +@@ -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 +1410,17 @@ bad_flags: +@@ -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 +1448,7 @@ bad_flags: +@@ -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 +1505,21 @@ bad_flags: +@@ -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 +1535,35 @@ bad_flags: +@@ -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 +1575,7 @@ 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 +1609,15 @@ 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,17 +1627,28 @@ bad_flags: +@@ -1381,19 +1729,30 @@ 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; + 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; ++ } ++ a->flags |= F_ATTR_AS4BYTE_NEW; goto optattr; -@@ -1440,8 +1697,8 @@ rde_attr_missing(struct rde_aspath *a, i + default: + if ((flags & ATTR_OPTIONAL) == 0) { +@@ -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 +1714,9 @@ rde_get_mp_nexthop(u_char *data, u_int16 +@@ -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 +1729,143 @@ rde_get_mp_nexthop(u_char *data, u_int16 +@@ -1471,72 +1867,143 @@ 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); + else + log_warnx("bad interface: %s", peer->conf.lliface); + } +#endif + break; + case AID_VPN_IPv4: /* - * lock the nexthop because it is not yet linked else - * withdraws may remove this nexthop which in turn would - * cause a use after free error. + * Neither RFC4364 nor RFC3107 specify the format of the + * nexthop in an explicit way. The quality of RFC went down -+ * the toilet the larger the the number got. ++ * 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 +1875,50 @@ rde_update_get_prefix6(u_char *p, u_int1 +@@ -1546,25 +2013,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 +1970,30 @@ rde_as4byte_fixup(struct rde_peer *peer, +@@ -1616,16 +2108,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 +2037,10 @@ rde_reflector(struct rde_peer *peer, str +@@ -1669,6 +2175,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) { -@@ -1724,7 +2096,7 @@ void +@@ -1677,10 +2187,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 +2234,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; -@@ -1748,23 +2120,23 @@ rde_dump_rib_as(struct prefix *p, struct + + 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 +2258,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; -+ rib.flags |= F_PREF_ACTIVE; - if (asp->peer->conf.ebgp == 0) +- 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 +2156,13 @@ rde_dump_rib_as(struct prefix *p, struct +@@ -1784,13 +2297,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,15 +2200,15 @@ rde_dump_filter(struct prefix *p, struct +@@ -1828,17 +2341,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, req->as.type, req->as.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); -@@ -1872,7 +2244,7 @@ rde_dump_prefix_upcall(struct rib_entry + } else if (req->flags & F_CTL_ADJ_OUT) { + if (p->rib->active != p) +@@ -1872,7 +2388,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 +2261,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1889,6 +2405,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 +2275,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1902,6 +2419,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 +2298,18 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1924,7 +2442,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 +2322,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1937,7 +2466,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); } -@@ -1974,10 +2359,10 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t +@@ -1971,13 +2500,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 +2370,25 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t +@@ -1985,13 +2518,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 +2408,45 @@ rde_send_kroute(struct prefix *new, stru +@@ -2011,43 +2556,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 (addr.vpn4.rd != rd->rd) -+ continue; + if (!rde_rdomain_import(p->aspath, rd)) + continue; + /* must send exit_nexthop so that correct MPLS tunnel + * is chosen + */ + if (type == IMSG_KROUTE_CHANGE) + memcpy(&kr.nexthop, + &p->aspath->nexthop->exit_nexthop, + sizeof(kr.nexthop)); + if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1, + &kr, sizeof(kr)) == -1) + fatal("imsg_compose error"); + } break; - case AF_INET6: - bzero(&kl6, sizeof(kl6)); - memcpy(&kl6.kr.prefix, &addr.v6, sizeof(struct in6_addr)); - kl6.kr.prefixlen = p->prefix->prefixlen; - if (p->aspath->flags & F_NEXTHOP_REJECT) - kl6.kr.flags |= F_REJECT; - if (p->aspath->flags & F_NEXTHOP_BLACKHOLE) - kl6.kr.flags |= F_BLACKHOLE; - if (type == IMSG_KROUTE_CHANGE) { - type = IMSG_KROUTE6_CHANGE; - memcpy(&kl6.kr.nexthop, - &p->aspath->nexthop->true_nexthop.v6, - sizeof(struct in6_addr)); - } else - type = IMSG_KROUTE6_DELETE; - strlcpy(kl6.label, rtlabel_id2name(p->aspath->rtlabelid), - sizeof(kl6.label)); - if (imsg_compose(ibuf_main, type, 0, 0, -1, &kl6, - sizeof(kl6)) == -1) + default: + if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1, + &kr, sizeof(kr)) == -1) fatal("imsg_compose error"); break; } -@@ -2098,7 +2497,6 @@ rde_send_pftable_commit(void) +@@ -2098,7 +2643,6 @@ rde_send_pftable_commit(void) void rde_send_nexthop(struct bgpd_addr *next, int valid) { - size_t size; int type; if (valid) -@@ -2106,8 +2504,6 @@ rde_send_nexthop(struct bgpd_addr *next, +@@ -2106,8 +2650,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 +2597,10 @@ rde_softreconfig_in(struct rib_entry *re +@@ -2201,6 +2743,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 +2628,7 @@ rde_softreconfig_in(struct rib_entry *re +@@ -2228,7 +2774,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 +2641,104 @@ done: +@@ -2241,6 +2787,104 @@ done: } } +void +rde_softreconfig_load(struct rib_entry *re, void *ptr) +{ + struct rib *rib = ptr; + struct prefix *p, *np; + struct pt_entry *pt; + struct rde_peer *peer; + struct rde_aspath *asp, *nasp; + enum filter_actions action; + struct bgpd_addr addr; + + pt = re->prefix; + pt_getaddr(pt, &addr); + for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) { + np = LIST_NEXT(p, rib_l); + + /* store aspath as prefix may change till we're done */ + asp = p->aspath; + peer = asp->peer; + + action = rde_filter(rib->id, &nasp, newrules, peer, asp, &addr, + pt->prefixlen, peer, DIR_IN); + nasp = nasp != NULL ? nasp : asp; + + if (action == ACTION_ALLOW) { + /* update Local-RIB */ + path_update(rib, peer, nasp, &addr, pt->prefixlen); + } + + if (nasp != asp) + path_put(nasp); + } +} + +void +rde_softreconfig_load_peer(struct rib_entry *re, void *ptr) +{ + struct rde_peer *peer = ptr; + struct prefix *p = re->active; + struct pt_entry *pt; + struct rde_aspath *nasp; + enum filter_actions na; + struct bgpd_addr addr; + + pt = re->prefix; + pt_getaddr(pt, &addr); + + /* check if prefix was announced */ + if (up_test_update(peer, p) != 1) + return; + + na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath, + &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); + nasp = nasp != NULL ? nasp : p->aspath; + + if (na == ACTION_DENY) + /* nothing todo */ + goto done; + + /* send update */ + up_generate(peer, nasp, &addr, pt->prefixlen); +done: + if (nasp != p->aspath) + path_put(nasp); +} + +void +rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr) +{ + struct rde_peer *peer = ptr; + struct prefix *p = re->active; + struct pt_entry *pt; + struct rde_aspath *oasp; + enum filter_actions oa; + struct bgpd_addr addr; + + pt = re->prefix; + pt_getaddr(pt, &addr); + + /* check if prefix was announced */ + if (up_test_update(peer, p) != 1) + return; + + oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath, + &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); + oasp = oasp != NULL ? oasp : p->aspath; + + if (oa == ACTION_DENY) + /* nothing todo */ + goto done; + + /* send withdraw */ + up_generate(peer, NULL, &addr, pt->prefixlen); +done: + if (oasp != p->aspath) + path_put(oasp); +} + /* * update specific functions */ -@@ -2252,7 +2750,7 @@ rde_up_dump_upcall(struct rib_entry *re, +@@ -2252,7 +2896,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 +2763,7 @@ rde_generate_updates(u_int16_t ribid, st +@@ -2265,7 +2909,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 +2784,7 @@ void +@@ -2286,7 +2930,7 @@ void rde_update_queue_runner(void) { struct rde_peer *peer; - int r, sent, max = RDE_RUNNER_ROUNDS; + int r, sent, max = RDE_RUNNER_ROUNDS, eor = 0; u_int16_t len, wd_len, wpos; len = sizeof(queue_buf) - MSGSIZE_HEADER; -@@ -2300,7 +2798,7 @@ rde_update_queue_runner(void) +@@ -2300,7 +2944,7 @@ rde_update_queue_runner(void) /* first withdraws */ wpos = 2; /* reserve space for the length field */ r = up_dump_prefix(queue_buf + wpos, len - wpos - 2, - &peer->withdraws, peer); + &peer->withdraws[AID_INET], peer); wd_len = r; /* write withdraws length filed */ wd_len = htons(wd_len); -@@ -2310,31 +2808,49 @@ rde_update_queue_runner(void) +@@ -2310,31 +2954,49 @@ rde_update_queue_runner(void) /* now bgp path attributes */ r = up_dump_attrnlri(queue_buf + wpos, len - wpos, peer); - wpos += r; - - if (wpos == 4) - /* - * No packet to send. The 4 bytes are the - * needed withdraw and path attribute length. - */ - continue; + switch (r) { + case -1: + eor = 1; + if (wd_len == 0) { + /* no withdraws queued just send EoR */ + peer_send_eor(peer, AID_INET); + continue; + } + break; + case 2: + if (wd_len == 0) { + /* + * No packet to send. No withdraws and + * no path attributes. Skip. + */ + continue; + } + /* FALLTHROUGH */ + default: + wpos += r; + break; + } /* finally send message to SE */ if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id, 0, -1, queue_buf, wpos) == -1) fatal("imsg_compose error"); sent++; + if (eor) { + eor = 0; + peer_send_eor(peer, AID_INET); + } } max -= sent; } while (sent != 0 && max > 0); } void -rde_update6_queue_runner(void) +rde_update6_queue_runner(u_int8_t aid) { struct rde_peer *peer; u_char *b; - int sent, max = RDE_RUNNER_ROUNDS / 2; + int r, sent, max = RDE_RUNNER_ROUNDS / 2; u_int16_t len; /* first withdraws ... */ -@@ -2346,7 +2862,7 @@ rde_update6_queue_runner(void) +@@ -2346,7 +3008,7 @@ rde_update6_queue_runner(void) if (peer->state != PEER_UP) continue; len = sizeof(queue_buf) - MSGSIZE_HEADER; - b = up_dump_mp_unreach(queue_buf, &len, peer); + b = up_dump_mp_unreach(queue_buf, &len, peer, aid); if (b == NULL) continue; -@@ -2369,10 +2885,18 @@ rde_update6_queue_runner(void) +@@ -2369,10 +3031,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; + continue; + case -1: + peer_send_eor(peer, aid); - continue; ++ continue; + default: + b = queue_buf + r; + break; + } + /* finally send message to SE */ if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id, 0, -1, b, len) == -1) -@@ -2411,7 +2935,7 @@ rde_decisionflags(void) +@@ -2411,7 +3081,7 @@ rde_decisionflags(void) int rde_as4byte(struct rde_peer *peer) { - return (peer->capa_announced.as4byte && peer->capa_received.as4byte); + return (peer->capa.as4byte); } /* -@@ -2429,7 +2953,6 @@ void +@@ -2429,7 +3099,6 @@ void peer_init(u_int32_t hashsize) { struct peer_config pc; - struct in_addr id; u_int32_t hs, i; for (hs = 1; hs < hashsize; hs <<= 1) -@@ -2445,17 +2968,13 @@ peer_init(u_int32_t hashsize) +@@ -2445,17 +3114,13 @@ peer_init(u_int32_t hashsize) peertable.peer_hashmask = hs - 1; bzero(&pc, sizeof(pc)); - pc.remote_as = conf->as; - id.s_addr = conf->bgpid; - snprintf(pc.descr, sizeof(pc.descr), "LOCAL: ID %s", inet_ntoa(id)); + snprintf(pc.descr, sizeof(pc.descr), "LOCAL"); peerself = peer_add(0, &pc); if (peerself == NULL) fatalx("peer_init add self"); peerself->state = PEER_UP; - peerself->remote_bgpid = ntohl(conf->bgpid); - peerself->short_as = conf->short_as; } void -@@ -2534,14 +3053,10 @@ peer_localaddrs(struct rde_peer *peer, s +@@ -2534,14 +3199,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 +3074,7 @@ peer_localaddrs(struct rde_peer *peer, s +@@ -2559,13 +3220,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,6 +3086,7 @@ void +@@ -2577,23 +3232,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) { -@@ -2590,10 +3100,7 @@ peer_up(u_int32_t id, struct session_up +- 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 +3114,10 @@ peer_up(u_int32_t id, struct session_up +@@ -2607,7 +3261,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 -@@ -2642,42 +3152,32 @@ peer_down(u_int32_t id) +@@ -2641,43 +3298,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_dump(u_int32_t id, u_int8_t aid) ++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_dump: 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); -+ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) -+ up_generate_default(rules_l, peer, aid); -+ else -+ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid); -+ if (peer->capa.restart) -+ up_generate_marker(peer, aid); ++ /* 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 */ -+/* End-of-RIB marker, RFC 4724 */ void -peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi) -+peer_send_eor(struct rde_peer *peer, u_int8_t aid) ++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 +3188,9 @@ peer_send_eor(struct rde_peer *peer, u_i +@@ -2688,6 +3392,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,25 +3212,43 @@ peer_send_eor(struct rde_peer *peer, u_i +@@ -2709,39 +3416,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; + } + } + } + - asp = path_get(); - asp->aspath = aspath_get(NULL, 0); - asp->origin = ORIGIN_IGP; -@@ -2737,7 +3258,9 @@ network_add(struct network_config *nc, i ++ 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); -@@ -2749,12 +3272,41 @@ network_add(struct network_config *nc, i +- + path_put(asp); + filterset_free(&nc->attrset); + } +@@ -2749,12 +3478,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 +3316,31 @@ void +@@ -2764,38 +3522,31 @@ void network_dump_upcall(struct rib_entry *re, void *ptr) { struct prefix *p; - struct kroute k; - struct kroute6 k6; + struct kroute_full k; struct bgpd_addr addr; struct rde_dump_ctx *ctx = ptr; LIST_FOREACH(p, &re->prefix_h, rib_l) { if (!(p->aspath->flags & F_PREFIX_ANNOUNCED)) continue; - if (p->prefix->af == AF_INET) { - bzero(&k, sizeof(k)); - pt_getaddr(p->prefix, &addr); - k.prefix.s_addr = addr.v4.s_addr; - k.prefixlen = p->prefix->prefixlen; - if (p->aspath->peer == peerself) - k.flags = F_KERNEL; - if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0, - ctx->req.pid, -1, &k, sizeof(k)) == -1) - log_warnx("network_dump_upcall: " - "imsg_compose error"); - } - if (p->prefix->af == AF_INET6) { - bzero(&k6, sizeof(k6)); - pt_getaddr(p->prefix, &addr); - memcpy(&k6.prefix, &addr.v6, sizeof(k6.prefix)); - k6.prefixlen = p->prefix->prefixlen; - if (p->aspath->peer == peerself) - k6.flags = F_KERNEL; - if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK6, 0, - ctx->req.pid, -1, &k6, sizeof(k6)) == -1) - log_warnx("network_dump_upcall: " - "imsg_compose error"); - } + pt_getaddr(p->prefix, &addr); + + bzero(&k, sizeof(k)); + memcpy(&k.prefix, &addr, sizeof(k.prefix)); + if (p->aspath->nexthop == NULL || + p->aspath->nexthop->state != NEXTHOP_REACH) + k.nexthop.aid = k.prefix.aid; + else + memcpy(&k.nexthop, &p->aspath->nexthop->true_nexthop, + sizeof(k.nexthop)); + k.prefixlen = p->prefix->prefixlen; + k.flags = F_KERNEL; + if ((p->aspath->flags & F_ANN_DYNAMIC) == 0) + k.flags = F_STATIC; + if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0, + ctx->req.pid, -1, &k, sizeof(k)) == -1) + log_warnx("network_dump_upcall: " + "imsg_compose error"); } } -@@ -2841,10 +3386,10 @@ sa_cmp(struct bgpd_addr *a, struct socka +@@ -2841,10 +3592,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) Index: head/net/openbgpd/files/patch-bgpd_rde.h =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde.h (revision 305848) @@ -1,229 +1,356 @@ 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.11 -diff -u -p -r1.1.1.8 -r1.1.1.11 +retrieving revision 1.1.1.12 +diff -u -p -r1.1.1.8 -r1.1.1.12 --- bgpd/rde.h 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/rde.h 12 Jun 2011 10:44:25 -0000 1.1.1.11 ++++ bgpd/rde.h 13 Oct 2012 18:22:46 -0000 1.1.1.12 @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.120 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: rde.h,v 1.138 2010/11/18 12:18:31 claudio Exp $ */ ++/* $OpenBSD: rde.h,v 1.143 2012/08/12 14:24:56 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and -@@ -56,12 +56,9 @@ struct rde_peer { +@@ -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; -@@ -77,10 +74,13 @@ struct rde_peer { + 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); -@@ -163,6 +163,7 @@ LIST_HEAD(prefix_head, prefix); +@@ -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 +221,14 @@ struct nexthop { +@@ -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 +236,25 @@ struct pt_entry4 { +@@ -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 +264,7 @@ struct rib_context { +@@ -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 +276,15 @@ 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 { -@@ -293,7 +299,7 @@ extern struct rde_memstats rdemem; +@@ -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 +315,7 @@ int rde_as4byte(struct rde_peer *); +@@ -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 +333,7 @@ int aspath_verify(void *, u_int16_t, i +@@ -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); -@@ -342,21 +349,30 @@ int aspath_loopfree(struct aspath *, u +@@ -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 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); -@@ -395,7 +411,7 @@ void prefix_network_clean(struct rde_p +@@ -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 *); -@@ -415,12 +431,15 @@ int up_generate(struct rde_peer *, str +@@ -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); - /* rde_prefix.c */ - #define pt_empty(pt) ((pt)->refcnt == 0) -@@ -452,8 +471,7 @@ enum filter_actions rde_filter(u_int16_t - struct rde_aspath *, struct bgpd_addr *, u_int8_t, - struct rde_peer *, enum directions); - void rde_apply_set(struct rde_aspath *, struct filter_set_head *, -- sa_family_t, struct rde_peer *, struct rde_peer *); --int rde_filter_community(struct rde_aspath *, int, int); -+ u_int8_t, struct rde_peer *, struct rde_peer *); - int rde_filter_equal(struct filter_head *, struct filter_head *, - struct rde_peer *, enum directions); - + #endif /* __RDE_H__ */ Index: head/net/openbgpd/files/patch-bgpd_rde_attr.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_attr.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_attr.c (revision 305848) @@ -1,465 +1,562 @@ 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.6 -diff -u -p -r1.1.1.6 -r1.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 2 Jul 2011 16:06:38 -0000 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.83 2010/03/29 09:24:07 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" -@@ -63,7 +71,7 @@ attr_write(void *p, u_int16_t p_len, u_i +@@ -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]; -@@ -80,9 +88,9 @@ attr_writebuf(struct buf *buf, u_int8_t + ++ 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 */ -@@ -405,6 +416,7 @@ aspath_verify(void *data, u_int16_t len, +@@ -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 +431,15 @@ aspath_verify(void *data, u_int16_t len, +@@ -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 +451,7 @@ aspath_verify(void *data, u_int16_t 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 -@@ -972,14 +992,62 @@ aspath_match(struct aspath *a, enum as_s +@@ -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 --community_match(void *data, u_int16_t len, int as, int type) +-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 *p = data; -- u_int16_t eas, etype; -+ u_int8_t *seg; + 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; -+ + 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); -+ } + return (1); + else + return (0); + } -- len >>= 2; /* divide by four */ +- 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; + seg = a->data; + for (len = a->len; len > 0; len -= seg_size, seg += seg_size) { + seg_type = seg[0]; + seg_len = seg[1]; + seg_size = 2 + sizeof(u_int32_t) * seg_len; -- for (; len > 0; len--) { -+ for (i = 0; i < seg_len; i++) { +- 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); -+} -+ + } + } + return (0); + } + +/* + * Functions handling communities and extended communities. + */ + +int community_ext_matchone(struct filter_extcommunity *, u_int16_t, u_int64_t); + -+int + 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 +1068,6 @@ community_set(struct rde_aspath *asp, in +@@ -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 +1084,7 @@ community_set(struct rde_aspath *asp, in +@@ -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 +1099,10 @@ community_set(struct rde_aspath *asp, in +@@ -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 +1115,7 @@ community_delete(struct rde_aspath *asp, +@@ -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 +1166,250 @@ community_delete(struct rde_aspath *asp, +@@ -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); -+} -+ + 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); - } - ++ 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: head/net/openbgpd/files/patch-bgpd_rde_decide.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_decide.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_decide.c (revision 305848) @@ -1,53 +1,133 @@ Index: bgpd/rde_decide.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_decide.c,v retrieving revision 1.1.1.6 -diff -u -p -r1.1.1.6 rde_decide.c +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 3 Jul 2011 04:44:36 -0000 ++++ 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.59 2009/08/06 08:53:11 claudio Exp $ */ ++/* $OpenBSD: rde_decide.c,v 1.61 2012/04/12 17:31:05 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker -@@ -118,6 +118,12 @@ prefix_cmp(struct prefix *p1, struct pre +@@ -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); -@@ -204,7 +210,7 @@ prefix_cmp(struct prefix *p1, struct pre +@@ -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 +251,7 @@ prefix_evaluate(struct prefix *p, struct +@@ -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 +269,7 @@ prefix_evaluate(struct prefix *p, struct +@@ -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: head/net/openbgpd/files/patch-bgpd_rde_filter.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_filter.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_filter.c (revision 305848) @@ -1,241 +1,242 @@ 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.7 -diff -u -p -r1.1.1.7 -r1.7 +retrieving revision 1.8 +diff -u -p -r1.1.1.7 -r1.8 --- bgpd/rde_filter.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 -+++ bgpd/rde_filter.c 2 Jul 2011 16:06:38 -0000 1.7 ++++ bgpd/rde_filter.c 13 Oct 2012 18:36:00 -0000 1.8 @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_filter.c,v 1.56 2009/06/06 01:10:29 claudio Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.62 2010/03/05 15:25:00 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -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; @@ -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,6 +250,17 @@ 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; } } } -@@ -251,11 +269,21 @@ int +@@ -251,11 +269,22 @@ int rde_filter_match(struct filter_rule *f, struct rde_aspath *asp, struct bgpd_addr *prefix, u_int8_t plen, struct rde_peer *peer) { - int as, type; + u_int32_t pas; + int cas, type; - if (asp != NULL && f->match.as.type != AS_NONE) - if (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, f->match.as.type, pas) == 0) ++ 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 +291,10 @@ rde_filter_match(struct filter_rule *f, +@@ -263,10 +292,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 +309,17 @@ rde_filter_match(struct filter_rule *f, +@@ -281,12 +310,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 +355,7 @@ rde_filter_match(struct filter_rule *f, +@@ -322,7 +356,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); -@@ -356,19 +389,6 @@ rde_filter_match(struct filter_rule *f, +@@ -356,19 +390,6 @@ rde_filter_match(struct filter_rule *f, } int -rde_filter_community(struct rde_aspath *asp, int as, int type) -{ - struct attr *a; - - a = attr_optget(asp, ATTR_COMMUNITIES); - if (a == NULL) - /* no communities, no match */ - return (0); - - return (community_match(a->data, a->len, as, type)); -} - -int rde_filter_equal(struct filter_head *a, struct filter_head *b, struct rde_peer *peer, enum directions dir) { -@@ -476,6 +496,12 @@ filterset_cmp(struct filter_set *a, stru +@@ -476,6 +497,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 +509,29 @@ filterset_cmp(struct filter_set *a, stru +@@ -483,13 +510,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 +616,19 @@ filterset_equal(struct filter_set_head * +@@ -574,6 +617,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 +671,14 @@ filterset_name(enum action_types type) +@@ -616,7 +672,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: head/net/openbgpd/files/patch-bgpd_rde_prefix.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_prefix.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_prefix.c (revision 305848) @@ -1,301 +1,301 @@ 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.5 -diff -u -p -r1.1.1.6 -r1.5 +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 10 Apr 2010 12:16:23 -0000 1.5 ++++ 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.32 2010/03/26 15:41:04 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: head/net/openbgpd/files/patch-bgpd_rde_rib.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_rib.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_rib.c (revision 305848) @@ -1,399 +1,513 @@ Index: bgpd/rde_rib.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_rib.c,v retrieving revision 1.1.1.7 -diff -u -p -r1.1.1.7 rde_rib.c +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 3 Jul 2011 04:45:31 -0000 ++++ 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.125 2010/04/07 09:44:11 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 */ -@@ -632,11 +639,11 @@ prefix_compare(const struct bgpd_addr *a - int i; - u_int8_t m; +@@ -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); -+ if (a->aid != b->aid) -+ return (a->aid - b->aid); - +- - switch (a->af) { - case AF_INET: -+ switch (a->aid) { -+ case AID_INET: - if (prefixlen > 32) - fatalx("prefix_cmp: bad IPv4 prefixlen"); - mask = htonl(prefixlen2mask(prefixlen)); -@@ -645,7 +652,7 @@ prefix_compare(const struct bgpd_addr *a - if (aa != ba) - return (aa - ba); - return (0); +- 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: -+ case AID_INET6: - if (prefixlen > 128) - fatalx("prefix_cmp: bad IPv6 prefixlen"); - for (i = 0; i < prefixlen / 8; i++) -@@ -660,6 +667,24 @@ prefix_compare(const struct bgpd_addr *a - (b->v6.s6_addr[prefixlen / 8] & m)); - } - return (0); -+ case AID_VPN_IPv4: -+ if (prefixlen > 32) -+ fatalx("prefix_cmp: bad IPv4 VPN prefixlen"); -+ if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd)) -+ return (1); -+ if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd)) -+ return (-1); -+ mask = htonl(prefixlen2mask(prefixlen)); -+ aa = ntohl(a->vpn4.addr.s_addr & mask); -+ ba = ntohl(b->vpn4.addr.s_addr & mask); -+ if (aa != ba) -+ return (aa - ba); -+ if (a->vpn4.labellen > b->vpn4.labellen) -+ return (1); -+ if (a->vpn4.labellen < b->vpn4.labellen) -+ return (-1); -+ return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, -+ a->vpn4.labellen)); - default: - fatalx("prefix_cmp: unknown af"); - } -@@ -806,16 +831,33 @@ prefix_write(u_char *buf, int len, struc +- 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) -- return (-1); + switch (prefix->aid) { + case AID_INET: + case AID_INET6: + totlen = PREFIX_SIZE(plen); - -- 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) ++ + 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 +903,7 @@ prefix_updateall(struct rde_aspath *asp, +@@ -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; } -@@ -885,16 +927,12 @@ prefix_updateall(struct rde_aspath *asp, +@@ -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,7 +945,6 @@ prefix_network_clean(struct rde_peer *pe +@@ -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); -@@ -916,12 +953,8 @@ prefix_network_clean(struct rde_peer *pe +- 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 +987,11 @@ prefix_link(struct prefix *pref, struct +@@ -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 +999,8 @@ prefix_unlink(struct prefix *pref) +@@ -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 +1008,8 @@ prefix_unlink(struct prefix *pref) +@@ -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 +1105,6 @@ nexthop_update(struct kroute_nexthop *ms +@@ -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 +1119,13 @@ nexthop_update(struct kroute_nexthop *ms +@@ -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,7 +1141,7 @@ nexthop_update(struct kroute_nexthop *ms +@@ -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; -@@ -1138,7 +1161,7 @@ nexthop_modify(struct rde_aspath *asp, s - asp->flags |= F_NEXTHOP_SELF; +- 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) -+ if (aid != nexthop->aid) - return; +- 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); + } - nh = nexthop_get(nexthop); -@@ -1233,17 +1256,17 @@ nexthop_compare(struct nexthop *na, stru + 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 +1292,14 @@ nexthop_hash(struct bgpd_addr *nexthop) +@@ -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: head/net/openbgpd/files/patch-bgpd_rde_update.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_rde_update.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_rde_update.c (revision 305848) @@ -1,612 +1,644 @@ Index: bgpd/rde_update.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_update.c,v retrieving revision 1.1.1.7 -diff -u -p -r1.1.1.7 rde_update.c +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 3 Jul 2011 04:45:50 -0000 ++++ 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,21 +291,14 @@ up_test_update(struct rde_peer *peer, st +@@ -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 == 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 || +- 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: head/net/openbgpd/files/patch-bgpd_session.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_session.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_session.c (revision 305848) @@ -1,1344 +1,2034 @@ Index: bgpd/session.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.c,v retrieving revision 1.1.1.8 -retrieving revision 1.9 -diff -u -p -r1.1.1.8 -r1.9 +retrieving revision 1.12 +diff -u -p -r1.1.1.8 -r1.12 --- bgpd/session.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/session.c 3 Jul 2011 11:18:26 -0000 1.9 ++++ bgpd/session.c 13 Oct 2012 19:10:00 -0000 1.12 @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.293 2009/06/07 05:56:24 eric Exp $ */ -+/* $OpenBSD: session.c,v 1.304 2010/01/05 08:49:57 claudio Exp $ */ ++/* $OpenBSD: session.c,v 1.324 2012/09/12 05:56:22 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer -@@ -21,6 +21,8 @@ +@@ -21,18 +21,21 @@ #include #include +#include +#include #include ++#include #include #include -@@ -50,7 +52,12 @@ + #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 +72,8 @@ void session_accept(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,7 +81,7 @@ void session_keepalive(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 *); -@@ -83,22 +89,22 @@ int parse_update(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; -@@ -175,12 +181,11 @@ setup_listeners(u_int *la_cnt) +@@ -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_LOCAL, SOCK_STREAM, 0); ++ 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; -+ struct rlimit rl; + int nfds, timeout, pfkeysock; unsigned int i, j, idx_peers, idx_listeners, idx_mrts; pid_t pid; u_int pfd_elms = 0, peer_l_elms = 0, mrt_l_elms = 0; -@@ -189,19 +194,13 @@ session_main(struct bgpd_config *config, +@@ -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 +210,6 @@ session_main(struct bgpd_config *config, +@@ -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); -@@ -229,28 +221,31 @@ session_main(struct bgpd_config *config, +@@ -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"); -+ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) -+ fatal("getrlimit"); -+ rl.rlim_cur = rl.rlim_max; -+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) -+ fatal("setrlimit"); -+ + pfkeysock = pfkey_init(&sysdep); if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("can't drop privileges"); - listener_cnt = 0; - setup_listeners(&listener_cnt); - signal(SIGTERM, session_sighdlr); signal(SIGINT, session_sighdlr); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); - log_info("session engine ready"); + signal(SIGALRM, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + close(pipe_m2s[0]); close(pipe_s2r[1]); close(pipe_s2rctl[1]); close(pipe_m2r[0]); close(pipe_m2r[1]); - init_conf(conf); if ((ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL || (ibuf_rde_ctl = malloc(sizeof(struct imsgbuf))) == NULL || (ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL) -@@ -258,37 +253,21 @@ session_main(struct bgpd_config *config, +@@ -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 +287,9 @@ session_main(struct bgpd_config *config, +@@ -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 +297,7 @@ session_main(struct bgpd_config *config, +@@ -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 +326,17 @@ session_main(struct bgpd_config *config, +@@ -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,14 +382,19 @@ session_main(struct bgpd_config *config, +@@ -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; +- 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; -@@ -534,6 +527,14 @@ session_main(struct bgpd_config *config, +- 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) { -@@ -557,7 +558,7 @@ session_main(struct bgpd_config *config, +@@ -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 +644,9 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +746,6 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +779,8 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +791,6 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +814,8 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +826,6 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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 +855,8 @@ bgp_fsm(struct peer *peer, enum session_ +@@ -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; } -@@ -923,6 +923,7 @@ change_state(struct peer *peer, enum ses +@@ -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); -@@ -1069,7 +1070,7 @@ session_connect(struct peer *peer) + 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 +1101,7 @@ session_connect(struct peer *peer) +@@ -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 +1139,50 @@ session_setup_socket(struct peer *p) +@@ -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,14 +1193,6 @@ session_setup_socket(struct peer *p) +@@ -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 */ -@@ -1244,40 +1244,32 @@ session_tcp_established(struct peer *pee + 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) -+session_capa_add(struct ibuf *opb, u_int8_t capa_code, u_int8_t capa_len) - { +-{ - u_int8_t op_type, op_len, tot_len, errs = 0; -+ int 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(buf, &afi, sizeof(afi)); -+ errs += ibuf_add(buf, &pad, sizeof(pad)); -+ errs += ibuf_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 +1279,22 @@ session_newmsg(enum msg_type msgtype, u_ +@@ -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 +1320,7 @@ session_sendmsg(struct bgp_msg *msg, str +@@ -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 +1329,38 @@ void +@@ -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]; - +- /* 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 */ +- c[0] = 0x80; /* we're always restarting */ - errs += session_capa_add(p, opb, CAPA_RESTART, 2, &optparamlen); - errs += buf_add(opb, &c, 2); -+ c[1] = 0; -+ errs += session_capa_add(opb, CAPA_RESTART, 2); -+ errs += ibuf_add(opb, &c, 2); ++ /* 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 +1368,17 @@ session_open(struct peer *p) +@@ -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 +1392,24 @@ session_open(struct peer *p) +@@ -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 +1457,8 @@ session_update(u_int32_t peerid, void *d +@@ -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 +1478,27 @@ session_notification(struct peer *p, u_i +@@ -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 +1517,29 @@ session_notification(struct peer *p, u_i +@@ -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 +1547,12 @@ session_rrefresh(struct peer *p, u_int16 +@@ -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; -@@ -1853,12 +1855,6 @@ parse_open(struct peer *peer) +@@ -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; ++int ++session_process_msg(struct peer *p) ++{ ++ ssize_t rpos, av, left; ++ int processed = 0; ++ u_int16_t msglen; ++ u_int8_t msgtype; + +- 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); ++ rpos = 0; ++ av = p->rbuf->wpos; + +- if (rpos < av) { +- left = av - rpos; +- memcpy(&p->rbuf->buf, p->rbuf->buf + rpos, left); +- p->rbuf->wpos = left; +- } else +- p->rbuf->wpos = 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; + +- return (1); ++ 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 +1962,15 @@ parse_open(struct peer *peer) +@@ -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 +1979,14 @@ parse_open(struct peer *peer) +@@ -1974,6 +2191,14 @@ parse_open(struct peer *peer) return (-1); } + if (capa_neg_calc(peer) == -1) { + log_peer_warnx(&peer->conf, -+ "capabilitiy negotiation calculation failed"); ++ "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 +2021,35 @@ int +@@ -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 +2059,12 @@ int +@@ -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 +2084,7 @@ parse_notification(struct peer *peer) +@@ -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 +2119,8 @@ parse_notification(struct peer *peer) +@@ -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; -@@ -2139,13 +2164,14 @@ parse_notification(struct peer *peer) +@@ -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,13 +2376,17 @@ 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) { -@@ -2182,29 +2208,16 @@ parse_capabilities(struct peer *peer, u_ +@@ -2182,36 +2423,65 @@ parse_capabilities(struct peer *peer, u_ "expect len 4, len is %u", capa_len); return (-1); } - memcpy(&mp_afi, capa_val, sizeof(mp_afi)); - mp_afi = ntohs(mp_afi); - memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi)); - switch (mp_afi) { - case AFI_IPv4: - if (mp_safi < 1 || mp_safi > 3) - log_peer_warnx(&peer->conf, - "parse_capabilities: AFI IPv4, " - "mp_safi %u unknown", mp_safi); - else - peer->capa.peer.mp_v4 = mp_safi; - break; - case AFI_IPv6: - if (mp_safi < 1 || mp_safi > 3) - log_peer_warnx(&peer->conf, - "parse_capabilities: AFI IPv6, " - "mp_safi %u unknown", mp_safi); - else - peer->capa.peer.mp_v6 = mp_safi; - break; - default: /* ignore */ + memcpy(&afi, capa_val, sizeof(afi)); + afi = ntohs(afi); + memcpy(&safi, capa_val + 3, sizeof(safi)); + if (afi2aid(afi, safi, &aid) == -1) { + log_peer_warnx(&peer->conf, + "parse_capabilities: AFI %u, " + "safi %u unknown", afi, safi); break; } + peer->capa.peer.mp[aid] = 1; break; case CAPA_REFRESH: peer->capa.peer.refresh = 1; -@@ -2232,6 +2245,37 @@ parse_capabilities(struct peer *peer, u_ + 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, ++ "parse_capabilities: " ++ "expect len 2 + x*4, len is %u", capa_len); ++ return (-1); ++ } ++ ++ 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, ++ "graceful restart timeout is zero"); ++ return (-1); ++ } ++ ++ 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, ++ "parse_capabilities: restart: AFI " ++ "%u, safi %u unknown", afi, safi); ++ return (-1); ++ } ++ 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) { +@@ -2232,6 +2502,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 for default IPv4 unicast mode */ ++ /* if no MP capability present default to IPv4 unicast mode */ + if (!hasmp) + p->capa.neg.mp[AID_INET] = 1; + -+ p->capa.neg.restart = p->capa.peer.restart; ++ /* ++ * 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,7 +2288,7 @@ session_dispatch_imsg(struct imsgbuf *ib +@@ -2244,8 +2574,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 errcode, subcode; ++ u_int8_t aid, errcode, subcode; if ((n = imsg_read(ibuf)) == -1) -@@ -2332,15 +2376,42 @@ session_dispatch_imsg(struct imsgbuf *ib + fatal("session_dispatch_imsg: imsg_read error"); +@@ -2332,15 +2662,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) { -@@ -2408,7 +2479,8 @@ session_dispatch_imsg(struct imsgbuf *ib +@@ -2388,6 +2745,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 +2756,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 +2765,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 +2528,10 @@ session_dispatch_imsg(struct imsgbuf *ib +@@ -2456,10 +2814,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 +2541,6 @@ session_dispatch_imsg(struct imsgbuf *ib +@@ -2469,7 +2827,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"); -@@ -2612,29 +2683,23 @@ getpeerbydesc(const char *descr) +@@ -2531,6 +2888,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 +3003,23 @@ getpeerbydesc(const char *descr) struct peer * getpeerbyip(struct sockaddr *ip) { + struct bgpd_addr addr; struct peer *p, *newpeer, *loose = NULL; u_int32_t id; + sa2addr(ip, &addr); + /* we might want a more effective way to find peers by IP */ for (p = peers; p != NULL; p = p->next) if (!p->conf.template && - p->conf.remote_addr.af == ip->sa_family) { - if (p->conf.remote_addr.af == AF_INET && - p->conf.remote_addr.v4.s_addr == - ((struct sockaddr_in *)ip)->sin_addr.s_addr) - return (p); - if (p->conf.remote_addr.af == AF_INET6 && - !bcmp(&p->conf.remote_addr.v6, - &((struct sockaddr_in6 *)ip)->sin6_addr, - sizeof(p->conf.remote_addr.v6))) - return (p); - } + !memcmp(&addr, &p->conf.remote_addr, sizeof(addr))) + return (p); /* try template matching */ for (p = peers; p != NULL; p = p->next) if (p->conf.template && - p->conf.remote_addr.af == ip->sa_family && - session_match_mask(p, ip)) + p->conf.remote_addr.aid == addr.aid && + session_match_mask(p, &addr)) if (loose == NULL || loose->conf.remote_masklen < p->conf.remote_masklen) loose = p; -@@ -2653,21 +2718,19 @@ getpeerbyip(struct sockaddr *ip) +@@ -2653,21 +3038,19 @@ getpeerbyip(struct sockaddr *ip) break; } } - if (newpeer->conf.remote_addr.af == AF_INET) { - newpeer->conf.remote_addr.v4.s_addr = - ((struct sockaddr_in *)ip)->sin_addr.s_addr; + sa2addr(ip, &newpeer->conf.remote_addr); + switch (ip->sa_family) { + case AF_INET: newpeer->conf.remote_masklen = 32; - } - if (newpeer->conf.remote_addr.af == AF_INET6) { - memcpy(&p->conf.remote_addr.v6, - &((struct sockaddr_in6 *)ip)->sin6_addr, - sizeof(newpeer->conf.remote_addr.v6)); + break; + case AF_INET6: newpeer->conf.remote_masklen = 128; + break; } newpeer->conf.template = 0; newpeer->conf.cloned = 1; newpeer->state = newpeer->prev_state = STATE_NONE; - newpeer->conf.reconf_action = RECONF_REINIT; + newpeer->conf.reconf_action = RECONF_KEEP; newpeer->rbuf = NULL; init_peer(newpeer); bgp_fsm(newpeer, EVNT_START); -@@ -2680,40 +2743,24 @@ getpeerbyip(struct sockaddr *ip) +@@ -2680,40 +3063,24 @@ getpeerbyip(struct sockaddr *ip) } int -session_match_mask(struct peer *p, struct sockaddr *ip) +session_match_mask(struct peer *p, struct bgpd_addr *a) { - int i; in_addr_t v4mask; - struct in6_addr *in; - struct in6_addr mask; + struct in6_addr masked; - if (p->conf.remote_addr.af == AF_INET) { + switch (p->conf.remote_addr.aid) { + case AID_INET: v4mask = htonl(prefixlen2mask(p->conf.remote_masklen)); - if (p->conf.remote_addr.v4.s_addr == - ((((struct sockaddr_in *)ip)->sin_addr.s_addr) & v4mask)) + if (p->conf.remote_addr.v4.s_addr == (a->v4.s_addr & v4mask)) return (1); - else - return (0); - } - - if (p->conf.remote_addr.af == AF_INET6) { - bzero(&mask, sizeof(mask)); - for (i = 0; i < p->conf.remote_masklen / 8; i++) - mask.s6_addr[i] = 0xff; - i = p->conf.remote_masklen % 8; - if (i) - mask.s6_addr[p->conf.remote_masklen / 8] = 0xff00 >> i; - - in = &((struct sockaddr_in6 *)ip)->sin6_addr; - - for (i = 0; i < 16; i++) - if ((in->s6_addr[i] & mask.s6_addr[i]) != - p->conf.remote_addr.addr8[i]) - return (0); + return (0); + case AID_INET6: + inet6applymask(&masked, &a->v6, p->conf.remote_masklen); - return (1); + if (!memcmp(&masked, &p->conf.remote_addr.v6, sizeof(masked))) + return (1); + return (0); } - return (0); } -@@ -2733,6 +2780,7 @@ getpeerbyid(u_int32_t peerid) +@@ -2733,6 +3100,7 @@ getpeerbyid(u_int32_t peerid) void session_down(struct peer *peer) { + bzero(&peer->capa.neg, sizeof(peer->capa.neg)); peer->stats.last_updown = time(NULL); if (imsg_compose(ibuf_rde, IMSG_SESSION_DOWN, peer->conf.id, 0, -1, NULL, 0) == -1) -@@ -2748,35 +2796,12 @@ session_up(struct peer *p) - &p->conf, sizeof(p->conf)) == -1) - fatalx("imsg_compose error"); +@@ -2744,39 +3112,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 +2809,10 @@ session_up(struct peer *p) +@@ -2784,9 +3130,10 @@ session_up(struct peer *p) } int -imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) +imsg_compose_parent(int type, u_int32_t peerid, pid_t pid, void *data, + u_int16_t datalen) { - return (imsg_compose(ibuf_main, type, 0, pid, -1, data, datalen)); + return (imsg_compose(ibuf_main, type, peerid, pid, -1, data, datalen)); } int -@@ -2795,34 +2821,6 @@ imsg_compose_rde(int type, pid_t pid, vo +@@ -2795,34 +3142,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 +2835,19 @@ session_demote(struct peer *p, int level +@@ -2837,3 +3156,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: head/net/openbgpd/files/patch-bgpd_session.h =================================================================== --- head/net/openbgpd/files/patch-bgpd_session.h (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_session.h (revision 305848) @@ -1,127 +1,188 @@ 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.9 -diff -u -p -r1.1.1.7 -r1.1.1.9 +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 12 Jun 2011 10:44:25 -0000 1.1.1.9 ++++ 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.111 2010/12/09 13:50:41 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; }; -@@ -189,6 +196,7 @@ struct peer { +@@ -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 +209,7 @@ struct peer { +@@ -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,7 +225,7 @@ struct peer { +@@ -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; -@@ -226,38 +234,36 @@ struct ctl_timer { + time_t val; + }; - /* session.c */ - void session_socket_blockmode(int, enum blockmodes); +-/* session.c */ +-void session_socket_blockmode(int, enum blockmodes); -pid_t session_main(struct bgpd_config *, struct peer *, - struct network_head *, struct filter_head *, - struct mrt_head *, struct rib_names *, - int[2], int[2], int[2], int[2]); -+pid_t session_main(int[2], int[2], int[2], int[2]); - void bgp_fsm(struct peer *, enum session_events); - int session_neighbor_rrefresh(struct peer *p); - struct peer *getpeerbyaddr(struct bgpd_addr *); - struct peer *getpeerbydesc(const char *); +-void bgp_fsm(struct peer *, enum session_events); +-int session_neighbor_rrefresh(struct peer *p); +-struct peer *getpeerbyaddr(struct bgpd_addr *); +-struct peer *getpeerbydesc(const char *); -int imsg_compose_parent(int, pid_t, void *, u_int16_t); -+int imsg_compose_parent(int, u_int32_t, pid_t, void *, u_int16_t); - int imsg_compose_rde(int, pid_t, void *, u_int16_t); -+void session_stop(struct peer *, u_int8_t); - - /* log.c */ - char *log_fmt_peer(const struct peer_config *); - void log_statechange(struct peer *, enum session_state, - enum session_events); - void log_notification(const struct peer *, u_int8_t, u_int8_t, +-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); -+ u_char *, u_int16_t, const char *); - void log_conn_attempt(const struct peer *, struct sockaddr *); - - /* parse.y */ - int parse_config(char *, struct bgpd_config *, struct mrt_head *, +-void log_conn_attempt(const struct peer *, struct sockaddr *); +- +-/* parse.y */ +-int parse_config(char *, struct bgpd_config *, struct mrt_head *, - struct peer **, struct network_head *, struct filter_head *); -+ struct peer **, struct network_head *, struct filter_head *, -+ struct rdomain_head *); ++/* 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 *); -+int get_mpe_label(struct rdomain *); - - /* rde.c */ +- +-/* rde.c */ -pid_t rde_main(struct bgpd_config *, struct peer *, struct network_head *, - struct filter_head *, struct mrt_head *, struct rib_names *, - int[2], int[2], int[2], int[2], int); -+pid_t rde_main(int[2], int[2], int[2], int[2], int); ++int get_mpe_label(struct rdomain *); /* control.c */ int control_init(int, char *); -@@ -267,6 +273,7 @@ int control_dispatch_msg(struct pollfd * +@@ -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,7 +281,7 @@ 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); +-/* 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: head/net/openbgpd/files/patch-bgpd_timer.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_timer.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_timer.c (revision 305848) @@ -1,23 +1,32 @@ 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.3 -diff -u -p -r1.1.1.2 -r1.1.1.3 +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 12 Jun 2011 10:44:25 -0000 1.1.1.3 ++++ 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 -@@ -43,7 +43,7 @@ timer_get(struct peer *p, enum Timer tim +@@ -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: head/net/openbgpd/files/patch-bgpd_util.c =================================================================== --- head/net/openbgpd/files/patch-bgpd_util.c (revision 305847) +++ head/net/openbgpd/files/patch-bgpd_util.c (revision 305848) @@ -1,305 +1,440 @@ Index: bgpd/util.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/util.c,v retrieving revision 1.1.1.6 -retrieving revision 1.6 -diff -u -p -r1.1.1.6 -r1.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 2 Jul 2011 16:06:38 -0000 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); + 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 (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) -@@ -276,3 +376,115 @@ inet6applymask(struct in6_addr *dest, co +@@ -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: head/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h =================================================================== --- head/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h (revision 305847) +++ head/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h (revision 305848) @@ -1,94 +1,98 @@ 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 3 Jul 2011 04:46:38 -0000 1.6 -@@ -0,0 +1,87 @@ ++++ 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.6 2011/07/03 04:46:38 hrs Exp $ ++ * $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 */