diff options
author | hrs <hrs@FreeBSD.org> | 2009-07-19 15:31:04 +0800 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2009-07-19 15:31:04 +0800 |
commit | 785f10bf3723c60d1c213956b9e2bb9d2cac4aa3 (patch) | |
tree | 524a40b46c2d9507a9b14053306e1a4aebddf94e /net | |
parent | 4eea60c6dd564e9c12700a23529c5c81c6be07be (diff) | |
download | freebsd-ports-graphics-785f10bf3723c60d1c213956b9e2bb9d2cac4aa3.tar.gz freebsd-ports-graphics-785f10bf3723c60d1c213956b9e2bb9d2cac4aa3.tar.zst freebsd-ports-graphics-785f10bf3723c60d1c213956b9e2bb9d2cac4aa3.zip |
Update to 4.5.20090709 (from snapshot as of 2009/7/9).
Add support for nexthop with an IPv6 link-local address. To
enable this, specify "interface" in bgpd.conf (see bgpd.conf(5)).
Diffstat (limited to 'net')
38 files changed, 8485 insertions, 114 deletions
diff --git a/net/openbgpd/Makefile b/net/openbgpd/Makefile index eb2343a099d..93a788c8c8c 100644 --- a/net/openbgpd/Makefile +++ b/net/openbgpd/Makefile @@ -6,32 +6,40 @@ # PORTNAME= openbgpd -PORTVERSION= 4.4.1 -PORTREVISION= 2 +PORTVERSION= 4.5.20090709 CATEGORIES= net MASTER_SITES= ${MASTER_SITE_OPENBSD} MASTER_SITE_SUBDIR= OpenBGPD +DISTNAME= ${PORTNAME}-4.4.1 EXTRACT_SUFX= .tgz -DIST_SUBDIR= openbgpd +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 + +.include <bsd.port.pre.mk> + WRKSRC= ${WRKDIR} MANCOMPRESSED= yes -USE_RC_SUBR= openbgpd.sh +USE_RC_SUBR= ${PORTNAME}.sh PLIST_FILES= sbin/bgpctl sbin/bgpd SUB_FILES= pkg-message 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.h \ ${WRKSRC}/bgpd/bgpd.conf.5 \ ${WRKSRC}/bgpctl/bgpctl.8 @@ -39,4 +47,4 @@ post-install: @${SH} ${PKGINSTALL} ${PKGNAME} POST-INSTALL @${CAT} ${PKGMESSAGE} -.include <bsd.port.mk> +.include <bsd.port.post.mk> diff --git a/net/openbgpd/files/patch-bgpctl_bgpctl.8 b/net/openbgpd/files/patch-bgpctl_bgpctl.8 index e90455ce182..0b329535d39 100644 --- a/net/openbgpd/files/patch-bgpctl_bgpctl.8 +++ b/net/openbgpd/files/patch-bgpctl_bgpctl.8 @@ -2,11 +2,44 @@ Index: bgpctl/bgpctl.8 =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.8,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/bgpctl.8 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/bgpctl.8 30 Jun 2009 06:40:05 -0000 1.2 -@@ -244,7 +244,7 @@ in a terse format. ++++ bgpctl/bgpctl.8 9 Jul 2009 17:22:12 -0000 1.3 +@@ -1,4 +1,4 @@ +-.\" $OpenBSD: bgpctl.8,v 1.47 2008/06/07 18:14:41 henning Exp $ ++.\" $OpenBSD: bgpctl.8,v 1.49 2009/06/06 06:11:17 claudio Exp $ + .\" + .\" Copyright (c) 2003 Henning Brauer <henning@openbsd.org> + .\" +@@ -14,7 +14,7 @@ + .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + .\" +-.Dd $Mdocdate: June 7 2008 $ ++.Dd $Mdocdate: December 6 2008 $ + .Dt BGPCTL 8 + .Os + .Sh NAME +@@ -25,7 +25,7 @@ + .Op Fl n + .Op Fl s Ar socket + .Ar command +-.Op Ar arguments ... ++.Op Ar argument ... + .Sh DESCRIPTION + The + .Nm +@@ -202,6 +202,8 @@ Show all entries with community + .Ar community . + .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 summary + This is the same as the + .Ic show summary +@@ -244,7 +246,7 @@ in a terse format. .El .Sh FILES .Bl -tag -width "/var/run/bgpd.sockXXX" -compact diff --git a/net/openbgpd/files/patch-bgpctl_bgpctl.c b/net/openbgpd/files/patch-bgpctl_bgpctl.c index 4d48e132522..5af61333be3 100644 --- a/net/openbgpd/files/patch-bgpctl_bgpctl.c +++ b/net/openbgpd/files/patch-bgpctl_bgpctl.c @@ -2,10 +2,16 @@ Index: bgpctl/bgpctl.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.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/bgpctl.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/bgpctl.c 30 Jun 2009 06:40:06 -0000 1.2 ++++ bgpctl/bgpctl.c 9 Jul 2009 17:22:12 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: bgpctl.c,v 1.134 2008/06/07 20:23:15 henning Exp $ */ ++/* $OpenBSD: bgpctl.c,v 1.142 2009/06/06 06:33:15 eric Exp $ */ + + /* + * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -16,11 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ @@ -49,7 +55,58 @@ diff -u -p -r1.1.1.1 -r1.2 enum neighbor_views { NV_DEFAULT, NV_TIMERS -@@ -677,7 +693,7 @@ print_neighbor_msgstats(struct peer *p) +@@ -89,8 +105,8 @@ usage(void) + { + extern char *__progname; + +- fprintf(stderr, "usage: %s [-n] [-s socket] " +- "command [arguments ...]\n", __progname); ++ fprintf(stderr, "usage: %s [-n] [-s socket] command [argument ...]\n", ++ __progname); + exit(1); + } + +@@ -174,8 +190,7 @@ main(int argc, char *argv[]) + -1 || + imsg_add(msg, &res->af, sizeof(res->af)) == -1) + errx(1, "imsg_add failure"); +- if (imsg_close(ibuf, msg) < 0) +- errx(1, "imsg_close error"); ++ imsg_close(ibuf, msg); + } else + imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, + &res->addr, sizeof(res->addr)); +@@ -220,6 +235,7 @@ main(int argc, char *argv[]) + } + memcpy(&ribreq.neighbor, &neighbor, + sizeof(ribreq.neighbor)); ++ strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); + ribreq.af = res->af; + ribreq.flags = res->flags; + imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq)); +@@ -289,8 +305,11 @@ main(int argc, char *argv[]) + done = 1; + break; + case NETWORK_SHOW: ++ bzero(&ribreq, sizeof(ribreq)); ++ ribreq.af = res->af; ++ strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); + imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1, +- &res->af, sizeof(res->af)); ++ &ribreq, sizeof(ribreq)); + show_network_head(); + break; + } +@@ -410,7 +429,7 @@ fmt_peer(const char *descr, const struct + void + show_summary_head(void) + { +- printf("%-20s %-8s %-10s %-10s %-5s %-8s %s\n", "Neighbor", "AS", ++ printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", + "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); + } + +@@ -677,7 +696,7 @@ print_neighbor_msgstats(struct peer *p) } void @@ -58,3 +115,59 @@ diff -u -p -r1.1.1.1 -r1.2 { printf(" %-20s ", name); +@@ -738,7 +757,7 @@ show_fib_head(void) + printf("flags: * = valid, B = BGP, C = Connected, S = Static\n"); + printf(" N = BGP Nexthop reachable via this route\n"); + printf(" r = reject route, b = blackhole route\n\n"); +- printf("flags destination gateway\n"); ++ printf("flags prio destination gateway\n"); + } + + void +@@ -801,7 +820,7 @@ show_fib_msg(struct imsg *imsg) + if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) == + -1) + err(1, NULL); +- printf("%-20s ", p); ++ printf("%4i %-20s ", k->priority, p); + free(p); + + if (k->nexthop.s_addr) +@@ -822,7 +841,7 @@ show_fib_msg(struct imsg *imsg) + if (asprintf(&p, "%s/%u", log_in6addr(&k6->prefix), + k6->prefixlen) == -1) + err(1, NULL); +- printf("%-20s ", p); ++ printf("%4i %-20s ", k6->priority, p); + free(p); + + if (!IN6_IS_ADDR_UNSPECIFIED(&k6->nexthop)) +@@ -1186,8 +1205,8 @@ show_rib_detail_msg(struct imsg *imsg, i + case ATTR_AGGREGATOR: + memcpy(&as, data, sizeof(as)); + memcpy(&id, data + sizeof(as), sizeof(id)); +- printf(" Aggregator: %s [%s]\n", log_as(as), +- inet_ntoa(id)); ++ printf(" Aggregator: %s [%s]\n", ++ log_as(htonl(as)), inet_ntoa(id)); + break; + case ATTR_ORIGINATOR_ID: + memcpy(&id, data, sizeof(id)); +@@ -1249,6 +1268,9 @@ show_rib_memory_msg(struct imsg *imsg) + printf("%10lld IPv6 network entries using " + "%s of memory\n", (long long)stats.pt6_cnt, + fmt_mem(stats.pt6_cnt * sizeof(struct pt_entry6))); ++ printf("%10lld rib entries using %s of memory\n", ++ (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt * ++ sizeof(struct rib_entry))); + printf("%10lld prefix entries using %s of memory\n", + (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt * + sizeof(struct prefix))); +@@ -1270,6 +1292,7 @@ show_rib_memory_msg(struct imsg *imsg) + stats.pt4_cnt * sizeof(struct pt_entry4) + + stats.pt6_cnt * sizeof(struct pt_entry6) + + stats.prefix_cnt * sizeof(struct prefix) + ++ stats.rib_cnt * sizeof(struct rib_entry) + + stats.path_cnt * sizeof(struct rde_aspath) + + stats.aspath_size + stats.attr_cnt * sizeof(struct attr) + + stats.attr_data)); diff --git a/net/openbgpd/files/patch-bgpctl_irr_asset.c b/net/openbgpd/files/patch-bgpctl_irr_asset.c new file mode 100644 index 00000000000..4ced146617d --- /dev/null +++ b/net/openbgpd/files/patch-bgpctl_irr_asset.c @@ -0,0 +1,23 @@ +Index: bgpctl/irr_asset.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/irr_asset.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_asset.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpctl/irr_asset.c 9 Jul 2009 16:49:55 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: irr_asset.c,v 1.7 2007/03/31 12:46:55 henning Exp $ */ ++/* $OpenBSD: irr_asset.c,v 1.8 2009/04/14 21:10:54 jj Exp $ */ + + /* + * Copyright (c) 2007 Henning Brauer <henning@openbsd.org> +@@ -105,7 +105,7 @@ asset_get(char *name) + break; + case T_AUTNUM: + /* +- * make a dummy as-set with the the AS both as name ++ * make a dummy as-set with the AS both as name + * and its only member + */ + asset_add_as(ass, name); diff --git a/net/openbgpd/files/patch-bgpctl_parser.c b/net/openbgpd/files/patch-bgpctl_parser.c index da0571bd66e..bb3e6ef03a5 100644 --- a/net/openbgpd/files/patch-bgpctl_parser.c +++ b/net/openbgpd/files/patch-bgpctl_parser.c @@ -2,10 +2,16 @@ Index: bgpctl/parser.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/parser.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/parser.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpctl/parser.c 30 Jun 2009 06:40:06 -0000 1.2 ++++ bgpctl/parser.c 9 Jul 2009 17:22:12 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: parser.c,v 1.50 2008/06/15 09:58:43 claudio Exp $ */ ++/* $OpenBSD: parser.c,v 1.54 2009/06/12 16:44:02 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -16,6 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ @@ -17,3 +23,126 @@ diff -u -p -r1.1.1.1 -r1.2 #include <sys/types.h> #include <sys/socket.h> +@@ -42,6 +46,7 @@ enum token_type { + ASTYPE, + PREFIX, + PEERDESC, ++ RIBNAME, + COMMUNITY, + LOCALPREF, + MED, +@@ -72,6 +77,7 @@ 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_rib_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[]; +@@ -148,6 +154,7 @@ static const struct token t_show_rib[] = + { FLAG, "in", F_CTL_ADJ_IN, t_show_rib}, + { FLAG, "out", F_CTL_ADJ_OUT, t_show_rib}, + { KEYWORD, "neighbor", NONE, t_show_rib_neigh}, ++ { KEYWORD, "table", NONE, t_show_rib_rib}, + { KEYWORD, "summary", SHOW_SUMMARY, t_show_summary}, + { KEYWORD, "memory", SHOW_RIB_MEM, NULL}, + { FAMILY, "", NONE, t_show_rib}, +@@ -161,6 +168,11 @@ static const struct token t_show_rib_nei + { ENDTOKEN, "", NONE, NULL} + }; + ++static const struct token t_show_rib_rib[] = { ++ { RIBNAME, "", NONE, t_show_rib}, ++ { ENDTOKEN, "", NONE, NULL} ++}; ++ + static const struct token t_show_neighbor[] = { + { NOTOKEN, "", NONE, NULL}, + { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, +@@ -456,6 +468,15 @@ match_token(int *argc, char **argv[], co + t = &table[i]; + } + break; ++ case RIBNAME: ++ if (!match && word != NULL && strlen(word) > 0) { ++ if (strlcpy(res.rib, word, sizeof(res.rib)) >= ++ sizeof(res.rib)) ++ errx(1, "rib name too long"); ++ match++; ++ t = &table[i]; ++ } ++ break; + case COMMUNITY: + if (word != NULL && strlen(word) > 0 && + parse_community(word, &res)) { +@@ -547,6 +568,9 @@ show_valid_args(const struct token table + case PEERDESC: + fprintf(stderr, " <neighbor description>\n"); + break; ++ case RIBNAME: ++ fprintf(stderr, " <rib name>\n"); ++ break; + case COMMUNITY: + fprintf(stderr, " <community>\n"); + break; +@@ -686,7 +710,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, USHRT_MAX - 1, &errstr); ++ uval = strtonum(word, 0, ASNUM_MAX - 1, &errstr); + if (errstr) + errx(1, "AS number is %s: %s", errstr, word); + } +@@ -801,7 +825,7 @@ parse_community(const char *word, struct + type = getcommunity(p); + + done: +- if (as == 0 || as == USHRT_MAX) { ++ if (as == 0) { + fprintf(stderr, "Invalid community\n"); + return (0); + } +@@ -814,7 +838,7 @@ done: + break; + default: + /* unknown */ +- fprintf(stderr, "Invalid well-known community\n"); ++ fprintf(stderr, "Unknown well-known community\n"); + return (0); + } + +@@ -856,33 +880,6 @@ parse_nexthop(const char *word, struct p + return (1); + } + +-/* XXX local copies from kroute.c, should go to a shared file */ +-in_addr_t +-prefixlen2mask(u_int8_t prefixlen) +-{ +- if (prefixlen == 0) +- return (0); +- +- return (0xffffffff << (32 - prefixlen)); +-} +- +-void +-inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) +-{ +- struct in6_addr mask; +- int i; +- +- bzero(&mask, sizeof(mask)); +- for (i = 0; i < prefixlen / 8; i++) +- mask.s6_addr[i] = 0xff; +- i = prefixlen % 8; +- if (i) +- mask.s6_addr[prefixlen / 8] = 0xff00 >> i; +- +- for (i = 0; i < 16; i++) +- dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; +-} +- + int + bgpctl_getopt(int *argc, char **argv[], int type) + { diff --git a/net/openbgpd/files/patch-bgpctl_parser.h b/net/openbgpd/files/patch-bgpctl_parser.h index 2bd14da4507..a5ffc4417d5 100644 --- a/net/openbgpd/files/patch-bgpctl_parser.h +++ b/net/openbgpd/files/patch-bgpctl_parser.h @@ -1,9 +1,22 @@ ---- bgpctl/parser.h.orig 2009-01-16 23:03:29.000000000 +0900 -+++ bgpctl/parser.h 2009-06-22 14:54:34.000000000 +0900 -@@ -63,5 +63,5 @@ - sa_family_t af; - }; +Index: bgpctl/parser.h +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/parser.h,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/parser.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpctl/parser.h 9 Jul 2009 16:49:55 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: parser.h,v 1.18 2008/06/07 18:14:41 henning Exp $ */ ++/* $OpenBSD: parser.h,v 1.19 2009/06/06 06:05:41 claudio Exp $ */ --__dead void usage(void); -+void usage(void); - struct parse_result *parse(int, char *[]); + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -56,6 +56,7 @@ struct parse_result { + struct filter_set_head set; + struct filter_community community; + char peerdesc[PEER_DESCR_LEN]; ++ char rib[PEER_DESCR_LEN]; + char *irr_outdir; + int flags; + enum actions action; diff --git a/net/openbgpd/files/patch-bgpd_Makefile b/net/openbgpd/files/patch-bgpd_Makefile index 80ee1f6855d..4c73aee2ade 100644 --- a/net/openbgpd/files/patch-bgpd_Makefile +++ b/net/openbgpd/files/patch-bgpd_Makefile @@ -2,12 +2,13 @@ Index: bgpd/Makefile =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/Makefile,v retrieving revision 1.1.1.1 -retrieving revision 1.4 -diff -u -p -r1.1.1.1 -r1.4 +retrieving revision 1.6 +diff -u -p -r1.1.1.1 -r1.6 --- bgpd/Makefile 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/Makefile 3 Jul 2009 15:32:15 -0000 1.4 -@@ -1,17 +1,20 @@ - # $OpenBSD: Makefile,v 1.27 2007/12/20 17:08:47 henning Exp $ ++++ bgpd/Makefile 9 Jul 2009 17:22:14 -0000 1.6 +@@ -1,17 +1,23 @@ +-# $OpenBSD: Makefile,v 1.27 2007/12/20 17:08:47 henning Exp $ ++# $OpenBSD: Makefile,v 1.28 2009/06/25 14:14:54 deraadt Exp $ -.PATH: ${.CURDIR}/.. +.PATH: ${.CURDIR}/.. ${.CURDIR}/../openbsd-compat @@ -27,6 +28,9 @@ diff -u -p -r1.1.1.1 -r1.4 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wsign-compare +CFLAGS+= -DCONFFILE=\"${CONFFILE}\" ++.if defined(IPV6_LINKLOCAL_PEER) ++CFLAGS+= -DIPV6_LINKLOCAL_PEER ++.endif YFLAGS= MAN= bgpd.8 bgpd.conf.5 diff --git a/net/openbgpd/files/patch-bgpd_bgpd.8 b/net/openbgpd/files/patch-bgpd_bgpd.8 index 97c39833a3f..6bb958544a8 100644 --- a/net/openbgpd/files/patch-bgpd_bgpd.8 +++ b/net/openbgpd/files/patch-bgpd_bgpd.8 @@ -2,10 +2,16 @@ Index: bgpd/bgpd.8 =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.8,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 --- bgpd/bgpd.8 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/bgpd.8 30 Jun 2009 18:50:35 -0000 1.3 ++++ bgpd/bgpd.8 9 Jul 2009 17:22:14 -0000 1.4 +@@ -1,4 +1,4 @@ +-.\" $OpenBSD: bgpd.8,v 1.27 2007/05/31 19:20:22 jmc Exp $ ++.\" $OpenBSD: bgpd.8,v 1.28 2009/01/13 23:01:36 sthen Exp $ + .\" + .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + .\" @@ -48,9 +48,9 @@ Please refer to that document for more i .Nm is usually started at boot time, and can be enabled by @@ -36,3 +42,15 @@ diff -u -p -r1.1.1.1 -r1.3 default .Nm configuration file +@@ -195,9 +195,9 @@ control socket + .%D January 2007 + .Re + .Rs +-.%R draft-ietf-idr-as4bytes-13 ++.%R RFC 4893 + .%T "BGP Support for Four-octet AS Number Space" +-.%D February 2007 ++.%D May 2007 + .Re + .Sh HISTORY + The diff --git a/net/openbgpd/files/patch-bgpd_bgpd.c b/net/openbgpd/files/patch-bgpd_bgpd.c new file mode 100644 index 00000000000..0d7c55e1054 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_bgpd.c @@ -0,0 +1,87 @@ +Index: bgpd/bgpd.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.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 +--- bgpd/bgpd.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/bgpd.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: bgpd.c,v 1.145 2008/05/12 19:15:02 pyr Exp $ */ ++/* $OpenBSD: bgpd.c,v 1.148 2009/06/07 00:30:23 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -58,6 +58,7 @@ volatile sig_atomic_t reconfig = 0; + pid_t reconfpid = 0; + struct imsgbuf *ibuf_se; + struct imsgbuf *ibuf_rde; ++struct rib_names ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames); + + void + sighdlr(int sig) +@@ -108,6 +109,7 @@ main(int argc, char *argv[]) + struct filter_rule *r; + 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; +@@ -181,7 +183,8 @@ main(int argc, char *argv[]) + + if (conf.opts & BGPD_OPT_NOACTION) { + if (conf.opts & BGPD_OPT_VERBOSE) +- print_config(&conf, &net_l, peer_l, rules_l, &mrt_l); ++ print_config(&conf, &ribnames, &net_l, peer_l, rules_l, ++ &mrt_l); + else + fprintf(stderr, "configuration OK\n"); + exit(0); +@@ -225,9 +228,9 @@ main(int argc, char *argv[]) + prepare_listeners(&conf); + + /* fork children */ +- rde_pid = rde_main(&conf, peer_l, &net_l, rules_l, &mrt_l, ++ 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, ++ io_pid = session_main(&conf, peer_l, &net_l, rules_l, &mrt_l, &ribnames, + pipe_m2s, pipe_s2r, pipe_m2r, pipe_s2r_c); + + setproctitle("parent"); +@@ -271,6 +274,10 @@ main(int argc, char *argv[]) + close(la->fd); + la->fd = -1; + } ++ while ((rr = SIMPLEQ_FIRST(&ribnames))) { ++ SIMPLEQ_REMOVE_HEAD(&ribnames, entry); ++ free(rr); ++ } + + mrt_reconfigure(&mrt_l); + +@@ -452,6 +459,7 @@ reconfigure(char *conffile, struct bgpd_ + struct peer *p; + struct filter_rule *r; + struct listen_addr *la; ++ struct rde_rib *rr; + + if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, rules_l)) { + log_warnx("config file %s has errors, not reloading", +@@ -488,6 +496,15 @@ reconfigure(char *conffile, struct bgpd_ + la->fd = -1; + } + ++ /* RIBs for the RDE */ ++ while ((rr = SIMPLEQ_FIRST(&ribnames))) { ++ SIMPLEQ_REMOVE_HEAD(&ribnames, entry); ++ 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, diff --git a/net/openbgpd/files/patch-bgpd_bgpd.conf.5 b/net/openbgpd/files/patch-bgpd_bgpd.conf.5 index 160ef81ec5d..6d6792e545f 100644 --- a/net/openbgpd/files/patch-bgpd_bgpd.conf.5 +++ b/net/openbgpd/files/patch-bgpd_bgpd.conf.5 @@ -2,11 +2,100 @@ Index: bgpd/bgpd.conf.5 =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.conf.5,v retrieving revision 1.1.1.1 -retrieving revision 1.2 -diff -u -p -r1.1.1.1 -r1.2 +retrieving revision 1.4 +diff -u -p -r1.1.1.1 -r1.4 --- bgpd/bgpd.conf.5 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/bgpd.conf.5 30 Jun 2009 06:40:07 -0000 1.2 -@@ -611,11 +611,11 @@ is responsible for managing the session ++++ bgpd/bgpd.conf.5 9 Jul 2009 17:22:14 -0000 1.4 +@@ -1,4 +1,4 @@ +-.\" $OpenBSD: bgpd.conf.5,v 1.88 2008/03/22 08:38:38 claudio Exp $ ++.\" $OpenBSD: bgpd.conf.5,v 1.94 2009/06/07 00:31:22 claudio Exp $ + .\" + .\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> + .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -16,7 +16,7 @@ + .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + .\" +-.Dd $Mdocdate: March 22 2008 $ ++.Dd $Mdocdate: June 4 2009 $ + .Dt BGPD.CONF 5 + .Os + .Sh NAME +@@ -123,14 +123,26 @@ sets the local AS to 65001. + The AS numbers 64512 \(en 65534 are designated for private use. + The AS number 23456 is a specially designated Autonomous System Number and + should not be used. +-4-byte AS numbers are specified as two numbers separated by a dot. +-For example: ++4-byte AS numbers are specified as two numbers separated by a dot ++(ASDOT format), ++for example: + .Bd -literal -offset indent + AS 3.10 + .Ed + .Pp ++or as a large number (ASPLAIN format), for example: ++.Bd -literal -offset indent ++AS 196618 ++.Ed ++.Pp ++.It Ic connect-retry Ar seconds ++Set the number of seconds before retrying to open a connection. ++This timer should be sufficiently large in EBGP configurations. ++The default is 120 seconds. ++.Pp + .It Xo + .Ic dump ++.Op Ic rib Ar name + .Pq Ic table Ns \&| Ns Ic table-mp + .Ar file Op Ar timeout + .Xc +@@ -145,7 +157,8 @@ Dump the RIB, a.k.a. the + 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. +-Excessive dumping may result in delayed update processing. ++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 +@@ -297,6 +310,21 @@ is only compared between peers belonging + .Pp + .It Xo + .Ic rde ++.Ic rib Ar name ++.Op Ic no Ic evaluate ++.Xc ++Creat an additional RIB named ++.Ar name . ++It is possible to disable the decision process per RIB with the ++.Ic no Ic evaluate ++flag. ++.Ic Adj-RIB-In ++and ++.Ic Loc-RIB ++are created automaticaly and used as default. ++.Pp ++.It Xo ++.Ic rde + .Ic route-age + .Pq Ic ignore Ns \&| Ns Ic evaluate + .Xc +@@ -561,6 +589,12 @@ 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 +@@ -611,11 +645,11 @@ is responsible for managing the session With .Xr isakmpd 8 , it is sufficient to copy the peer's public key, found in @@ -20,7 +109,44 @@ diff -u -p -r1.1.1.1 -r1.2 The local public key must be copied to the peer in the same way. As .Xr bgpd 8 -@@ -1137,8 +1137,8 @@ For prefixes with equally long paths, th +@@ -670,6 +704,9 @@ 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 ++Bind the neighbor to the specified RIB. ++.Pp + .It Ic route-reflector Op Ar address + Act as an RFC 2796 + .Em route-reflector +@@ -728,6 +765,18 @@ tcp md5sig key deadbeef + .Ed + .Pp + .It Xo ++.Ic transparent-as ++.Pq Ic yes Ns \&| Ns Ic no ++.Xc ++If set to ++.Ic yes , ++.Em AS paths ++to EBGP neighbors are not prepended with their own AS. ++The default is inherited from the global ++.Ic transparent-as ++setting. ++.Pp ++.It Xo + .Ic ttl-security + .Pq Ic yes Ns \&| Ns Ic no + .Xc +@@ -1048,6 +1097,7 @@ will be adjusted by adding or subtractin + .Ar number ; + otherwise it will be set to + .Ar number . ++The default is 100. + .Pp + .It Ic med Ar number + .It Ic metric Ar number +@@ -1137,8 +1187,8 @@ For prefixes with equally long paths, th is selected. .El .Sh FILES diff --git a/net/openbgpd/files/patch-bgpd_bgpd.h b/net/openbgpd/files/patch-bgpd_bgpd.h index 99227411826..713df711b9d 100644 --- a/net/openbgpd/files/patch-bgpd_bgpd.h +++ b/net/openbgpd/files/patch-bgpd_bgpd.h @@ -2,18 +2,28 @@ Index: bgpd/bgpd.h =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/bgpd.h,v retrieving revision 1.1.1.1 -retrieving revision 1.3 -diff -u -p -r1.1.1.1 -r1.3 +retrieving revision 1.5 +diff -u -p -r1.1.1.1 -r1.5 --- bgpd/bgpd.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/bgpd.h 30 Jun 2009 06:56:51 -0000 1.3 -@@ -30,9 +30,15 @@ - #include <poll.h> - #include <stdarg.h> ++++ bgpd/bgpd.h 9 Jul 2009 17:22:14 -0000 1.5 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: bgpd.h,v 1.222 2008/01/23 08:11:32 claudio Exp $ */ ++/* $OpenBSD: bgpd.h,v 1.241 2009/06/12 16:42:53 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -27,12 +27,19 @@ + #include <net/if.h> + #include <net/pfkeyv2.h> +#if defined(__FreeBSD__) /* compat */ +#include "openbsd-compat.h" +#endif /* defined(__FreeBSD__) */ + + #include <poll.h> + #include <stdarg.h> ++#include <imsg.h> + #define BGP_VERSION 4 #define BGP_PORT 179 +#ifndef CONFFILE @@ -22,3 +32,365 @@ diff -u -p -r1.1.1.1 -r1.3 #define BGPD_USER "_bgpd" #define PEER_DESCR_LEN 32 #define PFTABLE_LEN 16 +@@ -40,6 +47,8 @@ + #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 +@@ -85,8 +94,8 @@ + + /* + * Limit the number of control messages generated by the RDE and queued in +- * session enigine. The RDE limit defines how many imsg are generated in +- * on poll round. The if the SE limit is hit the RDE control socket will no ++ * session engine. The RDE limit defines how many imsg are generated in ++ * one poll round. Then if the SE limit is hit the RDE control socket will no + * longer be polled. + */ + #define RDE_RUNNER_ROUNDS 100 +@@ -105,21 +114,6 @@ enum reconf_action { + RECONF_DELETE + }; + +-struct buf { +- TAILQ_ENTRY(buf) entry; +- u_char *buf; +- size_t size; +- size_t wpos; +- size_t rpos; +- int fd; +-}; +- +-struct msgbuf { +- TAILQ_HEAD(, buf) bufs; +- u_int32_t queued; +- int fd; +-}; +- + struct bgpd_addr { + sa_family_t af; + union { +@@ -169,12 +163,7 @@ struct bgpd_config { + u_int16_t short_as; + u_int16_t holdtime; + u_int16_t min_holdtime; +-}; +- +-struct buf_read { +- u_char buf[READ_BUF_SIZE]; +- u_char *rptr; +- size_t wpos; ++ u_int16_t connectretry; + }; + + enum announce_type { +@@ -235,11 +224,13 @@ struct peer_config { + struct capabilities capabilities; + char group[PEER_DESCR_LEN]; + char descr[PEER_DESCR_LEN]; ++ char rib[PEER_DESCR_LEN]; + char if_depend[IFNAMSIZ]; + char demote_group[IFNAMSIZ]; + u_int32_t id; + u_int32_t groupid; + u_int32_t remote_as; ++ u_int32_t local_as; + u_int32_t max_prefix; + enum announce_type announce_type; + enum enforce_as enforce_as; +@@ -247,6 +238,7 @@ struct peer_config { + u_int16_t max_prefix_restart; + u_int16_t holdtime; + u_int16_t min_holdtime; ++ u_int16_t local_short_as; + u_int8_t template; + u_int8_t remote_masklen; + u_int8_t cloned; +@@ -259,8 +251,13 @@ struct peer_config { + u_int8_t softreconfig_in; + u_int8_t softreconfig_out; + u_int8_t ttlsec; /* TTL security hack */ ++ u_int8_t flags; ++ u_int8_t pad[3]; ++ char lliface[IFNAMSIZ]; + }; + ++#define PEERFLAG_TRANS_AS 0x01 ++ + struct network_config { + struct bgpd_addr prefix; + struct filter_set_head attrset; +@@ -274,54 +271,8 @@ struct network { + TAILQ_ENTRY(network) entry; + }; + +-/* ipc messages */ +- +-#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +-#define MAX_IMSGSIZE 8192 +- +-struct imsg_fd { +- TAILQ_ENTRY(imsg_fd) entry; +- int fd; +-}; +- +-struct imsgbuf { +- TAILQ_HEAD(fds, imsg_fd) fds; +- struct buf_read r; +- struct msgbuf w; +- int fd; +- pid_t pid; +-}; +- + enum imsg_type { + IMSG_NONE, +- IMSG_RECONF_CONF, +- IMSG_RECONF_PEER, +- IMSG_RECONF_FILTER, +- IMSG_RECONF_LISTENER, +- IMSG_RECONF_DONE, +- IMSG_UPDATE, +- IMSG_UPDATE_ERR, +- IMSG_SESSION_ADD, +- IMSG_SESSION_UP, +- IMSG_SESSION_DOWN, +- 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, +- IMSG_PFTABLE_ADD, +- IMSG_PFTABLE_REMOVE, +- IMSG_PFTABLE_COMMIT, +- IMSG_NETWORK_ADD, +- IMSG_NETWORK_REMOVE, +- IMSG_NETWORK_FLUSH, +- IMSG_NETWORK_DONE, +- IMSG_FILTER_SET, + IMSG_CTL_END, + IMSG_CTL_RELOAD, + IMSG_CTL_FIB_COUPLE, +@@ -347,23 +298,40 @@ enum imsg_type { + IMSG_CTL_SHOW_RIB_MEM, + IMSG_CTL_SHOW_TERSE, + IMSG_CTL_SHOW_TIMER, ++ IMSG_NETWORK_ADD, ++ IMSG_NETWORK_REMOVE, ++ IMSG_NETWORK_FLUSH, ++ IMSG_NETWORK_DONE, ++ IMSG_FILTER_SET, ++ IMSG_RECONF_CONF, ++ IMSG_RECONF_RIB, ++ IMSG_RECONF_PEER, ++ IMSG_RECONF_FILTER, ++ IMSG_RECONF_LISTENER, ++ IMSG_RECONF_DONE, ++ IMSG_UPDATE, ++ IMSG_UPDATE_ERR, ++ IMSG_SESSION_ADD, ++ IMSG_SESSION_UP, ++ IMSG_SESSION_DOWN, ++ 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, ++ IMSG_PFTABLE_ADD, ++ IMSG_PFTABLE_REMOVE, ++ IMSG_PFTABLE_COMMIT, + IMSG_REFRESH, + IMSG_IFINFO, + IMSG_DEMOTE + }; + +-struct imsg_hdr { +- u_int32_t peerid; +- pid_t pid; +- enum imsg_type type; +- u_int16_t len; +-}; +- +-struct imsg { +- struct imsg_hdr hdr; +- void *data; +-}; +- + struct demote_msg { + char demote_group[IFNAMSIZ]; + int level; +@@ -424,6 +392,7 @@ struct kroute { + u_int16_t labelid; + u_short ifindex; + u_int8_t prefixlen; ++ u_int8_t priority; + }; + + struct kroute6 { +@@ -433,6 +402,7 @@ struct kroute6 { + u_int16_t labelid; + u_short ifindex; + u_int8_t prefixlen; ++ u_int8_t priority; + }; + + struct kroute_nexthop { +@@ -510,7 +480,7 @@ struct ctl_show_rib { + u_int32_t med; + u_int32_t prefix_cnt; + u_int32_t active_cnt; +- u_int32_t adjrib_cnt; ++ u_int32_t rib_cnt; + u_int16_t aspath_len; + u_int16_t flags; + u_int8_t prefixlen; +@@ -545,6 +515,7 @@ struct filter_community { + }; + + struct ctl_show_rib_request { ++ char rib[PEER_DESCR_LEN]; + struct ctl_neighbor neighbor; + struct bgpd_addr prefix; + struct filter_as as; +@@ -590,6 +561,7 @@ enum comp_ops { + struct filter_peers { + u_int32_t peerid; + u_int32_t groupid; ++ u_int16_t ribid; + }; + + /* special community type */ +@@ -644,6 +616,7 @@ TAILQ_HEAD(filter_head, filter_rule); + + struct filter_rule { + TAILQ_ENTRY(filter_rule) entry; ++ char rib[PEER_DESCR_LEN]; + struct filter_peers peer; + struct filter_match match; + struct filter_set_head set; +@@ -697,6 +670,7 @@ struct rrefresh { + 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 nexthop_cnt; +@@ -709,6 +683,15 @@ struct rde_memstats { + int64_t attr_dcnt; + }; + ++struct rde_rib { ++ SIMPLEQ_ENTRY(rde_rib) entry; ++ char name[PEER_DESCR_LEN]; ++ u_int16_t id; ++ u_int16_t flags; ++}; ++SIMPLEQ_HEAD(rib_names, rde_rib); ++extern struct rib_names ribnames; ++ + /* Address Family Numbers as per RFC 1700 */ + #define AFI_IPv4 1 + #define AFI_IPv6 2 +@@ -723,6 +706,18 @@ struct rde_memstats { + /* 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 ++ + /* prototypes */ + /* bgpd.c */ + void send_nexthop_update(struct kroute_nexthop *); +@@ -730,18 +725,6 @@ void send_imsg_session(int, pid_t, voi + int bgpd_redistribute(int, struct kroute *, struct kroute6 *); + int bgpd_filternexthop(struct kroute *, struct kroute6 *); + +-/* buffer.c */ +-struct buf *buf_open(size_t); +-struct buf *buf_grow(struct buf *, size_t); +-int buf_add(struct buf *, const void *, size_t); +-void *buf_reserve(struct buf *, size_t); +-int buf_close(struct msgbuf *, struct buf *); +-int buf_write(int, struct buf *); +-void buf_free(struct buf *); +-void msgbuf_init(struct msgbuf *); +-void msgbuf_clear(struct msgbuf *); +-int msgbuf_write(struct msgbuf *); +- + /* log.c */ + void log_init(int); + void vlog(int, const char *, va_list); +@@ -760,19 +743,6 @@ int cmdline_symset(char *); + /* config.c */ + int host(const char *, struct bgpd_addr *, u_int8_t *); + +-/* imsg.c */ +-void imsg_init(struct imsgbuf *, int); +-int imsg_read(struct imsgbuf *); +-int imsg_get(struct imsgbuf *, struct imsg *); +-int imsg_compose(struct imsgbuf *, enum imsg_type, u_int32_t, pid_t, int, +- const void *, u_int16_t); +-struct buf *imsg_create(struct imsgbuf *, enum imsg_type, u_int32_t, pid_t, +- u_int16_t); +-int imsg_add(struct buf *, const void *, u_int16_t); +-int imsg_close(struct imsgbuf *, struct buf *); +-void imsg_free(struct imsg *); +-int imsg_get_fd(struct imsgbuf *); +- + /* kroute.c */ + int kr_init(int, u_int); + int kr_change(struct kroute_label *); +@@ -788,10 +758,7 @@ void kr_nexthop_delete(struct bgpd_add + void kr_show_route(struct imsg *); + void kr_ifinfo(char *); + int kr_reload(void); +-in_addr_t prefixlen2mask(u_int8_t); + struct in6_addr *prefixlen2mask6(u_int8_t prefixlen); +-void inet6applymask(struct in6_addr *, const struct in6_addr *, +- int); + + /* control.c */ + void control_cleanup(const char *); +@@ -806,6 +773,10 @@ int pftable_addr_remove(struct pftable_m + int pftable_commit(void); + + /* name2id.c */ ++u_int16_t rib_name2id(const char *); ++const char *rib_id2name(u_int16_t); ++void rib_unref(u_int16_t); ++void rib_ref(u_int16_t); + u_int16_t rtlabel_name2id(const char *); + const char *rtlabel_id2name(u_int16_t); + void rtlabel_unref(u_int16_t); +@@ -829,5 +800,8 @@ const char *log_as(u_int32_t); + int aspath_snprint(char *, size_t, void *, u_int16_t); + int aspath_asprint(char **, void *, u_int16_t); + size_t aspath_strlen(void *, u_int16_t); ++in_addr_t prefixlen2mask(u_int8_t); ++void inet6applymask(struct in6_addr *, const struct in6_addr *, ++ int); + + #endif /* __BGPD_H__ */ diff --git a/net/openbgpd/files/patch-bgpd_buffer.c b/net/openbgpd/files/patch-bgpd_buffer.c new file mode 100644 index 00000000000..371bf9ecf1f --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_buffer.c @@ -0,0 +1,234 @@ +Index: bgpd/buffer.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/buffer.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 +--- bgpd/buffer.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/buffer.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: buffer.c,v 1.39 2008/03/24 16:11:02 deraadt Exp $ */ ++/* $OpenBSD: buffer.c,v 1.43 2009/06/06 06:33:15 eric Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -16,18 +16,19 @@ + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +-#include <sys/types.h> ++#include <sys/param.h> ++#include <sys/queue.h> ++#include <sys/socket.h> + #include <sys/uio.h> + + #include <errno.h> +-#include <limits.h> +-#include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <unistd.h> + +-#include "bgpd.h" ++#include "imsg.h" + ++int buf_realloc(struct buf *, size_t); + void buf_enqueue(struct msgbuf *, struct buf *); + void buf_dequeue(struct msgbuf *, struct buf *); + +@@ -42,35 +43,55 @@ buf_open(size_t len) + free(buf); + return (NULL); + } +- buf->size = len; ++ buf->size = buf->max = len; + buf->fd = -1; + + return (buf); + } + + struct buf * +-buf_grow(struct buf *buf, size_t len) ++buf_dynamic(size_t len, size_t max) + { +- void *p; ++ struct buf *buf; + +- if ((p = realloc(buf->buf, buf->size + len)) == NULL) { +- free(buf->buf); +- buf->buf = NULL; +- buf->size = 0; ++ if (max < len) ++ return (NULL); ++ ++ if ((buf = buf_open(len)) == NULL) + return (NULL); +- } + +- buf->buf = p; +- buf->size += len; ++ if (max > 0) ++ buf->max = max; + + return (buf); + } + + int ++buf_realloc(struct buf *buf, size_t len) ++{ ++ u_char *b; ++ ++ /* on static buffers max is eq size and so the following fails */ ++ if (buf->wpos + len > buf->max) { ++ errno = ENOMEM; ++ return (-1); ++ } ++ ++ b = realloc(buf->buf, buf->wpos + len); ++ if (b == NULL) ++ return (-1); ++ buf->buf = b; ++ buf->size = buf->wpos + len; ++ ++ return (0); ++} ++ ++int + buf_add(struct buf *buf, const void *data, size_t len) + { + if (buf->wpos + len > buf->size) +- return (-1); ++ if (buf_realloc(buf, len) == -1) ++ return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; +@@ -83,27 +104,60 @@ buf_reserve(struct buf *buf, size_t len) + void *b; + + if (buf->wpos + len > buf->size) +- return (NULL); ++ if (buf_realloc(buf, len) == -1) ++ return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); + } + +-int ++void * ++buf_seek(struct buf *buf, size_t pos, size_t len) ++{ ++ /* only allowed to seek in already written parts */ ++ if (pos + len > buf->wpos) ++ return (NULL); ++ ++ return (buf->buf + pos); ++} ++ ++size_t ++buf_size(struct buf *buf) ++{ ++ return (buf->wpos); ++} ++ ++size_t ++buf_left(struct buf *buf) ++{ ++ return (buf->max - buf->wpos); ++} ++ ++void + buf_close(struct msgbuf *msgbuf, struct buf *buf) + { + buf_enqueue(msgbuf, buf); +- return (1); + } + + int +-buf_write(int sock, struct buf *buf) ++buf_write(struct msgbuf *msgbuf) + { ++ struct iovec iov[IOV_MAX]; ++ struct buf *buf, *next; ++ unsigned int i = 0; + ssize_t n; + +- if ((n = write(sock, buf->buf + buf->rpos, +- buf->size - buf->rpos)) == -1) { ++ bzero(&iov, sizeof(iov)); ++ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { ++ if (i >= IOV_MAX) ++ break; ++ iov[i].iov_base = buf->buf + buf->rpos; ++ iov[i].iov_len = buf->size - buf->rpos; ++ i++; ++ } ++ ++ if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EAGAIN || errno == ENOBUFS || + errno == EINTR) /* try later */ + return (0); +@@ -116,11 +170,19 @@ buf_write(int sock, struct buf *buf) + return (-2); + } + +- if (buf->rpos + n < buf->size) { /* not all data written yet */ +- buf->rpos += n; +- return (0); +- } else +- return (1); ++ for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; ++ buf = next) { ++ next = TAILQ_NEXT(buf, entry); ++ if (buf->rpos + n >= buf->size) { ++ n -= buf->size - buf->rpos; ++ buf_dequeue(msgbuf, buf); ++ } else { ++ buf->rpos += n; ++ n = 0; ++ } ++ } ++ ++ return (0); + } + + void +@@ -152,13 +214,13 @@ msgbuf_write(struct msgbuf *msgbuf) + { + struct iovec iov[IOV_MAX]; + struct buf *buf, *next; +- int i = 0; ++ unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { +- struct cmsghdr hdr; +- char buf[CMSG_SPACE(sizeof(int))]; ++ struct cmsghdr hdr; ++ char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + bzero(&iov, sizeof(iov)); +@@ -167,7 +229,7 @@ msgbuf_write(struct msgbuf *msgbuf) + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; +- iov[i].iov_len = buf->size - buf->rpos; ++ iov[i].iov_len = buf->wpos - buf->rpos; + i++; + if (buf->fd != -1) + break; +@@ -211,8 +273,8 @@ msgbuf_write(struct msgbuf *msgbuf) + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); +- if (buf->rpos + n >= buf->size) { +- n -= buf->size - buf->rpos; ++ if (buf->rpos + n >= buf->wpos) { ++ n -= buf->wpos - buf->rpos; + buf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; diff --git a/net/openbgpd/files/patch-bgpd_carp.c b/net/openbgpd/files/patch-bgpd_carp.c index 0edf5e07216..53dcacbec44 100644 --- a/net/openbgpd/files/patch-bgpd_carp.c +++ b/net/openbgpd/files/patch-bgpd_carp.c @@ -2,11 +2,30 @@ Index: bgpd/carp.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/carp.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 --- bgpd/carp.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/carp.c 30 Jun 2009 06:40:07 -0000 1.2 -@@ -102,6 +102,9 @@ carp_demote_shutdown(void) ++++ bgpd/carp.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: carp.c,v 1.5 2007/04/23 14:52:28 claudio Exp $ */ ++/* $OpenBSD: carp.c,v 1.6 2008/09/10 15:00:01 tobias Exp $ */ + + /* + * Copyright (c) 2006 Henning Brauer <henning@openbsd.org> +@@ -72,8 +72,11 @@ carp_demote_init(char *group, int force) + } + + /* only demote if this group already is demoted */ +- if ((level = carp_demote_get(group)) == -1) ++ if ((level = carp_demote_get(group)) == -1) { ++ free(c->group); ++ free(c); + return (-1); ++ } + if (level > 0 || force) + c->do_demote = 1; + +@@ -102,6 +105,9 @@ carp_demote_shutdown(void) int carp_demote_get(char *group) { @@ -16,7 +35,7 @@ diff -u -p -r1.1.1.1 -r1.2 int s; struct ifgroupreq ifgr; -@@ -124,6 +127,7 @@ carp_demote_get(char *group) +@@ -124,6 +130,7 @@ carp_demote_get(char *group) close(s); return ((int)ifgr.ifgr_attrib.ifg_carp_demoted); @@ -24,7 +43,7 @@ diff -u -p -r1.1.1.1 -r1.2 } int -@@ -156,6 +160,9 @@ carp_demote_set(char *group, int demote) +@@ -156,6 +163,9 @@ carp_demote_set(char *group, int demote) int carp_demote_ioctl(char *group, int demote) { @@ -34,7 +53,7 @@ diff -u -p -r1.1.1.1 -r1.2 int s, res; struct ifgroupreq ifgr; -@@ -178,4 +185,5 @@ carp_demote_ioctl(char *group, int demot +@@ -178,4 +188,5 @@ carp_demote_ioctl(char *group, int demot close(s); return (res); diff --git a/net/openbgpd/files/patch-bgpd_config.c b/net/openbgpd/files/patch-bgpd_config.c new file mode 100644 index 00000000000..c0a43a16d5a --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_config.c @@ -0,0 +1,23 @@ +Index: bgpd/config.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/config.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 +--- bgpd/config.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/config.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: config.c,v 1.50 2007/10/13 16:35:20 deraadt Exp $ */ ++/* $OpenBSD: config.c,v 1.51 2009/01/26 23:10:02 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> +@@ -145,7 +145,7 @@ get_bgpid(void) + cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; + if ((cur & localnet) == localnet) /* skip 127/8 */ + continue; +- if (cur > ip) ++ if (ntohl(cur) > ntohl(ip)) + ip = cur; + } + freeifaddrs(ifap); diff --git a/net/openbgpd/files/patch-bgpd_control.c b/net/openbgpd/files/patch-bgpd_control.c new file mode 100644 index 00000000000..b858e4fd5e1 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_control.c @@ -0,0 +1,28 @@ +Index: bgpd/control.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/control.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 +--- bgpd/control.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/control.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: control.c,v 1.60 2008/05/11 01:08:05 henning Exp $ */ ++/* $OpenBSD: control.c,v 1.61 2009/05/05 20:09:19 sthen Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -396,6 +396,13 @@ control_dispatch_msg(struct pollfd *pfd, + control_result(c, CTL_RES_NOCAP); + break; + } ++ if ((imsg.hdr.type == IMSG_CTL_SHOW_RIB_PREFIX) ++ && (ribreq->prefix.af != AF_INET) ++ && (ribreq->prefix.af != AF_INET6)) { ++ /* malformed request, must specify af */ ++ control_result(c, CTL_RES_PARSE_ERROR); ++ break; ++ } + c->ibuf.pid = imsg.hdr.pid; + imsg_compose_rde(imsg.hdr.type, imsg.hdr.pid, + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); diff --git a/net/openbgpd/files/patch-bgpd_imsg.c b/net/openbgpd/files/patch-bgpd_imsg.c new file mode 100644 index 00000000000..32deac90e98 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_imsg.c @@ -0,0 +1,264 @@ +Index: bgpd/imsg.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/imsg.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 +--- bgpd/imsg.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/imsg.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: imsg.c,v 1.42 2008/03/24 16:11:02 deraadt Exp $ */ ++/* $OpenBSD: imsg.c,v 1.47 2009/06/08 08:30:06 dlg Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -16,7 +16,9 @@ + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +-#include <sys/types.h> ++#include <sys/param.h> ++#include <sys/queue.h> ++#include <sys/socket.h> + #include <sys/uio.h> + + #include <errno.h> +@@ -24,7 +26,9 @@ + #include <string.h> + #include <unistd.h> + +-#include "bgpd.h" ++#include "imsg.h" ++ ++int imsg_get_fd(struct imsgbuf *); + + void + imsg_init(struct imsgbuf *ibuf, int fd) +@@ -37,14 +41,14 @@ imsg_init(struct imsgbuf *ibuf, int fd) + TAILQ_INIT(&ibuf->fds); + } + +-int ++ssize_t + imsg_read(struct imsgbuf *ibuf) + { + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; +- char buf[CMSG_SPACE(sizeof(int) * 16)]; ++ char buf[CMSG_SPACE(sizeof(int) * 16)]; + } cmsgbuf; + struct iovec iov; + ssize_t n; +@@ -52,6 +56,7 @@ imsg_read(struct imsgbuf *ibuf) + struct imsg_fd *ifd; + + bzero(&msg, sizeof(msg)); ++ + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; +@@ -61,7 +66,6 @@ imsg_read(struct imsgbuf *ibuf) + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno != EINTR && errno != EAGAIN) { +- log_warn("imsg_read: pipe read error"); + return (-1); + } + return (-2); +@@ -74,19 +78,20 @@ imsg_read(struct imsgbuf *ibuf) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fd = (*(int *)CMSG_DATA(cmsg)); +- if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) +- fatal("imsg_read calloc"); ++ if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) { ++ /* XXX: this return can leak */ ++ return (-1); ++ } + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); +- } else +- log_warn("imsg_read: got unexpected ctl data level %d " +- "type %d", cmsg->cmsg_level, cmsg->cmsg_type); ++ } ++ /* we do not handle other ctl data level */ + } + + return (n); + } + +-int ++ssize_t + imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) + { + size_t av, left, datalen; +@@ -99,18 +104,21 @@ imsg_get(struct imsgbuf *ibuf, struct im + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { +- log_warnx("imsg_get: imsg hdr len %u out of bounds, type=%u", +- imsg->hdr.len, imsg->hdr.type); ++ errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; +- if ((imsg->data = malloc(datalen)) == NULL) { +- log_warn("imsg_get"); ++ if ((imsg->data = malloc(datalen)) == NULL) + return (-1); +- } ++ ++ if (imsg->hdr.flags & IMSGF_HASFD) ++ imsg->fd = imsg_get_fd(ibuf); ++ else ++ imsg->fd = -1; ++ + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { +@@ -124,11 +132,10 @@ imsg_get(struct imsgbuf *ibuf, struct im + } + + int +-imsg_compose(struct imsgbuf *ibuf, enum imsg_type type, u_int32_t peerid, +- pid_t pid, int fd, const void *data, u_int16_t datalen) ++imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, ++ pid_t pid, int fd, void *data, u_int16_t datalen) + { + struct buf *wbuf; +- int n; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); +@@ -138,33 +145,55 @@ imsg_compose(struct imsgbuf *ibuf, enum + + wbuf->fd = fd; + +- if ((n = imsg_close(ibuf, wbuf)) < 0) ++ imsg_close(ibuf, wbuf); ++ ++ return (1); ++} ++ ++int ++imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, ++ pid_t pid, int fd, const struct iovec *iov, int iovcnt) ++{ ++ struct buf *wbuf; ++ int i, datalen = 0; ++ ++ for (i = 0; i < iovcnt; i++) ++ datalen += iov[i].iov_len; ++ ++ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + +- return (n); ++ for (i = 0; i < iovcnt; i++) ++ if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) ++ return (-1); ++ ++ wbuf->fd = fd; ++ ++ imsg_close(ibuf, wbuf); ++ ++ return (1); + } + ++/* ARGSUSED */ + struct buf * +-imsg_create(struct imsgbuf *ibuf, enum imsg_type type, u_int32_t peerid, ++imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, u_int16_t datalen) + { + struct buf *wbuf; + struct imsg_hdr hdr; + +- if (datalen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { +- log_warnx("imsg_create: len %u > MAX_IMSGSIZE; " +- "type %u peerid %lu", datalen + IMSG_HEADER_SIZE, +- type, peerid); ++ datalen += IMSG_HEADER_SIZE; ++ if (datalen > MAX_IMSGSIZE) { ++ errno = ERANGE; + return (NULL); + } + +- hdr.len = datalen + IMSG_HEADER_SIZE; + hdr.type = type; ++ hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; +- if ((wbuf = buf_open(hdr.len)) == NULL) { +- log_warn("imsg_create: buf_open"); ++ if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) +@@ -174,28 +203,30 @@ imsg_create(struct imsgbuf *ibuf, enum i + } + + int +-imsg_add(struct buf *msg, const void *data, u_int16_t datalen) ++imsg_add(struct buf *msg, void *data, u_int16_t datalen) + { + if (datalen) + if (buf_add(msg, data, datalen) == -1) { +- log_warnx("imsg_add: buf_add error"); + buf_free(msg); + return (-1); + } + return (datalen); + } + +-int ++void + imsg_close(struct imsgbuf *ibuf, struct buf *msg) + { +- int n; ++ struct imsg_hdr *hdr; + +- if ((n = buf_close(&ibuf->w, msg)) < 0) { +- log_warnx("imsg_close: buf_close error"); +- buf_free(msg); +- return (-1); +- } +- return (n); ++ hdr = (struct imsg_hdr *)msg->buf; ++ ++ hdr->flags &= ~IMSGF_HASFD; ++ if (msg->fd != -1) ++ hdr->flags |= IMSGF_HASFD; ++ ++ hdr->len = (u_int16_t)msg->wpos; ++ ++ buf_close(&ibuf->w, msg); + } + + void +@@ -219,3 +250,19 @@ imsg_get_fd(struct imsgbuf *ibuf) + + return (fd); + } ++ ++int ++imsg_flush(struct imsgbuf *ibuf) ++{ ++ while (ibuf->w.queued) ++ if (msgbuf_write(&ibuf->w) < 0) ++ return (-1); ++ return (0); ++} ++ ++void ++imsg_clear(struct imsgbuf *ibuf) ++{ ++ while (ibuf->w.queued) ++ msgbuf_clear(&ibuf->w); ++} diff --git a/net/openbgpd/files/patch-bgpd_imsg.h b/net/openbgpd/files/patch-bgpd_imsg.h new file mode 100644 index 00000000000..a81694fd379 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_imsg.h @@ -0,0 +1,115 @@ +Index: bgpd/imsg.h +=================================================================== +RCS file: bgpd/imsg.h +diff -N bgpd/imsg.h +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ bgpd/imsg.h 9 Jul 2009 16:49:54 -0000 1.1.1.1 +@@ -0,0 +1,108 @@ ++/* $OpenBSD: imsg.h,v 1.3 2009/06/07 05:56:24 eric Exp $ */ ++ ++/* ++ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> ++ * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> ++ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include <sys/tree.h> ++ ++#define READ_BUF_SIZE 65535 ++#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) ++#define MAX_IMSGSIZE 16384 ++ ++struct buf { ++ TAILQ_ENTRY(buf) entry; ++ u_char *buf; ++ size_t size; ++ size_t max; ++ size_t wpos; ++ size_t rpos; ++ int fd; ++}; ++ ++struct msgbuf { ++ TAILQ_HEAD(, buf) bufs; ++ u_int32_t queued; ++ int fd; ++}; ++ ++struct buf_read { ++ u_char buf[READ_BUF_SIZE]; ++ u_char *rptr; ++ size_t wpos; ++}; ++ ++struct imsg_fd { ++ TAILQ_ENTRY(imsg_fd) entry; ++ int fd; ++}; ++ ++struct imsgbuf { ++ TAILQ_HEAD(, imsg_fd) fds; ++ struct buf_read r; ++ struct msgbuf w; ++ int fd; ++ pid_t pid; ++}; ++ ++#define IMSGF_HASFD 1 ++ ++struct imsg_hdr { ++ u_int32_t type; ++ u_int16_t len; ++ u_int16_t flags; ++ u_int32_t peerid; ++ u_int32_t pid; ++}; ++ ++struct imsg { ++ struct imsg_hdr hdr; ++ int fd; ++ void *data; ++}; ++ ++ ++/* buffer.c */ ++struct buf *buf_open(size_t); ++struct buf *buf_dynamic(size_t, size_t); ++int buf_add(struct buf *, const void *, size_t); ++void *buf_reserve(struct buf *, size_t); ++void *buf_seek(struct buf *, size_t, size_t); ++size_t buf_size(struct buf *); ++size_t buf_left(struct buf *); ++void buf_close(struct msgbuf *, struct buf *); ++int buf_write(struct msgbuf *); ++void buf_free(struct buf *); ++void msgbuf_init(struct msgbuf *); ++void msgbuf_clear(struct msgbuf *); ++int msgbuf_write(struct msgbuf *); ++ ++/* imsg.c */ ++void imsg_init(struct imsgbuf *, int); ++ssize_t imsg_read(struct imsgbuf *); ++ssize_t imsg_get(struct imsgbuf *, struct imsg *); ++int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, ++ int, void *, u_int16_t); ++int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, ++ int, const struct iovec *, int); ++struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, ++ u_int16_t); ++int imsg_add(struct buf *, void *, u_int16_t); ++void imsg_close(struct imsgbuf *, struct buf *); ++void imsg_free(struct imsg *); ++int imsg_flush(struct imsgbuf *); ++void imsg_clear(struct imsgbuf *); diff --git a/net/openbgpd/files/patch-bgpd_kroute.c b/net/openbgpd/files/patch-bgpd_kroute.c index 11431fb1545..c8df99557ad 100644 --- a/net/openbgpd/files/patch-bgpd_kroute.c +++ b/net/openbgpd/files/patch-bgpd_kroute.c @@ -2,11 +2,628 @@ Index: bgpd/kroute.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/kroute.c,v retrieving revision 1.1.1.1 -retrieving revision 1.2 -diff -u -p -r1.1.1.1 -r1.2 +retrieving revision 1.4 +diff -u -p -r1.1.1.1 -r1.4 --- bgpd/kroute.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/kroute.c 30 Jun 2009 06:40:07 -0000 1.2 -@@ -1747,7 +1747,9 @@ send_rtmsg(int fd, int action, struct kr ++++ bgpd/kroute.c 9 Jul 2009 17:35:40 -0000 1.4 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: kroute.c,v 1.160 2008/05/09 12:45:25 henning Exp $ */ ++/* $OpenBSD: kroute.c,v 1.169 2009/06/25 15:54:22 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -48,11 +48,13 @@ struct { + struct kroute_node { + RB_ENTRY(kroute_node) entry; + struct kroute r; ++ struct kroute_node *next; + }; + + struct kroute6_node { + RB_ENTRY(kroute6_node) entry; + struct kroute6 r; ++ struct kroute6_node *next; + }; + + struct knexthop_node { +@@ -88,12 +90,17 @@ int kroute6_compare(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); ++struct kroute_node *kroute_find(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); + +-struct kroute6_node *kroute6_find(const struct in6_addr *, u_int8_t); ++struct kroute6_node *kroute6_find(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); +@@ -118,6 +125,7 @@ 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 *); +@@ -164,8 +172,8 @@ kr_init(int fs, u_int rtableid) + int opt = 0, rcvbuf, default_rcvbuf; + socklen_t optlen; + +- kr_state.fib_sync = fs; + 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"); +@@ -219,13 +227,9 @@ kr_change(struct kroute_label *kl) + struct kroute_node *kr; + int action = RTM_ADD; + +- if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen)) != +- NULL) { +- if (kr->r.flags & F_BGPD_INSERTED) +- action = RTM_CHANGE; +- else /* a non-bgp route already exists. not a problem */ +- return (0); +- } ++ if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) ++ != NULL) ++ action = RTM_CHANGE; + + /* nexthop within 127/8 -> ignore silently */ + if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) == +@@ -252,6 +256,7 @@ kr_change(struct kroute_label *kl) + 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.priority = RTP_BGP; + kr->r.labelid = kl->kr.labelid; + + if (kroute_insert(kr) == -1) +@@ -277,8 +282,8 @@ kr_delete(struct kroute_label *kl) + { + struct kroute_node *kr; + +- if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen)) == +- NULL) ++ if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) ++ == NULL) + return (0); + + if (!(kr->r.flags & F_BGPD_INSERTED)) +@@ -307,12 +312,9 @@ kr6_change(struct kroute6_label *kl) + int action = RTM_ADD; + struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; + +- if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen)) != NULL) { +- if (kr6->r.flags & F_BGPD_INSERTED) +- action = RTM_CHANGE; +- else /* a non-bgp route already exists. not a problem */ +- return (0); +- } ++ if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) ++ != NULL) ++ action = RTM_CHANGE; + + /* nexthop to loopback -> ignore silently */ + if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop)) +@@ -340,6 +342,7 @@ kr6_change(struct kroute6_label *kl) + 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; + + if (kroute6_insert(kr6) == -1) +@@ -366,7 +369,8 @@ kr6_delete(struct kroute6_label *kl) + { + struct kroute6_node *kr6; + +- if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen)) == NULL) ++ if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) ++ == NULL) + return (0); + + if (!(kr6->r.flags & F_BGPD_INSERTED)) +@@ -509,8 +513,8 @@ kr_nexthop_delete(struct bgpd_addr *addr + void + kr_show_route(struct imsg *imsg) + { +- struct kroute_node *kr; +- struct kroute6_node *kr6; ++ struct kroute_node *kr, *kn; ++ struct kroute6_node *kr6, *kn6; + struct bgpd_addr *addr; + int flags; + sa_family_t af; +@@ -530,16 +534,26 @@ kr_show_route(struct imsg *imsg) + 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) +- send_imsg_session(IMSG_CTL_KROUTE, +- imsg->hdr.pid, &kr->r, +- sizeof(kr->r)); ++ 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); ++ } + if (!af || af == AF_INET6) + RB_FOREACH(kr6, kroute6_tree, &krt6) +- if (!flags || kr6->r.flags & flags) +- send_imsg_session(IMSG_CTL_KROUTE6, +- imsg->hdr.pid, &kr6->r, +- sizeof(kr6->r)); ++ 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); ++ } + break; + case IMSG_CTL_KROUTE_ADDR: + if (imsg->hdr.len != IMSG_HEADER_SIZE + +@@ -791,6 +805,14 @@ kroute_compare(struct kroute_node *a, st + return (-1); + if (a->r.prefixlen > b->r.prefixlen) + return (1); ++ ++ /* if the priority is RTP_ANY finish on the first address hit */ ++ if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY) ++ return (0); ++ if (a->r.priority < b->r.priority) ++ return (-1); ++ if (a->r.priority > b->r.priority) ++ return (1); + return (0); + } + +@@ -810,6 +832,14 @@ kroute6_compare(struct kroute6_node *a, + return (-1); + if (a->r.prefixlen > b->r.prefixlen) + return (1); ++ ++ /* if the priority is RTP_ANY finish on the first address hit */ ++ if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY) ++ return (0); ++ if (a->r.priority < b->r.priority) ++ return (-1); ++ if (a->r.priority > b->r.priority) ++ return (1); + return (0); + } + +@@ -853,27 +883,62 @@ kif_compare(struct kif_node *a, struct k + */ + + struct kroute_node * +-kroute_find(in_addr_t prefix, u_int8_t prefixlen) ++kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio) + { + struct kroute_node s; ++ struct kroute_node *kn, *tmp; + + s.r.prefix.s_addr = prefix; + s.r.prefixlen = prefixlen; ++ s.r.priority = prio; ++ ++ kn = RB_FIND(kroute_tree, &krt, &s); ++ if (kn && prio == RTP_ANY) { ++ tmp = RB_PREV(kroute_tree, &krt, kn); ++ while (tmp) { ++ if (kroute_compare(&s, tmp) == 0) ++ kn = tmp; ++ else ++ break; ++ tmp = RB_PREV(kroute_tree, &krt, kn); ++ } ++ } ++ return (kn); ++} ++ ++struct kroute_node * ++kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in) ++{ ++ in_addr_t nexthop; + +- return (RB_FIND(kroute_tree, &krt, &s)); ++ if (sa_in == NULL) { ++ log_warnx("kroute_matchgw: no nexthop defined"); ++ return (NULL); ++ } ++ nexthop = sa_in->sin_addr.s_addr; ++ ++ while (kr) { ++ if (kr->r.nexthop.s_addr == nexthop) ++ return (kr); ++ kr = kr->next; ++ } ++ ++ return (NULL); + } + + int + kroute_insert(struct kroute_node *kr) + { ++ struct kroute_node *krm; + struct knexthop_node *h; + in_addr_t mask, ina; + +- if (RB_INSERT(kroute_tree, &krt, kr) != NULL) { +- log_warnx("kroute_tree insert failed for %s/%u", +- inet_ntoa(kr->r.prefix), kr->r.prefixlen); +- free(kr); +- return (-1); ++ if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) { ++ /* multipath route, add at end of list */ ++ while (krm->next != NULL) ++ krm = krm->next; ++ krm->next = kr; ++ kr->next = NULL; /* to be sure */ + } + + if (kr->r.flags & F_KERNEL) { +@@ -888,29 +953,61 @@ kroute_insert(struct kroute_node *kr) + if (kif_kr_insert(kr) == -1) + return (-1); + +- kr_redistribute(IMSG_NETWORK_ADD, &kr->r); ++ if (krm == NULL) ++ /* redistribute multipath routes only once */ ++ kr_redistribute(IMSG_NETWORK_ADD, &kr->r); + } + return (0); + } + ++ + int + kroute_remove(struct kroute_node *kr) + { ++ struct kroute_node *krm; + struct knexthop_node *s; + +- if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) { +- log_warnx("kroute_remove failed for %s/%u", ++ if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) { ++ log_warnx("kroute_remove failed to find %s/%u", + inet_ntoa(kr->r.prefix), kr->r.prefixlen); + return (-1); + } + ++ if (krm == kr) { ++ /* head element */ ++ if (RB_REMOVE(kroute_tree, &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) { ++ log_warnx("kroute_remove failed to add %s/%u", ++ inet_ntoa(kr->r.prefix), kr->r.prefixlen); ++ return (-1); ++ } ++ } ++ } else { ++ /* somewhere in the list */ ++ while (krm->next != kr && krm->next != NULL) ++ krm = krm->next; ++ if (krm->next == NULL) { ++ log_warnx("kroute_remove multipath list corrupted " ++ "for %s/%u", inet_ntoa(kr->r.prefix), ++ kr->r.prefixlen); ++ return (-1); ++ } ++ krm->next = kr->next; ++ } ++ + /* check whether a nexthop depends on this kroute */ + if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) + RB_FOREACH(s, knexthop_tree, &knt) + if (s->kroute == kr) + knexthop_validate(s); + +- if (kr->r.flags & F_KERNEL) ++ if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) ++ /* again remove only once */ + kr_redistribute(IMSG_NETWORK_REMOVE, &kr->r); + + if (kr->r.flags & F_CONNECTED) +@@ -933,27 +1030,62 @@ kroute_clear(void) + } + + struct kroute6_node * +-kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen) ++kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio) + { + struct kroute6_node s; ++ struct kroute6_node *kn6, *tmp; + + memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr)); + s.r.prefixlen = prefixlen; ++ s.r.priority = prio; ++ ++ kn6 = RB_FIND(kroute6_tree, &krt6, &s); ++ if (kn6 && prio == RTP_ANY) { ++ tmp = RB_PREV(kroute6_tree, &krt6, kn6); ++ while (tmp) { ++ if (kroute6_compare(&s, tmp) == 0) ++ kn6 = tmp; ++ else ++ break; ++ tmp = RB_PREV(kroute6_tree, &krt6, kn6); ++ } ++ } ++ return (kn6); ++} ++ ++struct kroute6_node * ++kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6) ++{ ++ struct in6_addr nexthop; ++ ++ if (sa_in6 == NULL) { ++ log_warnx("kroute6_matchgw: no nexthop defined"); ++ return (NULL); ++ } ++ memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop)); ++ ++ while (kr) { ++ if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0) ++ return (kr); ++ kr = kr->next; ++ } + +- return (RB_FIND(kroute6_tree, &krt6, &s)); ++ return (NULL); + } + + int + kroute6_insert(struct kroute6_node *kr) + { ++ struct kroute6_node *krm; + struct knexthop_node *h; + struct in6_addr ina, inb; + +- if (RB_INSERT(kroute6_tree, &krt6, kr) != NULL) { +- log_warnx("kroute_tree insert failed for %s/%u", +- log_in6addr(&kr->r.prefix), kr->r.prefixlen); +- free(kr); +- return (-1); ++ if ((krm = RB_INSERT(kroute6_tree, &krt6, kr)) != NULL) { ++ /* multipath route, add at end of list */ ++ while (krm->next != NULL) ++ krm = krm->next; ++ krm->next = kr; ++ kr->next = NULL; /* to be sure */ + } + + if (kr->r.flags & F_KERNEL) { +@@ -970,7 +1102,9 @@ kroute6_insert(struct kroute6_node *kr) + if (kif_kr6_insert(kr) == -1) + return (-1); + +- kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); ++ if (krm == NULL) ++ /* redistribute multipath routes only once */ ++ kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); + } + + return (0); +@@ -979,21 +1113,51 @@ kroute6_insert(struct kroute6_node *kr) + int + kroute6_remove(struct kroute6_node *kr) + { ++ struct kroute6_node *krm; + struct knexthop_node *s; + +- if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) { +- log_warnx("kroute_remove failed for %s/%u", ++ if ((krm = RB_FIND(kroute6_tree, &krt6, kr)) == NULL) { ++ log_warnx("kroute6_remove failed for %s/%u", + log_in6addr(&kr->r.prefix), kr->r.prefixlen); + return (-1); + } + ++ if (krm == kr) { ++ /* head element */ ++ if (RB_REMOVE(kroute6_tree, &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) { ++ log_warnx("kroute6_remove failed to add %s/%u", ++ log_in6addr(&kr->r.prefix), ++ kr->r.prefixlen); ++ return (-1); ++ } ++ } ++ } else { ++ /* somewhere in the list */ ++ while (krm->next != kr && krm->next != NULL) ++ krm = krm->next; ++ if (krm->next == NULL) { ++ log_warnx("kroute6_remove multipath list corrupted " ++ "for %s/%u", log_in6addr(&kr->r.prefix), ++ kr->r.prefixlen); ++ return (-1); ++ } ++ krm->next = kr->next; ++ } ++ + /* check whether a nexthop depends on this kroute */ + if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) + RB_FOREACH(s, knexthop_tree, &knt) + if (s->kroute == kr) + knexthop_validate(s); + +- if (kr->r.flags & F_KERNEL) ++ if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) ++ /* again remove only once */ + kr_redistribute6(IMSG_NETWORK_REMOVE, &kr->r); + + if (kr->r.flags & F_CONNECTED) +@@ -1374,6 +1538,46 @@ knexthop_validate(struct knexthop_node * + } + } + ++void ++knexthop_track(void *krn) ++{ ++ struct knexthop_node *kn; ++ struct kroute_node *kr; ++ struct kroute6_node *kr6; ++ struct kroute_nexthop n; ++ ++ RB_FOREACH(kn, knexthop_tree, &knt) ++ if (kn->kroute == krn) { ++ bzero(&n, sizeof(n)); ++ memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); ++ ++ switch (kn->nexthop.af) { ++ case AF_INET: ++ kr = krn; ++ n.valid = 1; ++ n.connected = kr->r.flags & F_CONNECTED; ++ if ((n.gateway.v4.s_addr = ++ kr->r.nexthop.s_addr) != 0) ++ n.gateway.af = AF_INET; ++ memcpy(&n.kr.kr4, &kr->r, sizeof(n.kr.kr4)); ++ break; ++ case AF_INET6: ++ kr6 = krn; ++ n.valid = 1; ++ n.connected = kr6->r.flags & F_CONNECTED; ++ if (memcmp(&kr6->r.nexthop, &in6addr_any, ++ sizeof(struct in6_addr)) != 0) { ++ n.gateway.af = AF_INET6; ++ memcpy(&n.gateway.v6, &kr6->r.nexthop, ++ sizeof(struct in6_addr)); ++ } ++ memcpy(&n.kr.kr6, &kr6->r, sizeof(n.kr.kr6)); ++ break; ++ } ++ send_nexthop_update(&n); ++ } ++} ++ + struct kroute_node * + kroute_match(in_addr_t key, int matchall) + { +@@ -1385,13 +1589,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)) != NULL) ++ if ((kr = kroute_find(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)) != NULL) ++ if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL) + if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) + return (kr); + +@@ -1408,13 +1612,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)) != NULL) ++ if ((kr6 = kroute6_find(&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)) != NULL) ++ if ((kr6 = kroute6_find(&in6addr_any, 0, RTP_ANY)) != NULL) + if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0) + return (kr6); + +@@ -1456,7 +1660,6 @@ kroute_detach_nexthop(struct knexthop_no + kn->kroute = NULL; + } + +- + /* + * misc helpers + */ +@@ -1568,15 +1771,6 @@ mask2prefixlen6(struct sockaddr_in6 *sa_ + return (l); + } + +-in_addr_t +-prefixlen2mask(u_int8_t prefixlen) +-{ +- if (prefixlen == 0) +- return (0); +- +- return (0xffffffff << (32 - prefixlen)); +-} +- + struct in6_addr * + prefixlen2mask6(u_int8_t prefixlen) + { +@@ -1593,25 +1787,8 @@ prefixlen2mask6(u_int8_t prefixlen) + return (&mask); + } + +-void +-inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) +-{ +- struct in6_addr mask; +- int i; +- +- bzero(&mask, sizeof(mask)); +- for (i = 0; i < prefixlen / 8; i++) +- mask.s6_addr[i] = 0xff; +- i = prefixlen % 8; +- if (i) +- mask.s6_addr[prefixlen / 8] = 0xff00 >> i; +- +- for (i = 0; i < 16; i++) +- dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; +-} +- +-#define ROUNDUP(a, size) \ +- (((a) & ((size) - 1)) ? (1 + ((a) | ((size) - 1))) : (a)) ++#define ROUNDUP(a) \ ++ (((a) & ((sizeof(long)) - 1)) ? (1 + ((a) | ((sizeof(long)) - 1))) : (a)) + + void + get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +@@ -1622,7 +1799,7 @@ get_rtaddrs(int addrs, struct sockaddr * + if (addrs & (1 << i)) { + rti_info[i] = sa; + sa = (struct sockaddr *)((char *)(sa) + +- ROUNDUP(sa->sa_len, sizeof(long))); ++ ROUNDUP(sa->sa_len)); + } else + rti_info[i] = NULL; + } +@@ -1747,7 +1924,9 @@ send_rtmsg(int fd, int action, struct kr struct sockaddr_in prefix; struct sockaddr_in nexthop; struct sockaddr_in mask; @@ -16,7 +633,7 @@ diff -u -p -r1.1.1.1 -r1.2 int iovcnt = 0; if (kr_state.fib_sync == 0) -@@ -1757,9 +1759,13 @@ send_rtmsg(int fd, int action, struct kr +@@ -1757,9 +1936,13 @@ send_rtmsg(int fd, int action, struct kr bzero(&hdr, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; @@ -30,7 +647,7 @@ diff -u -p -r1.1.1.1 -r1.2 if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; if (kroute->flags & F_REJECT) -@@ -1809,6 +1815,7 @@ send_rtmsg(int fd, int action, struct kr +@@ -1809,6 +1992,7 @@ send_rtmsg(int fd, int action, struct kr iov[iovcnt++].iov_len = sizeof(mask); if (kroute->labelid) { @@ -38,7 +655,7 @@ diff -u -p -r1.1.1.1 -r1.2 bzero(&label, sizeof(label)); label.sr_len = sizeof(label); strlcpy(label.sr_label, rtlabel_id2name(kroute->labelid), -@@ -1819,6 +1826,7 @@ send_rtmsg(int fd, int action, struct kr +@@ -1819,6 +2003,7 @@ send_rtmsg(int fd, int action, struct kr /* adjust iovec */ iov[iovcnt].iov_base = &label; iov[iovcnt++].iov_len = sizeof(label); @@ -46,17 +663,24 @@ diff -u -p -r1.1.1.1 -r1.2 } retry: -@@ -1860,7 +1868,9 @@ send_rt6msg(int fd, int action, struct k - struct sockaddr_in6 prefix; - struct sockaddr_in6 nexthop; - struct sockaddr_in6 mask; +@@ -1857,10 +2042,13 @@ send_rt6msg(int fd, int action, struct k + { + struct iovec iov[5]; + struct rt_msghdr hdr; +- struct sockaddr_in6 prefix; +- struct sockaddr_in6 nexthop; +- struct sockaddr_in6 mask; ++ struct pad { ++ 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) -@@ -1870,7 +1880,9 @@ send_rt6msg(int fd, int action, struct k +@@ -1870,7 +2058,9 @@ send_rt6msg(int fd, int action, struct k bzero(&hdr, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; @@ -66,23 +690,95 @@ diff -u -p -r1.1.1.1 -r1.2 hdr.rtm_flags = RTF_PROTO1; if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; -@@ -1924,6 +1936,7 @@ send_rt6msg(int fd, int action, struct k - iov[iovcnt++].iov_len = sizeof(mask); +@@ -1885,44 +2075,46 @@ send_rt6msg(int fd, int action, struct k + iov[iovcnt++].iov_len = sizeof(hdr); + + bzero(&prefix, sizeof(prefix)); +- prefix.sin6_len = sizeof(prefix); +- prefix.sin6_family = AF_INET6; +- memcpy(&prefix.sin6_addr, &kroute->prefix, sizeof(struct in6_addr)); ++ prefix.addr.sin6_len = sizeof(struct sockaddr_in6); ++ prefix.addr.sin6_family = AF_INET6; ++ memcpy(&prefix.addr.sin6_addr, &kroute->prefix, ++ sizeof(struct in6_addr)); + /* XXX scope does not matter or? */ + /* adjust header */ + hdr.rtm_addrs |= RTA_DST; +- hdr.rtm_msglen += sizeof(prefix); ++ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); + /* adjust iovec */ + iov[iovcnt].iov_base = &prefix; +- iov[iovcnt++].iov_len = sizeof(prefix); ++ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); + + if (memcmp(&kroute->nexthop, &in6addr_any, sizeof(struct in6_addr))) { + bzero(&nexthop, sizeof(nexthop)); +- nexthop.sin6_len = sizeof(nexthop); +- nexthop.sin6_family = AF_INET6; +- memcpy(&nexthop.sin6_addr, &kroute->nexthop, ++ nexthop.addr.sin6_len = sizeof(struct sockaddr_in6); ++ nexthop.addr.sin6_family = AF_INET6; ++ memcpy(&nexthop.addr.sin6_addr, &kroute->nexthop, + sizeof(struct in6_addr)); + /* adjust header */ + hdr.rtm_flags |= RTF_GATEWAY; + hdr.rtm_addrs |= RTA_GATEWAY; +- hdr.rtm_msglen += sizeof(nexthop); ++ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); + /* adjust iovec */ + iov[iovcnt].iov_base = &nexthop; +- iov[iovcnt++].iov_len = sizeof(nexthop); ++ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); + } + + bzero(&mask, sizeof(mask)); +- mask.sin6_len = sizeof(mask); +- mask.sin6_family = AF_INET6; +- memcpy(&mask.sin6_addr, prefixlen2mask6(kroute->prefixlen), ++ mask.addr.sin6_len = sizeof(struct sockaddr_in6); ++ mask.addr.sin6_family = AF_INET6; ++ memcpy(&mask.addr.sin6_addr, prefixlen2mask6(kroute->prefixlen), + sizeof(struct in6_addr)); + /* adjust header */ + hdr.rtm_addrs |= RTA_NETMASK; +- hdr.rtm_msglen += sizeof(mask); ++ hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); + /* adjust iovec */ + iov[iovcnt].iov_base = &mask; +- iov[iovcnt++].iov_len = sizeof(mask); ++ iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); - if (kroute->labelid) { +#if !defined(__FreeBSD__) /* FreeBSD has no route labeling. */ + if (kroute->labelid) { bzero(&label, sizeof(label)); label.sr_len = sizeof(label); - strlcpy(label.sr_label, rtlabel_id2name(kroute->labelid), -@@ -1934,6 +1947,7 @@ send_rt6msg(int fd, int action, struct k - /* adjust iovec */ +@@ -1935,6 +2127,7 @@ send_rt6msg(int fd, int action, struct k iov[iovcnt].iov_base = &label; iov[iovcnt++].iov_len = sizeof(label); -+#endif /* !defined(__FreeBSD__) */ } ++#endif /* !defined(__FreeBSD__) */ retry: -@@ -1970,8 +1984,8 @@ retry: + if (writev(fd, iov, iovcnt) == -1) { +@@ -1949,7 +2142,7 @@ retry: + kroute->prefixlen); + return (0); + } else { +- log_warnx("send_rtmsg: action %u, " ++ log_warnx("send_rt6msg: action %u, " + "prefix %s/%u: %s", hdr.rtm_type, + log_in6addr(&kroute->prefix), + kroute->prefixlen, strerror(errno)); +@@ -1957,7 +2150,7 @@ retry: + } + break; + default: +- log_warnx("send_rtmsg: action %u, prefix %s/%u: %s", ++ log_warnx("send_rt6msg: action %u, prefix %s/%u: %s", + hdr.rtm_type, log_in6addr(&kroute->prefix), + kroute->prefixlen, strerror(errno)); + return (0); +@@ -1970,8 +2163,8 @@ retry: int fetchtable(u_int rtableid, int connected_only) { @@ -93,7 +789,7 @@ diff -u -p -r1.1.1.1 -r1.2 char *buf, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa, *gw, *rti_info[RTAX_MAX]; -@@ -1986,9 +2000,8 @@ fetchtable(u_int rtableid, int connected +@@ -1986,9 +2179,8 @@ fetchtable(u_int rtableid, int connected mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; @@ -104,7 +800,7 @@ diff -u -p -r1.1.1.1 -r1.2 if (rtableid != 0 && errno == EINVAL) /* table nonexistent */ return (0); log_warn("sysctl"); -@@ -1998,7 +2011,7 @@ fetchtable(u_int rtableid, int connected +@@ -1998,7 +2190,7 @@ fetchtable(u_int rtableid, int connected log_warn("fetchtable"); return (-1); } @@ -113,7 +809,101 @@ diff -u -p -r1.1.1.1 -r1.2 log_warn("sysctl"); free(buf); return (-1); -@@ -2252,12 +2265,14 @@ dispatch_rtmsg(void) +@@ -2007,7 +2199,13 @@ fetchtable(u_int rtableid, int connected + lim = buf + len; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; +- sa = (struct sockaddr *)(rtm + 1); ++ if (rtm->rtm_version != RTM_VERSION) ++ continue; ++#if !defined(__FreeBSD__) /* no rtm_hdrlen on 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) +@@ -2016,10 +2214,6 @@ fetchtable(u_int rtableid, int connected + if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ + continue; + +-#ifdef RTF_MPATH +- if (rtm->rtm_flags & RTF_MPATH) /* multipath */ +- continue; +-#endif + switch (sa->sa_family) { + case AF_INET: + if ((kr = calloc(1, sizeof(struct kroute_node))) == +@@ -2030,6 +2224,9 @@ fetchtable(u_int rtableid, int connected + } + + kr->r.flags = F_KERNEL; ++#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */ ++ kr->r.priority = RTP_BGP; ++#endif + kr->r.ifindex = rtm->rtm_index; + kr->r.prefix.s_addr = + ((struct sockaddr_in *)sa)->sin_addr.s_addr; +@@ -2062,6 +2259,9 @@ fetchtable(u_int rtableid, int connected + } + + kr6->r.flags = F_KERNEL; ++#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */ ++ kr->r.priority = RTP_BGP; ++#endif + kr6->r.ifindex = rtm->rtm_index; + memcpy(&kr6->r.prefix, + &((struct sockaddr_in6 *)sa)->sin6_addr, +@@ -2113,7 +2313,12 @@ fetchtable(u_int rtableid, int connected + } + + if (sa->sa_family == AF_INET) { +- if (rtm->rtm_flags & RTF_PROTO1) { ++#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */ ++ if (rtm->rtm_priority == RTP_BGP) { ++#else ++ /* never delete route */ ++ if (0) { ++#endif + send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); + free(kr); + } else if (connected_only && +@@ -2122,7 +2327,12 @@ fetchtable(u_int rtableid, int connected + else + kroute_insert(kr); + } else if (sa->sa_family == AF_INET6) { +- if (rtm->rtm_flags & RTF_PROTO1) { ++#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */ ++ if (rtm->rtm_priority == RTP_BGP) { ++#else ++ /* never delete route */ ++ if (0) { ++#endif + send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r); + free(kr6); + } else if (connected_only && +@@ -2234,12 +2444,18 @@ dispatch_rtmsg(void) + lim = buf + n; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; ++ if (rtm->rtm_version != RTM_VERSION) ++ continue; + + switch (rtm->rtm_type) { + case RTM_ADD: + case RTM_CHANGE: + case RTM_DELETE: +- sa = (struct sockaddr *)(rtm + 1); ++#if !defined(__FreeBSD__) /* no rtm_hdrlen on 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 */ +@@ -2252,12 +2468,14 @@ dispatch_rtmsg(void) continue; connected_only = 0; @@ -128,3 +918,192 @@ diff -u -p -r1.1.1.1 -r1.2 if (dispatch_rtmsg_addr(rtm, rti_info, connected_only) == -1) +@@ -2289,9 +2507,10 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + struct kroute_node *kr; + struct kroute6_node *kr6; + struct bgpd_addr prefix; +- int flags, oflags; ++ int flags, oflags, mpath = 0; + u_int16_t ifindex; + u_int8_t prefixlen; ++ u_int8_t prio; + + flags = F_KERNEL; + ifindex = 0; +@@ -2309,7 +2528,16 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + flags |= F_REJECT; + if (rtm->rtm_flags & RTF_DYNAMIC) + flags |= F_DYNAMIC; ++#ifdef RTF_MPATH ++ if (rtm->rtm_flags & RTF_MPATH) ++ mpath = 1; ++#endif + ++#if !defined(__FreeBSD__) /* no rtm_priority on FreeBSD */ ++ prio = rtm->rtm_priority; ++#else ++ prio = RTP_BGP; ++#endif + prefix.af = sa->sa_family; + switch (prefix.af) { + case AF_INET: +@@ -2341,22 +2569,54 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + return (0); + } + ++ if ((sa = rti_info[RTAX_GATEWAY]) != NULL) ++ switch (sa->sa_family) { ++ case AF_LINK: ++ flags |= F_CONNECTED; ++ ifindex = rtm->rtm_index; ++ sa = NULL; ++ mpath = 0; /* link local stuff can't be mpath */ ++ break; ++ } ++ + if (rtm->rtm_type == RTM_DELETE) { + switch (prefix.af) { + case AF_INET: ++ sa_in = (struct sockaddr_in *)sa; + if ((kr = kroute_find(prefix.v4.s_addr, +- prefixlen)) == NULL) ++ prefixlen, prio)) == NULL) + return (0); + if (!(kr->r.flags & F_KERNEL)) + return (0); ++ ++ if (mpath) ++ /* get the correct route */ ++ if ((kr = kroute_matchgw(kr, sa_in)) == NULL) { ++ log_warnx("dispatch_rtmsg[delete] " ++ "mpath route not found"); ++ return (0); ++ } ++ + if (kroute_remove(kr) == -1) + return (-1); + break; + case AF_INET6: +- if ((kr6 = kroute6_find(&prefix.v6, prefixlen)) == NULL) ++ sa_in6 = (struct sockaddr_in6 *)sa; ++ if ((kr6 = kroute6_find(&prefix.v6, prefixlen, ++ prio)) == NULL) + return (0); + if (!(kr6->r.flags & F_KERNEL)) + return (0); ++ ++ if (mpath) ++ /* get the correct route */ ++ if ((kr6 = kroute6_matchgw(kr6, sa_in6)) == ++ NULL) { ++ log_warnx("dispatch_rtmsg[delete] " ++ "IPv6 mpath route not found"); ++ return (0); ++ } ++ + if (kroute6_remove(kr6) == -1) + return (-1); + break; +@@ -2364,15 +2624,6 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + return (0); + } + +- if ((sa = rti_info[RTAX_GATEWAY]) != NULL) +- switch (sa->sa_family) { +- case AF_LINK: +- flags |= F_CONNECTED; +- ifindex = rtm->rtm_index; +- sa = NULL; +- break; +- } +- + if (connected_only && !(flags & F_CONNECTED)) + return (0); + +@@ -2385,8 +2636,18 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + switch (prefix.af) { + case AF_INET: + sa_in = (struct sockaddr_in *)sa; +- if ((kr = kroute_find(prefix.v4.s_addr, prefixlen)) != NULL) { ++ if ((kr = kroute_find(prefix.v4.s_addr, prefixlen, ++ prio)) != NULL) { + if (kr->r.flags & F_KERNEL) { ++ /* get the correct route */ ++ if (mpath && rtm->rtm_type == RTM_CHANGE && ++ (kr = kroute_matchgw(kr, sa_in)) == NULL) { ++ log_warnx("dispatch_rtmsg[change] " ++ "mpath route not found"); ++ return (-1); ++ } else if (mpath && rtm->rtm_type == RTM_ADD) ++ goto add4; ++ + if (sa_in != NULL) + kr->r.nexthop.s_addr = + sa_in->sin_addr.s_addr; +@@ -2409,12 +2670,15 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + kr_redistribute(IMSG_NETWORK_ADD, + &kr->r); + } ++ if (kr->r.flags & F_NEXTHOP) ++ knexthop_track(kr); + } + } else if (rtm->rtm_type == RTM_CHANGE) { + log_warnx("change req for %s/%u: not in table", + log_addr(&prefix), prefixlen); + return (0); + } else { ++add4: + if ((kr = calloc(1, + sizeof(struct kroute_node))) == NULL) { + log_warn("dispatch_rtmsg"); +@@ -2428,14 +2692,25 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + kr->r.nexthop.s_addr = 0; + kr->r.flags = flags; + kr->r.ifindex = ifindex; ++ kr->r.priority = prio; + + kroute_insert(kr); + } + break; + case AF_INET6: + sa_in6 = (struct sockaddr_in6 *)sa; +- if ((kr6 = kroute6_find(&prefix.v6, prefixlen)) != NULL) { ++ if ((kr6 = kroute6_find(&prefix.v6, prefixlen, prio)) != NULL) { + if (kr6->r.flags & F_KERNEL) { ++ /* get the correct route */ ++ if (mpath && rtm->rtm_type == RTM_CHANGE && ++ (kr6 = kroute6_matchgw(kr6, sa_in6)) == ++ NULL) { ++ log_warnx("dispatch_rtmsg[change] " ++ "mpath route not found"); ++ return (-1); ++ } else if (mpath && rtm->rtm_type == RTM_ADD) ++ goto add6; ++ + if (sa_in6 != NULL) + memcpy(&kr6->r.nexthop, + &sa_in6->sin6_addr, +@@ -2461,12 +2736,15 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + kr_redistribute6(IMSG_NETWORK_ADD, + &kr6->r); + } ++ if (kr6->r.flags & F_NEXTHOP) ++ knexthop_track(kr6); + } + } else if (rtm->rtm_type == RTM_CHANGE) { + log_warnx("change req for %s/%u: not in table", + log_addr(&prefix), prefixlen); + return (0); + } else { ++add6: + if ((kr6 = calloc(1, + sizeof(struct kroute6_node))) == NULL) { + log_warn("dispatch_rtmsg"); +@@ -2483,6 +2761,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt + sizeof(struct in6_addr)); + kr6->r.flags = flags; + kr6->r.ifindex = ifindex; ++ kr6->r.priority = prio; + + kroute6_insert(kr6); + } diff --git a/net/openbgpd/files/patch-bgpd_log.h b/net/openbgpd/files/patch-bgpd_log.h new file mode 100644 index 00000000000..18c6457cfd9 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_log.h @@ -0,0 +1,21 @@ +Index: bgpd/log.h +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/log.h,v +retrieving revision 1.1.1.1 +retrieving revision 1.1.1.2 +diff -u -p -r1.1.1.1 -r1.1.1.2 +--- bgpd/log.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/log.h 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: log.h,v 1.10 2007/12/23 18:26:13 henning Exp $ */ ++/* $OpenBSD: log.h,v 1.11 2008/09/11 14:49:58 henning Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -119,5 +119,6 @@ static const char * const timernames[] = + "HoldTimer", + "IdleHoldTimer", + "IdleHoldResetTimer", ++ "CarpUndemoteTimer", + "" + }; diff --git a/net/openbgpd/files/patch-bgpd_mrt.c b/net/openbgpd/files/patch-bgpd_mrt.c new file mode 100644 index 00000000000..76853d01791 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_mrt.c @@ -0,0 +1,1002 @@ +Index: bgpd/mrt.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/mrt.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 +--- bgpd/mrt.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/mrt.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: mrt.c,v 1.53 2007/04/23 13:04:24 claudio Exp $ */ ++/* $OpenBSD: mrt.c,v 1.63 2009/06/29 12:22:16 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> +@@ -32,24 +32,21 @@ + + #include "mrt.h" + +-static u_int16_t mrt_attr_length(struct rde_aspath *, int); +-static int mrt_attr_dump(void *, u_int16_t, struct rde_aspath *, +- struct bgpd_addr *); +-static int mrt_dump_entry_mp(struct mrt *, struct prefix *, +- u_int16_t, struct rde_peer*); +-static int mrt_dump_entry(struct mrt *, struct prefix *, +- u_int16_t, struct rde_peer*); +-static int mrt_dump_header(struct buf *, u_int16_t, u_int16_t, +- u_int32_t); +-static int mrt_open(struct mrt *, time_t); ++int mrt_attr_dump(struct buf *, struct rde_aspath *, struct bgpd_addr *); ++int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t, ++ struct rde_peer*); ++int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*); ++int mrt_dump_hdr_se(struct buf **, struct peer *, u_int16_t, u_int16_t, ++ u_int32_t, int); ++int mrt_dump_hdr_rde(struct buf **, 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"); \ +- buf_free((x)); \ +- return (-1); \ ++ goto fail; \ + } \ + } while (0) + +@@ -59,8 +56,7 @@ static int mrt_open(struct mrt *, time_ + t = htons((s)); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump2: buf_add error"); \ +- buf_free((x)); \ +- return (-1); \ ++ goto fail; \ + } \ + } while (0) + +@@ -70,8 +66,7 @@ static int mrt_open(struct mrt *, time_ + t = htonl((l)); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump3: buf_add error"); \ +- buf_free((x)); \ +- return (-1); \ ++ goto fail; \ + } \ + } while (0) + +@@ -80,327 +75,175 @@ static int mrt_open(struct mrt *, time_ + u_int32_t t = (l); \ + if (buf_add((x), &t, sizeof(t)) == -1) { \ + log_warnx("mrt_dump4: buf_add error"); \ +- buf_free((x)); \ +- return (-1); \ ++ goto fail; \ + } \ + } while (0) + +-int ++void + mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, +- struct peer *peer, struct bgpd_config *bgp) ++ struct peer *peer) + { + struct buf *buf; +- u_int16_t len; + int incoming = 0; + +- switch (peer->sa_local.ss_family) { +- case AF_INET: +- len = pkglen + MRT_BGP4MP_IPv4_HEADER_SIZE; +- break; +- case AF_INET6: +- len = pkglen + MRT_BGP4MP_IPv6_HEADER_SIZE; +- break; +- default: +- return (-1); +- } +- + /* 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 ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { +- log_warnx("mrt_dump_bgp_msg: buf_open error"); +- return (-1); +- } +- +- if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, +- len) == -1) { +- log_warnx("mrt_dump_bgp_msg: buf_add error"); +- return (-1); +- } +- +- if (!incoming) +- DUMP_SHORT(buf, bgp->short_as); +- DUMP_SHORT(buf, peer->short_as); +- if (incoming) +- DUMP_SHORT(buf, bgp->short_as); +- DUMP_SHORT(buf, /* ifindex */ 0); +- switch (peer->sa_local.ss_family) { +- case AF_INET: +- DUMP_SHORT(buf, AFI_IPv4); +- if (!incoming) +- DUMP_NLONG(buf, ((struct sockaddr_in *) +- &peer->sa_local)->sin_addr.s_addr); +- DUMP_NLONG(buf, +- ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr); +- if (incoming) +- DUMP_NLONG(buf, ((struct sockaddr_in *) +- &peer->sa_local)->sin_addr.s_addr); +- break; +- case AF_INET6: +- DUMP_SHORT(buf, AFI_IPv6); +- if (!incoming) +- if (buf_add(buf, &((struct sockaddr_in6 *) +- &peer->sa_local)->sin6_addr, +- sizeof(struct in6_addr)) == -1) { +- log_warnx("mrt_dump_bgp_msg: buf_add error"); +- buf_free(buf); +- return (-1); +- } +- if (buf_add(buf, +- &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, +- sizeof(struct in6_addr)) == -1) { +- log_warnx("mrt_dump_bgp_msg: buf_add error"); +- buf_free(buf); +- return (-1); +- } +- if (incoming) +- if (buf_add(buf, &((struct sockaddr_in6 *) +- &peer->sa_local)->sin6_addr, +- sizeof(struct in6_addr)) == -1) { +- log_warnx("mrt_dump_bgp_msg: buf_add error"); +- buf_free(buf); +- return (-1); +- } +- break; +- } ++ if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, ++ pkglen, incoming) == -1) ++ return; + + if (buf_add(buf, pkg, pkglen) == -1) { + log_warnx("mrt_dump_bgp_msg: buf_add error"); + buf_free(buf); +- return (-1); ++ return; + } + +- TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); +- mrt->queued++; +- +- return (len + MRT_HEADER_SIZE); ++ buf_close(&mrt->wbuf, buf); + } + +-int ++void + mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, +- struct peer *peer, struct bgpd_config *bgp) ++ struct peer *peer) + { + struct buf *buf; +- u_int16_t len; +- +- switch (peer->sa_local.ss_family) { +- case AF_INET: +- len = 4 + MRT_BGP4MP_IPv4_HEADER_SIZE; +- break; +- case AF_INET6: +- len = 4 + MRT_BGP4MP_IPv6_HEADER_SIZE; +- break; +- default: +- return (-1); +- } +- +- if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { +- log_warnx("mrt_dump_bgp_state: buf_open error"); +- return (-1); +- } + +- if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE, +- len) == -1) { +- log_warnx("mrt_dump_bgp_state: buf_add error"); +- return (-1); +- } +- +- DUMP_SHORT(buf, bgp->short_as); +- DUMP_SHORT(buf, peer->short_as); +- DUMP_SHORT(buf, /* ifindex */ 0); +- switch (peer->sa_local.ss_family) { +- case AF_INET: +- DUMP_SHORT(buf, AFI_IPv4); +- DUMP_NLONG(buf, +- ((struct sockaddr_in *)&peer->sa_local)->sin_addr.s_addr); +- DUMP_NLONG(buf, +- ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr); +- break; +- case AF_INET6: +- DUMP_SHORT(buf, AFI_IPv6); +- if (buf_add(buf, +- &((struct sockaddr_in6 *)&peer->sa_local)->sin6_addr, +- sizeof(struct in6_addr)) == -1 || +- buf_add(buf, +- &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, +- sizeof(struct in6_addr)) == -1) { +- log_warnx("mrt_dump_bgp_msg: buf_add error"); +- buf_free(buf); +- return (-1); +- } +- break; +- } ++ if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, ++ 2 * sizeof(short), 0) == -1) ++ return; + + DUMP_SHORT(buf, old_state); + DUMP_SHORT(buf, new_state); + +- TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); +- mrt->queued++; +- +- return (len + MRT_HEADER_SIZE); +-} +- +-static u_int16_t +-mrt_attr_length(struct rde_aspath *a, int oldform) +-{ +- u_int16_t alen, plen; +- u_int8_t l; ++ buf_close(&mrt->wbuf, buf); ++ return; + +- alen = 4 /* origin */ + 7 /* lpref */; +- if (oldform) +- alen += 7 /* nexthop */; +- plen = aspath_length(a->aspath); +- alen += 2 + plen + (plen > 255 ? 2 : 1); +- if (a->med != 0) +- alen += 7; +- +- for (l = 0; l < a->others_len; l++) +- if (a->others[l] != NULL) +- alen += 2 + a->others[l]->len + +- (a->others[l]->len > 255 ? 2 : 1); +- else +- break; +- +- return alen; ++fail: ++ buf_free(buf); + } + +-static int +-mrt_attr_dump(void *p, u_int16_t len, struct rde_aspath *a, +- struct bgpd_addr *nexthop) ++int ++mrt_attr_dump(struct buf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop) + { + struct attr *oa; +- u_char *buf = p; +- u_int32_t tmp32; +- int r; +- u_int16_t aslen, wlen = 0; ++ u_char *pdata; ++ u_int32_t tmp; ++ int neednewpath = 0; ++ u_int16_t plen; + u_int8_t l; + + /* origin */ +- if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, ATTR_ORIGIN, +- &a->origin, 1)) == -1) ++ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, ++ &a->origin, 1) == -1) + return (-1); +- wlen += r; len -= r; + + /* aspath */ +- aslen = aspath_length(a->aspath); +- if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, ATTR_ASPATH, +- aspath_dump(a->aspath), aslen)) == -1) ++ pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); ++ pdata = aspath_deflate(pdata, &plen, &neednewpath); ++ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata, plen) == -1) + return (-1); +- wlen += r; len -= r; ++ free(pdata); + + if (nexthop) { + /* nexthop, already network byte order */ +- if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, +- ATTR_NEXTHOP, &nexthop->v4.s_addr, 4)) == -1) ++ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP, ++ &nexthop->v4.s_addr, 4) == -1) + return (-1); +- wlen += r; len -= r; + } + + /* MED, non transitive */ + if (a->med != 0) { +- tmp32 = htonl(a->med); +- if ((r = attr_write(buf + wlen, len, ATTR_OPTIONAL, ATTR_MED, +- &tmp32, 4)) == -1) ++ tmp = htonl(a->med); ++ if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1) + return (-1); +- wlen += r; len -= r; + } + + /* local preference, only valid for ibgp */ +- tmp32 = htonl(a->lpref); +- if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, ATTR_LOCALPREF, +- &tmp32, 4)) == -1) ++ tmp = htonl(a->lpref); ++ if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) + return (-1); +- wlen += r; len -= r; + + /* dump all other path attributes without modification */ + for (l = 0; l < a->others_len; l++) { + if ((oa = a->others[l]) == NULL) + break; +- if ((r = attr_write(buf + wlen, len, oa->flags, oa->type, +- oa->data, oa->len)) == -1) ++ if (attr_writebuf(buf, oa->flags, oa->type, ++ oa->data, oa->len) == -1) + return (-1); +- wlen += r; len -= r; + } + +- return (wlen); ++ 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) ++ return (-1); ++ free(pdata); ++ } ++ ++ return (0); + } + +-static int ++int + mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, + struct rde_peer *peer) + { +- struct buf *buf; ++ struct buf *buf, *hbuf = NULL, *h2buf = NULL; + void *bptr; + struct bgpd_addr addr, nexthop, *nh; +- u_int16_t len, attr_len; ++ u_int16_t len; + u_int8_t p_len; + sa_family_t af; + +- attr_len = mrt_attr_length(p->aspath, 0); +- p_len = PREFIX_SIZE(p->prefix->prefixlen); +- pt_getaddr(p->prefix, &addr); +- +- af = peer->remote_addr.af == 0 ? addr.af : peer->remote_addr.af; +- switch (af) { +- case AF_INET: +- len = MRT_BGP4MP_IPv4_HEADER_SIZE; +- break; +- case AF_INET6: +- len = MRT_BGP4MP_IPv6_HEADER_SIZE; +- break; +- default: +- return (-1); +- } +- +- switch (addr.af) { +- case AF_INET: +- len += MRT_BGP4MP_IPv4_ENTRY_SIZE + p_len + attr_len; +- break; +- case AF_INET6: +- len += MRT_BGP4MP_IPv4_ENTRY_SIZE + p_len + attr_len; +- break; +- default: ++ if ((buf = buf_dynamic(0, MAX_PKTSIZE)) == NULL) { ++ log_warn("mrt_dump_entry_mp: buf_dynamic"); + return (-1); + } + +- if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { +- log_warnx("mrt_dump_entry_mp: buf_open error"); +- return (-1); ++ if (mrt_attr_dump(buf, p->aspath, NULL) == -1) { ++ log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); ++ goto fail; + } ++ len = buf_size(buf); + +- if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, +- len) == -1) { +- log_warnx("mrt_dump_entry_mp: buf_add error"); +- return (-1); ++ if ((h2buf = buf_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"); ++ goto fail; + } + +- DUMP_SHORT(buf, rde_local_as()); +- DUMP_SHORT(buf, peer->short_as); +- DUMP_SHORT(buf, /* ifindex */ 0); ++ DUMP_SHORT(h2buf, rde_local_as()); ++ DUMP_SHORT(h2buf, peer->short_as); ++ 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: +- DUMP_SHORT(buf, AFI_IPv4); +- DUMP_NLONG(buf, peer->local_v4_addr.v4.s_addr); +- DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); ++ 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: +- DUMP_SHORT(buf, AFI_IPv6); +- if (buf_add(buf, &peer->local_v6_addr.v6, ++ DUMP_SHORT(h2buf, AFI_IPv6); ++ if (buf_add(h2buf, &peer->local_v6_addr.v6, + sizeof(struct in6_addr)) == -1 || +- buf_add(buf, &peer->remote_addr.v6, ++ buf_add(h2buf, &peer->remote_addr.v6, + sizeof(struct in6_addr)) == -1) { + log_warnx("mrt_dump_entry_mp: buf_add error"); +- buf_free(buf); +- return (-1); ++ goto fail; + } + break; ++ default: ++ log_warnx("king bula found new AF %d in mrt_dump_entry_mp", af); ++ goto fail; + } + +- DUMP_SHORT(buf, 0); /* view */ +- DUMP_SHORT(buf, 1); /* status */ +- DUMP_LONG(buf, p->lastchange); /* originated */ ++ DUMP_SHORT(h2buf, 0); /* view */ ++ DUMP_SHORT(h2buf, 1); /* status */ ++ DUMP_LONG(h2buf, p->lastchange); /* originated */ + + if (p->aspath->nexthop == NULL) { + bzero(&nexthop, sizeof(struct bgpd_addr)); +@@ -409,95 +252,74 @@ mrt_dump_entry_mp(struct mrt *mrt, struc + } else + nh = &p->aspath->nexthop->exit_nexthop; + ++ pt_getaddr(p->prefix, &addr); + switch (addr.af) { + case AF_INET: +- DUMP_SHORT(buf, AFI_IPv4); /* afi */ +- DUMP_BYTE(buf, SAFI_UNICAST); /* safi */ +- DUMP_BYTE(buf, 4); /* nhlen */ +- DUMP_NLONG(buf, nh->v4.s_addr); /* nexthop */ ++ 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: +- DUMP_SHORT(buf, AFI_IPv6); /* afi */ +- DUMP_BYTE(buf, SAFI_UNICAST); /* safi */ +- DUMP_BYTE(buf, 16); /* nhlen */ +- if (buf_add(buf, &nh->v6, sizeof(struct in6_addr)) == -1) { ++ 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"); +- buf_free(buf); +- return (-1); ++ goto fail; + } + break; ++ default: ++ log_warnx("king bula found new AF in mrt_dump_entry_mp"); ++ goto fail; + } + +- if ((bptr = buf_reserve(buf, p_len)) == NULL) { ++ p_len = PREFIX_SIZE(p->prefix->prefixlen); ++ if ((bptr = buf_reserve(h2buf, p_len)) == NULL) { + log_warnx("mrt_dump_entry_mp: buf_reserve error"); +- buf_free(buf); +- return (-1); ++ goto fail; + } + if (prefix_write(bptr, p_len, &addr, p->prefix->prefixlen) == -1) { + log_warnx("mrt_dump_entry_mp: prefix_write error"); +- buf_free(buf); +- return (-1); ++ goto fail; + } + +- DUMP_SHORT(buf, attr_len); +- if ((bptr = buf_reserve(buf, attr_len)) == NULL) { +- log_warnx("mrt_dump_entry_mp: buf_reserve error"); +- buf_free(buf); +- return (-1); +- } ++ DUMP_SHORT(h2buf, len); ++ len += buf_size(h2buf); + +- if (mrt_attr_dump(bptr, attr_len, p->aspath, NULL) == -1) { +- log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); +- buf_free(buf); +- return (-1); +- } ++ if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, ++ len) == -1) ++ goto fail; + +- TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); +- mrt->queued++; ++ buf_close(&mrt->wbuf, hbuf); ++ buf_close(&mrt->wbuf, h2buf); ++ buf_close(&mrt->wbuf, buf); + + return (len + MRT_HEADER_SIZE); ++ ++fail: ++ if (hbuf) ++ buf_free(hbuf); ++ if (h2buf); ++ buf_free(h2buf); ++ buf_free(buf); ++ return (-1); + } + +-static int ++int + mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, + struct rde_peer *peer) + { +- struct buf *buf; +- void *bptr; ++ struct buf *buf, *hbuf; + struct bgpd_addr addr, *nh; +- u_int16_t len, attr_len; ++ size_t len; + + if (p->prefix->af != AF_INET && peer->remote_addr.af == AF_INET) +- /* only for true IPv4 */ ++ /* only able to dump IPv4 */ + return (0); + +- attr_len = mrt_attr_length(p->aspath, 1); +- len = MRT_DUMP_HEADER_SIZE + attr_len; +- pt_getaddr(p->prefix, &addr); +- +- if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { +- log_warnx("mrt_dump_entry: buf_open error"); +- return (-1); +- } +- +- if (mrt_dump_header(buf, MSG_TABLE_DUMP, AFI_IPv4, len) == -1) { +- log_warnx("mrt_dump_entry: buf_add error"); +- return (-1); +- } +- +- DUMP_SHORT(buf, 0); +- DUMP_SHORT(buf, snum); +- DUMP_NLONG(buf, addr.v4.s_addr); +- DUMP_BYTE(buf, p->prefix->prefixlen); +- DUMP_BYTE(buf, 1); /* state */ +- DUMP_LONG(buf, p->lastchange); /* originated */ +- DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); +- DUMP_SHORT(buf, peer->short_as); +- +- DUMP_SHORT(buf, attr_len); +- if ((bptr = buf_reserve(buf, attr_len)) == NULL) { +- log_warnx("mrt_dump_entry: buf_reserve error"); +- buf_free(buf); ++ if ((buf = buf_dynamic(0, MAX_PKTSIZE)) == NULL) { ++ log_warnx("mrt_dump_entry: buf_dynamic"); + return (-1); + } + +@@ -507,28 +329,44 @@ mrt_dump_entry(struct mrt *mrt, struct p + nh = &addr; + } else + nh = &p->aspath->nexthop->exit_nexthop; +- if (mrt_attr_dump(bptr, attr_len, p->aspath, nh) == -1) { ++ if (mrt_attr_dump(buf, p->aspath, nh) == -1) { + log_warnx("mrt_dump_entry: mrt_attr_dump error"); + buf_free(buf); + return (-1); + } ++ len = buf_size(buf); + +- TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); +- mrt->queued++; ++ if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, AFI_IPv4, len) == -1) { ++ buf_free(buf); ++ return (-1); ++ } + +- return (len + MRT_HEADER_SIZE); +-} ++ DUMP_SHORT(hbuf, 0); ++ DUMP_SHORT(hbuf, snum); + +-static u_int16_t sequencenum = 0; ++ pt_getaddr(p->prefix, &addr); ++ DUMP_NLONG(hbuf, addr.v4.s_addr); ++ DUMP_BYTE(hbuf, p->prefix->prefixlen); + +-void +-mrt_clear_seq(void) +-{ +- sequencenum = 0; ++ DUMP_BYTE(hbuf, 1); /* state */ ++ DUMP_LONG(hbuf, p->lastchange); /* originated */ ++ DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); ++ DUMP_SHORT(hbuf, peer->short_as); ++ DUMP_SHORT(hbuf, len); ++ ++ buf_close(&mrt->wbuf, hbuf); ++ buf_close(&mrt->wbuf, buf); ++ ++ return (len + MRT_HEADER_SIZE); ++ ++fail: ++ buf_free(hbuf); ++ buf_free(buf); ++ return (-1); + } + + void +-mrt_dump_upcall(struct pt_entry *pt, void *ptr) ++mrt_dump_upcall(struct rib_entry *re, void *ptr) + { + struct mrt *mrtbuf = ptr; + struct prefix *p; +@@ -538,53 +376,172 @@ mrt_dump_upcall(struct pt_entry *pt, voi + * dumps the table so we do the same. If only the active route should + * be dumped p should be set to p = pt->active. + */ +- LIST_FOREACH(p, &pt->prefix_h, prefix_l) { +- /* for now dump only stuff from the local-RIB */ +- if (!(p->flags & F_LOCAL)) +- continue; ++ LIST_FOREACH(p, &re->prefix_h, rib_l) { + if (mrtbuf->type == MRT_TABLE_DUMP) +- mrt_dump_entry(mrtbuf, p, sequencenum++, ++ mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++, + p->aspath->peer); + else +- mrt_dump_entry_mp(mrtbuf, p, sequencenum++, ++ mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++, + p->aspath->peer); + } + } + +-static int +-mrt_dump_header(struct buf *buf, u_int16_t type, u_int16_t subtype, +- u_int32_t len) ++void ++mrt_dump_done(void *ptr) ++{ ++ struct mrt *mrtbuf = ptr; ++ ++ mrtbuf->state = MRT_STATE_REMOVE; ++} ++ ++int ++mrt_dump_hdr_se(struct buf ** bp, struct peer *peer, u_int16_t type, ++ u_int16_t subtype, u_int32_t len, int swap) + { +- time_t now; ++ time_t now; ++ ++ if ((*bp = buf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + ++ MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) { ++ log_warnx("mrt_dump_hdr_se: buf_open error"); ++ return (-1); ++ } + + now = time(NULL); + +- DUMP_LONG(buf, now); +- DUMP_SHORT(buf, type); +- DUMP_SHORT(buf, subtype); +- DUMP_LONG(buf, len); ++ DUMP_LONG(*bp, now); ++ DUMP_SHORT(*bp, type); ++ DUMP_SHORT(*bp, subtype); ++ ++ switch (peer->sa_local.ss_family) { ++ case AF_INET: ++ if (subtype == BGP4MP_STATE_CHANGE_AS4 || ++ subtype == BGP4MP_MESSAGE_AS4) ++ len += MRT_BGP4MP_AS4_IPv4_HEADER_SIZE; ++ else ++ len += MRT_BGP4MP_IPv4_HEADER_SIZE; ++ break; ++ case AF_INET6: ++ if (subtype == BGP4MP_STATE_CHANGE_AS4 || ++ subtype == BGP4MP_MESSAGE_AS4) ++ len += MRT_BGP4MP_AS4_IPv6_HEADER_SIZE; ++ else ++ len += MRT_BGP4MP_IPv6_HEADER_SIZE; ++ break; ++ case 0: ++ goto fail; ++ default: ++ log_warnx("king bula found new AF in mrt_dump_hdr_se"); ++ goto fail; ++ } ++ ++ DUMP_LONG(*bp, len); ++ ++ if (subtype == BGP4MP_STATE_CHANGE_AS4 || ++ subtype == BGP4MP_MESSAGE_AS4) { ++ if (!swap) ++ DUMP_LONG(*bp, peer->conf.local_as); ++ DUMP_LONG(*bp, peer->conf.remote_as); ++ if (swap) ++ DUMP_LONG(*bp, peer->conf.local_as); ++ } else { ++ if (!swap) ++ DUMP_SHORT(*bp, peer->conf.local_short_as); ++ DUMP_SHORT(*bp, peer->short_as); ++ if (swap) ++ DUMP_SHORT(*bp, peer->conf.local_short_as); ++ } ++ ++ DUMP_SHORT(*bp, /* ifindex */ 0); ++ ++ switch (peer->sa_local.ss_family) { ++ case AF_INET: ++ DUMP_SHORT(*bp, AFI_IPv4); ++ if (!swap) ++ DUMP_NLONG(*bp, ((struct sockaddr_in *) ++ &peer->sa_local)->sin_addr.s_addr); ++ DUMP_NLONG(*bp, ++ ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr); ++ if (swap) ++ DUMP_NLONG(*bp, ((struct sockaddr_in *) ++ &peer->sa_local)->sin_addr.s_addr); ++ break; ++ case AF_INET6: ++ DUMP_SHORT(*bp, AFI_IPv6); ++ if (!swap) ++ if (buf_add(*bp, &((struct sockaddr_in6 *) ++ &peer->sa_local)->sin6_addr, ++ sizeof(struct in6_addr)) == -1) { ++ log_warnx("mrt_dump_hdr_se: buf_add error"); ++ goto fail; ++ } ++ if (buf_add(*bp, ++ &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, ++ sizeof(struct in6_addr)) == -1) { ++ log_warnx("mrt_dump_hdr_se: buf_add error"); ++ goto fail; ++ } ++ if (swap) ++ if (buf_add(*bp, &((struct sockaddr_in6 *) ++ &peer->sa_local)->sin6_addr, ++ sizeof(struct in6_addr)) == -1) { ++ log_warnx("mrt_dump_hdr_se: buf_add error"); ++ goto fail; ++ } ++ break; ++ } + + return (0); ++ ++fail: ++ buf_free(*bp); ++ return (-1); + } + + int +-mrt_write(struct mrt *mrt) ++mrt_dump_hdr_rde(struct buf **bp, u_int16_t type, u_int16_t subtype, ++ u_int32_t len) + { +- struct buf *b; +- int r = 0; ++ time_t now; + +- while ((b = TAILQ_FIRST(&mrt->bufs)) && +- (r = buf_write(mrt->fd, b)) == 1) { +- TAILQ_REMOVE(&mrt->bufs, b, entry); +- mrt->queued--; +- buf_free(b); +- } +- if (r <= -1) { +- log_warn("mrt dump write"); +- mrt_clean(mrt); ++ if ((*bp = buf_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"); + return (-1); + } ++ ++ now = time(NULL); ++ DUMP_LONG(*bp, now); ++ DUMP_SHORT(*bp, type); ++ DUMP_SHORT(*bp, subtype); ++ ++ switch (type) { ++ case MSG_TABLE_DUMP: ++ DUMP_LONG(*bp, MRT_DUMP_HEADER_SIZE + len); ++ break; ++ case MSG_PROTOCOL_BGP4MP: ++ DUMP_LONG(*bp, len); ++ break; ++ default: ++ log_warnx("mrt_dump_hdr_rde: unsupported type"); ++ goto fail; ++ } + return (0); ++ ++fail: ++ buf_free(*bp); ++ return (-1); ++} ++ ++void ++mrt_write(struct mrt *mrt) ++{ ++ int r; ++ ++ if ((r = buf_write(&mrt->wbuf)) < 0) { ++ log_warn("mrt dump aborted, mrt_write"); ++ mrt_clean(mrt); ++ } + } + + void +@@ -592,12 +549,12 @@ mrt_clean(struct mrt *mrt) + { + struct buf *b; + +- close(mrt->fd); +- while ((b = TAILQ_FIRST(&mrt->bufs))) { +- TAILQ_REMOVE(&mrt->bufs, b, entry); ++ close(mrt->wbuf.fd); ++ while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) { ++ TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry); + buf_free(b); + } +- mrt->queued = 0; ++ mrt->wbuf.queued = 0; + } + + static struct imsgbuf *mrt_imsgbuf[2]; +@@ -613,30 +570,30 @@ int + mrt_open(struct mrt *mrt, time_t now) + { + enum imsg_type type; +- int i; ++ int i = 1, fd; + + if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), + MRT2MC(mrt)->name, localtime(&now)) == 0) { + log_warnx("mrt_open: strftime conversion failed"); +- mrt->fd = -1; + return (-1); + } + +- mrt->fd = open(MRT2MC(mrt)->file, ++ fd = open(MRT2MC(mrt)->file, + O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644); +- if (mrt->fd == -1) { ++ if (fd == -1) { + log_warn("mrt_open %s", MRT2MC(mrt)->file); + return (1); + } + +- if (MRT2MC(mrt)->state == MRT_STATE_OPEN) ++ if (mrt->state == MRT_STATE_OPEN) + type = IMSG_MRT_OPEN; + else + type = IMSG_MRT_REOPEN; + +- i = mrt->type == MRT_TABLE_DUMP ? 0 : 1; ++ if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP) ++ i = 0; + +- if (imsg_compose(mrt_imsgbuf[i], type, 0, 0, mrt->fd, ++ if (imsg_compose(mrt_imsgbuf[i], type, 0, 0, fd, + mrt, sizeof(struct mrt)) == -1) + log_warn("mrt_open"); + +@@ -652,7 +609,7 @@ mrt_timeout(struct mrt_head *mrt) + + now = time(NULL); + LIST_FOREACH(m, mrt, entry) { +- if (MRT2MC(m)->state == MRT_STATE_RUNNING && ++ if (m->state == MRT_STATE_RUNNING && + MRT2MC(m)->ReopenTimerInterval != 0) { + if (MRT2MC(m)->ReopenTimer <= now) { + mrt_open(m, now); +@@ -675,16 +632,16 @@ mrt_reconfigure(struct mrt_head *mrt) + now = time(NULL); + for (m = LIST_FIRST(mrt); m != NULL; m = xm) { + xm = LIST_NEXT(m, entry); +- if (MRT2MC(m)->state == MRT_STATE_OPEN || +- MRT2MC(m)->state == MRT_STATE_REOPEN) { ++ if (m->state == MRT_STATE_OPEN || ++ m->state == MRT_STATE_REOPEN) { + if (mrt_open(m, now) == -1) + continue; + if (MRT2MC(m)->ReopenTimerInterval != 0) + MRT2MC(m)->ReopenTimer = + now + MRT2MC(m)->ReopenTimerInterval; +- MRT2MC(m)->state = MRT_STATE_RUNNING; ++ m->state = MRT_STATE_RUNNING; + } +- if (MRT2MC(m)->state == MRT_STATE_REMOVE) { ++ if (m->state == MRT_STATE_REMOVE) { + LIST_REMOVE(m, entry); + free(m); + continue; +@@ -700,7 +657,7 @@ mrt_handler(struct mrt_head *mrt) + + now = time(NULL); + LIST_FOREACH(m, mrt, entry) { +- if (MRT2MC(m)->state == MRT_STATE_RUNNING && ++ if (m->state == MRT_STATE_RUNNING && + (MRT2MC(m)->ReopenTimerInterval != 0 || + m->type == MRT_TABLE_DUMP)) { + if (mrt_open(m, now) == -1) +@@ -719,8 +676,8 @@ mrt_get(struct mrt_head *c, struct mrt * + LIST_FOREACH(t, c, entry) { + if (t->type != m->type) + continue; +- if (t->type == MRT_TABLE_DUMP) +- return (t); ++ if (strcmp(t->rib, m->rib)) ++ continue; + if (t->peer_id == m->peer_id && + t->group_id == m->group_id) + return (t); +@@ -739,8 +696,7 @@ mrt_mergeconfig(struct mrt_head *xconf, + if ((xm = calloc(1, sizeof(struct mrt_config))) == NULL) + fatal("mrt_mergeconfig"); + memcpy(xm, m, sizeof(struct mrt_config)); +- xm->fd = -1; +- MRT2MC(xm)->state = MRT_STATE_OPEN; ++ xm->state = MRT_STATE_OPEN; + LIST_INSERT_HEAD(xconf, xm, entry); + } else { + /* MERGE */ +@@ -750,14 +706,14 @@ mrt_mergeconfig(struct mrt_head *xconf, + fatalx("mrt_mergeconfig: strlcpy"); + MRT2MC(xm)->ReopenTimerInterval = + MRT2MC(m)->ReopenTimerInterval; +- MRT2MC(xm)->state = MRT_STATE_REOPEN; ++ xm->state = MRT_STATE_REOPEN; + } + } + + LIST_FOREACH(xm, xconf, entry) + if (mrt_get(nconf, xm) == NULL) + /* REMOVE */ +- MRT2MC(xm)->state = MRT_STATE_REMOVE; ++ xm->state = MRT_STATE_REMOVE; + + /* free config */ + while ((m = LIST_FIRST(nconf)) != NULL) { +@@ -767,4 +723,3 @@ mrt_mergeconfig(struct mrt_head *xconf, + + return (0); + } +- diff --git a/net/openbgpd/files/patch-bgpd_mrt.h b/net/openbgpd/files/patch-bgpd_mrt.h new file mode 100644 index 00000000000..08240024971 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_mrt.h @@ -0,0 +1,208 @@ +Index: bgpd/mrt.h +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/mrt.h,v +retrieving revision 1.1.1.1 +retrieving revision 1.1.1.2 +diff -u -p -r1.1.1.1 -r1.1.1.2 +--- bgpd/mrt.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/mrt.h 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: mrt.h,v 1.16 2007/05/30 04:28:27 msf Exp $ */ ++/* $OpenBSD: mrt.h,v 1.23 2009/06/29 12:22:16 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> +@@ -20,12 +20,10 @@ + + #include "bgpd.h" + +-/* In cases of failure wait at least MRT_MIN_RETRY. */ +-#define MRT_MIN_RETRY 300 +- + /* +- * MRT binary packet format as used by zebra. ++ * MRT binary packet format + * For more info see: ++ * draft-ietf-grow-mrt-04.txt, "MRT routing information export format" + * http://www.quagga.net/docs/docs-multi/Packet-Binary-Dump-Format.html + */ + +@@ -38,24 +36,33 @@ + * +--------+--------+--------+--------+ + * | length | length of packet excluding this header + * +--------+--------+--------+--------+ ++ * ++ * ET types include an additional 32bit microsecond field comming after the ++ * length field. + */ + #define MRT_HEADER_SIZE 12 + + enum MRT_MSG_TYPES { +- MSG_NULL, ++ MSG_NULL, /* 0 empty msg (deprecated) */ + MSG_START, /* 1 sender is starting up */ +- MSG_DIE, /* 2 receiver should shut down */ ++ MSG_DIE, /* 2 receiver should shut down (deprecated) */ + MSG_I_AM_DEAD, /* 3 sender is shutting down */ +- MSG_PEER_DOWN, /* 4 sender's peer is down */ +- MSG_PROTOCOL_BGP, /* 5 msg is a BGP packet */ ++ MSG_PEER_DOWN, /* 4 sender's peer is down (deprecated) */ ++ MSG_PROTOCOL_BGP, /* 5 msg is a BGP packet (deprecated) */ + MSG_PROTOCOL_RIP, /* 6 msg is a RIP packet */ +- MSG_PROTOCOL_IDRP, /* 7 msg is an IDRP packet */ ++ MSG_PROTOCOL_IDRP, /* 7 msg is an IDRP packet (deprecated) */ + MSG_PROTOCOL_RIPNG, /* 8 msg is a RIPNG packet */ +- MSG_PROTOCOL_BGP4PLUS, /* 9 msg is a BGP4+ packet */ +- MSG_PROTOCOL_BGP4PLUS1, /* 10 msg is a BGP4+ (draft 01) packet */ ++ MSG_PROTOCOL_BGP4PLUS, /* 9 msg is a BGP4+ packet (deprecated) */ ++ MSG_PROTOCOL_BGP4PLUS1, /* 10 msg is a BGP4+ (draft 01) (deprecated) */ + MSG_PROTOCOL_OSPF, /* 11 msg is an OSPF packet */ + MSG_TABLE_DUMP, /* 12 routing table dump */ +- MSG_PROTOCOL_BGP4MP=16 /* 16 zebras own packet format */ ++ MSG_TABLE_DUMP_V2, /* 13 routing table dump */ ++ MSG_PROTOCOL_BGP4MP=16, /* 16 zebras own packet format */ ++ MSG_PROTOCOL_BGP4MP_ET=17, ++ MSG_PROTOCOL_ISIS=32, /* 32 msg is a ISIS package */ ++ MSG_PROTOCOL_ISIS_ET=33, ++ MSG_PROTOCOL_OSPFV3=48, /* 48 msg is a OSPFv3 package */ ++ MSG_PROTOCOL_OSPFV3_ET=49 + }; + + /* +@@ -64,15 +71,20 @@ enum MRT_MSG_TYPES { + * In most cases this is the format to choose to dump updates et al. + */ + enum MRT_BGP4MP_TYPES { +- BGP4MP_STATE_CHANGE=0, /* state change */ +- BGP4MP_MESSAGE=1, /* bgp message */ +- BGP4MP_ENTRY=2, /* table dumps */ +- BGP4MP_SNAPSHOT=3 ++ BGP4MP_STATE_CHANGE, /* state change */ ++ BGP4MP_MESSAGE, /* bgp message */ ++ BGP4MP_ENTRY, /* table dumps (deprecated) */ ++ BGP4MP_SNAPSHOT, /* file name for dump (deprecated) */ ++ BGP4MP_STATE_CHANGE_AS4, ++ BGP4MP_MESSAGE_AS4 /* same as BGP4MP_MESSAGE with 4byte AS */ + }; + + /* size of the BGP4MP headers without payload */ + #define MRT_BGP4MP_IPv4_HEADER_SIZE 16 + #define MRT_BGP4MP_IPv6_HEADER_SIZE 40 ++/* 4-byte AS variants of the previous */ ++#define MRT_BGP4MP_AS4_IPv4_HEADER_SIZE 20 ++#define MRT_BGP4MP_AS4_IPv6_HEADER_SIZE 44 + + /* If the type is PROTOCOL_BGP4MP and the subtype is either BGP4MP_STATE_CHANGE + * or BGP4MP_MESSAGE the message consists of a common header plus the payload. +@@ -110,6 +122,7 @@ enum MRT_BGP4MP_TYPES { + */ + #define MRT_BGP4MP_IPv4_ENTRY_SIZE 18 + #define MRT_BGP4MP_IPv6_ENTRY_SIZE 30 ++#define MRT_BGP4MP_MAX_PREFIXLEN 17 + /* + * The "new" table dump format consists of messages of type PROTOCOL_BGP4MP + * and subtype BGP4MP_ENTRY. +@@ -151,9 +164,9 @@ enum MRT_BGP4MP_TYPES { + * +--------+--------+--------+--------+ + * | prefix | + * +--------+--------+--------+--------+ +- * | plen | status | originated ++ * | plen | status | originated time + * +--------+--------+--------+--------+ +- * originated | peer_ip ++ * originated time | peer_ip + * +--------+--------+--------+--------+ + * peer_ip | peer_as | + * +--------+--------+--------+--------+ +@@ -166,8 +179,7 @@ enum MRT_BGP4MP_TYPES { + * + * + * View is normaly 0 and seqnum just a simple counter for this dump. +- * The status seems to be 1 by default but probably something to indicate +- * the status of a prefix would be more useful. ++ * The status field is unused and should be set to 1. + */ + + /* size of the dump header until attr_len */ +@@ -186,10 +198,14 @@ enum MRT_BGP_TYPES { + and announcements) */ + MSG_BGP_PREF_UPDATE, /* tlv preferences followed by raw update */ + MSG_BGP_STATE_CHANGE, /* state change */ +- MSG_BGP_SYNC ++ MSG_BGP_SYNC, /* file name for a table dump */ ++ MSG_BGP_OPEN, /* BGP open messages */ ++ MSG_BGP_NOTIFY, /* BGP notify messages */ ++ MSG_BGP_KEEPALIVE /* BGP keepalives */ + }; + +-/* if type MSG_PROTOCOL_BGP and subtype MSG_BGP_UPDATE ++/* if type MSG_PROTOCOL_BGP and subtype MSG_BGP_UPDATE, MSG_BGP_OPEN, ++ * MSG_BGP_NOTIFY or MSG_BGP_KEEPALIVE + * + * +--------+--------+--------+--------+ + * | source_as | source_ip +@@ -225,7 +241,7 @@ enum MRT_BGP_TYPES { + /* + * if type MSG_PROTOCOL_BGP and subtype MSG_BGP_SYNC OR + * if type MSG_PROTOCOL_BGP4MP and subtype BGP4MP_SNAPSHOT +- * What is this for? ++ * *DEPRECATED* + * + * +--------+--------+--------+--------+ + * | view | filename +@@ -255,22 +271,22 @@ enum mrt_state { + }; + + struct mrt { +- enum mrt_type type; ++ char rib[PEER_DESCR_LEN]; ++ struct msgbuf wbuf; ++ LIST_ENTRY(mrt) entry; + u_int32_t peer_id; + u_int32_t group_id; +- u_int32_t queued; +- int fd; +- TAILQ_HEAD(, buf) bufs; +- LIST_ENTRY(mrt) entry; ++ enum mrt_type type; ++ enum mrt_state state; ++ u_int16_t seqnum; + }; + + struct mrt_config { + struct mrt conf; +- time_t ReopenTimer; +- time_t ReopenTimerInterval; +- enum mrt_state state; + 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)) +@@ -278,16 +294,17 @@ struct mrt_config { + + struct peer; + struct prefix; +-struct pt_entry; ++struct rib_entry; + + /* prototypes */ +-int mrt_dump_bgp_msg(struct mrt *, void *, u_int16_t, +- struct peer *, struct bgpd_config *); +-int mrt_dump_state(struct mrt *, u_int16_t, u_int16_t, +- struct peer *, struct bgpd_config *); ++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 pt_entry *, void *); +-int mrt_write(struct mrt *); ++void mrt_dump_upcall(struct rib_entry *, void *); ++void mrt_dump_done(void *); ++void mrt_write(struct mrt *); + void mrt_clean(struct mrt *); + void mrt_init(struct imsgbuf *, struct imsgbuf *); + int mrt_timeout(struct mrt_head *); diff --git a/net/openbgpd/files/patch-bgpd_name2id.c b/net/openbgpd/files/patch-bgpd_name2id.c new file mode 100644 index 00000000000..7a3cea38348 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_name2id.c @@ -0,0 +1,14 @@ +Index: bgpd/name2id.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/name2id.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 +--- bgpd/name2id.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/name2id.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: name2id.c,v 1.7 2006/05/02 14:41:26 claudio Exp $ */ ++/* $OpenBSD: name2id.c,v 1.9 2009/06/04 04:46:42 claudio Exp $ */ + + /* + * Copyright (c) 2004, 2005 Henning Brauer <henning@openbsd.org> diff --git a/net/openbgpd/files/patch-bgpd_parse.y b/net/openbgpd/files/patch-bgpd_parse.y index 84b2d3ba0c0..d51dda7cc8b 100644 --- a/net/openbgpd/files/patch-bgpd_parse.y +++ b/net/openbgpd/files/patch-bgpd_parse.y @@ -2,11 +2,140 @@ Index: bgpd/parse.y =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/parse.y,v retrieving revision 1.1.1.1 -retrieving revision 1.2 -diff -u -p -r1.1.1.1 -r1.2 +retrieving revision 1.4 +diff -u -p -r1.1.1.1 -r1.4 --- bgpd/parse.y 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/parse.y 30 Jun 2009 06:40:07 -0000 1.2 -@@ -523,11 +523,16 @@ conf_main : AS as4number { ++++ bgpd/parse.y 9 Jul 2009 17:22:14 -0000 1.4 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: parse.y,v 1.217 2008/07/08 13:14:58 claudio Exp $ */ ++/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */ + + /* + * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -39,6 +39,7 @@ + #include "bgpd.h" + #include "mrt.h" + #include "session.h" ++#include "rde.h" + + TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); + static struct file { +@@ -110,7 +111,10 @@ struct filter_match_l { + struct peer *alloc_peer(void); + struct peer *new_peer(void); + struct peer *new_group(void); +-int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *); ++int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *, ++ char *); ++int add_rib(char *, u_int16_t); ++int 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 *); +@@ -155,10 +159,10 @@ typedef struct { + %} + + %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE RTABLE +-%token RDE EVALUATE IGNORE COMPARE ++%token RDE RIB EVALUATE IGNORE COMPARE + %token GROUP NEIGHBOR NETWORK +-%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART +-%token ANNOUNCE DEMOTE ++%token REMOTEAS DESCR LLIFACE LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART ++%token ANNOUNCE DEMOTE CONNECTRETRY + %token ENFORCE NEIGHBORAS CAPABILITIES REFLECTOR DEPEND DOWN SOFTRECONFIG + %token DUMP IN OUT + %token LOG ROUTECOLL TRANSPARENT +@@ -178,7 +182,7 @@ typedef struct { + %token <v.number> NUMBER + %type <v.number> asnumber as4number optnumber yesno inout + %type <v.number> espah family restart +-%type <v.string> string ++%type <v.string> string filter_rib + %type <v.addr> address + %type <v.prefix> prefix addrspec + %type <v.u8> action quick direction delete +@@ -207,8 +211,8 @@ grammar : /* empty */ + ; + + asnumber : NUMBER { +- if ($1 < 0 || $1 >= USHRT_MAX) { +- yyerror("AS too big: max %u", USHRT_MAX - 1); ++ if ($1 < 0 || $1 >= ASNUM_MAX) { ++ yyerror("AS too big: max %u", ASNUM_MAX - 1); + YYERROR; + } + } +@@ -381,6 +385,24 @@ conf_main : AS as4number { + else + conf->flags &= ~BGPD_FLAG_NO_EVALUATE; + } ++ | RDE RIB STRING { ++ if (add_rib($3, F_RIB_NOFIB)) { ++ free($3); ++ YYERROR; ++ } ++ free($3); ++ } ++ | RDE RIB STRING yesno EVALUATE { ++ if ($4) { ++ free($3); ++ YYERROR; ++ } ++ if (!add_rib($3, F_RIB_NOEVALUATE)) { ++ free($3); ++ YYERROR; ++ } ++ free($3); ++ } + | TRANSPARENT yesno { + if ($2 == 1) + conf->flags |= BGPD_FLAG_DECISION_TRANS_AS; +@@ -469,12 +491,42 @@ conf_main : AS as4number { + YYERROR; + } + free($2); +- if (add_mrtconfig(action, $3, $4, NULL) == -1) { ++ if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) { + free($3); + YYERROR; + } + free($3); + } ++ | DUMP RIB STRING STRING STRING optnumber { ++ int action; ++ ++ if ($6 < 0 || $6 > UINT_MAX) { ++ yyerror("bad timeout"); ++ free($3); ++ free($4); ++ free($5); ++ YYERROR; ++ } ++ if (!strcmp($4, "table")) ++ action = MRT_TABLE_DUMP; ++ else if (!strcmp($4, "table-mp")) ++ action = MRT_TABLE_DUMP_MP; ++ else { ++ yyerror("unknown mrt dump type"); ++ free($3); ++ free($4); ++ free($5); ++ YYERROR; ++ } ++ free($4); ++ if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) { ++ free($3); ++ free($5); ++ YYERROR; ++ } ++ free($3); ++ free($5); ++ } + | mrtdump + | RDE STRING EVALUATE { + if (!strcmp($2, "route-age")) +@@ -523,11 +575,23 @@ conf_main : AS as4number { free($4); } | RTABLE NUMBER { @@ -20,6 +149,314 @@ diff -u -p -r1.1.1.1 -r1.2 } conf->rtableid = $2; +#endif /* defined(__FreeBSD__) */ ++ } ++ | CONNECTRETRY NUMBER { ++ if ($2 > USHRT_MAX || $2 < 1) { ++ yyerror("invalid connect-retry"); ++ YYERROR; ++ } ++ conf->connectretry = $2; + } + ; + +@@ -550,7 +614,8 @@ mrtdump : DUMP STRING inout STRING optn + free($4); + YYERROR; + } +- if (add_mrtconfig(action, $4, $5, curpeer) == -1) { ++ if (add_mrtconfig(action, $4, $5, curpeer, NULL) == ++ -1) { + free($2); + free($4); + YYERROR; +@@ -742,6 +807,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)); +@@ -759,6 +835,22 @@ peeropts : REMOTEAS as4number { + | DOWN { + curpeer->conf.down = 1; } ++ | RIB STRING { ++ if (!find_rib($2)) { ++ yyerror("rib \"%s\" does not exist.", $2); ++ free($2); ++ YYERROR; ++ } ++ if (strlcpy(curpeer->conf.rib, $2, ++ sizeof(curpeer->conf.rib)) >= ++ sizeof(curpeer->conf.rib)) { ++ yyerror("rib name \"%s\" too long: max %u", ++ $2, sizeof(curpeer->conf.rib) - 1); ++ free($2); ++ YYERROR; ++ } ++ free($2); ++ } + | HOLDTIME NUMBER { + if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) { + yyerror("holdtime must be between %u and %u", +@@ -1058,6 +1150,12 @@ peeropts : REMOTEAS as4number { + else + curpeer->conf.softreconfig_out = $3; + } ++ | TRANSPARENT yesno { ++ if ($2 == 1) ++ curpeer->conf.flags |= PEERFLAG_TRANS_AS; ++ else ++ curpeer->conf.flags &= ~PEERFLAG_TRANS_AS; ++ } ; + restart : /* nada */ { $$ = 0; } +@@ -1115,16 +1213,37 @@ encspec : /* nada */ { + } + ; + +-filterrule : action quick direction filter_peer_h filter_match_h filter_set ++filterrule : action quick filter_rib direction filter_peer_h filter_match_h filter_set + { + struct filter_rule r; + + bzero(&r, sizeof(r)); + r.action = $1; + r.quick = $2; +- r.dir = $3; +- +- if (expand_rule(&r, $4, &$5, $6) == -1) ++ r.dir = $4; ++ if ($3) { ++ if (r.dir != DIR_IN) { ++ yyerror("rib only allowed on \"from\" " ++ "rules."); ++ free($3); ++ YYERROR; ++ } ++ if (!find_rib($3)) { ++ yyerror("rib \"%s\" does not exist.", ++ $3); ++ free($3); ++ YYERROR; ++ } ++ if (strlcpy(r.rib, $3, sizeof(r.rib)) >= ++ sizeof(r.rib)) { ++ yyerror("rib name \"%s\" too long: " ++ "max %u", $3, sizeof(r.rib) - 1); ++ free($3); ++ YYERROR; ++ } ++ free($3); ++ } ++ if (expand_rule(&r, $5, &$6, $7) == -1) + YYERROR; + } + ; +@@ -1142,6 +1261,9 @@ direction : FROM { $$ = DIR_IN; } + | TO { $$ = DIR_OUT; } + ; + ++filter_rib : /* empty */ { $$ = NULL; } ++ | RIB STRING { $$ = $2; } ++ + filter_peer_h : filter_peer + | '{' filter_peer_l '}' { $$ = $2; } + ; +@@ -1396,7 +1518,7 @@ prefixlenop : unaryop NUMBER { + YYERROR; + } + if ($1 >= $3) { +- yyerror("start prefixlen is bigger that end"); ++ yyerror("start prefixlen is bigger than end"); + YYERROR; + } + $$.op = $2; +@@ -1771,6 +1893,7 @@ lookup(char *s) + { "capabilities", CAPABILITIES}, + { "community", COMMUNITY}, + { "compare", COMPARE}, ++ { "connect-retry", CONNECTRETRY}, + { "connected", CONNECTED}, + { "delete", DELETE}, + { "demote", DEMOTE}, +@@ -1792,6 +1915,9 @@ lookup(char *s) + { "include", INCLUDE}, + { "inet", IPV4}, + { "inet6", IPV6}, ++#if defined(IPV6_LINKLOCAL_PEER) ++ { "interface", LLIFACE}, ++#endif + { "ipsec", IPSEC}, + { "key", KEY}, + { "listen", LISTEN}, +@@ -1826,6 +1952,7 @@ lookup(char *s) + { "reject", REJECT}, + { "remote-as", REMOTEAS}, + { "restart", RESTART}, ++ { "rib", RIB}, + { "route-collector", ROUTECOLL}, + { "route-reflector", REFLECTOR}, + { "router-id", ROUTERID}, +@@ -1933,11 +2060,13 @@ findeol(void) + int c; + + parsebuf = NULL; +- pushback_index = 0; + + /* skip to either EOF or the first real EOL */ + while (1) { +- c = lgetc(0); ++ if (pushback_index) ++ c = pushback_buffer[--pushback_index]; ++ else ++ c = lgetc(0); + if (c == '\n') { + file->lineno++; + break; +@@ -2118,9 +2247,13 @@ pushfile(const char *name, int secret) + { + struct file *nfile; + +- if ((nfile = calloc(1, sizeof(struct file))) == NULL || +- (nfile->name = strdup(name)) == NULL) { ++ if ((nfile = calloc(1, sizeof(struct file))) == NULL) { ++ log_warn("malloc"); ++ return (NULL); ++ } ++ if ((nfile->name = strdup(name)) == NULL) { + log_warn("malloc"); ++ free(nfile); + return (NULL); + } + if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { +@@ -2207,6 +2340,9 @@ parse_config(char *filename, struct bgpd + /* init the empty filter list for later */ + TAILQ_INIT(xfilter_l); + ++ add_rib("Adj-RIB-In", F_RIB_NOEVALUATE); ++ add_rib("Loc-RIB", 0); ++ + yyparse(); + errors = file->errors; + popfile(); +@@ -2452,6 +2588,8 @@ alloc_peer(void) + p->conf.capabilities.refresh = 1; + p->conf.capabilities.restart = 0; + p->conf.capabilities.as4byte = 0; ++ p->conf.local_as = conf->as; ++ p->conf.local_short_as = conf->short_as; + p->conf.softreconfig_in = 1; + p->conf.softreconfig_out = 1; + +@@ -2473,10 +2611,16 @@ 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; + } + p->next = NULL; +- ++ if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) ++ p->conf.flags |= PEERFLAG_TRANS_AS; + return (p); + } + +@@ -2487,11 +2631,15 @@ new_group(void) + } + + int +-add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p) ++add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p, ++ char *rib) + { + struct mrt *m, *n; + + LIST_FOREACH(m, mrtconf, entry) { ++ if ((rib && strcmp(rib, m->rib)) || ++ (!rib && *m->rib)) ++ continue; + if (p == NULL) { + if (m->peer_id != 0 || m->group_id != 0) + continue; +@@ -2527,6 +2675,20 @@ add_mrtconfig(enum mrt_type type, char * + n->group_id = 0; + } + } ++ if (rib) { ++ if (!find_rib(rib)) { ++ yyerror("rib \"%s\" does not exist.", rib); ++ free(n); ++ return (-1); ++ } ++ if (strlcpy(n->rib, rib, sizeof(n->rib)) >= ++ sizeof(n->rib)) { ++ yyerror("rib name \"%s\" too long: max %u", ++ name, sizeof(n->rib) - 1); ++ free(n); ++ return (-1); ++ } ++ } + + LIST_INSERT_HEAD(mrtconf, n, entry); + +@@ -2534,6 +2696,42 @@ add_mrtconfig(enum mrt_type type, char * + } + + int ++add_rib(char *name, u_int16_t flags) ++{ ++ struct rde_rib *rr; ++ ++ 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 (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) { ++ yyerror("rib name \"%s\" too long: max %u", ++ name, sizeof(rr->name) - 1); ++ return (-1); ++ } ++ rr->flags |= flags; ++ SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry); ++ return (0); ++} ++ ++int ++find_rib(char *name) ++{ ++ struct rde_rib *rr; ++ ++ SIMPLEQ_FOREACH(rr, &ribnames, entry) { ++ if (!strcmp(rr->name, name)) ++ return (1); ++ } ++ return (0); ++} ++ ++int + get_id(struct peer *newpeer) + { + struct peer *p; diff --git a/net/openbgpd/files/patch-bgpd_pfkey.c b/net/openbgpd/files/patch-bgpd_pfkey.c new file mode 100644 index 00000000000..1c57da3b9d0 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_pfkey.c @@ -0,0 +1,81 @@ +Index: bgpd/pfkey.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/pfkey.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 +--- bgpd/pfkey.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/pfkey.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: pfkey.c,v 1.34 2006/10/26 14:26:49 henning Exp $ */ ++/* $OpenBSD: pfkey.c,v 1.37 2009/04/21 15:25:52 henning Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -36,7 +36,8 @@ + #define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1)) + #define IOV_CNT 20 + +-static u_int32_t sadb_msg_seq = 1; ++static u_int32_t sadb_msg_seq = 0; ++static u_int32_t pid = 0; /* should pid_t but pfkey needs u_int32_t */ + static int fd; + + int pfkey_reply(int, u_int32_t *); +@@ -74,6 +75,9 @@ pfkey_send(int sd, uint8_t satype, uint8 + int iov_cnt; + struct sockaddr_storage ssrc, sdst, speer, smask, dmask; + ++ if (!pid) ++ pid = getpid(); ++ + /* we need clean sockaddr... no ports set */ + bzero(&ssrc, sizeof(ssrc)); + bzero(&smask, sizeof(smask)); +@@ -129,8 +133,8 @@ pfkey_send(int sd, uint8_t satype, uint8 + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; +- smsg.sadb_msg_seq = sadb_msg_seq++; +- smsg.sadb_msg_pid = getpid(); ++ smsg.sadb_msg_seq = ++sadb_msg_seq; ++ smsg.sadb_msg_pid = pid; + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = mtype; + smsg.sadb_msg_satype = satype; +@@ -415,10 +419,23 @@ pfkey_reply(int sd, u_int32_t *spip) + u_int8_t *data; + ssize_t len; + +- if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { +- log_warn("pfkey peek"); +- return (-1); ++ for (;;) { ++ if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { ++ log_warn("pfkey peek"); ++ return (-1); ++ } ++ ++ if (hdr.sadb_msg_seq == sadb_msg_seq && ++ hdr.sadb_msg_pid == pid) ++ break; ++ ++ /* not ours, discard */ ++ if (read(sd, &hdr, sizeof(hdr)) == -1) { ++ log_warn("pfkey read"); ++ return (-1); ++ } + } ++ + if (hdr.sadb_msg_errno != 0) { + errno = hdr.sadb_msg_errno; + if (errno == ESRCH) +@@ -497,6 +514,8 @@ pfkey_sa_remove(struct bgpd_addr *src, s + int + pfkey_md5sig_establish(struct peer *p) + { ++ sleep(1); ++ + if (!p->auth.spi_out) + if (pfkey_sa_add(&p->auth.local_addr, &p->conf.remote_addr, + p->conf.auth.md5key_len, p->conf.auth.md5key, diff --git a/net/openbgpd/files/patch-bgpd_printconf.c b/net/openbgpd/files/patch-bgpd_printconf.c index c511f3fd450..a341234905a 100644 --- a/net/openbgpd/files/patch-bgpd_printconf.c +++ b/net/openbgpd/files/patch-bgpd_printconf.c @@ -2,11 +2,17 @@ Index: bgpd/printconf.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/printconf.c,v retrieving revision 1.1.1.1 -retrieving revision 1.2 -diff -u -p -r1.1.1.1 -r1.2 +retrieving revision 1.4 +diff -u -p -r1.1.1.1 -r1.4 --- bgpd/printconf.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/printconf.c 30 Jun 2009 06:40:07 -0000 1.2 -@@ -19,6 +19,9 @@ ++++ bgpd/printconf.c 9 Jul 2009 17:22:14 -0000 1.4 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: printconf.c,v 1.65 2007/11/22 11:37:25 henning Exp $ */ ++/* $OpenBSD: printconf.c,v 1.70 2009/06/06 01:10:29 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -19,10 +19,14 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -16,3 +22,110 @@ diff -u -p -r1.1.1.1 -r1.2 #include "bgpd.h" #include "mrt.h" + #include "session.h" ++#include "rde.h" + + void print_op(enum comp_ops); + void print_community(int, int); +@@ -185,6 +189,8 @@ print_mainconf(struct bgpd_config *conf) + printf("holdtime %u\n", conf->holdtime); + if (conf->min_holdtime) + printf("holdtime min %u\n", conf->min_holdtime); ++ if (conf->connectretry) ++ printf("connect-retry %u\n", conf->connectretry); + + if (conf->flags & BGPD_FLAG_NO_FIB_UPDATE) + printf("fib-update no\n"); +@@ -200,9 +206,6 @@ print_mainconf(struct bgpd_config *conf) + if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS) + printf("rde med compare always\n"); + +- if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) +- printf("transparent-as yes\n"); +- + if (conf->log & BGPD_LOG_UPDATES) + printf("log updates\n"); + +@@ -271,6 +274,8 @@ print_peer(struct peer_config *p, struct + printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr)); + if (p->descr[0]) + printf("%s\tdescr \"%s\"\n", c, p->descr); ++ if (p->rib[0]) ++ printf("%s\trib \"%s\"\n", c, p->rib); + if (p->remote_as) + printf("%s\tremote-as %s\n", c, log_as(p->remote_as)); + if (p->down) +@@ -320,6 +325,12 @@ print_peer(struct peer_config *p, struct + printf("%s\tdemote %s\n", c, p->demote_group); + if (p->if_depend[0]) + 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); +@@ -419,10 +430,12 @@ print_rule(struct peer *peer_l, struct f + printf("deny "); + else + printf("match "); +- + if (r->quick) + printf("quick "); + ++ if (r->rib[0]) ++ printf("rib %s ", r->rib); ++ + if (r->dir == DIR_IN) + printf("from "); + else if (r->dir == DIR_OUT) +@@ -532,12 +545,14 @@ print_mrt(u_int32_t pid, u_int32_t gid, + LIST_FOREACH(m, xmrt_l, entry) + if ((gid != 0 && m->group_id == gid) || + (m->peer_id == pid && m->group_id == gid)) { ++ printf("%s%sdump ", prep, prep2); ++ if (m->rib[0]) ++ printf("rib %s ", m->rib); + if (MRT2MC(m)->ReopenTimerInterval == 0) +- printf("%s%sdump %s %s\n", prep, prep2, +- mrt_type(m->type), MRT2MC(m)->name); ++ printf("%s %s\n", mrt_type(m->type), ++ MRT2MC(m)->name); + else +- printf("%s%sdump %s %s %d\n", prep, prep2, +- mrt_type(m->type), ++ printf("%s %s %d\n", mrt_type(m->type), + MRT2MC(m)->name, + MRT2MC(m)->ReopenTimerInterval); + } +@@ -602,16 +617,25 @@ peer_compare(const void *aa, const void + } + + void +-print_config(struct bgpd_config *conf, struct network_head *net_l, +- struct peer *peer_l, struct filter_head *rules_l, struct mrt_head *mrt_l) ++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_rule *r; + struct network *n; ++ struct rde_rib *rr; + + xmrt_l = mrt_l; + printf("\n"); + print_mainconf(conf); + printf("\n"); ++ SIMPLEQ_FOREACH(rr, rib_l, entry) { ++ if (rr->flags & F_RIB_NOEVALUATE) ++ printf("rde rib %s no evaluate\n", rr->name); ++ else ++ printf("rde rib %s\n", rr->name); ++ } ++ printf("\n"); + TAILQ_FOREACH(n, net_l, entry) + print_network(&n->net); + printf("\n"); diff --git a/net/openbgpd/files/patch-bgpd_rde.c b/net/openbgpd/files/patch-bgpd_rde.c new file mode 100644 index 00000000000..2575431261c --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_rde.c @@ -0,0 +1,1572 @@ +Index: bgpd/rde.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v +retrieving revision 1.1.1.1 +retrieving revision 1.4 +diff -u -p -r1.1.1.1 -r1.4 +--- bgpd/rde.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/rde.c 9 Jul 2009 17:26:41 -0000 1.4 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde.c,v 1.232.2.1 2009/01/30 22:37:34 claudio Exp $ */ ++/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -38,24 +38,28 @@ + #define PFD_PIPE_MAIN 0 + #define PFD_PIPE_SESSION 1 + #define PFD_PIPE_SESSION_CTL 2 +-#define PFD_MRT_FILE 3 ++#define PFD_PIPE_COUNT 3 + + void rde_sighdlr(int); + void rde_dispatch_imsg_session(struct imsgbuf *); + void rde_dispatch_imsg_parent(struct imsgbuf *); + int rde_update_dispatch(struct imsg *); ++void rde_update_update(struct rde_peer *, struct rde_aspath *, ++ struct bgpd_addr *, u_int8_t); ++void rde_update_withdraw(struct rde_peer *, struct bgpd_addr *, ++ u_int8_t); + int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *, + struct rde_aspath *, struct mpattr *); + u_int8_t rde_attr_missing(struct rde_aspath *, int, u_int16_t); + int rde_get_mp_nexthop(u_char *, u_int16_t, u_int16_t, +- struct rde_aspath *); ++ struct rde_aspath *, struct rde_peer *); + 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 *); + void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t, + void *, u_int16_t); +-void rde_update_log(const char *, ++void rde_update_log(const char *, u_int16_t, + const struct rde_peer *, const struct bgpd_addr *, + const struct bgpd_addr *, u_int8_t); + void rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *); +@@ -67,19 +71,16 @@ void rde_dump_filter(struct prefix *, + struct ctl_show_rib_request *); + void rde_dump_filterout(struct rde_peer *, struct prefix *, + struct ctl_show_rib_request *); +-void rde_dump_upcall(struct pt_entry *, void *); +-void rde_dump_as(struct ctl_show_rib_request *); +-void rde_dump_prefix_upcall(struct pt_entry *, void *); +-void rde_dump_prefix(struct ctl_show_rib_request *); +-void rde_dump_community(struct ctl_show_rib_request *); ++void rde_dump_upcall(struct rib_entry *, void *); ++void rde_dump_prefix_upcall(struct rib_entry *, void *); + void rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t, + enum imsg_type); +-void rde_dump_runner(void); +-int rde_dump_pending(void); ++void rde_dump_mrt_new(struct mrt *, pid_t, int); ++void rde_dump_done(void *); + +-void rde_up_dump_upcall(struct pt_entry *, void *); +-void rde_softreconfig_out(struct pt_entry *, void *); +-void rde_softreconfig_in(struct pt_entry *, void *); ++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_update_queue_runner(void); + void rde_update6_queue_runner(void); + +@@ -96,8 +97,7 @@ void peer_send_eor(struct rde_peer *, + 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 pt_entry *, void *); +-void network_flush(int); ++void network_dump_upcall(struct rib_entry *, void *); + + void rde_shutdown(void); + int sa_cmp(struct bgpd_addr *, struct sockaddr *); +@@ -106,23 +106,26 @@ volatile sig_atomic_t rde_quit = 0; + struct bgpd_config *conf, *nconf; + time_t reloadtime; + struct rde_peer_head peerlist; +-struct rde_peer peerself; +-struct rde_peer peerdynamic; ++struct rde_peer *peerself; + struct filter_head *rules_l, *newrules; + struct imsgbuf *ibuf_se; + struct imsgbuf *ibuf_se_ctl; + struct imsgbuf *ibuf_main; +-struct mrt *mrt; + struct rde_memstats rdemem; + + struct rde_dump_ctx { +- TAILQ_ENTRY(rde_dump_ctx) entry; +- struct pt_context ptc; ++ struct rib_context ribctx; + struct ctl_show_rib_request req; + sa_family_t af; + }; + +-TAILQ_HEAD(, rde_dump_ctx) rde_dump_h = TAILQ_HEAD_INITIALIZER(rde_dump_h); ++struct rde_mrt_ctx { ++ struct mrt mrt; ++ struct rib_context ribctx; ++}; ++ ++struct mrt_head rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts); ++u_int rde_mrt_cnt; + + void + rde_sighdlr(int sig) +@@ -143,18 +146,22 @@ 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, int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], +- int pipe_s2rctl[2], int debug) ++ 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) + { + pid_t pid; + struct passwd *pw; + struct peer *p; + struct listen_addr *la; +- struct pollfd pfd[4]; ++ struct pollfd *pfd = NULL; + struct filter_rule *f; + struct filter_set *set; + struct nexthop *nh; +- int i, timeout; ++ struct rde_rib *rr; ++ struct mrt *mrt, *xmrt; ++ void *newp; ++ u_int pfd_elms = 0, i, j; ++ int timeout; + + switch (pid = fork()) { + case -1: +@@ -213,7 +220,6 @@ rde_main(struct bgpd_config *config, str + LIST_REMOVE(mrt, entry); + free(mrt); + } +- mrt = NULL; + + while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) { + TAILQ_REMOVE(config->listen_addrs, la, entry); +@@ -223,6 +229,11 @@ rde_main(struct bgpd_config *config, str + 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); +@@ -234,6 +245,7 @@ rde_main(struct bgpd_config *config, str + 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); +@@ -243,8 +255,20 @@ rde_main(struct bgpd_config *config, str + } + + while (rde_quit == 0) { ++ if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) { ++ if ((newp = realloc(pfd, sizeof(struct pollfd) * ++ (PFD_PIPE_COUNT + rde_mrt_cnt))) == NULL) { ++ /* panic for now */ ++ log_warn("could not resize pfd from %u -> %u" ++ " entries", pfd_elms, PFD_PIPE_COUNT + ++ rde_mrt_cnt); ++ fatalx("exiting"); ++ } ++ pfd = newp; ++ pfd_elms = PFD_PIPE_COUNT + rde_mrt_cnt; ++ } + timeout = INFTIM; +- bzero(pfd, sizeof(pfd)); ++ bzero(pfd, sizeof(struct pollfd) * pfd_elms); + pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd; + pfd[PFD_PIPE_MAIN].events = POLLIN; + if (ibuf_main->w.queued > 0) +@@ -259,14 +283,16 @@ rde_main(struct bgpd_config *config, str + pfd[PFD_PIPE_SESSION_CTL].events = POLLIN; + if (ibuf_se_ctl->w.queued > 0) + pfd[PFD_PIPE_SESSION_CTL].events |= POLLOUT; +- else if (rde_dump_pending()) ++ else if (rib_dump_pending()) + timeout = 0; + +- i = 3; +- if (mrt && mrt->queued) { +- pfd[PFD_MRT_FILE].fd = mrt->fd; +- pfd[PFD_MRT_FILE].events = POLLOUT; +- i++; ++ i = PFD_PIPE_COUNT; ++ LIST_FOREACH(mrt, &rde_mrts, entry) { ++ if (mrt->wbuf.queued) { ++ pfd[i].fd = mrt->wbuf.fd; ++ pfd[i].events = POLLOUT; ++ i++; ++ } + } + + if (poll(pfd, i, timeout) == -1) { +@@ -299,24 +325,39 @@ rde_main(struct bgpd_config *config, str + if (pfd[PFD_PIPE_SESSION_CTL].revents & POLLIN) + rde_dispatch_imsg_session(ibuf_se_ctl); + +- if (pfd[PFD_MRT_FILE].revents & POLLOUT) { +- if (mrt_write(mrt) == -1) { ++ 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 && ++ 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); +- mrt = NULL; +- } else if (mrt->queued == 0) +- close(mrt->fd); ++ rde_mrt_cnt--; ++ } ++ mrt = xmrt; + } + + rde_update_queue_runner(); + rde_update6_queue_runner(); + if (ibuf_se_ctl->w.queued <= 0) +- rde_dump_runner(); ++ rib_dump_runner(); + } + + /* do not clean up on shutdown on production, it takes ages. */ + 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); ++ } ++ + msgbuf_clear(&ibuf_se->w); + free(ibuf_se); + msgbuf_clear(&ibuf_se_ctl->w); +@@ -344,7 +385,6 @@ rde_dispatch_imsg_session(struct imsgbuf + struct filter_set *s; + struct nexthop *nh; + int n; +- sa_family_t af = AF_UNSPEC; + + if ((n = imsg_read(ibuf)) == -1) + fatal("rde_dispatch_imsg_session: imsg_read error"); +@@ -438,7 +478,8 @@ badnet: + log_warnx("rde_dispatch: wrong imsg len"); + break; + } +- network_flush(0); ++ prefix_network_clean(peerself, time(NULL), ++ F_ANN_DYNAMIC); + break; + case IMSG_FILTER_SET: + if (imsg.hdr.len - IMSG_HEADER_SIZE != +@@ -462,54 +503,16 @@ badnet: + } + break; + case IMSG_CTL_SHOW_NETWORK: +- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(af)) { +- log_warnx("rde_dispatch: wrong imsg len"); +- break; +- } +- bzero(&req, sizeof(req)); +- memcpy(&req.af, imsg.data, sizeof(af)); +- rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); +- break; + case IMSG_CTL_SHOW_RIB: +- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { +- log_warnx("rde_dispatch: wrong imsg len"); +- break; +- } +- memcpy(&req, imsg.data, sizeof(req)); +- rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); +- break; + case IMSG_CTL_SHOW_RIB_AS: +- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { +- log_warnx("rde_dispatch: wrong imsg len"); +- break; +- } +- memcpy(&req, imsg.data, sizeof(req)); +- req.pid = imsg.hdr.pid; +- rde_dump_as(&req); +- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, +- NULL, 0); +- break; +- case IMSG_CTL_SHOW_RIB_PREFIX: +- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { +- log_warnx("rde_dispatch: wrong imsg len"); +- break; +- } +- memcpy(&req, imsg.data, sizeof(req)); +- req.pid = imsg.hdr.pid; +- rde_dump_prefix(&req); +- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, +- NULL, 0); +- break; + case IMSG_CTL_SHOW_RIB_COMMUNITY: ++ case IMSG_CTL_SHOW_RIB_PREFIX: + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { + log_warnx("rde_dispatch: wrong imsg len"); + break; + } + memcpy(&req, imsg.data, sizeof(req)); +- req.pid = imsg.hdr.pid; +- rde_dump_community(&req); +- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, +- NULL, 0); ++ rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); + break; + case IMSG_CTL_SHOW_NEIGHBOR: + if (imsg.hdr.len - IMSG_HEADER_SIZE != +@@ -552,12 +555,14 @@ void + rde_dispatch_imsg_parent(struct imsgbuf *ibuf) + { + struct imsg imsg; ++ struct mrt xmrt; ++ struct rde_rib rn; + struct rde_peer *peer; + struct filter_rule *r; + struct filter_set *s; +- struct mrt *xmrt; + struct nexthop *nh; +- int n, reconf_in = 0, reconf_out = 0; ++ int n, fd, reconf_in = 0, reconf_out = 0; ++ u_int16_t rid; + + if ((n = imsg_read(ibuf)) == -1) + fatal("rde_dispatch_imsg_parent: imsg_read error"); +@@ -581,6 +586,8 @@ rde_dispatch_imsg_parent(struct imsgbuf + 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: + memcpy(&netconf_p, imsg.data, sizeof(netconf_p)); +@@ -601,6 +608,17 @@ rde_dispatch_imsg_parent(struct imsgbuf + TAILQ_INIT(&netconf_p.attrset); + network_delete(&netconf_p, 1); + break; ++ case IMSG_RECONF_RIB: ++ if (imsg.hdr.len - IMSG_HEADER_SIZE != ++ sizeof(struct rde_rib)) ++ fatalx("IMSG_RECONF_RIB bad len"); ++ 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; ++ break; + case IMSG_RECONF_FILTER: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct filter_rule)) +@@ -609,6 +627,7 @@ rde_dispatch_imsg_parent(struct imsgbuf + fatal(NULL); + memcpy(r, imsg.data, sizeof(struct filter_rule)); + TAILQ_INIT(&r->set); ++ r->peer.ribid = rib_find(r->rib); + parent_set = &r->set; + TAILQ_INSERT_TAIL(newrules, r, entry); + break; +@@ -628,10 +647,12 @@ rde_dispatch_imsg_parent(struct imsgbuf + free(nconf); + nconf = NULL; + parent_set = NULL; +- prefix_network_clean(&peerself, reloadtime); ++ prefix_network_clean(peerself, reloadtime, 0); + + /* check if filter changed */ + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; + peer->reconf_out = 0; + peer->reconf_in = 0; + if (peer->conf.softreconfig_out && +@@ -647,12 +668,18 @@ rde_dispatch_imsg_parent(struct imsgbuf + reconf_in = 1; + } + } ++ /* XXX this needs rework anyway */ + /* sync local-RIB first */ + if (reconf_in) +- pt_dump(rde_softreconfig_in, NULL, AF_UNSPEC); ++ rib_dump(&ribs[0], rde_softreconfig_in, NULL, ++ AF_UNSPEC); + /* then sync peers */ +- if (reconf_out) +- pt_dump(rde_softreconfig_out, NULL, AF_UNSPEC); ++ if (reconf_out) { ++ int i; ++ for (i = 1; i < rib_size; i++) ++ rib_dump(&ribs[i], rde_softreconfig_out, ++ NULL, AF_UNSPEC); ++ } + + while ((r = TAILQ_FIRST(rules_l)) != NULL) { + TAILQ_REMOVE(rules_l, r, entry); +@@ -661,6 +688,10 @@ 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"); + break; + case IMSG_NEXTHOP_UPDATE: +@@ -689,30 +720,15 @@ rde_dispatch_imsg_parent(struct imsgbuf + log_warnx("wrong imsg len"); + break; + } +- +- xmrt = calloc(1, sizeof(struct mrt)); +- if (xmrt == NULL) +- fatal("rde_dispatch_imsg_parent"); +- memcpy(xmrt, imsg.data, sizeof(struct mrt)); +- TAILQ_INIT(&xmrt->bufs); +- +- if ((xmrt->fd = imsg_get_fd(ibuf)) == -1) ++ memcpy(&xmrt, imsg.data, sizeof(xmrt)); ++ if ((fd = imsg.fd) == -1) + log_warnx("expected to receive fd for mrt dump " + "but didn't receive any"); +- +- if (xmrt->type == MRT_TABLE_DUMP) { +- /* do not dump if another is still running */ +- if (mrt == NULL || mrt->queued == 0) { +- free(mrt); +- mrt = xmrt; +- mrt_clear_seq(); +- pt_dump(mrt_dump_upcall, mrt, +- AF_UNSPEC); +- break; +- } +- } +- close(xmrt->fd); +- free(xmrt); ++ else if (xmrt.type == MRT_TABLE_DUMP || ++ xmrt.type == MRT_TABLE_DUMP_MP) { ++ rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd); ++ } else ++ close(fd); + break; + case IMSG_MRT_CLOSE: + /* ignore end message because a dump is atomic */ +@@ -729,7 +745,7 @@ int + rde_update_dispatch(struct imsg *imsg) + { + struct rde_peer *peer; +- struct rde_aspath *asp = NULL, *fasp; ++ struct rde_aspath *asp = NULL; + u_char *p, *mpp = NULL; + int error = -1, pos = 0; + u_int16_t afi, len, mplen; +@@ -795,7 +811,7 @@ rde_update_dispatch(struct imsg *imsg) + } + + /* +- * if either ATTR_NEW_AGGREGATOR or ATTR_NEW_ASPATH is present ++ * 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. + */ +@@ -808,6 +824,8 @@ rde_update_dispatch(struct imsg *imsg) + 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, + NULL, 0); + goto done; +@@ -850,14 +868,19 @@ rde_update_dispatch(struct imsg *imsg) + goto done; + } + +- peer->prefix_rcvd_withdraw++; +- rde_update_log("withdraw", peer, NULL, &prefix, prefixlen); +- prefix_remove(peer, &prefix, prefixlen, F_LOCAL); +- prefix_remove(peer, &prefix, prefixlen, F_ORIGINAL); ++ rde_update_withdraw(peer, &prefix, prefixlen); + } + +- if (attrpath_len == 0) /* 0 = no NLRI information in this message */ ++ if (attrpath_len == 0) { ++ /* 0 = no NLRI information in this message */ ++ if (nlri_len != 0) { ++ /* crap at end of update which should not be there */ ++ rde_update_err(peer, ERR_UPDATE, ++ ERR_UPD_ATTRLIST, NULL, 0); ++ return (-1); ++ } + return (0); ++ } + + /* withdraw MP_UNREACH_NLRI if available */ + if (mpa.unreach_len != 0) { +@@ -900,13 +923,7 @@ rde_update_dispatch(struct imsg *imsg) + mpp += pos; + mplen -= pos; + +- peer->prefix_rcvd_withdraw++; +- rde_update_log("withdraw", peer, NULL, +- &prefix, prefixlen); +- prefix_remove(peer, &prefix, prefixlen, +- F_LOCAL); +- prefix_remove(peer, &prefix, prefixlen, +- F_ORIGINAL); ++ rde_update_withdraw(peer, &prefix, prefixlen); + } + break; + default: +@@ -954,17 +971,7 @@ rde_update_dispatch(struct imsg *imsg) + goto done; + } + +- peer->prefix_rcvd_update++; +- /* add original path to the Adj-RIB-In */ +- if (peer->conf.softreconfig_in) +- path_update(peer, asp, &prefix, prefixlen, F_ORIGINAL); +- +- /* input filter */ +- if (rde_filter(&fasp, rules_l, peer, asp, &prefix, prefixlen, +- peer, DIR_IN) == ACTION_DENY) { +- path_put(fasp); +- continue; +- } ++ rde_update_update(peer, asp, &prefix, prefixlen); + + /* max prefix checker */ + if (peer->conf.max_prefix && +@@ -972,20 +979,9 @@ rde_update_dispatch(struct imsg *imsg) + log_peer_warnx(&peer->conf, "prefix limit reached"); + rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX, + NULL, 0); +- path_put(fasp); + goto done; + } + +- if (fasp == NULL) +- fasp = asp; +- +- rde_update_log("update", peer, &fasp->nexthop->exit_nexthop, +- &prefix, prefixlen); +- path_update(peer, fasp, &prefix, prefixlen, F_LOCAL); +- +- /* free modified aspath */ +- if (fasp != asp) +- path_put(fasp); + } + + /* add MP_REACH_NLRI if available */ +@@ -1008,7 +1004,7 @@ 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) { ++ if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp, peer)) == -1) { + log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix"); + rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, + mpa.reach, mpa.reach_len); +@@ -1047,19 +1043,8 @@ rde_update_dispatch(struct imsg *imsg) + mpp += pos; + mplen -= pos; + +- peer->prefix_rcvd_update++; +- /* add original path to the Adj-RIB-In */ +- if (peer->conf.softreconfig_in) +- path_update(peer, asp, &prefix, +- prefixlen, F_ORIGINAL); +- +- /* input filter */ +- if (rde_filter(&fasp, rules_l, peer, asp, +- &prefix, prefixlen, peer, DIR_IN) == +- ACTION_DENY) { +- path_put(fasp); +- continue; +- } ++ rde_update_update(peer, asp, &prefix, ++ prefixlen); + + /* max prefix checker */ + if (peer->conf.max_prefix && +@@ -1068,22 +1053,9 @@ rde_update_dispatch(struct imsg *imsg) + "prefix limit reached"); + rde_update_err(peer, ERR_CEASE, + ERR_CEASE_MAX_PREFIX, NULL, 0); +- path_put(fasp); + goto done; + } + +- if (fasp == NULL) +- fasp = asp; +- +- rde_update_log("update", peer, +- &asp->nexthop->exit_nexthop, +- &prefix, prefixlen); +- path_update(peer, fasp, &prefix, prefixlen, +- F_LOCAL); +- +- /* free modified aspath */ +- if (fasp != asp) +- path_put(fasp); + } + break; + default: +@@ -1106,6 +1078,67 @@ done: + return (error); + } + ++extern u_int16_t rib_size; ++ ++void ++rde_update_update(struct rde_peer *peer, struct rde_aspath *asp, ++ struct bgpd_addr *prefix, u_int8_t prefixlen) ++{ ++ struct rde_aspath *fasp; ++ int r = 0; ++ u_int16_t i; ++ ++ peer->prefix_rcvd_update++; ++ /* add original path to the Adj-RIB-In */ ++ if (peer->conf.softreconfig_in) ++ r += path_update(&ribs[0], peer, asp, prefix, prefixlen); ++ ++ 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; ++ ++ 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); ++ ++done: ++ /* free modified aspath */ ++ if (fasp != asp) ++ path_put(fasp); ++ } ++ ++ if (r) ++ peer->prefix_cnt++; ++} ++ ++void ++rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix, ++ u_int8_t prefixlen) ++{ ++ int r = 0; ++ u_int16_t i; ++ ++ peer->prefix_rcvd_withdraw++; ++ ++ for (i = rib_size - 1; ; i--) { ++ if (prefix_remove(&ribs[i], peer, prefix, prefixlen, 0)) { ++ rde_update_log("withdraw", i, peer, NULL, prefix, ++ prefixlen); ++ r++; ++ } ++ if (i == 0) ++ break; ++ } ++ ++ if (r) ++ peer->prefix_cnt--; ++} ++ + /* + * BGP UPDATE parser functions + */ +@@ -1336,7 +1369,7 @@ bad_flags: + mpa->unreach_len = attr_len; + plen += attr_len; + break; +- case ATTR_NEW_AGGREGATOR: ++ case ATTR_AS4_AGGREGATOR: + if (attr_len != 8) + goto bad_len; + if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, +@@ -1344,7 +1377,7 @@ bad_flags: + goto bad_flags; + a->flags |= F_ATTR_AS4BYTE_NEW; + goto optattr; +- case ATTR_NEW_ASPATH: ++ case ATTR_AS4_PATH: + if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, + ATTR_PARTIAL)) + goto bad_flags; +@@ -1408,7 +1441,7 @@ 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) ++ struct rde_aspath *asp, struct rde_peer *peer) + { + struct bgpd_addr nexthop; + u_int8_t totlen, nhlen; +@@ -1440,6 +1473,18 @@ rde_get_mp_nexthop(u_char *data, u_int16 + } + nexthop.af = AF_INET6; + memcpy(&nexthop.v6.s6_addr, data, 16); ++#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 + asp->nexthop = nexthop_get(&nexthop); + /* + * lock the nexthop because it is not yet linked else +@@ -1540,13 +1585,12 @@ rde_update_err(struct rde_peer *peer, u_ + imsg_add(wbuf, &suberr, sizeof(suberr)) == -1 || + imsg_add(wbuf, data, size) == -1) + fatal("imsg_add error"); +- if (imsg_close(ibuf_se, wbuf) == -1) +- fatal("imsg_close error"); ++ imsg_close(ibuf_se, wbuf); + peer->state = PEER_ERR; + } + + void +-rde_update_log(const char *message, ++rde_update_log(const char *message, u_int16_t rid, + const struct rde_peer *peer, const struct bgpd_addr *next, + const struct bgpd_addr *prefix, u_int8_t prefixlen) + { +@@ -1563,7 +1607,7 @@ rde_update_log(const char *message, + if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1) + p = NULL; + l = log_fmt_peer(&peer->conf); +- log_info("%s AS%s: %s %s%s", ++ log_info("Rib %s: %s AS%s: %s %s%s", ribs[rid].name, + l, log_as(peer->conf.remote_as), message, + p ? p : "out of memory", n ? n : ""); + +@@ -1585,8 +1629,8 @@ rde_as4byte_fixup(struct rde_peer *peer, + u_int32_t as; + + /* first get the attributes */ +- nasp = attr_optget(a, ATTR_NEW_ASPATH); +- naggr = attr_optget(a, ATTR_NEW_AGGREGATOR); ++ nasp = attr_optget(a, ATTR_AS4_PATH); ++ naggr = attr_optget(a, ATTR_AS4_AGGREGATOR); + + if (rde_as4byte(peer)) { + /* NEW session using 4-byte ASNs */ +@@ -1601,7 +1645,7 @@ rde_as4byte_fixup(struct rde_peer *peer, + if ((oaggr = attr_optget(a, ATTR_AGGREGATOR))) { + memcpy(&as, oaggr->data, sizeof(as)); + if (ntohl(as) != AS_TRANS) { +- /* per RFC draft ignore NEW_ASPATH and NEW_AGGREGATOR */ ++ /* per RFC ignore AS4_PATH and AS4_AGGREGATOR */ + if (nasp) + attr_free(a, nasp); + if (naggr) +@@ -1616,11 +1660,11 @@ rde_as4byte_fixup(struct rde_peer *peer, + fatalx("attr_optadd failed but impossible"); + } + } +- /* there is no need for NEW_AGGREGATOR any more */ ++ /* there is no need for AS4_AGGREGATOR any more */ + if (naggr) + attr_free(a, naggr); + +- /* merge NEW_ASPATH with ASPATH */ ++ /* merge AS4_PATH with ASPATH */ + if (nasp) + aspath_merge(a, nasp); + } +@@ -1703,7 +1747,6 @@ rde_dump_rib_as(struct prefix *p, struct + rib.med = asp->med; + rib.prefix_cnt = asp->prefix_cnt; + rib.active_cnt = asp->active_cnt; +- rib.adjrib_cnt = asp->adjrib_cnt; + strlcpy(rib.descr, asp->peer->conf.descr, sizeof(rib.descr)); + memcpy(&rib.remote_addr, &asp->peer->remote_addr, + sizeof(rib.remote_addr)); +@@ -1724,7 +1767,7 @@ rde_dump_rib_as(struct prefix *p, struct + rib.prefixlen = p->prefix->prefixlen; + rib.origin = asp->origin; + rib.flags = 0; +- if (p->prefix->active == p) ++ if (p->rib->active == p) + rib.flags |= F_RIB_ACTIVE; + if (asp->peer->conf.ebgp == 0) + rib.flags |= F_RIB_INTERNAL; +@@ -1743,8 +1786,7 @@ rde_dump_rib_as(struct prefix *p, struct + imsg_add(wbuf, aspath_dump(asp->aspath), + rib.aspath_len) == -1) + return; +- if (imsg_close(ibuf_se_ctl, wbuf) == -1) +- return; ++ imsg_close(ibuf_se_ctl, wbuf); + + if (flags & F_CTL_DETAIL) + for (l = 0; l < asp->others_len; l++) { +@@ -1763,8 +1805,7 @@ rde_dump_rib_as(struct prefix *p, struct + buf_free(wbuf); + return; + } +- if (imsg_close(ibuf_se_ctl, wbuf) == -1) +- return; ++ imsg_close(ibuf_se_ctl, wbuf); + } + } + +@@ -1780,7 +1821,7 @@ rde_dump_filterout(struct rde_peer *peer + return; + + pt_getaddr(p->prefix, &addr); +- a = rde_filter(&asp, rules_l, peer, p->aspath, &addr, ++ a = rde_filter(1 /* XXX */, &asp, rules_l, peer, p->aspath, &addr, + p->prefix->prefixlen, p->aspath->peer, DIR_OUT); + if (asp) + asp->peer = p->aspath->peer; +@@ -1799,108 +1840,57 @@ rde_dump_filter(struct prefix *p, struct + { + struct rde_peer *peer; + +- if ((req->flags & F_CTL_ADJ_IN && p->flags & F_ORIGINAL) || +- (!(req->flags & (F_CTL_ADJ_IN|F_CTL_ADJ_OUT)) && +- p->flags & F_LOCAL)) { ++ 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)) ++ return; ++ if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY && ++ !rde_filter_community(p->aspath, req->community.as, ++ req->community.type)) ++ return; + rde_dump_rib_as(p, p->aspath, req->pid, req->flags); +- } else if (req->flags & F_CTL_ADJ_OUT && p->flags & F_LOCAL) { +- if (p->prefix->active != p) ++ } else if (req->flags & F_CTL_ADJ_OUT) { ++ if (p->rib->active != p) + /* only consider active prefix */ + return; +- + if (req->peerid) { + if ((peer = peer_get(req->peerid)) != NULL) + rde_dump_filterout(peer, p, req); + return; + } +- LIST_FOREACH(peer, &peerlist, peer_l) +- rde_dump_filterout(peer, p, req); + } + } + + void +-rde_dump_upcall(struct pt_entry *pt, void *ptr) ++rde_dump_upcall(struct rib_entry *re, void *ptr) + { + struct prefix *p; +- struct ctl_show_rib_request *req = ptr; ++ struct rde_dump_ctx *ctx = ptr; + +- LIST_FOREACH(p, &pt->prefix_h, prefix_l) +- rde_dump_filter(p, req); ++ LIST_FOREACH(p, &re->prefix_h, rib_l) ++ rde_dump_filter(p, &ctx->req); + } + + void +-rde_dump_as(struct ctl_show_rib_request *req) ++rde_dump_prefix_upcall(struct rib_entry *re, void *ptr) + { +- extern struct path_table pathtable; +- struct rde_aspath *asp; +- struct prefix *p; +- u_int32_t i; +- +- for (i = 0; i <= pathtable.path_hashmask; i++) { +- LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) { +- if (!aspath_match(asp->aspath, req->as.type, +- req->as.as)) +- continue; +- /* match found */ +- LIST_FOREACH(p, &asp->prefix_h, path_l) +- rde_dump_filter(p, req); +- } +- } +-} +- +-void +-rde_dump_prefix_upcall(struct pt_entry *pt, void *ptr) +-{ +- struct ctl_show_rib_request *req = ptr; +- struct prefix *p; +- struct bgpd_addr addr; ++ struct rde_dump_ctx *ctx = ptr; ++ struct prefix *p; ++ struct pt_entry *pt; ++ struct bgpd_addr addr; + ++ pt = re->prefix; + pt_getaddr(pt, &addr); +- if (addr.af != req->prefix.af) ++ if (addr.af != ctx->req.prefix.af) + return; +- if (req->prefixlen > pt->prefixlen) ++ if (ctx->req.prefixlen > pt->prefixlen) + return; +- if (!prefix_compare(&req->prefix, &addr, req->prefixlen)) +- LIST_FOREACH(p, &pt->prefix_h, prefix_l) +- rde_dump_filter(p, req); +-} +- +-void +-rde_dump_prefix(struct ctl_show_rib_request *req) +-{ +- struct pt_entry *pt; +- +- if (req->prefixlen == 32) { +- if ((pt = pt_lookup(&req->prefix)) != NULL) +- rde_dump_upcall(pt, req); +- } else if (req->flags & F_LONGER) { +- pt_dump(rde_dump_prefix_upcall, req, req->prefix.af); +- } else { +- if ((pt = pt_get(&req->prefix, req->prefixlen)) != NULL) +- rde_dump_upcall(pt, req); +- } +-} +- +-void +-rde_dump_community(struct ctl_show_rib_request *req) +-{ +- extern struct path_table pathtable; +- struct rde_aspath *asp; +- struct prefix *p; +- u_int32_t i; +- +- for (i = 0; i <= pathtable.path_hashmask; i++) { +- LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) { +- if (!rde_filter_community(asp, req->community.as, +- req->community.type)) +- continue; +- /* match found */ +- LIST_FOREACH(p, &asp->prefix_h, path_l) +- rde_dump_filter(p, req); +- } +- } ++ if (!prefix_compare(&ctx->req.prefix, &addr, ctx->req.prefixlen)) ++ LIST_FOREACH(p, &re->prefix_h, rib_l) ++ rde_dump_filter(p, &ctx->req); + } + + void +@@ -1908,7 +1898,9 @@ rde_dump_ctx_new(struct ctl_show_rib_req + enum imsg_type type) + { + struct rde_dump_ctx *ctx; ++ struct rib_entry *re; + u_int error; ++ u_int16_t id; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { + log_warn("rde_dump_ctx_new"); +@@ -1917,52 +1909,89 @@ rde_dump_ctx_new(struct ctl_show_rib_req + sizeof(error)); + return; + } ++ if ((id = rib_find(req->rib)) == RIB_FAILED) { ++ log_warnx("rde_dump_ctx_new: no such rib %s", req->rib); ++ error = CTL_RES_NOSUCHPEER; ++ imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error, ++ sizeof(error)); ++ return; ++ } ++ + memcpy(&ctx->req, req, sizeof(struct ctl_show_rib_request)); + ctx->req.pid = pid; + ctx->req.type = type; +- ctx->ptc.count = RDE_RUNNER_ROUNDS; +- ctx->af = ctx->req.af; +- if (ctx->af == AF_UNSPEC) +- ctx->af = AF_INET; +- +- TAILQ_INSERT_TAIL(&rde_dump_h, ctx, entry); ++ ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS; ++ ctx->ribctx.ctx_rib = &ribs[id]; ++ switch (ctx->req.type) { ++ case IMSG_CTL_SHOW_NETWORK: ++ ctx->ribctx.ctx_upcall = network_dump_upcall; ++ break; ++ case IMSG_CTL_SHOW_RIB: ++ case IMSG_CTL_SHOW_RIB_AS: ++ case IMSG_CTL_SHOW_RIB_COMMUNITY: ++ ctx->ribctx.ctx_upcall = rde_dump_upcall; ++ break; ++ case IMSG_CTL_SHOW_RIB_PREFIX: ++ if (req->flags & F_LONGER) { ++ ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall; ++ break; ++ } ++ if (req->prefixlen == 32) ++ re = rib_lookup(&ribs[id], &req->prefix); ++ else ++ re = rib_get(&ribs[id], &req->prefix, req->prefixlen); ++ if (re) ++ rde_dump_upcall(re, ctx); ++ rde_dump_done(ctx); ++ return; ++ default: ++ fatalx("rde_dump_ctx_new: unsupported imsg type"); ++ } ++ ctx->ribctx.ctx_done = rde_dump_done; ++ ctx->ribctx.ctx_arg = ctx; ++ ctx->ribctx.ctx_af = ctx->req.af; ++ rib_dump_r(&ctx->ribctx); + } + + void +-rde_dump_runner(void) ++rde_dump_done(void *arg) + { +- struct rde_dump_ctx *ctx, *next; ++ struct rde_dump_ctx *ctx = arg; + +- for (ctx = TAILQ_FIRST(&rde_dump_h); ctx != NULL; ctx = next) { +- next = TAILQ_NEXT(ctx, entry); +- if (ctx->ptc.done) { +- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, +- -1, NULL, 0); +- TAILQ_REMOVE(&rde_dump_h, ctx, entry); +- free(ctx); +- continue; +- } +- switch (ctx->req.type) { +- case IMSG_CTL_SHOW_NETWORK: +- pt_dump_r(network_dump_upcall, &ctx->req.pid, +- ctx->af, &ctx->ptc); +- break; +- case IMSG_CTL_SHOW_RIB: +- pt_dump_r(rde_dump_upcall, &ctx->req, ctx->af, +- &ctx->ptc); +- break; +- default: +- fatalx("rde_dump_runner: unsupported imsg type"); +- } +- if (ctx->ptc.done && ctx->req.af == AF_UNSPEC) +- ctx->af = AF_INET6; +- } ++ imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, ++ -1, NULL, 0); ++ free(ctx); + } + +-int +-rde_dump_pending(void) ++void ++rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd) + { +- return (!TAILQ_EMPTY(&rde_dump_h)); ++ struct rde_mrt_ctx *ctx; ++ u_int16_t id; ++ ++ if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { ++ log_warn("rde_dump_mrt_new"); ++ return; ++ } ++ memcpy(&ctx->mrt, mrt, sizeof(struct mrt)); ++ TAILQ_INIT(&ctx->mrt.wbuf.bufs); ++ ctx->mrt.wbuf.fd = fd; ++ ctx->mrt.state = MRT_STATE_RUNNING; ++ id = rib_find(ctx->mrt.rib); ++ if (id == RIB_FAILED) { ++ log_warnx("non existing RIB %s for mrt dump", ctx->mrt.rib); ++ free(ctx); ++ return; ++ } ++ 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_arg = &ctx->mrt; ++ ctx->ribctx.ctx_af = AF_UNSPEC; ++ LIST_INSERT_HEAD(&rde_mrts, &ctx->mrt, entry); ++ rde_mrt_cnt++; ++ rib_dump_r(&ctx->ribctx); + } + + /* +@@ -2100,9 +2129,10 @@ rde_send_nexthop(struct bgpd_addr *next, + * soft reconfig specific functions + */ + void +-rde_softreconfig_out(struct pt_entry *pt, void *ptr) ++rde_softreconfig_out(struct rib_entry *re, void *ptr) + { +- struct prefix *p = pt->active; ++ struct prefix *p = re->active; ++ struct pt_entry *pt; + struct rde_peer *peer; + struct rde_aspath *oasp, *nasp; + enum filter_actions oa, na; +@@ -2111,17 +2141,22 @@ rde_softreconfig_out(struct pt_entry *pt + if (p == NULL) + return; + ++ pt = re->prefix; + pt_getaddr(pt, &addr); + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; ++ if (peer->ribid != re->ribid) ++ continue; + if (peer->reconf_out == 0) + continue; + if (up_test_update(peer, p) != 1) + continue; + +- oa = rde_filter(&oasp, rules_l, peer, p->aspath, &addr, +- pt->prefixlen, p->aspath->peer, DIR_OUT); +- na = rde_filter(&nasp, newrules, peer, p->aspath, &addr, +- pt->prefixlen, p->aspath->peer, DIR_OUT); ++ oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath, ++ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); ++ na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath, ++ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); + oasp = oasp != NULL ? oasp : p->aspath; + nasp = nasp != NULL ? nasp : p->aspath; + +@@ -2154,60 +2189,67 @@ done: + } + + void +-rde_softreconfig_in(struct pt_entry *pt, void *ptr) ++rde_softreconfig_in(struct rib_entry *re, void *ptr) + { + struct prefix *p, *np; ++ struct pt_entry *pt; + struct rde_peer *peer; + struct rde_aspath *asp, *oasp, *nasp; + enum filter_actions oa, na; + struct bgpd_addr addr; ++ u_int16_t i; + ++ pt = re->prefix; + pt_getaddr(pt, &addr); +- for (p = LIST_FIRST(&pt->prefix_h); p != NULL; p = np) { +- np = LIST_NEXT(p, prefix_l); +- if (!(p->flags & F_ORIGINAL)) +- continue; ++ 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; + ++ /* XXX how can this happen ??? */ + if (peer->reconf_in == 0) + continue; + +- /* check if prefix changed */ +- oa = rde_filter(&oasp, rules_l, peer, asp, &addr, +- pt->prefixlen, peer, DIR_IN); +- na = rde_filter(&nasp, newrules, peer, asp, &addr, +- pt->prefixlen, peer, DIR_IN); +- oasp = oasp != NULL ? oasp : asp; +- nasp = nasp != NULL ? nasp : asp; ++ for (i = 1; i < rib_size; i++) { ++ /* check if prefix changed */ ++ oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr, ++ pt->prefixlen, peer, DIR_IN); ++ na = rde_filter(i, &nasp, newrules, peer, asp, &addr, ++ pt->prefixlen, peer, DIR_IN); ++ oasp = oasp != NULL ? oasp : asp; ++ nasp = nasp != NULL ? nasp : asp; + +- if (oa == ACTION_DENY && na == ACTION_DENY) +- /* nothing todo */ +- goto done; +- if (oa == ACTION_DENY && na == ACTION_ALLOW) { +- /* update Local-RIB */ +- path_update(peer, nasp, &addr, pt->prefixlen, F_LOCAL); +- goto done; +- } +- if (oa == ACTION_ALLOW && na == ACTION_DENY) { +- /* remove from Local-RIB */ +- prefix_remove(peer, &addr, pt->prefixlen, F_LOCAL); +- goto done; +- } +- if (oa == ACTION_ALLOW && na == ACTION_ALLOW) { +- if (path_compare(nasp, oasp) == 0) ++ if (oa == ACTION_DENY && na == ACTION_DENY) ++ /* nothing todo */ + goto done; +- /* send update */ +- path_update(peer, nasp, &addr, pt->prefixlen, F_LOCAL); +- } ++ if (oa == ACTION_DENY && na == ACTION_ALLOW) { ++ /* update Local-RIB */ ++ path_update(&ribs[i], peer, nasp, &addr, ++ pt->prefixlen); ++ goto done; ++ } ++ if (oa == ACTION_ALLOW && na == ACTION_DENY) { ++ /* remove from Local-RIB */ ++ prefix_remove(&ribs[i], peer, &addr, ++ pt->prefixlen, 0); ++ goto done; ++ } ++ if (oa == ACTION_ALLOW && na == ACTION_ALLOW) { ++ if (path_compare(nasp, oasp) == 0) ++ goto done; ++ /* send update */ ++ path_update(&ribs[1], peer, nasp, &addr, ++ pt->prefixlen); ++ } + + done: +- if (oasp != asp) +- path_put(oasp); +- if (nasp != asp) +- path_put(nasp); ++ if (oasp != asp) ++ path_put(oasp); ++ if (nasp != asp) ++ path_put(nasp); ++ } + } + } + +@@ -2217,17 +2259,19 @@ done: + u_char queue_buf[4096]; + + void +-rde_up_dump_upcall(struct pt_entry *pt, void *ptr) ++rde_up_dump_upcall(struct rib_entry *re, void *ptr) + { + struct rde_peer *peer = ptr; + +- if (pt->active == NULL) ++ if (re->ribid != peer->ribid) ++ fatalx("King Bula: monsterous evil horror."); ++ if (re->active == NULL) + return; +- up_generate_updates(rules_l, peer, pt->active, NULL); ++ up_generate_updates(rules_l, peer, re->active, NULL); + } + + void +-rde_generate_updates(struct prefix *new, struct prefix *old) ++rde_generate_updates(u_int16_t ribid, struct prefix *new, struct prefix *old) + { + struct rde_peer *peer; + +@@ -2240,6 +2284,10 @@ rde_generate_updates(struct prefix *new, + return; + + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; ++ if (peer->ribid != ribid) ++ continue; + if (peer->state != PEER_UP) + continue; + up_generate_updates(rules_l, peer, new, old); +@@ -2257,6 +2305,8 @@ rde_update_queue_runner(void) + do { + sent = 0; + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; + if (peer->state != PEER_UP) + continue; + /* first withdraws */ +@@ -2303,6 +2353,8 @@ rde_update6_queue_runner(void) + do { + sent = 0; + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; + if (peer->state != PEER_UP) + continue; + len = sizeof(queue_buf) - MSGSIZE_HEADER; +@@ -2324,6 +2376,8 @@ rde_update6_queue_runner(void) + do { + sent = 0; + LIST_FOREACH(peer, &peerlist, peer_l) { ++ if (peer->conf.id == 0) ++ continue; + if (peer->state != PEER_UP) + continue; + len = sizeof(queue_buf) - MSGSIZE_HEADER; +@@ -2386,6 +2440,8 @@ struct peer_table { + 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) +@@ -2399,6 +2455,19 @@ peer_init(u_int32_t hashsize) + LIST_INIT(&peerlist); + + 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)); ++ ++ 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 +@@ -2444,6 +2513,7 @@ peer_add(u_int32_t id, struct peer_confi + LIST_INIT(&peer->path_h); + memcpy(&peer->conf, p_conf, sizeof(struct peer_config)); + peer->remote_bgpid = 0; ++ peer->ribid = rib_find(peer->conf.rib); + peer->state = PEER_NONE; + up_init(peer); + +@@ -2573,6 +2643,7 @@ peer_down(u_int32_t id) + path_remove(asp); + } + LIST_INIT(&peer->path_h); ++ peer->prefix_cnt = 0; + + /* Deletions are performed in path_remove() */ + rde_send_pftable_commit(); +@@ -2595,19 +2666,19 @@ peer_dump(u_int32_t id, u_int16_t afi, u + + if (afi == AFI_ALL || afi == AFI_IPv4) + if (safi == SAFI_ALL || safi == SAFI_UNICAST) { +- if (peer->conf.announce_type == +- ANNOUNCE_DEFAULT_ROUTE) ++ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) + up_generate_default(rules_l, peer, AF_INET); + else +- pt_dump(rde_up_dump_upcall, peer, AF_INET); ++ 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) ++ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) + up_generate_default(rules_l, peer, AF_INET6); + else +- pt_dump(rde_up_dump_upcall, peer, AF_INET6); ++ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, ++ peer, AF_INET6); + } + + if (peer->capa_received.restart && peer->capa_announced.restart) +@@ -2653,24 +2724,8 @@ void + network_init(struct network_head *net_l) + { + struct network *n; +- struct in_addr id; + + reloadtime = time(NULL); +- bzero(&peerself, sizeof(peerself)); +- peerself.state = PEER_UP; +- peerself.remote_bgpid = ntohl(conf->bgpid); +- id.s_addr = conf->bgpid; +- peerself.conf.remote_as = conf->as; +- peerself.short_as = conf->short_as; +- snprintf(peerself.conf.descr, sizeof(peerself.conf.descr), +- "LOCAL: ID %s", inet_ntoa(id)); +- bzero(&peerdynamic, sizeof(peerdynamic)); +- peerdynamic.state = PEER_UP; +- peerdynamic.remote_bgpid = ntohl(conf->bgpid); +- peerdynamic.conf.remote_as = conf->as; +- peerdynamic.short_as = conf->short_as; +- snprintf(peerdynamic.conf.descr, sizeof(peerdynamic.conf.descr), +- "LOCAL: ID %s", inet_ntoa(id)); + + while ((n = TAILQ_FIRST(net_l)) != NULL) { + TAILQ_REMOVE(net_l, n, entry); +@@ -2683,7 +2738,7 @@ void + network_add(struct network_config *nc, int flagstatic) + { + struct rde_aspath *asp; +- struct rde_peer *p; ++ u_int16_t i; + + asp = path_get(); + asp->aspath = aspath_get(NULL, 0); +@@ -2691,15 +2746,13 @@ network_add(struct network_config *nc, i + 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; + +- if (flagstatic) +- p = &peerself; +- else +- p = &peerdynamic; +- +- rde_apply_set(asp, &nc->attrset, nc->prefix.af, p, p); +- path_update(p, asp, &nc->prefix, nc->prefixlen, F_ORIGINAL); +- path_update(p, asp, &nc->prefix, nc->prefixlen, F_LOCAL); ++ rde_apply_set(asp, &nc->attrset, nc->prefix.af, peerself, peerself); ++ for (i = 1; i < rib_size; i++) ++ path_update(&ribs[i], peerself, asp, &nc->prefix, ++ nc->prefixlen); + + path_put(asp); + filterset_free(&nc->attrset); +@@ -2708,29 +2761,27 @@ network_add(struct network_config *nc, i + void + network_delete(struct network_config *nc, int flagstatic) + { +- struct rde_peer *p; ++ u_int32_t flags = F_PREFIX_ANNOUNCED; ++ u_int32_t i; + +- if (flagstatic) +- p = &peerself; +- else +- p = &peerdynamic; ++ if (!flagstatic) ++ flags |= F_ANN_DYNAMIC; + +- prefix_remove(p, &nc->prefix, nc->prefixlen, F_LOCAL); +- prefix_remove(p, &nc->prefix, nc->prefixlen, F_ORIGINAL); ++ for (i = rib_size - 1; i > 0; i--) ++ prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen, ++ flags); + } + + void +-network_dump_upcall(struct pt_entry *pt, void *ptr) ++network_dump_upcall(struct rib_entry *re, void *ptr) + { + struct prefix *p; + struct kroute k; + struct kroute6 k6; + struct bgpd_addr addr; +- pid_t pid; +- +- memcpy(&pid, ptr, sizeof(pid)); ++ struct rde_dump_ctx *ctx = ptr; + +- LIST_FOREACH(p, &pt->prefix_h, prefix_l) { ++ LIST_FOREACH(p, &re->prefix_h, rib_l) { + if (!(p->aspath->flags & F_PREFIX_ANNOUNCED)) + continue; + if (p->prefix->af == AF_INET) { +@@ -2738,10 +2789,10 @@ network_dump_upcall(struct pt_entry *pt, + pt_getaddr(p->prefix, &addr); + k.prefix.s_addr = addr.v4.s_addr; + k.prefixlen = p->prefix->prefixlen; +- if (p->aspath->peer == &peerself) ++ if (p->aspath->peer == peerself) + k.flags = F_KERNEL; + if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0, +- pid, -1, &k, sizeof(k)) == -1) ++ ctx->req.pid, -1, &k, sizeof(k)) == -1) + log_warnx("network_dump_upcall: " + "imsg_compose error"); + } +@@ -2750,31 +2801,21 @@ network_dump_upcall(struct pt_entry *pt, + pt_getaddr(p->prefix, &addr); + memcpy(&k6.prefix, &addr.v6, sizeof(k6.prefix)); + k6.prefixlen = p->prefix->prefixlen; +- if (p->aspath->peer == &peerself) ++ if (p->aspath->peer == peerself) + k6.flags = F_KERNEL; + if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK6, 0, +- pid, -1, &k6, sizeof(k6)) == -1) ++ ctx->req.pid, -1, &k6, sizeof(k6)) == -1) + log_warnx("network_dump_upcall: " + "imsg_compose error"); + } + } + } + +-void +-network_flush(int flagstatic) +-{ +- if (flagstatic) +- prefix_network_clean(&peerself, time(NULL)); +- else +- prefix_network_clean(&peerdynamic, time(NULL)); +-} +- + /* clean up */ + void + rde_shutdown(void) + { + struct rde_peer *p; +- struct rde_aspath *asp, *nasp; + struct filter_rule *r; + u_int32_t i; + +@@ -2790,21 +2831,6 @@ rde_shutdown(void) + while ((p = LIST_FIRST(&peertable.peer_hashtbl[i])) != NULL) + peer_down(p->conf.id); + +- /* free announced network prefixes */ +- peerself.remote_bgpid = 0; +- peerself.state = PEER_DOWN; +- for (asp = LIST_FIRST(&peerself.path_h); asp != NULL; asp = nasp) { +- nasp = LIST_NEXT(asp, peer_l); +- path_remove(asp); +- } +- +- peerdynamic.remote_bgpid = 0; +- peerdynamic.state = PEER_DOWN; +- for (asp = LIST_FIRST(&peerdynamic.path_h); asp != NULL; asp = nasp) { +- nasp = LIST_NEXT(asp, peer_l); +- path_remove(asp); +- } +- + /* free filters */ + while ((r = TAILQ_FIRST(rules_l)) != NULL) { + TAILQ_REMOVE(rules_l, r, entry); +@@ -2819,7 +2845,6 @@ rde_shutdown(void) + attr_shutdown(); + pt_shutdown(); + peer_shutdown(); +- free(mrt); + } + + int diff --git a/net/openbgpd/files/patch-bgpd_rde.h b/net/openbgpd/files/patch-bgpd_rde.h new file mode 100644 index 00000000000..cd84a23a152 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_rde.h @@ -0,0 +1,309 @@ +Index: bgpd/rde.h +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.h,v +retrieving revision 1.1.1.1 +retrieving revision 1.1.1.2 +diff -u -p -r1.1.1.1 -r1.1.1.2 +--- bgpd/rde.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/rde.h 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde.h,v 1.102 2008/01/23 08:11:32 claudio Exp $ */ ++/* $OpenBSD: rde.h,v 1.120 2009/06/06 01:10:29 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and +@@ -42,6 +42,7 @@ LIST_HEAD(rde_peer_head, rde_peer); + LIST_HEAD(aspath_head, rde_aspath); + RB_HEAD(uptree_prefix, update_prefix); + RB_HEAD(uptree_attr, update_attr); ++RB_HEAD(rib_tree, rib_entry); + TAILQ_HEAD(uplist_prefix, update_prefix); + TAILQ_HEAD(uplist_attr, update_attr); + +@@ -66,13 +67,13 @@ struct rde_peer { + u_int64_t prefix_sent_update; + u_int64_t prefix_sent_withdraw; + u_int32_t prefix_cnt; /* # of prefixes */ +- u_int32_t adjrib_cnt; /* # of p. in Adj-RIB-In */ + u_int32_t remote_bgpid; /* host byte order! */ + u_int32_t up_pcnt; + u_int32_t up_acnt; + u_int32_t up_nlricnt; + u_int32_t up_wcnt; + enum peer_state state; ++ u_int16_t ribid; + u_int16_t short_as; + u_int8_t reconf_in; /* in filter changed */ + u_int8_t reconf_out; /* out filter changed */ +@@ -107,8 +108,8 @@ enum attrtypes { + ATTR_MP_REACH_NLRI=14, + ATTR_MP_UNREACH_NLRI=15, + ATTR_EXT_COMMUNITIES=16, +- ATTR_NEW_ASPATH=17, +- ATTR_NEW_AGGREGATOR=18 ++ ATTR_AS4_PATH=17, ++ ATTR_AS4_AGGREGATOR=18 + }; + + /* attribute flags. 4 low order bits reserved */ +@@ -154,16 +155,15 @@ LIST_HEAD(prefix_head, prefix); + #define F_ATTR_MED_ANNOUNCE 0x00020 + #define F_ATTR_MP_REACH 0x00040 + #define F_ATTR_MP_UNREACH 0x00080 +-#define F_ATTR_AS4BYTE_NEW 0x00100 /* NEW_ASPATH or NEW_AGGREGATOR */ ++#define F_ATTR_AS4BYTE_NEW 0x00100 /* AS4_PATH or AS4_AGGREGATOR */ + #define F_ATTR_LOOP 0x00200 /* path would cause a route loop */ +-#define F_PREFIX_ANNOUNCED 0x01000 ++#define F_PREFIX_ANNOUNCED 0x00400 ++#define F_ANN_DYNAMIC 0x00800 ++#define F_NEXTHOP_SELF 0x01000 + #define F_NEXTHOP_REJECT 0x02000 + #define F_NEXTHOP_BLACKHOLE 0x04000 + #define F_NEXTHOP_NOMODIFY 0x08000 +-#define F_NEXTHOP_SELF 0x10000 + #define F_ATTR_LINKED 0x20000 +-#define F_LOCAL 0x40000 /* Local-RIB */ +-#define F_ORIGINAL 0x80000 /* Adj-RIB-In */ + + + #define ORIGIN_IGP 0 +@@ -184,7 +184,6 @@ struct rde_aspath { + u_int32_t weight; /* low prio lpref */ + u_int32_t prefix_cnt; /* # of prefixes */ + u_int32_t active_cnt; /* # of active prefixes */ +- u_int32_t adjrib_cnt; /* # of p. in Adj-RIB-In */ + u_int32_t flags; /* internally used */ + u_int16_t rtlabelid; /* route label id */ + u_int16_t pftableid; /* pf table id */ +@@ -223,53 +222,71 @@ struct pt_entry { + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; + u_int8_t prefixlen; +- struct prefix_head prefix_h; +- struct prefix *active; /* for fast access */ ++ u_int16_t refcnt; + }; + + struct pt_entry4 { + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; + u_int8_t prefixlen; +- struct prefix_head prefix_h; +- struct prefix *active; /* for fast access */ ++ u_int16_t refcnt; + struct in_addr prefix4; +- /* +- * Route Flap Damping structures +- * Currently I think they belong into the prefix but for the moment +- * we just ignore the dampening at all. +- */ + }; + + struct pt_entry6 { + RB_ENTRY(pt_entry) pt_e; + sa_family_t af; + u_int8_t prefixlen; +- struct prefix_head prefix_h; +- struct prefix *active; /* for fast access */ ++ u_int16_t refcnt; + struct in6_addr prefix6; + }; + +-struct pt_context { +- union { +- struct pt_entry p; +- struct pt_entry4 p4; +- struct pt_entry6 p6; +- } pu; +-#define ctx_p pu.p +-#define ctx_p4 pu.p4 +-#define ctx_p6 pu.p6 +- /* only count and done should be accessed by callers */ +- unsigned int count; +- int done; +-}; ++struct rib_context { ++ LIST_ENTRY(rib_context) entry; ++ struct rib_entry *ctx_re; ++ struct rib *ctx_rib; ++ void (*ctx_upcall)(struct rib_entry *, void *); ++ void (*ctx_done)(void *); ++ void (*ctx_wait)(void *); ++ void *ctx_arg; ++ unsigned int ctx_count; ++ sa_family_t ctx_af; ++}; ++ ++struct rib_entry { ++ RB_ENTRY(rib_entry) rib_e; ++ struct prefix_head prefix_h; ++ struct prefix *active; /* for fast access */ ++ struct pt_entry *prefix; ++ u_int16_t ribid; ++ 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_int16_t flags; ++ u_int16_t id; ++}; ++ ++#define F_RIB_ENTRYLOCK 0x0001 ++#define F_RIB_NOEVALUATE 0x0002 ++#define F_RIB_NOFIB 0x0004 ++#define RIB_FAILED 0xffff + + struct prefix { +- LIST_ENTRY(prefix) prefix_l, path_l; ++ LIST_ENTRY(prefix) rib_l, path_l; + struct rde_aspath *aspath; + struct pt_entry *prefix; ++ struct rib_entry *rib; /* NULL for Adj-RIB-In */ + time_t lastchange; +- u_int32_t flags; + }; + + extern struct rde_memstats rdemem; +@@ -282,7 +299,8 @@ void rde_send_pftable(u_int16_t, struc + u_int8_t, int); + void rde_send_pftable_commit(void); + +-void rde_generate_updates(struct prefix *, struct prefix *); ++void rde_generate_updates(u_int16_t, struct prefix *, ++ struct prefix *); + u_int32_t rde_local_as(void); + int rde_noevaluate(void); + int rde_decisionflags(void); +@@ -291,6 +309,8 @@ 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 *, ++ u_int16_t); + void attr_init(u_int32_t); + void attr_shutdown(void); + int attr_optadd(struct rde_aspath *, u_int8_t, u_int8_t, +@@ -327,10 +347,24 @@ int community_set(struct rde_aspath *, + void community_delete(struct rde_aspath *, int, int); + + /* 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_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 rib_dump_r(struct rib_context *); ++void rib_dump_runner(void); ++int rib_dump_pending(void); ++ + void path_init(u_int32_t); + void path_shutdown(void); +-void path_update(struct rde_peer *, struct rde_aspath *, +- struct bgpd_addr *, int, u_int32_t); ++int path_update(struct rib *, struct rde_peer *, ++ struct rde_aspath *, struct bgpd_addr *, int); + 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 *); +@@ -343,18 +377,20 @@ 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 rde_peer *, struct bgpd_addr *, int, +- u_int32_t); +-struct pt_entry *prefix_add(struct rde_aspath *, struct bgpd_addr *, int, +- u_int32_t); +-struct pt_entry *prefix_move(struct rde_aspath *, struct prefix *, u_int32_t); +-void prefix_remove(struct rde_peer *, struct bgpd_addr *, int, +- u_int32_t); ++struct prefix *prefix_get(struct rib *, struct rde_peer *, ++ struct bgpd_addr *, int, u_int32_t); ++int prefix_add(struct rib *, struct rde_aspath *, ++ struct bgpd_addr *, int); ++void prefix_move(struct rde_aspath *, struct prefix *); ++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); +-struct prefix *prefix_bypeer(struct pt_entry *, struct rde_peer *, u_int32_t); +-void prefix_updateall(struct rde_aspath *, enum nexthop_state); ++struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *, ++ u_int32_t); ++void prefix_updateall(struct rde_aspath *, enum nexthop_state, ++ enum nexthop_state); + void prefix_destroy(struct prefix *); +-void prefix_network_clean(struct rde_peer *, time_t); ++void prefix_network_clean(struct rde_peer *, time_t, u_int32_t); + + void nexthop_init(u_int32_t); + void nexthop_shutdown(void); +@@ -368,7 +404,7 @@ struct nexthop *nexthop_get(struct bgpd_ + int nexthop_compare(struct nexthop *, struct nexthop *); + + /* rde_decide.c */ +-void prefix_evaluate(struct prefix *, struct pt_entry *); ++void prefix_evaluate(struct prefix *, struct rib_entry *); + + /* rde_update.c */ + void up_init(struct rde_peer *); +@@ -387,24 +423,34 @@ u_char *up_dump_mp_unreach(u_char *, u_ + u_char *up_dump_mp_reach(u_char *, u_int16_t *, struct rde_peer *); + + /* rde_prefix.c */ +-void pt_init(void); +-void pt_shutdown(void); +-int pt_empty(struct pt_entry *); +-void pt_getaddr(struct pt_entry *, struct bgpd_addr *); ++#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 *); ++void pt_remove(struct pt_entry *); + struct pt_entry *pt_lookup(struct bgpd_addr *); +-void pt_dump(void (*)(struct pt_entry *, void *), void *, +- sa_family_t); +-void pt_dump_r(void (*)(struct pt_entry *, void *), void *, +- sa_family_t, struct pt_context *); ++int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); ++ + + /* rde_filter.c */ +-enum filter_actions rde_filter(struct rde_aspath **, struct filter_head *, +- struct rde_peer *, struct rde_aspath *, +- struct bgpd_addr *, u_int8_t, struct rde_peer *, +- enum directions); ++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); diff --git a/net/openbgpd/files/patch-bgpd_rde_attr.c b/net/openbgpd/files/patch-bgpd_rde_attr.c index db5f385ca62..b6ad8ab1872 100644 --- a/net/openbgpd/files/patch-bgpd_rde_attr.c +++ b/net/openbgpd/files/patch-bgpd_rde_attr.c @@ -2,10 +2,16 @@ Index: bgpd/rde_attr.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_attr.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 --- bgpd/rde_attr.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_attr.c 30 Jun 2009 06:40:07 -0000 1.2 ++++ bgpd/rde_attr.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_attr.c,v 1.76.2.1 2009/02/18 20:30:36 claudio Exp $ */ ++/* $OpenBSD: rde_attr.c,v 1.79 2009/03/19 06:52:59 claudio Exp $ */ + + /* + * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -17,7 +17,11 @@ */ @@ -28,3 +34,44 @@ diff -u -p -r1.1.1.1 -r1.2 #include "bgpd.h" #include "rde.h" +@@ -62,6 +69,31 @@ attr_write(void *p, u_int16_t p_len, u_i + return (tot_len); + } + ++int ++attr_writebuf(struct buf *buf, u_int8_t flags, u_int8_t type, void *data, ++ u_int16_t data_len) ++{ ++ u_char hdr[4]; ++ ++ 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) ++ return (-1); ++ if (buf_add(buf, data, data_len) == -1) ++ return (-1); ++ return (0); ++} ++ + /* optional attribute specific functions */ + int attr_diff(struct attr *, struct attr *); + struct attr *attr_alloc(u_int8_t, u_int8_t, const void *, u_int16_t); +@@ -588,7 +620,7 @@ aspath_merge(struct rde_aspath *a, struc + + ascnt = aspath_count(attr->data, attr->len); + if (ascnt > a->aspath->ascnt) { +- /* ASPATH is shorter then NEW_ASPATH no way to merge */ ++ /* ASPATH is shorter then AS4_PATH no way to merge */ + attr_free(a, attr); + return; + } diff --git a/net/openbgpd/files/patch-bgpd_rde_decide.c b/net/openbgpd/files/patch-bgpd_rde_decide.c new file mode 100644 index 00000000000..425007c3f95 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_rde_decide.c @@ -0,0 +1,127 @@ +Index: bgpd/rde_decide.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_decide.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 +--- bgpd/rde_decide.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/rde_decide.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_decide.c,v 1.51 2008/05/08 09:51:46 henning Exp $ */ ++/* $OpenBSD: rde_decide.c,v 1.58 2009/06/29 14:10:13 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> +@@ -115,12 +115,6 @@ prefix_cmp(struct prefix *p1, struct pre + if (p2 == NULL) + return (1); + +- /* only prefixes in the Local-RIB are eligible */ +- if (!(p1->flags & F_LOCAL)) +- return (-1); +- if (!(p2->flags & F_LOCAL)) +- return (1); +- + asp1 = p1->aspath; + asp2 = p2->aspath; + +@@ -201,9 +195,16 @@ 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 */ ++ if ((asp1->flags & F_ANN_DYNAMIC) != (asp2->flags & F_ANN_DYNAMIC)) { ++ if (asp1->flags & F_ANN_DYNAMIC) ++ return (1); ++ else ++ return (-1); ++ } ++ + fatalx("Uh, oh a politician in the decision process"); + /* NOTREACHED */ +- return (0); + } + + /* +@@ -212,59 +213,59 @@ prefix_cmp(struct prefix *p1, struct pre + * The to evaluate prefix must not be in the prefix list. + */ + void +-prefix_evaluate(struct prefix *p, struct pt_entry *pte) ++prefix_evaluate(struct prefix *p, struct rib_entry *re) + { + struct prefix *xp; + +- if (rde_noevaluate()) { ++ if (re->flags & F_RIB_NOEVALUATE || rde_noevaluate()) { + /* decision process is turned off */ + if (p != NULL) +- LIST_INSERT_HEAD(&pte->prefix_h, p, prefix_l); +- if (pte->active != NULL) { +- pte->active->aspath->active_cnt--; +- pte->active = NULL; ++ LIST_INSERT_HEAD(&re->prefix_h, p, rib_l); ++ if (re->active != NULL) { ++ re->active->aspath->active_cnt--; ++ re->active = NULL; + } + return; + } + + if (p != NULL) { +- if (LIST_EMPTY(&pte->prefix_h)) +- LIST_INSERT_HEAD(&pte->prefix_h, p, prefix_l); ++ if (LIST_EMPTY(&re->prefix_h)) ++ LIST_INSERT_HEAD(&re->prefix_h, p, rib_l); + else { +- LIST_FOREACH(xp, &pte->prefix_h, prefix_l) ++ LIST_FOREACH(xp, &re->prefix_h, rib_l) + if (prefix_cmp(p, xp) > 0) { +- LIST_INSERT_BEFORE(xp, p, prefix_l); ++ LIST_INSERT_BEFORE(xp, p, rib_l); + break; +- } else if (LIST_NEXT(xp, prefix_l) == NULL) { ++ } else if (LIST_NEXT(xp, rib_l) == NULL) { + /* if xp last element ... */ +- LIST_INSERT_AFTER(xp, p, prefix_l); ++ LIST_INSERT_AFTER(xp, p, rib_l); + break; + } + } + } + +- xp = LIST_FIRST(&pte->prefix_h); +- if (xp == NULL || !(xp->flags & F_LOCAL) || +- xp->aspath->flags & F_ATTR_LOOP || ++ xp = LIST_FIRST(&re->prefix_h); ++ if (xp == NULL || xp->aspath->flags & F_ATTR_LOOP || + (xp->aspath->nexthop != NULL && + xp->aspath->nexthop->state != NEXTHOP_REACH)) + /* xp is ineligible */ + xp = NULL; + +- if (pte->active != xp) { ++ if (re->active != xp) { + /* need to generate an update */ +- if (pte->active != NULL) +- pte->active->aspath->active_cnt--; ++ if (re->active != NULL) ++ re->active->aspath->active_cnt--; + + /* +- * Send update with remove for pte->active and add for xp ++ * Send update with remove for re->active and add for xp + * but remember that xp may be NULL aka ineligible. + * Additional decision may be made by the called functions. + */ +- rde_generate_updates(xp, pte->active); +- rde_send_kroute(xp, pte->active); ++ rde_generate_updates(re->ribid, xp, re->active); ++ if ((re->flags & F_RIB_NOFIB) == 0) ++ rde_send_kroute(xp, re->active); + +- pte->active = xp; ++ re->active = xp; + if (xp != NULL) + xp->aspath->active_cnt++; + } diff --git a/net/openbgpd/files/patch-bgpd_rde_filter.c b/net/openbgpd/files/patch-bgpd_rde_filter.c index a26ad64e42c..a9004869e8b 100644 --- a/net/openbgpd/files/patch-bgpd_rde_filter.c +++ b/net/openbgpd/files/patch-bgpd_rde_filter.c @@ -2,11 +2,49 @@ Index: bgpd/rde_filter.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_filter.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 --- bgpd/rde_filter.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_filter.c 30 Jun 2009 06:51:37 -0000 1.2 -@@ -614,4 +614,5 @@ filterset_name(enum action_types type) ++++ bgpd/rde_filter.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_filter.c,v 1.54 2008/06/15 10:19:21 claudio Exp $ */ ++/* $OpenBSD: rde_filter.c,v 1.56 2009/06/06 01:10:29 claudio Exp $ */ + + /* + * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> +@@ -30,7 +30,7 @@ int rde_filter_match(struct filter_rule + int filterset_equal(struct filter_set_head *, struct filter_set_head *); + + enum filter_actions +-rde_filter(struct rde_aspath **new, struct filter_head *rules, ++rde_filter(u_int16_t ribid, struct rde_aspath **new, struct filter_head *rules, + struct rde_peer *peer, struct rde_aspath *asp, struct bgpd_addr *prefix, + u_int8_t prefixlen, struct rde_peer *from, enum directions dir) + { +@@ -43,6 +43,8 @@ rde_filter(struct rde_aspath **new, stru + TAILQ_FOREACH(f, rules, entry) { + if (dir != f->dir) + continue; ++ if (dir == DIR_IN && f->peer.ribid != ribid) ++ continue; + if (f->peer.groupid != 0 && + f->peer.groupid != peer->conf.groupid) + continue; +@@ -283,8 +285,11 @@ rde_filter_match(struct filter_rule *f, + return (0); + } + +- if (f->match.prefix.addr.af != 0 && +- f->match.prefix.addr.af == prefix->af) { ++ if (f->match.prefix.addr.af != 0) { ++ if (f->match.prefix.addr.af != prefix->af) ++ /* don't use IPv4 rules for IPv6 and vice versa */ ++ return (0); ++ + if (prefix_compare(prefix, &f->match.prefix.addr, + f->match.prefix.len)) + return (0); +@@ -614,4 +619,5 @@ filterset_name(enum action_types type) } fatalx("filterset_name: got lost"); diff --git a/net/openbgpd/files/patch-bgpd_rde_prefix.c b/net/openbgpd/files/patch-bgpd_rde_prefix.c index ff797e12660..60093010f27 100644 --- a/net/openbgpd/files/patch-bgpd_rde_prefix.c +++ b/net/openbgpd/files/patch-bgpd_rde_prefix.c @@ -2,16 +2,331 @@ Index: bgpd/rde_prefix.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_prefix.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 --- bgpd/rde_prefix.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_prefix.c 30 Jun 2009 06:42:23 -0000 1.2 -@@ -365,7 +365,7 @@ pt_free(struct pt_entry *pte) - static struct pt_entry * - pt_restart(struct pt_context *ctx) ++++ bgpd/rde_prefix.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_prefix.c,v 1.25 2007/05/11 11:27:59 claudio Exp $ */ ++/* $OpenBSD: rde_prefix.c,v 1.29 2009/05/30 18:27:17 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> +@@ -40,46 +40,30 @@ + * pt_init: initialize prefix table. + * pt_alloc?: allocate a AF specific pt_entry. Internal function. + * pt_free: free a pt_entry. Internal function. +- * pt_restart used to restart a tree walk at the spot it was aborted earlier. + */ + + /* internal prototypes */ + static struct pt_entry4 *pt_alloc4(void); + static struct pt_entry6 *pt_alloc6(void); + static void pt_free(struct pt_entry *); +-static struct pt_entry *pt_restart(struct pt_context *); + +-int pt_prefix_cmp(const struct pt_entry *, const struct pt_entry *); +- +-#define MIN_PREFIX 0 +-#define MAX_PREFIX 32 + 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); + +-struct pt_tree pttable4; +-struct pt_tree pttable6; ++struct pt_tree pttable; + + void + pt_init(void) { -- struct pt_entry *tmp, *prev = NULL; -+ struct pt_entry *tmp = NULL, *prev = NULL; - int comp; +- RB_INIT(&pttable4); +- RB_INIT(&pttable6); ++ RB_INIT(&pttable); + } + + void + pt_shutdown(void) + { +- if (!RB_EMPTY(&pttable4)) +- log_debug("pt_shutdown: IPv4 tree is not empty."); +- if (!RB_EMPTY(&pttable6)) +- log_debug("pt_shutdown: IPv6 tree is not empty."); +-} +- +-int +-pt_empty(struct pt_entry *pte) +-{ +- return LIST_EMPTY(&pte->prefix_h); ++ if (!RB_EMPTY(&pttable)) ++ log_debug("pt_shutdown: tree is not empty."); + } + + void +@@ -103,14 +87,15 @@ pt_getaddr(struct pt_entry *pte, struct + } + + struct pt_entry * +-pt_get(struct bgpd_addr *prefix, int prefixlen) ++pt_fill(struct bgpd_addr *prefix, int prefixlen) + { +- struct pt_entry4 pte4; +- struct pt_entry6 pte6; ++ static struct pt_entry4 pte4; ++ static struct pt_entry6 pte6; + in_addr_t addr_hbo; + + switch (prefix->af) { + case AF_INET: ++ bzero(&pte4, sizeof(pte4)); + if (prefixlen > 32) + fatalx("pt_get: bad IPv4 prefixlen"); + pte4.af = AF_INET; +@@ -118,24 +103,33 @@ pt_get(struct bgpd_addr *prefix, int pre + pte4.prefix4.s_addr = htonl(addr_hbo & + prefixlen2mask(prefixlen)); + pte4.prefixlen = prefixlen; +- return RB_FIND(pt_tree, &pttable4, (struct pt_entry *)&pte4); ++ return ((struct pt_entry *)&pte4); + case AF_INET6: ++ bzero(&pte6, sizeof(pte6)); + if (prefixlen > 128) + fatalx("pt_get: bad IPv6 prefixlen"); + pte6.af = AF_INET6; + pte6.prefixlen = prefixlen; + inet6applymask(&pte6.prefix6, &prefix->v6, prefixlen); +- return RB_FIND(pt_tree, &pttable6, (struct pt_entry *)&pte6); ++ return ((struct pt_entry *)&pte6); + default: + log_warnx("pt_get: unknown af"); ++ return (NULL); + } +- return (NULL); ++} ++ ++struct pt_entry * ++pt_get(struct bgpd_addr *prefix, int prefixlen) ++{ ++ struct pt_entry *pte; ++ ++ pte = pt_fill(prefix, prefixlen); ++ return RB_FIND(pt_tree, &pttable, pte); + } - /* first select correct tree */ + struct pt_entry * + pt_add(struct bgpd_addr *prefix, int prefixlen) + { +- struct pt_tree *tree = NULL; + struct pt_entry *p = NULL; + struct pt_entry4 *p4; + struct pt_entry6 *p6; +@@ -152,7 +146,6 @@ pt_add(struct bgpd_addr *prefix, int pre + p4->prefix4.s_addr = htonl(addr_hbo & + prefixlen2mask(prefixlen)); + p = (struct pt_entry *)p4; +- tree = &pttable4; + break; + case AF_INET6: + p6 = pt_alloc6(); +@@ -162,15 +155,13 @@ pt_add(struct bgpd_addr *prefix, int pre + p6->prefixlen = prefixlen; + inet6applymask(&p6->prefix6, &prefix->v6, prefixlen); + p = (struct pt_entry *)p6; +- tree = &pttable6; + break; + default: + fatalx("pt_add: unknown af"); + } +- LIST_INIT(&p->prefix_h); + +- if (RB_INSERT(pt_tree, tree, p) != NULL) { +- log_warnx("prefix_add: insert failed"); ++ if (RB_INSERT(pt_tree, &pttable, p) != NULL) { ++ log_warnx("pt_add: insert failed"); + return (NULL); + } + +@@ -181,101 +172,35 @@ void + pt_remove(struct pt_entry *pte) + { + if (!pt_empty(pte)) +- fatalx("pt_remove: entry not empty"); +- +- switch (pte->af) { +- case AF_INET: +- if (RB_REMOVE(pt_tree, &pttable4, pte) == NULL) +- log_warnx("pt_remove: remove failed."); +- break; +- case AF_INET6: +- if (RB_REMOVE(pt_tree, &pttable6, pte) == NULL) +- log_warnx("pt_remove: remove failed."); +- break; +- default: +- fatalx("pt_remove: unknown af"); +- } ++ fatalx("pt_remove: entry still holds references"); + ++ if (RB_REMOVE(pt_tree, &pttable, pte) == NULL) ++ log_warnx("pt_remove: remove failed."); + pt_free(pte); + } + + struct pt_entry * +-pt_lookup(struct bgpd_addr *prefix) ++pt_lookup(struct bgpd_addr *addr) + { + struct pt_entry *p; + int i; + +- switch (prefix->af) { ++ switch (addr->af) { + case AF_INET: +- for (i = 32; i >= 0; i--) { +- p = pt_get(prefix, i); +- if (p != NULL) +- return (p); +- } ++ i = 32; + break; + case AF_INET6: +- for (i = 128; i >= 0; i--) { +- p = pt_get(prefix, i); +- if (p != NULL) +- return (p); +- } ++ i = 128; + break; + default: + fatalx("pt_lookup: unknown af"); + } +- return (NULL); +-} +- +-void +-pt_dump(void (*upcall)(struct pt_entry *, void *), void *arg, sa_family_t af) +-{ +- if (af == AF_INET || af == AF_UNSPEC) +- pt_dump_r(upcall, arg, AF_INET, NULL); +- if (af == AF_INET6 || af == AF_UNSPEC) +- pt_dump_r(upcall, arg, AF_INET6, NULL); +-} +- +-void +-pt_dump_r(void (*upcall)(struct pt_entry *, void *), void *arg, +- sa_family_t af, struct pt_context *ctx) +-{ +- struct pt_entry *p; +- unsigned int i; +- +- if (ctx == NULL || ctx->ctx_p.af != af) { +- switch (af) { +- case AF_INET: +- p = RB_MIN(pt_tree, &pttable4); +- break; +- case AF_INET6: +- p = RB_MIN(pt_tree, &pttable6); +- break; +- default: +- return; +- } +- } else +- p = pt_restart(ctx); +- +- for (i = 0; p != NULL; p = RB_NEXT(pt_tree, unused, p)) { +- if (ctx && i++ >= ctx->count) { +- /* store next start point */ +- switch (p->af) { +- case AF_INET: +- ctx->ctx_p4 = *(struct pt_entry4 *)p; +- break; +- case AF_INET6: +- ctx->ctx_p6 = *(struct pt_entry6 *)p; +- break; +- default: +- fatalx("pt_dump_r: unknown af"); +- } +- return; +- } +- upcall(p, arg); ++ for (; i >= 0; i--) { ++ p = pt_get(addr, i); ++ if (p != NULL) ++ return (p); + } +- +- if (ctx) +- ctx->done = 1; ++ return (NULL); + } + + int +@@ -285,8 +210,10 @@ pt_prefix_cmp(const struct pt_entry *a, + const struct pt_entry6 *a6, *b6; + int i; + +- if (a->af != b->af) +- fatalx("king bula sez: comparing pears with apples"); ++ if (a->af > b->af) ++ return (1); ++ if (a->af < b->af) ++ return (-1); + + switch (a->af) { + case AF_INET: +@@ -361,56 +288,3 @@ pt_free(struct pt_entry *pte) + } + free(pte); + } +- +-static struct pt_entry * +-pt_restart(struct pt_context *ctx) +-{ +- struct pt_entry *tmp, *prev = NULL; +- int comp; +- +- /* first select correct tree */ +- switch (ctx->ctx_p.af) { +- case AF_INET: +- tmp = RB_ROOT(&pttable4); +- break; +- case AF_INET6: +- tmp = RB_ROOT(&pttable6); +- break; +- default: +- fatalx("pt_restart: unknown af"); +- } +- +- /* then try to find the element */ +- while (tmp) { +- prev = tmp; +- comp = pt_prefix_cmp(&ctx->ctx_p, tmp); +- if (comp < 0) +- tmp = RB_LEFT(tmp, pt_e); +- else if (comp > 0) +- tmp = RB_RIGHT(tmp, pt_e); +- else +- return (tmp); +- } +- +- /* no match, empty tree */ +- if (prev == NULL) +- return (NULL); +- +- /* +- * no perfect match +- * if last element was bigger use that as new start point +- */ +- if (comp < 0) +- return (prev); +- +- /* backtrack until parent is bigger */ +- do { +- prev = RB_PARENT(prev, pt_e); +- if (prev == NULL) +- /* all elements in the tree are smaler */ +- return (NULL); +- comp = pt_prefix_cmp(&ctx->ctx_p, prev); +- } while (comp > 0); +- +- return (prev); +-} diff --git a/net/openbgpd/files/patch-bgpd_rde_rib.c b/net/openbgpd/files/patch-bgpd_rde_rib.c index 86c48091c90..6bd5c74700c 100644 --- a/net/openbgpd/files/patch-bgpd_rde_rib.c +++ b/net/openbgpd/files/patch-bgpd_rde_rib.c @@ -2,10 +2,16 @@ Index: bgpd/rde_rib.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_rib.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 --- bgpd/rde_rib.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_rib.c 30 Jun 2009 06:40:07 -0000 1.2 ++++ bgpd/rde_rib.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_rib.c,v 1.96 2007/06/01 04:17:30 claudio Exp $ */ ++/* $OpenBSD: rde_rib.c,v 1.116 2009/06/29 14:13:48 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -18,7 +18,11 @@ #include <sys/types.h> @@ -18,3 +24,891 @@ diff -u -p -r1.1.1.1 -r1.2 #include <stdlib.h> #include <string.h> +@@ -33,14 +37,312 @@ + * Therefore one thing needs to be absolutely avoided, long table walks. + * This is achieved by heavily linking the different parts together. + */ ++u_int16_t rib_size; ++struct rib *ribs; ++ ++LIST_HEAD(, rib_context) rib_dump_h = LIST_HEAD_INITIALIZER(rib_dump_h); ++ ++struct rib_entry *rib_add(struct rib *, struct bgpd_addr *, int); ++int rib_compare(const struct rib_entry *, const struct rib_entry *); ++void rib_remove(struct rib_entry *); ++int rib_empty(struct rib_entry *); ++struct rib_entry *rib_restart(struct rib_context *); ++ ++RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare); ++RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare); ++ ++ ++/* RIB specific functions */ ++u_int16_t ++rib_new(int id, char *name, u_int16_t flags) ++{ ++ struct rib *xribs; ++ size_t newsize; ++ ++ if (id < 0) { ++ for (id = 0; id < rib_size; id++) { ++ if (*ribs[id].name == '\0') ++ break; ++ } ++ } ++ ++ if (id == RIB_FAILED) ++ fatalx("rib_new: trying to use reserved id"); ++ ++ if (id >= rib_size) { ++ newsize = sizeof(struct rib) * (id + 1); ++ if ((xribs = realloc(ribs, newsize)) == NULL) { ++ /* XXX this is not clever */ ++ fatal("rib_add"); ++ } ++ ribs = xribs; ++ rib_size = id + 1; ++ } ++ ++ 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].id = id; ++ ribs[id].flags = flags; ++ ++ return (id); ++} ++ ++u_int16_t ++rib_find(char *name) ++{ ++ u_int16_t id; ++ ++ if (name == NULL || *name == '\0') ++ return (1); /* XXX */ ++ ++ for (id = 0; id < rib_size; id++) { ++ if (!strcmp(ribs[id].name, name)) ++ return (id); ++ } ++ ++ return (RIB_FAILED); ++} ++ ++void ++rib_free(struct rib *rib) ++{ ++ struct rib_context *ctx, *next; ++ struct rib_entry *re, *xre; ++ struct prefix *p, *np; ++ ++ for (ctx = LIST_FIRST(&rib_dump_h); ctx != NULL; ctx = next) { ++ next = LIST_NEXT(ctx, entry); ++ if (ctx->ctx_rib == rib) { ++ re = ctx->ctx_re; ++ re->flags &= ~F_RIB_ENTRYLOCK; ++ LIST_REMOVE(ctx, entry); ++ if (ctx->ctx_done) ++ ctx->ctx_done(ctx->ctx_arg); ++ else ++ free(ctx); ++ } ++ } ++ ++ for (re = RB_MIN(rib_tree, &rib->rib); re != NULL; re = xre) { ++ xre = RB_NEXT(rib_tree, &rib->rib, re); ++ ++ /* ++ * Removing the prefixes is tricky because the last one ++ * will remove the rib_entry as well and at because we do ++ * a empty check in prefix_destroy() it is not possible to ++ * use the default for loop. ++ */ ++ while ((p = LIST_FIRST(&re->prefix_h))) { ++ np = LIST_NEXT(p, rib_l); ++ if (p->aspath->pftableid) { ++ struct bgpd_addr addr; ++ ++ pt_getaddr(p->prefix, &addr); ++ /* Commit is done in peer_down() */ ++ rde_send_pftable(p->aspath->pftableid, &addr, ++ p->prefix->prefixlen, 1); ++ } ++ prefix_destroy(p); ++ if (np == NULL) ++ break; ++ } ++ } ++ bzero(rib, sizeof(struct rib)); ++} ++ ++int ++rib_compare(const struct rib_entry *a, const struct rib_entry *b) ++{ ++ return (pt_prefix_cmp(a->prefix, b->prefix)); ++} ++ ++struct rib_entry * ++rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) ++{ ++ struct rib_entry xre; ++ struct pt_entry *pte; ++ ++ pte = pt_fill(prefix, prefixlen); ++ bzero(&xre, sizeof(xre)); ++ xre.prefix = pte; ++ ++ return (RB_FIND(rib_tree, &rib->rib, &xre)); ++} ++ ++struct rib_entry * ++rib_lookup(struct rib *rib, struct bgpd_addr *addr) ++{ ++ struct rib_entry *re; ++ int i; ++ ++ switch (addr->af) { ++ case AF_INET: ++ for (i = 32; i >= 0; i--) { ++ re = rib_get(rib, addr, i); ++ if (re != NULL) ++ return (re); ++ } ++ break; ++ case AF_INET6: ++ for (i = 128; i >= 0; i--) { ++ re = rib_get(rib, addr, i); ++ if (re != NULL) ++ return (re); ++ } ++ break; ++ default: ++ fatalx("rib_lookup: unknown af"); ++ } ++ return (NULL); ++} ++ ++ ++struct rib_entry * ++rib_add(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) ++{ ++ struct pt_entry *pte; ++ struct rib_entry *re; ++ ++ pte = pt_get(prefix, prefixlen); ++ if (pte == NULL) ++ pte = pt_add(prefix, prefixlen); ++ ++ if ((re = calloc(1, sizeof(*re))) == NULL) ++ fatal("rib_add"); ++ ++ LIST_INIT(&re->prefix_h); ++ re->prefix = pte; ++ re->flags = rib->flags; ++ re->ribid = rib->id; ++ ++ if (RB_INSERT(rib_tree, &rib->rib, re) != NULL) { ++ log_warnx("rib_add: insert failed"); ++ return (NULL); ++ } ++ ++ pt_ref(pte); ++ ++ rdemem.rib_cnt++; ++ ++ return (re); ++} ++ ++void ++rib_remove(struct rib_entry *re) ++{ ++ if (!rib_empty(re)) ++ fatalx("rib_remove: entry not empty"); ++ ++ if (re->flags & F_RIB_ENTRYLOCK) ++ /* entry is locked, don't free it. */ ++ return; ++ ++ pt_unref(re->prefix); ++ if (pt_empty(re->prefix)) ++ pt_remove(re->prefix); ++ ++ if (RB_REMOVE(rib_tree, &ribs[re->ribid].rib, re) == NULL) ++ log_warnx("rib_remove: remove failed."); ++ ++ free(re); ++ rdemem.rib_cnt--; ++} ++ ++int ++rib_empty(struct rib_entry *re) ++{ ++ return LIST_EMPTY(&re->prefix_h); ++} ++ ++void ++rib_dump(struct rib *rib, void (*upcall)(struct rib_entry *, void *), ++ void *arg, sa_family_t af) ++{ ++ struct rib_context *ctx; ++ ++ if ((ctx = calloc(1, sizeof(*ctx))) == NULL) ++ fatal("rib_dump"); ++ ctx->ctx_rib = rib; ++ ctx->ctx_upcall = upcall; ++ ctx->ctx_arg = arg; ++ ctx->ctx_af = af; ++ rib_dump_r(ctx); ++} ++ ++void ++rib_dump_r(struct rib_context *ctx) ++{ ++ struct rib_entry *re; ++ unsigned int i; ++ ++ if (ctx->ctx_re == NULL) { ++ re = RB_MIN(rib_tree, &ctx->ctx_rib->rib); ++ LIST_INSERT_HEAD(&rib_dump_h, ctx, entry); ++ } else ++ 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) ++ continue; ++ if (ctx->ctx_count && i++ >= ctx->ctx_count && ++ (re->flags & F_RIB_ENTRYLOCK) == 0) { ++ /* store and lock last element */ ++ ctx->ctx_re = re; ++ re->flags |= F_RIB_ENTRYLOCK; ++ return; ++ } ++ ctx->ctx_upcall(re, ctx->ctx_arg); ++ } ++ ++ LIST_REMOVE(ctx, entry); ++ if (ctx->ctx_done) ++ ctx->ctx_done(ctx->ctx_arg); ++ else ++ free(ctx); ++} ++ ++struct rib_entry * ++rib_restart(struct rib_context *ctx) ++{ ++ struct rib_entry *re; ++ ++ re = ctx->ctx_re; ++ re->flags &= ~F_RIB_ENTRYLOCK; ++ ++ /* find first non empty element */ ++ while (rib_empty(re)) ++ re = RB_NEXT(rib_tree, unused, re); ++ ++ /* free the previously locked rib element if empty */ ++ if (rib_empty(ctx->ctx_re)) ++ rib_remove(ctx->ctx_re); ++ ctx->ctx_re = NULL; ++ return (re); ++} ++ ++void ++rib_dump_runner(void) ++{ ++ struct rib_context *ctx, *next; ++ ++ for (ctx = LIST_FIRST(&rib_dump_h); ctx != NULL; ctx = next) { ++ next = LIST_NEXT(ctx, entry); ++ rib_dump_r(ctx); ++ } ++} ++ ++int ++rib_dump_pending(void) ++{ ++ return (!LIST_EMPTY(&rib_dump_h)); ++} + + /* used to bump correct prefix counters */ +-#define PREFIX_COUNT(x, f, op) \ +- do { \ +- if (f & F_LOCAL) \ +- (x)->prefix_cnt += (op); \ +- if (f & F_ORIGINAL) \ +- (x)->adjrib_cnt += (op); \ ++#define PREFIX_COUNT(x, op) \ ++ do { \ ++ (x)->prefix_cnt += (op); \ + } while (0) + + /* path specific functions */ +@@ -83,62 +385,29 @@ path_shutdown(void) + free(pathtable.path_hashtbl); + } + +-void +-path_update(struct rde_peer *peer, struct rde_aspath *nasp, +- struct bgpd_addr *prefix, int prefixlen, u_int32_t flags) ++int ++path_update(struct rib *rib, struct rde_peer *peer, struct rde_aspath *nasp, ++ struct bgpd_addr *prefix, int prefixlen) + { + struct rde_aspath *asp; +- struct prefix *p, *oldp = NULL; ++ struct prefix *p; + +- if (flags & F_LOCAL) { ++ if (nasp->pftableid) { + rde_send_pftable(nasp->pftableid, prefix, prefixlen, 0); + rde_send_pftable_commit(); + } + + /* +- * First try to find a prefix in the specified RIB or in the +- * Adj-RIB-In. This works because Local-RIB has precedence over the +- * Adj-RIB-In. In the end this saves use some additional lookups. ++ * First try to find a prefix in the specified RIB. + */ +- if ((p = prefix_get(peer, prefix, prefixlen, flags | F_ORIGINAL)) != +- NULL) { +- do { +- if (path_compare(nasp, p->aspath) == 0) { +- if ((p->flags & flags) == 0) { +- if (oldp != NULL) { +- asp = oldp->aspath; +- prefix_destroy(oldp); +- if (path_empty(asp)) +- path_destroy(asp); +- } +- p->flags |= flags; +- PREFIX_COUNT(p->aspath, flags, 1); +- PREFIX_COUNT(peer, flags, 1); +- +- /* re-evaluate prefix */ +- LIST_REMOVE(p, prefix_l); +- prefix_evaluate(p, p->prefix); +- } +- /* update last change */ +- p->lastchange = time(NULL); +- return; +- } +- /* +- * If the prefix is not already part of the Adj-RIB-In +- * do a lookup in there. But keep the original prefix +- * around so that it can be removed later. +- */ +- if (p->flags & F_ORIGINAL) +- break; +- oldp = p; +- p = prefix_get(peer, prefix, prefixlen, F_ORIGINAL); +- } while (p != NULL); ++ if ((p = prefix_get(rib, peer, prefix, prefixlen, 0)) != NULL) { ++ if (path_compare(nasp, p->aspath) == 0) { ++ /* no change, update last change */ ++ p->lastchange = time(NULL); ++ return (0); ++ } + } + +- /* Do not try to move a prefix that is in the wrong RIB. */ +- if (p == NULL || (p->flags & flags) == 0) +- p = oldp; +- + /* + * Either the prefix does not exist or the path changed. + * In both cases lookup the new aspath to make sure it is not +@@ -152,9 +421,10 @@ path_update(struct rde_peer *peer, struc + + /* If the prefix was found move it else add it to the aspath. */ + if (p != NULL) +- prefix_move(asp, p, flags); ++ prefix_move(asp, p); + else +- prefix_add(asp, prefix, prefixlen, flags); ++ return (prefix_add(rib, asp, prefix, prefixlen)); ++ return (0); + } + + int +@@ -220,19 +490,20 @@ path_lookup(struct rde_aspath *aspath, s + void + path_remove(struct rde_aspath *asp) + { +- struct prefix *p; +- struct bgpd_addr addr; ++ struct prefix *p, *np; + +- while ((p = LIST_FIRST(&asp->prefix_h)) != NULL) { +- /* Commit is done in peer_down() */ +- pt_getaddr(p->prefix, &addr); +- if (p->flags & F_LOCAL) ++ for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = np) { ++ np = LIST_NEXT(p, path_l); ++ if (asp->pftableid) { ++ struct bgpd_addr addr; ++ ++ pt_getaddr(p->prefix, &addr); ++ /* Commit is done in peer_down() */ + rde_send_pftable(p->aspath->pftableid, &addr, + p->prefix->prefixlen, 1); +- ++ } + prefix_destroy(p); + } +- path_destroy(asp); + } + + /* this function is only called by prefix_remove and path_remove */ +@@ -240,8 +511,7 @@ void + path_destroy(struct rde_aspath *asp) + { + /* path_destroy can only unlink and free empty rde_aspath */ +- if (asp->prefix_cnt != 0 || asp->active_cnt != 0 || +- asp->adjrib_cnt != 0) ++ if (asp->prefix_cnt != 0 || asp->active_cnt != 0) + log_warnx("path_destroy: prefix count out of sync"); + + nexthop_unlink(asp); +@@ -354,8 +624,8 @@ path_put(struct rde_aspath *asp) + + static struct prefix *prefix_alloc(void); + static void prefix_free(struct prefix *); +-static void prefix_link(struct prefix *, struct pt_entry *, +- struct rde_aspath *, u_int32_t); ++static void prefix_link(struct prefix *, struct rib_entry *, ++ struct rde_aspath *); + static void prefix_unlink(struct prefix *); + + int +@@ -404,51 +674,52 @@ prefix_compare(const struct bgpd_addr *a + * search for specified prefix of a peer. Returns NULL if not found. + */ + struct prefix * +-prefix_get(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen, +- u_int32_t flags) ++prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix, ++ int prefixlen, u_int32_t flags) + { +- struct pt_entry *pte; ++ struct rib_entry *re; + +- pte = pt_get(prefix, prefixlen); +- if (pte == NULL) ++ re = rib_get(rib, prefix, prefixlen); ++ if (re == NULL) + return (NULL); +- return (prefix_bypeer(pte, peer, flags)); ++ return (prefix_bypeer(re, peer, flags)); + } + + /* + * Adds or updates a prefix. + */ +-struct pt_entry * +-prefix_add(struct rde_aspath *asp, struct bgpd_addr *prefix, int prefixlen, +- u_int32_t flags) ++int ++prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix, ++ int prefixlen) + + { +- struct prefix *p; +- struct pt_entry *pte; ++ struct prefix *p; ++ struct rib_entry *re; + +- pte = pt_get(prefix, prefixlen); +- if (pte == NULL) +- pte = pt_add(prefix, prefixlen); ++ re = rib_get(rib, prefix, prefixlen); ++ if (re == NULL) ++ re = rib_add(rib, prefix, prefixlen); + +- p = prefix_bypeer(pte, asp->peer, flags); ++ p = prefix_bypeer(re, asp->peer, asp->flags); + if (p == NULL) { + p = prefix_alloc(); +- prefix_link(p, pte, asp, flags); ++ prefix_link(p, re, asp); ++ return (1); + } else { +- if (p->aspath != asp) ++ if (p->aspath != asp) { + /* prefix belongs to a different aspath so move */ +- return (prefix_move(asp, p, flags)); +- p->lastchange = time(NULL); ++ prefix_move(asp, p); ++ } else ++ p->lastchange = time(NULL); ++ return (0); + } +- +- return (pte); + } + + /* + * Move the prefix to the specified as path, removes the old asp if needed. + */ +-struct pt_entry * +-prefix_move(struct rde_aspath *asp, struct prefix *p, u_int32_t flags) ++void ++prefix_move(struct rde_aspath *asp, struct prefix *p) + { + struct prefix *np; + struct rde_aspath *oasp; +@@ -461,45 +732,18 @@ prefix_move(struct rde_aspath *asp, stru + np->aspath = asp; + /* peer and prefix pointers are still equal */ + np->prefix = p->prefix; ++ np->rib = p->rib; + np->lastchange = time(NULL); +- np->flags = flags; + + /* add to new as path */ + LIST_INSERT_HEAD(&asp->prefix_h, np, path_l); +- PREFIX_COUNT(asp, flags, 1); ++ PREFIX_COUNT(asp, 1); + /* + * no need to update the peer prefix count because we are only moving + * the prefix without changing the peer. + */ + + /* +- * fiddle around with the flags. If the p->flags is not equal +- * to flags the old prefix p may not be removed but instead p->flags +- * needs to be adjusted. +- */ +- if (p->flags != flags) { +- if ((p->flags & flags) == 0) +- fatalx("prefix_move: " +- "prefix is not part of desired RIB"); +- +- p->flags &= ~flags; +- PREFIX_COUNT(p->aspath, flags, -1); +- /* as before peer count needs no update because of move */ +- +- /* redo the route decision for p */ +- LIST_REMOVE(p, prefix_l); +- /* If the prefix is the active one remove it first. */ +- if (p == p->prefix->active) +- prefix_evaluate(NULL, p->prefix); +- prefix_evaluate(p, p->prefix); +- +- /* and now for np */ +- prefix_evaluate(np, np->prefix); +- +- return (np->prefix); +- } +- +- /* + * First kick the old prefix node out of the prefix list, + * afterwards run the route decision for new prefix node. + * Because of this only one update is generated if the prefix +@@ -507,78 +751,57 @@ prefix_move(struct rde_aspath *asp, stru + * This is save because we create a new prefix and so the change + * is noticed by prefix_evaluate(). + */ +- LIST_REMOVE(p, prefix_l); +- prefix_evaluate(np, np->prefix); ++ LIST_REMOVE(p, rib_l); ++ prefix_evaluate(np, np->rib); + + /* remove old prefix node */ + oasp = p->aspath; + LIST_REMOVE(p, path_l); +- PREFIX_COUNT(oasp, flags, -1); ++ PREFIX_COUNT(oasp, -1); + /* as before peer count needs no update because of move */ + + /* destroy all references to other objects and free the old prefix */ + p->aspath = NULL; + p->prefix = NULL; ++ p->rib = NULL; + prefix_free(p); + + /* destroy old path if empty */ + if (path_empty(oasp)) + path_destroy(oasp); +- +- return (np->prefix); + } + + /* + * Removes a prefix from all lists. If the parent objects -- path or + * pt_entry -- become empty remove them too. + */ +-void +-prefix_remove(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen, +- u_int32_t flags) ++int ++prefix_remove(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix, ++ int prefixlen, u_int32_t flags) + { + struct prefix *p; +- struct pt_entry *pte; ++ struct rib_entry *re; + struct rde_aspath *asp; + +- pte = pt_get(prefix, prefixlen); +- if (pte == NULL) /* Got a dummy withdrawn request */ +- return; ++ re = rib_get(rib, prefix, prefixlen); ++ if (re == NULL) /* Got a dummy withdrawn request */ ++ return (0); + +- p = prefix_bypeer(pte, peer, flags); ++ p = prefix_bypeer(re, peer, flags); + if (p == NULL) /* Got a dummy withdrawn request. */ +- return; ++ return (0); + + asp = p->aspath; + +- if (p->flags & F_LOCAL) { ++ if (asp->pftableid) { + /* only prefixes in the local RIB were pushed into pf */ + rde_send_pftable(asp->pftableid, prefix, prefixlen, 1); + rde_send_pftable_commit(); + } + +- /* if prefix belongs to more than one RIB just remove one instance */ +- if (p->flags != flags) { +- p->flags &= ~flags; +- +- PREFIX_COUNT(p->aspath, flags, -1); +- PREFIX_COUNT(peer, flags, -1); +- +- /* redo the route decision for p */ +- LIST_REMOVE(p, prefix_l); +- /* If the prefix is the active one remove it first. */ +- if (p == p->prefix->active) +- prefix_evaluate(NULL, p->prefix); +- prefix_evaluate(p, p->prefix); +- return; +- } +- +- prefix_unlink(p); +- prefix_free(p); ++ prefix_destroy(p); + +- if (pt_empty(pte)) +- pt_remove(pte); +- if (path_empty(asp)) +- path_destroy(asp); ++ return (1); + } + + /* dump a prefix into specified buffer */ +@@ -604,36 +827,50 @@ prefix_write(u_char *buf, int len, struc + * belonging to the peer peer. Returns NULL if no match found. + */ + struct prefix * +-prefix_bypeer(struct pt_entry *pte, struct rde_peer *peer, u_int32_t flags) ++prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t flags) + { + struct prefix *p; + +- LIST_FOREACH(p, &pte->prefix_h, prefix_l) { +- if (p->aspath->peer == peer && p->flags & flags) +- return (p); ++ LIST_FOREACH(p, &re->prefix_h, rib_l) { ++ if (p->aspath->peer != peer) ++ continue; ++ if (p->aspath->flags & flags && ++ (flags & F_ANN_DYNAMIC) != ++ (p->aspath->flags & F_ANN_DYNAMIC)) ++ continue; ++ return (p); + } + return (NULL); + } + + void +-prefix_updateall(struct rde_aspath *asp, enum nexthop_state state) ++prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, ++ enum nexthop_state oldstate) + { + struct prefix *p; + +- if (rde_noevaluate()) +- /* if the decision process is turned off this is a no-op */ +- return; +- + LIST_FOREACH(p, &asp->prefix_h, path_l) { + /* +- * skip non local-RIB nodes, only local-RIB prefixes are +- * eligible. Both F_LOCAL and F_ORIGINAL may be set. ++ * skip non local-RIBs or RIBs that are flagged as noeval. + */ +- if (!(p->flags & F_LOCAL)) ++ if (p->rib->flags & F_RIB_NOEVALUATE) + continue; + ++ if (oldstate == state && state == NEXTHOP_REACH) { ++ /* ++ * The state of the nexthop did not change. The only ++ * thing that may have changed is the true_nexthop ++ * or other internal infos. This will not change ++ * the routing decision so shortcut here. ++ */ ++ if ((p->rib->flags & F_RIB_NOFIB) == 0 && ++ p == p->rib->active) ++ rde_send_kroute(p, NULL); ++ continue; ++ } ++ + /* redo the route decision */ +- LIST_REMOVE(p, prefix_l); ++ LIST_REMOVE(p, rib_l); + /* + * If the prefix is the active one remove it first, + * this has to be done because we can not detect when +@@ -642,31 +879,35 @@ prefix_updateall(struct rde_aspath *asp, + * prefix_evaluate() will generate no update because + * the nexthop is unreachable or ineligible. + */ +- if (p == p->prefix->active) +- prefix_evaluate(NULL, p->prefix); +- prefix_evaluate(p, p->prefix); ++ if (p == p->rib->active) ++ prefix_evaluate(NULL, p->rib); ++ prefix_evaluate(p, p->rib); + } + } + +-/* kill a prefix. Only called by path_remove and path_update. */ ++/* kill a prefix. */ + void + prefix_destroy(struct prefix *p) + { +- struct pt_entry *pte; ++ struct rib_entry *re; ++ struct rde_aspath *asp; + +- pte = p->prefix; ++ re = p->rib; ++ asp = p->aspath; + prefix_unlink(p); + prefix_free(p); + +- if (pt_empty(pte)) +- pt_remove(pte); ++ if (rib_empty(re)) ++ rib_remove(re); ++ if (path_empty(asp)) ++ path_destroy(asp); + } + + /* + * helper function to clean up the connected networks after a reload + */ + void +-prefix_network_clean(struct rde_peer *peer, time_t reloadtime) ++prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags) + { + struct rde_aspath *asp, *xasp; + struct prefix *p, *xp; +@@ -674,6 +915,8 @@ prefix_network_clean(struct rde_peer *pe + + for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = xasp) { + xasp = LIST_NEXT(asp, peer_l); ++ 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) { +@@ -694,20 +937,19 @@ prefix_network_clean(struct rde_peer *pe + * Link a prefix into the different parent objects. + */ + static void +-prefix_link(struct prefix *pref, struct pt_entry *pte, struct rde_aspath *asp, +- u_int32_t flags) ++prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp) + { + LIST_INSERT_HEAD(&asp->prefix_h, pref, path_l); +- PREFIX_COUNT(asp, flags, 1); +- PREFIX_COUNT(asp->peer, flags, 1); ++ PREFIX_COUNT(asp, 1); + + pref->aspath = asp; +- pref->prefix = pte; ++ pref->rib = re; ++ pref->prefix = re->prefix; ++ pt_ref(pref->prefix); + pref->lastchange = time(NULL); +- pref->flags = flags; + + /* make route decision */ +- prefix_evaluate(pref, pte); ++ prefix_evaluate(pref, re); + } + + /* +@@ -716,17 +958,23 @@ prefix_link(struct prefix *pref, struct + static void + prefix_unlink(struct prefix *pref) + { +- /* make route decision */ +- LIST_REMOVE(pref, prefix_l); +- prefix_evaluate(NULL, pref->prefix); ++ if (pref->rib) { ++ /* make route decision */ ++ LIST_REMOVE(pref, rib_l); ++ prefix_evaluate(NULL, pref->rib); ++ } + + LIST_REMOVE(pref, path_l); +- PREFIX_COUNT(pref->aspath, pref->flags, -1); +- PREFIX_COUNT(pref->aspath->peer, pref->flags, -1); ++ PREFIX_COUNT(pref->aspath, -1); ++ ++ pt_unref(pref->prefix); ++ if (pt_empty(pref->prefix)) ++ pt_remove(pref->prefix); + + /* destroy all references to other objects */ + pref->aspath = NULL; + pref->prefix = NULL; ++ pref->rib = NULL; + + /* + * It's the caller's duty to remove empty aspath respectively pt_entry +@@ -817,6 +1065,7 @@ nexthop_update(struct kroute_nexthop *ms + { + struct nexthop *nh; + struct rde_aspath *asp; ++ enum nexthop_state oldstate; + + nh = nexthop_lookup(&msg->nexthop); + if (nh == NULL) { +@@ -825,15 +1074,16 @@ 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; + else + nh->state = NEXTHOP_UNREACH; + +- if (nexthop_delete(nh)) +- /* nexthop no longer used */ +- return; +- + if (msg->connected) { + nh->flags |= NEXTHOP_CONNECTED; + memcpy(&nh->true_nexthop, &nh->exit_nexthop, +@@ -866,7 +1116,7 @@ nexthop_update(struct kroute_nexthop *ms + return; + + LIST_FOREACH(asp, &nh->path_h, nexthop_l) { +- prefix_updateall(asp, nh->state); ++ prefix_updateall(asp, nh->state, oldstate); + } + } + diff --git a/net/openbgpd/files/patch-bgpd_rde_update.c b/net/openbgpd/files/patch-bgpd_rde_update.c index 05514097c69..8a611da33d9 100644 --- a/net/openbgpd/files/patch-bgpd_rde_update.c +++ b/net/openbgpd/files/patch-bgpd_rde_update.c @@ -2,10 +2,16 @@ Index: bgpd/rde_update.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_update.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 --- bgpd/rde_update.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_update.c 30 Jun 2009 06:40:07 -0000 1.2 ++++ bgpd/rde_update.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: rde_update.c,v 1.61 2007/11/27 01:13:54 claudio Exp $ */ ++/* $OpenBSD: rde_update.c,v 1.68 2009/06/06 01:10:29 claudio Exp $ */ + + /* + * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -17,10 +17,17 @@ */ #include <sys/types.h> @@ -24,3 +30,154 @@ diff -u -p -r1.1.1.1 -r1.2 #include "bgpd.h" #include "rde.h" +@@ -360,7 +367,7 @@ up_generate(struct rde_peer *peer, struc + if (asp) { + ua = calloc(1, sizeof(struct update_attr)); + if (ua == NULL) +- fatal("up_generate_updates"); ++ fatal("up_generate"); + + if (up_generate_attr(peer, ua, asp, addr->af) == -1) { + log_warnx("generation of bgp path attributes failed"); +@@ -379,7 +386,7 @@ up_generate(struct rde_peer *peer, struc + + up = calloc(1, sizeof(struct update_prefix)); + if (up == NULL) +- fatal("up_generate_updates"); ++ fatal("up_generate"); + up->prefix = *addr; + up->prefixlen = prefixlen; + +@@ -404,9 +411,9 @@ up_generate_updates(struct filter_head * + return; + + pt_getaddr(old->prefix, &addr); +- if (rde_filter(NULL, rules, peer, old->aspath, &addr, +- old->prefix->prefixlen, old->aspath->peer, DIR_OUT) == +- ACTION_DENY) ++ if (rde_filter(peer->ribid, NULL, rules, peer, old->aspath, ++ &addr, old->prefix->prefixlen, old->aspath->peer, ++ DIR_OUT) == ACTION_DENY) + return; + + /* withdraw prefix */ +@@ -423,9 +430,9 @@ up_generate_updates(struct filter_head * + } + + pt_getaddr(new->prefix, &addr); +- if (rde_filter(&asp, rules, peer, new->aspath, &addr, +- new->prefix->prefixlen, new->aspath->peer, DIR_OUT) == +- ACTION_DENY) { ++ if (rde_filter(peer->ribid, &asp, rules, peer, new->aspath, ++ &addr, new->prefix->prefixlen, new->aspath->peer, ++ DIR_OUT) == ACTION_DENY) { + path_put(asp); + up_generate_updates(rules, peer, NULL, old); + return; +@@ -473,8 +480,8 @@ up_generate_default(struct filter_head * + bzero(&addr, sizeof(addr)); + addr.af = af; + +- if (rde_filter(&fasp, rules, peer, asp, &addr, 0, NULL, DIR_OUT) == +- ACTION_DENY) { ++ if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL, ++ DIR_OUT) == ACTION_DENY) { + path_put(fasp); + path_put(asp); + return; +@@ -617,7 +624,7 @@ up_generate_attr(struct rde_peer *peer, + u_char *pdata; + u_int32_t tmp32; + in_addr_t nexthop; +- int r, ismp = 0, neednewpath = 0; ++ int flags, r, ismp = 0, neednewpath = 0; + u_int16_t len = sizeof(up_attr_buf), wlen = 0, plen; + u_int8_t l; + +@@ -629,7 +636,7 @@ up_generate_attr(struct rde_peer *peer, + + /* aspath */ + if (!peer->conf.ebgp || +- rde_decisionflags() & BGPD_FLAG_DECISION_TRANS_AS) ++ peer->conf.flags & PEERFLAG_TRANS_AS) + pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); + else + pdata = aspath_prepend(a->aspath, rde_local_as(), 1, &plen); +@@ -762,25 +769,29 @@ up_generate_attr(struct rde_peer *peer, + /* NEW to OLD conversion when going sending stuff to a 2byte AS peer */ + if (neednewpath) { + if (!peer->conf.ebgp || +- rde_decisionflags() & BGPD_FLAG_DECISION_TRANS_AS) ++ peer->conf.flags & PEERFLAG_TRANS_AS) + pdata = aspath_prepend(a->aspath, rde_local_as(), 0, + &plen); + else + pdata = aspath_prepend(a->aspath, rde_local_as(), 1, + &plen); ++ flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; ++ if (!(a->flags & F_PREFIX_ANNOUNCED)) ++ flags |= ATTR_PARTIAL; + if (plen == 0) + r = 0; +- else if ((r = attr_write(up_attr_buf + wlen, len, +- ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_NEW_ASPATH, +- pdata, plen)) == -1) ++ else if ((r = attr_write(up_attr_buf + wlen, len, flags, ++ ATTR_AS4_PATH, pdata, plen)) == -1) + return (-1); + wlen += r; len -= r; + free(pdata); + } + if (newaggr) { +- if ((r = attr_write(up_attr_buf + wlen, len, +- ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_NEW_AGGREGATOR, +- newaggr->data, newaggr->len)) == -1) ++ flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; ++ if (!(a->flags & F_PREFIX_ANNOUNCED)) ++ flags |= ATTR_PARTIAL; ++ if ((r = attr_write(up_attr_buf + wlen, len, flags, ++ ATTR_AS4_AGGREGATOR, newaggr->data, newaggr->len)) == -1) + return (-1); + wlen += r; len -= r; + } +@@ -913,13 +924,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_ + return (NULL); + + datalen += 3; /* afi + safi */ +- if (datalen > 255) { +- attrlen += 2 + datalen; +- flags |= ATTR_EXTLEN; +- } else { +- attrlen += 1 + datalen; +- buf++; +- } ++ + /* prepend header, need to do it reverse */ + /* safi & afi */ + buf[--wpos] = SAFI_UNICAST; +@@ -929,11 +934,15 @@ up_dump_mp_unreach(u_char *buf, u_int16_ + + /* attribute length */ + if (datalen > 255) { ++ attrlen += 2 + datalen; ++ flags |= ATTR_EXTLEN; + wpos -= sizeof(u_int16_t); + tmp = htons(datalen); + memcpy(buf + wpos, &tmp, sizeof(u_int16_t)); +- } else ++ } else { ++ attrlen += 1 + datalen; + buf[--wpos] = (u_char)datalen; ++ } + + /* mp attribute */ + buf[--wpos] = (u_char)ATTR_MP_UNREACH_NLRI; +@@ -954,7 +963,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_ + /* total length includes the two 2-bytes length fields. */ + *len = attrlen + 2 * sizeof(u_int16_t); + +- return (buf); ++ return (buf + wpos); + } + + u_char * diff --git a/net/openbgpd/files/patch-bgpd_session.c b/net/openbgpd/files/patch-bgpd_session.c index 2106b555043..8abb370a3ac 100644 --- a/net/openbgpd/files/patch-bgpd_session.c +++ b/net/openbgpd/files/patch-bgpd_session.c @@ -2,10 +2,16 @@ Index: bgpd/session.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.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 --- bgpd/session.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/session.c 30 Jun 2009 06:40:07 -0000 1.2 ++++ bgpd/session.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: session.c,v 1.282 2008/06/26 00:01:51 claudio Exp $ */ ++/* $OpenBSD: session.c,v 1.293 2009/06/07 05:56:24 eric Exp $ */ + + /* + * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> @@ -52,6 +52,10 @@ #define PFD_SOCK_RCTL 4 #define PFD_LISTENERS_START 5 @@ -17,3 +23,308 @@ diff -u -p -r1.1.1.1 -r1.2 void session_sighdlr(int); int setup_listeners(u_int *); void init_conf(struct bgpd_config *); +@@ -177,8 +181,8 @@ 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, int pipe_m2s[2], int pipe_s2r[2], int pipe_m2r[2], +- int pipe_s2rctl[2]) ++ 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]) + { + int nfds, timeout; + unsigned int i, j, idx_peers, idx_listeners, idx_mrts; +@@ -195,6 +199,7 @@ session_main(struct bgpd_config *config, + struct pollfd *pfd = NULL; + struct ctl_conn *ctl_conn; + struct listen_addr *la; ++ struct rde_rib *rr; + void *newp; + short events; + +@@ -283,6 +288,11 @@ session_main(struct bgpd_config *config, + 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); ++ } + + while (session_quit == 0) { + /* check for peers to be initialized or deleted */ +@@ -341,7 +351,7 @@ session_main(struct bgpd_config *config, + + mrt_cnt = 0; + LIST_FOREACH(m, &mrthead, entry) +- if (m->queued) ++ if (m->wbuf.queued) + mrt_cnt++; + + if (mrt_cnt > mrt_l_elms) { +@@ -438,6 +448,12 @@ session_main(struct bgpd_config *config, + Timer_IdleHoldReset, + p->IdleHoldTime); + break; ++ case Timer_CarpUndemote: ++ timer_stop(p, Timer_CarpUndemote); ++ if (p->demoted && ++ p->state == STATE_ESTABLISHED) ++ session_demote(p, -1); ++ break; + default: + fatalx("King Bula lost in time"); + } +@@ -446,17 +462,6 @@ session_main(struct bgpd_config *config, + nextaction < timeout) + timeout = nextaction; + +- /* XXX carp demotion */ +- if (p->demoted && p->state == STATE_ESTABLISHED) { +- if (time(NULL) - p->stats.last_updown >= +- INTERVAL_HOLD_DEMOTED) +- session_demote(p, -1); +- if (p->stats.last_updown + INTERVAL_HOLD_DEMOTED +- - time(NULL) < timeout) +- timeout = p->stats.last_updown + +- INTERVAL_HOLD_DEMOTED - time(NULL); +- } +- + /* are we waiting for a write? */ + events = POLLIN; + if (p->wbuf.queued > 0 || p->state == STATE_CONNECT) +@@ -474,8 +479,8 @@ session_main(struct bgpd_config *config, + idx_peers = i; + + LIST_FOREACH(m, &mrthead, entry) +- if (m->queued) { +- pfd[i].fd = m->fd; ++ if (m->wbuf.queued) { ++ pfd[i].fd = m->wbuf.fd; + pfd[i].events = POLLOUT; + mrt_l[i - idx_peers] = m; + i++; +@@ -594,6 +599,8 @@ init_conf(struct bgpd_config *c) + { + if (!c->holdtime) + c->holdtime = INTERVAL_HOLD; ++ if (!c->connectretry) ++ c->connectretry = INTERVAL_CONNECTRETRY; + } + + void +@@ -668,7 +675,7 @@ bgp_fsm(struct peer *peer, enum session_ + } else { + change_state(peer, STATE_CONNECT, event); + timer_set(peer, Timer_ConnectRetry, +- INTERVAL_CONNECTRETRY); ++ conf->connectretry); + session_connect(peer); + } + peer->passive = 0; +@@ -693,13 +700,13 @@ bgp_fsm(struct peer *peer, enum session_ + break; + case EVNT_CON_OPENFAIL: + timer_set(peer, Timer_ConnectRetry, +- INTERVAL_CONNECTRETRY); ++ conf->connectretry); + session_close_connection(peer); + change_state(peer, STATE_ACTIVE, event); + break; + case EVNT_TIMER_CONNRETRY: + timer_set(peer, Timer_ConnectRetry, +- INTERVAL_CONNECTRETRY); ++ conf->connectretry); + session_connect(peer); + break; + default: +@@ -722,7 +729,7 @@ bgp_fsm(struct peer *peer, enum session_ + break; + case EVNT_CON_OPENFAIL: + timer_set(peer, Timer_ConnectRetry, +- INTERVAL_CONNECTRETRY); ++ conf->connectretry); + session_close_connection(peer); + change_state(peer, STATE_ACTIVE, event); + break; +@@ -749,7 +756,7 @@ bgp_fsm(struct peer *peer, enum session_ + case EVNT_CON_CLOSED: + session_close_connection(peer); + timer_set(peer, Timer_ConnectRetry, +- INTERVAL_CONNECTRETRY); ++ conf->connectretry); + change_state(peer, STATE_ACTIVE, event); + break; + case EVNT_CON_FATAL: +@@ -953,6 +960,9 @@ change_state(struct peer *peer, enum ses + break; + case STATE_ESTABLISHED: + timer_set(peer, Timer_IdleHoldReset, peer->IdleHoldTime); ++ if (peer->demoted) ++ timer_set(peer, Timer_CarpUndemote, ++ INTERVAL_HOLD_DEMOTED); + session_up(peer); + break; + default: /* something seriously fucked */ +@@ -961,13 +971,12 @@ change_state(struct peer *peer, enum ses + + log_statechange(peer, state, event); + LIST_FOREACH(mrt, &mrthead, entry) { +- if (mrt->type != MRT_ALL_IN && mrt->type != MRT_ALL_OUT) ++ if (!(mrt->type == MRT_ALL_IN || mrt->type == MRT_ALL_OUT)) + continue; + if ((mrt->peer_id == 0 && mrt->group_id == 0) || +- mrt->peer_id == peer->conf.id || +- mrt->group_id == peer->conf.groupid) +- mrt_dump_state(mrt, peer->state, state, +- peer, conf); ++ mrt->peer_id == peer->conf.id || (mrt->group_id != 0 && ++ mrt->group_id == peer->conf.groupid)) ++ mrt_dump_state(mrt, peer->state, state, peer); + } + peer->prev_state = peer->state; + peer->state = state; +@@ -1255,8 +1264,6 @@ session_capa_add(struct peer *p, struct + 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; +- if (buf_grow(opb, tot_len) == NULL) +- return (1); + 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)); +@@ -1317,22 +1324,16 @@ session_sendmsg(struct bgp_msg *msg, str + struct mrt *mrt; + + LIST_FOREACH(mrt, &mrthead, entry) { +- if (mrt->type != MRT_ALL_OUT && +- msg->type == UPDATE && mrt->type != MRT_UPDATE_OUT) ++ if (!(mrt->type == MRT_ALL_OUT || (msg->type == UPDATE && ++ mrt->type == MRT_UPDATE_OUT))) + continue; + if ((mrt->peer_id == 0 && mrt->group_id == 0) || +- mrt->peer_id == p->conf.id || +- mrt->group_id == p->conf.groupid) +- mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p, conf); +- } +- +- if (buf_close(&p->wbuf, msg->buf) == -1) { +- log_peer_warn(&p->conf, "session_sendmsg buf_close"); +- buf_free(msg->buf); +- free(msg); +- return (-1); ++ mrt->peer_id == p->conf.id || (mrt->group_id == 0 && ++ mrt->group_id == p->conf.groupid)) ++ mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p); + } + ++ buf_close(&p->wbuf, msg->buf); + free(msg); + return (0); + } +@@ -1348,7 +1349,7 @@ session_open(struct peer *p) + u_int errs = 0; + + +- if ((opb = buf_open(0)) == NULL) { ++ if ((opb = buf_dynamic(0, MAX_PKTSIZE - MSGSIZE_OPEN_MIN)) == NULL) { + bgp_fsm(p, EVNT_CON_FATAL); + return; + } +@@ -1394,10 +1395,7 @@ session_open(struct peer *p) + } + + msg.version = 4; +- if (conf->as > USHRT_MAX) +- msg.myas = htons(conf->short_as); +- else +- msg.myas = htons(conf->as); ++ msg.myas = htons(conf->short_as); + if (p->conf.holdtime) + msg.holdtime = htons(p->conf.holdtime); + else +@@ -1809,13 +1807,13 @@ parse_header(struct peer *peer, u_char * + return (-1); + } + LIST_FOREACH(mrt, &mrthead, entry) { +- if (mrt->type != MRT_ALL_IN && (mrt->type != MRT_UPDATE_IN || +- *type != UPDATE)) ++ if (!(mrt->type == MRT_ALL_IN || (*type == UPDATE && ++ mrt->type == MRT_UPDATE_IN))) + continue; + if ((mrt->peer_id == 0 && mrt->group_id == 0) || +- mrt->peer_id == peer->conf.id || +- mrt->group_id == peer->conf.groupid) +- mrt_dump_bgp_msg(mrt, data, *len, peer, conf); ++ mrt->peer_id == peer->conf.id || (mrt->group_id != 0 && ++ mrt->group_id == peer->conf.groupid)) ++ mrt_dump_bgp_msg(mrt, data, *len, peer); + } + return (0); + } +@@ -2193,22 +2191,20 @@ parse_capabilities(struct peer *peer, u_ + memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi)); + switch (mp_afi) { + case AFI_IPv4: +- if (mp_safi < 1 || mp_safi > 3) { ++ if (mp_safi < 1 || mp_safi > 3) + log_peer_warnx(&peer->conf, + "parse_capabilities: AFI IPv4, " +- "mp_safi %u illegal", mp_safi); +- return (-1); +- } +- peer->capa.peer.mp_v4 = mp_safi; ++ "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) { ++ if (mp_safi < 1 || mp_safi > 3) + log_peer_warnx(&peer->conf, + "parse_capabilities: AFI IPv6, " +- "mp_safi %u illegal", mp_safi); +- return (-1); +- } +- peer->capa.peer.mp_v6 = mp_safi; ++ "mp_safi %u unknown", mp_safi); ++ else ++ peer->capa.peer.mp_v6 = mp_safi; + break; + default: /* ignore */ + break; +@@ -2318,7 +2314,7 @@ session_dispatch_imsg(struct imsgbuf *ib + fatalx("king bula sez: " + "expected REINIT"); + +- if ((nla->fd = imsg_get_fd(ibuf)) == -1) ++ if ((nla->fd = imsg.fd) == -1) + log_warnx("expected to receive fd for " + "%s but didn't receive any", + log_sockaddr((struct sockaddr *) +@@ -2429,7 +2425,7 @@ session_dispatch_imsg(struct imsgbuf *ib + } + + memcpy(&xmrt, imsg.data, sizeof(struct mrt)); +- if ((xmrt.fd = imsg_get_fd(ibuf)) == -1) ++ if ((xmrt.wbuf.fd = imsg.fd) == -1) + log_warnx("expected to receive fd for mrt dump " + "but didn't receive any"); + +@@ -2440,12 +2436,12 @@ session_dispatch_imsg(struct imsgbuf *ib + if (mrt == NULL) + fatal("session_dispatch_imsg"); + memcpy(mrt, &xmrt, sizeof(struct mrt)); +- TAILQ_INIT(&mrt->bufs); ++ TAILQ_INIT(&mrt->wbuf.bufs); + LIST_INSERT_HEAD(&mrthead, mrt, entry); + } else { + /* old dump reopened */ +- close(mrt->fd); +- mrt->fd = xmrt.fd; ++ close(mrt->wbuf.fd); ++ mrt->wbuf.fd = xmrt.wbuf.fd; + } + break; + case IMSG_MRT_CLOSE: diff --git a/net/openbgpd/files/patch-bgpd_session.h b/net/openbgpd/files/patch-bgpd_session.h new file mode 100644 index 00000000000..ddd590114c1 --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_session.h @@ -0,0 +1,55 @@ +Index: bgpd/session.h +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.h,v +retrieving revision 1.1.1.1 +retrieving revision 1.1.1.2 +diff -u -p -r1.1.1.1 -r1.1.1.2 +--- bgpd/session.h 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/session.h 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: session.h,v 1.98 2008/05/08 09:53:12 henning Exp $ */ ++/* $OpenBSD: session.h,v 1.101 2009/06/05 20:26:38 claudio Exp $ */ + + /* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> +@@ -171,6 +171,7 @@ enum Timer { + Timer_Hold, + Timer_IdleHold, + Timer_IdleHoldReset, ++ Timer_CarpUndemote, + Timer_Max + }; + +@@ -227,7 +228,8 @@ struct ctl_timer { + 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 *, int[2], int[2], int[2], int[2]); ++ struct mrt_head *, struct rib_names *, ++ int[2], int[2], int[2], int[2]); + void bgp_fsm(struct peer *, enum session_events); + int session_neighbor_rrefresh(struct peer *p); + struct peer *getpeerbyaddr(struct bgpd_addr *); +@@ -254,8 +256,8 @@ void prepare_listeners(struct bgpd_conf + + /* rde.c */ + pid_t rde_main(struct bgpd_config *, struct peer *, struct network_head *, +- struct filter_head *, struct mrt_head *, int[2], int[2], int[2], +- int[2], int); ++ struct filter_head *, struct mrt_head *, struct rib_names *, ++ int[2], int[2], int[2], int[2], int); + + /* control.c */ + int control_init(int, char *); +@@ -270,8 +272,9 @@ int pfkey_remove(struct peer *); + int pfkey_init(struct bgpd_sysdep *); + + /* printconf.c */ +-void print_config(struct bgpd_config *, struct network_head *, struct peer *, +- struct filter_head *, struct mrt_head *); ++void print_config(struct bgpd_config *, struct rib_names *, ++ struct network_head *, struct peer *, struct filter_head *, ++ struct mrt_head *); + + /* carp.c */ + int carp_demote_init(char *, int); diff --git a/net/openbgpd/files/patch-bgpd_timer.c b/net/openbgpd/files/patch-bgpd_timer.c new file mode 100644 index 00000000000..f72ec2efebf --- /dev/null +++ b/net/openbgpd/files/patch-bgpd_timer.c @@ -0,0 +1,14 @@ +Index: bgpd/timer.c +=================================================================== +RCS file: /home/cvs/private/hrs/openbgpd/bgpd/timer.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 +--- bgpd/timer.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 ++++ bgpd/timer.c 9 Jul 2009 16:49:54 -0000 1.1.1.2 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: timer.c,v 1.12.2.1 2009/02/20 07:20:15 henning Exp $ */ ++/* $OpenBSD: timer.c,v 1.13 2009/01/21 20:32:53 henning Exp $ */ + + /* + * Copyright (c) 2003-2007 Henning Brauer <henning@openbsd.org> diff --git a/net/openbgpd/files/patch-bgpd_util.c b/net/openbgpd/files/patch-bgpd_util.c index defdb995ee6..85bb12c7ccc 100644 --- a/net/openbgpd/files/patch-bgpd_util.c +++ b/net/openbgpd/files/patch-bgpd_util.c @@ -2,10 +2,16 @@ Index: bgpd/util.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/util.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 --- bgpd/util.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/util.c 30 Jun 2009 06:40:07 -0000 1.2 ++++ bgpd/util.c 9 Jul 2009 17:22:14 -0000 1.3 +@@ -1,4 +1,4 @@ +-/* $OpenBSD: util.c,v 1.4 2008/03/17 20:40:04 henning Exp $ */ ++/* $OpenBSD: util.c,v 1.6 2009/06/12 16:42:53 claudio Exp $ */ + + /* + * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> @@ -18,6 +18,9 @@ */ #include <sys/types.h> @@ -16,3 +22,42 @@ diff -u -p -r1.1.1.1 -r1.2 #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> +@@ -143,7 +146,7 @@ aspath_snprint(char *buf, size_t size, v + UPDATE(); + } + } +- /* ensure that we have a valid C-string especially for emtpy as path */ ++ /* ensure that we have a valid C-string especially for empty as path */ + if (size > 0) + *buf = '\0'; + +@@ -250,3 +253,29 @@ aspath_extract(const void *seg, int pos) + memcpy(&as, ptr, sizeof(u_int32_t)); + return (ntohl(as)); + } ++ ++in_addr_t ++prefixlen2mask(u_int8_t prefixlen) ++{ ++ if (prefixlen == 0) ++ return (0); ++ ++ return (0xffffffff << (32 - prefixlen)); ++} ++ ++void ++inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) ++{ ++ struct in6_addr mask; ++ int i; ++ ++ bzero(&mask, sizeof(mask)); ++ for (i = 0; i < prefixlen / 8; i++) ++ mask.s6_addr[i] = 0xff; ++ i = prefixlen % 8; ++ if (i) ++ mask.s6_addr[prefixlen / 8] = 0xff00 >> i; ++ ++ for (i = 0; i < 16; i++) ++ dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; ++} diff --git a/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h b/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h index 01a61866c27..ab89a4aba90 100644 --- a/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h +++ b/net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h @@ -3,10 +3,10 @@ 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 30 Jun 2009 06:52:12 -0000 1.2 -@@ -0,0 +1,23 @@ ++++ openbsd-compat/openbsd-compat.h 9 Jul 2009 17:22:14 -0000 1.3 +@@ -0,0 +1,46 @@ +/* -+ * $hrs: openbgpd/openbsd-compat/openbsd-compat.h,v 1.2 2009/06/30 06:52:12 hrs Exp $ ++ * $hrs: openbgpd/openbsd-compat/openbsd-compat.h,v 1.3 2009/07/09 17:22:14 hrs Exp $ + */ + +#ifndef _OPENBSD_COMPAT_H @@ -27,4 +27,27 @@ diff -N openbsd-compat/openbsd-compat.h +#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 */ ++ +#endif /* _OPENBSD_COMPAT_H */ |