aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2009-07-19 15:31:04 +0800
committerhrs <hrs@FreeBSD.org>2009-07-19 15:31:04 +0800
commit785f10bf3723c60d1c213956b9e2bb9d2cac4aa3 (patch)
tree524a40b46c2d9507a9b14053306e1a4aebddf94e /net
parent4eea60c6dd564e9c12700a23529c5c81c6be07be (diff)
downloadfreebsd-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')
-rw-r--r--net/openbgpd/Makefile20
-rw-r--r--net/openbgpd/files/patch-bgpctl_bgpctl.841
-rw-r--r--net/openbgpd/files/patch-bgpctl_bgpctl.c121
-rw-r--r--net/openbgpd/files/patch-bgpctl_irr_asset.c23
-rw-r--r--net/openbgpd/files/patch-bgpctl_parser.c135
-rw-r--r--net/openbgpd/files/patch-bgpctl_parser.h29
-rw-r--r--net/openbgpd/files/patch-bgpd_Makefile14
-rw-r--r--net/openbgpd/files/patch-bgpd_bgpd.824
-rw-r--r--net/openbgpd/files/patch-bgpd_bgpd.c87
-rw-r--r--net/openbgpd/files/patch-bgpd_bgpd.conf.5136
-rw-r--r--net/openbgpd/files/patch-bgpd_bgpd.h384
-rw-r--r--net/openbgpd/files/patch-bgpd_buffer.c234
-rw-r--r--net/openbgpd/files/patch-bgpd_carp.c33
-rw-r--r--net/openbgpd/files/patch-bgpd_config.c23
-rw-r--r--net/openbgpd/files/patch-bgpd_control.c28
-rw-r--r--net/openbgpd/files/patch-bgpd_imsg.c264
-rw-r--r--net/openbgpd/files/patch-bgpd_imsg.h115
-rw-r--r--net/openbgpd/files/patch-bgpd_kroute.c1025
-rw-r--r--net/openbgpd/files/patch-bgpd_log.h21
-rw-r--r--net/openbgpd/files/patch-bgpd_mrt.c1002
-rw-r--r--net/openbgpd/files/patch-bgpd_mrt.h208
-rw-r--r--net/openbgpd/files/patch-bgpd_name2id.c14
-rw-r--r--net/openbgpd/files/patch-bgpd_parse.y445
-rw-r--r--net/openbgpd/files/patch-bgpd_pfkey.c81
-rw-r--r--net/openbgpd/files/patch-bgpd_printconf.c121
-rw-r--r--net/openbgpd/files/patch-bgpd_rde.c1572
-rw-r--r--net/openbgpd/files/patch-bgpd_rde.h309
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_attr.c53
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_decide.c127
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_filter.c46
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_prefix.c335
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_rib.c900
-rw-r--r--net/openbgpd/files/patch-bgpd_rde_update.c163
-rw-r--r--net/openbgpd/files/patch-bgpd_session.c317
-rw-r--r--net/openbgpd/files/patch-bgpd_session.h55
-rw-r--r--net/openbgpd/files/patch-bgpd_timer.c14
-rw-r--r--net/openbgpd/files/patch-bgpd_util.c51
-rw-r--r--net/openbgpd/files/patch-openbsd-compat_openbsd-compat.h29
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 */