summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2007-04-23 13:04:24 +0000
committerclaudio <claudio@openbsd.org>2007-04-23 13:04:24 +0000
commit0c88bf70c0a32b8b136f16df8694c401ec527219 (patch)
tree3d77d6b93907f8b7f461f88cff1677a0b617eb73
parentincrement opackets and ipackets. clear OACTIVE when tx completes. (diff)
downloadwireguard-openbsd-0c88bf70c0a32b8b136f16df8694c401ec527219.tar.xz
wireguard-openbsd-0c88bf70c0a32b8b136f16df8694c401ec527219.zip
Make bgpd 4-byte AS compatible. All internal representations of AS numbers
are now 4-byte instead of the old 2-byte numbers. The only exception are communities because they can not be switched. The RDE will inflate and deflate the ASPATH and AGGREGATOR attributes on demand and create the NEW_ASPATH and NEW_AGGREGATOR field whenever needed. Both old and new stile sessions are supported and can be mixed. Currently new stile sessions with the 4-byte AS number capability turned on are only enabled if one of the AS numbers involved is a 4-byte one. This is based on an initial diff by Geoff Huston gih (at) apnic (dot) net Cleanup, testing and bug-fixes by myself (via AS 3.10). Currently mrt table dumps are producing incompatible output this will be fixed afterwards -- this diff is already big enough. "get it in if you think it is ready" henning@
-rw-r--r--usr.sbin/bgpd/bgpd.h17
-rw-r--r--usr.sbin/bgpd/log.c3
-rw-r--r--usr.sbin/bgpd/mrt.c16
-rw-r--r--usr.sbin/bgpd/parse.y68
-rw-r--r--usr.sbin/bgpd/printconf.c20
-rw-r--r--usr.sbin/bgpd/rde.c142
-rw-r--r--usr.sbin/bgpd/rde.h60
-rw-r--r--usr.sbin/bgpd/rde_attr.c317
-rw-r--r--usr.sbin/bgpd/rde_filter.c19
-rw-r--r--usr.sbin/bgpd/rde_update.c76
-rw-r--r--usr.sbin/bgpd/session.c71
-rw-r--r--usr.sbin/bgpd/session.h7
-rw-r--r--usr.sbin/bgpd/util.c56
13 files changed, 699 insertions, 173 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index e9351078a2d..2afd9cd77ff 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.215 2007/03/28 12:33:32 henning Exp $ */
+/* $OpenBSD: bgpd.h,v 1.216 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -165,7 +165,8 @@ struct bgpd_config {
u_int rtableid;
u_int32_t bgpid;
u_int32_t clusterid;
- u_int16_t as;
+ u_int32_t as;
+ u_int16_t short_as;
u_int16_t holdtime;
u_int16_t min_holdtime;
};
@@ -224,6 +225,7 @@ struct capabilities {
u_int8_t mp_v6;
u_int8_t refresh; /* route refresh, RFC 2918 */
u_int8_t restart; /* draft-ietf-idr-restart */
+ u_int8_t as4byte;
};
struct peer_config {
@@ -237,12 +239,12 @@ struct peer_config {
char demote_group[IFNAMSIZ];
u_int32_t id;
u_int32_t groupid;
+ u_int32_t remote_as;
u_int32_t max_prefix;
enum announce_type announce_type;
enum enforce_as enforce_as;
enum reconf_action reconf_action;
u_int16_t max_prefix_restart;
- u_int16_t remote_as;
u_int16_t holdtime;
u_int16_t min_holdtime;
u_int8_t template;
@@ -459,6 +461,7 @@ struct session_up {
struct capabilities capa_announced;
struct capabilities capa_received;
u_int32_t remote_bgpid;
+ u_int16_t short_as;
};
struct pftable_msg {
@@ -531,7 +534,7 @@ enum as_spec {
struct filter_as {
enum as_spec type;
- u_int16_t as;
+ u_int32_t as;
};
struct filter_community {
@@ -696,6 +699,9 @@ struct rde_memstats {
#define SAFI_MULTICAST 0x02
#define SAFI_ALL 0xff
+/* 4-byte magic AS number */
+#define AS_TRANS 23456
+
/* prototypes */
/* bgpd.c */
void send_nexthop_update(struct kroute_nexthop *);
@@ -798,7 +804,8 @@ const char *filterset_name(enum action_types);
/* util.c */
const char *log_addr(const struct bgpd_addr *);
const char *log_in6addr(const struct in6_addr *);
-const char * log_sockaddr(struct sockaddr *);
+const char *log_sockaddr(struct sockaddr *);
+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);
diff --git a/usr.sbin/bgpd/log.c b/usr.sbin/bgpd/log.c
index 39ff54fccc9..c426ee96037 100644
--- a/usr.sbin/bgpd/log.c
+++ b/usr.sbin/bgpd/log.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.49 2007/02/25 12:02:40 henning Exp $ */
+/* $OpenBSD: log.c,v 1.50 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -33,7 +33,6 @@
int debug;
-char *log_fmt_peer(const struct peer_config *);
void logit(int, const char *, ...);
char *
diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c
index 3b16001cc72..9f05a7a654f 100644
--- a/usr.sbin/bgpd/mrt.c
+++ b/usr.sbin/bgpd/mrt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mrt.c,v 1.52 2007/02/12 19:15:14 claudio Exp $ */
+/* $OpenBSD: mrt.c,v 1.53 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -120,10 +120,10 @@ mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen,
}
if (!incoming)
- DUMP_SHORT(buf, bgp->as);
- DUMP_SHORT(buf, peer->conf.remote_as);
+ DUMP_SHORT(buf, bgp->short_as);
+ DUMP_SHORT(buf, peer->short_as);
if (incoming)
- DUMP_SHORT(buf, bgp->as);
+ DUMP_SHORT(buf, bgp->short_as);
DUMP_SHORT(buf, /* ifindex */ 0);
switch (peer->sa_local.ss_family) {
case AF_INET:
@@ -206,8 +206,8 @@ mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state,
return (-1);
}
- DUMP_SHORT(buf, bgp->as);
- DUMP_SHORT(buf, peer->conf.remote_as);
+ 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:
@@ -376,7 +376,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
}
DUMP_SHORT(buf, rde_local_as());
- DUMP_SHORT(buf, peer->conf.remote_as);
+ DUMP_SHORT(buf, peer->short_as);
DUMP_SHORT(buf, /* ifindex */ 0);
switch (af) {
@@ -492,7 +492,7 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
DUMP_BYTE(buf, 1); /* state */
DUMP_LONG(buf, p->lastchange); /* originated */
DUMP_NLONG(buf, peer->remote_addr.v4.s_addr);
- DUMP_SHORT(buf, peer->conf.remote_as);
+ DUMP_SHORT(buf, peer->short_as);
DUMP_SHORT(buf, attr_len);
if ((bptr = buf_reserve(buf, attr_len)) == NULL) {
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 64c5852fe94..45bddeef586 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.203 2007/04/17 17:17:45 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.204 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -172,8 +172,8 @@ typedef struct {
%token IPV4 IPV6
%token QUALIFY VIA
%token <v.string> STRING
-%type <v.number> number asnumber optnumber yesno inout espah
-%type <v.number> family restart
+%type <v.number> number asnumber as4number optnumber yesno inout
+%type <v.number> espah family restart
%type <v.string> string
%type <v.addr> address
%type <v.prefix> prefix addrspec
@@ -224,7 +224,44 @@ asnumber : number {
}
}
-string : string STRING {
+as4number : STRING {
+ const char *errstr;
+ char *dot;
+ u_int32_t uvalh = 0, uval;
+
+ if ((dot = strchr($1,'.')) != NULL) {
+ *dot++ = '\0';
+ uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ yyerror("number %s is %s", $1, errstr);
+ free($1);
+ YYERROR;
+ }
+ uval = strtonum(dot, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ yyerror("number %s is %s", dot, errstr);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ } else {
+ uval = strtonum($1, 0, USHRT_MAX - 1, &errstr);
+ if (errstr) {
+ yyerror("number %s is %s", $1, errstr);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ if (uvalh == 0 && uval == AS_TRANS) {
+ yyerror("AS %u is reserved and may not be used",
+ AS_TRANS);
+ YYERROR;
+ }
+ $$ = uval | (uvalh << 16);
+ }
+
+string : string STRING {
if (asprintf(&$$, "%s %s", $1, $2) == -1)
fatal("string: asprintf");
free($1);
@@ -233,7 +270,7 @@ string : string STRING {
| STRING
;
-yesno : STRING {
+yesno : STRING {
if (!strcmp($1, "yes"))
$$ = 1;
else if (!strcmp($1, "no"))
@@ -256,7 +293,7 @@ varset : STRING '=' string {
}
;
-include : INCLUDE STRING {
+include : INCLUDE STRING {
struct file *nfile;
if ((nfile = include_file($2)) == NULL) {
@@ -271,8 +308,16 @@ include : INCLUDE STRING {
}
;
-conf_main : AS asnumber {
+conf_main : AS as4number {
conf->as = $2;
+ if ($2 > USHRT_MAX)
+ conf->short_as = AS_TRANS;
+ else
+ conf->short_as = $2;
+ }
+ | AS as4number asnumber {
+ conf->as = $2;
+ conf->short_as = $3;
}
| ROUTERID address {
if ($2.af != AF_INET) {
@@ -654,7 +699,7 @@ peeroptsl : peeropts nl
| error nl
;
-peeropts : REMOTEAS asnumber {
+peeropts : REMOTEAS as4number {
curpeer->conf.remote_as = $2;
}
| DESCR string {
@@ -1214,7 +1259,7 @@ filter_as_l : filter_as
}
;
-filter_as : asnumber {
+filter_as : as4number {
if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
NULL)
fatal(NULL);
@@ -2250,6 +2295,7 @@ alloc_peer(void)
p->conf.capabilities.mp_v6 = SAFI_NONE;
p->conf.capabilities.refresh = 1;
p->conf.capabilities.restart = 0;
+ p->conf.capabilities.as4byte = 0;
p->conf.softreconfig_in = 1;
p->conf.softreconfig_out = 1;
@@ -2511,6 +2557,10 @@ neighbor_consistent(struct peer *p)
return (-1);
}
+ /* for testing: enable 4-byte AS number capability if necessary */
+ if (conf->as > USHRT_MAX || p->conf.remote_as > USHRT_MAX)
+ p->conf.capabilities.as4byte = 1;
+
/* set default values if they where undefined */
p->conf.ebgp = (p->conf.remote_as != conf->as);
if (p->conf.announce_type == ANNOUNCE_UNDEF)
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index f72ef14e957..c6a7b2dd6a5 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.61 2007/03/29 13:09:26 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.62 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -176,9 +176,11 @@ print_mainconf(struct bgpd_config *conf)
struct in_addr ina;
struct listen_addr *la;
- printf("AS %u\n", conf->as);
+ printf("AS %s", log_as(conf->as));
+ if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS)
+ printf(" %u", conf->short_as);
ina.s_addr = conf->bgpid;
- printf("router-id %s\n", inet_ntoa(ina));
+ printf("\nrouter-id %s\n", inet_ntoa(ina));
if (conf->holdtime)
printf("holdtime %u\n", conf->holdtime);
if (conf->min_holdtime)
@@ -270,7 +272,7 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
if (p->descr[0])
printf("%s\tdescr \"%s\"\n", c, p->descr);
if (p->remote_as)
- printf("%s\tremote-as %u\n", c, p->remote_as);
+ printf("%s\tremote-as %s\n", c, log_as(p->remote_as));
if (p->distance > 1)
printf("%s\tmultihop %u\n", c, p->distance);
if (p->passive)
@@ -469,15 +471,15 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
if (r->match.as.type) {
if (r->match.as.type == AS_ALL)
- printf("AS %u ", r->match.as.as);
+ printf("AS %s ", log_as(r->match.as.as));
else if (r->match.as.type == AS_SOURCE)
- printf("source-as %u ", r->match.as.as);
+ printf("source-as %s ", log_as(r->match.as.as));
else if (r->match.as.type == AS_TRANSIT)
- printf("transit-as %u ", r->match.as.as);
+ printf("transit-as %s ", log_as(r->match.as.as));
else if (r->match.as.type == AS_PEER)
- printf("peer-as %u ", r->match.as.as);
+ printf("peer-as %s ", log_as(r->match.as.as));
else
- printf("unfluffy-as %u ", r->match.as.as);
+ printf("unfluffy-as %s ", log_as(r->match.as.as));
}
if (r->match.community.as != 0) {
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 39f4930d38f..5d66de45396 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.224 2007/04/06 18:03:50 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.225 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -58,6 +58,7 @@ void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void rde_update_log(const char *,
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 *);
int rde_reflector(struct rde_peer *, struct rde_aspath *);
void rde_dump_rib_as(struct prefix *, struct rde_aspath *,pid_t,
@@ -787,6 +788,13 @@ rde_update_dispatch(struct imsg *imsg)
goto done;
}
+ /*
+ * if either ATTR_NEW_AGGREGATOR or ATTR_NEW_ASPATH is present
+ * try to fixup the attributes.
+ */
+ if (asp->flags & F_ATTR_AS4BYTE_NEW)
+ rde_as4byte_fixup(peer, asp);
+
/* enforce remote AS if requested */
if (asp->flags & F_ATTR_ASPATH &&
peer->conf.enforce_as == ENFORCE_AS_ON)
@@ -1115,9 +1123,9 @@ rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
struct rde_aspath *a, struct mpattr *mpa)
{
struct bgpd_addr nexthop;
- u_char *op = p;
+ u_char *op = p, *npath;
u_int32_t tmp32;
- u_int16_t attr_len;
+ u_int16_t attr_len, nlen;
u_int16_t plen = 0;
u_int8_t flags;
u_int8_t type;
@@ -1176,15 +1184,22 @@ bad_flags:
case ATTR_ASPATH:
if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
goto bad_flags;
- if (aspath_verify(p, attr_len) != 0) {
+ if (aspath_verify(p, attr_len, rde_as4byte(peer)) != 0) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL, 0);
return (-1);
}
if (a->flags & F_ATTR_ASPATH)
goto bad_list;
+ if (rde_as4byte(peer)) {
+ npath = p;
+ nlen = attr_len;
+ } else
+ npath = aspath_inflate(p, attr_len, &nlen);
a->flags |= F_ATTR_ASPATH;
- a->aspath = aspath_get(p, attr_len);
+ a->aspath = aspath_get(npath, nlen);
+ if (npath != p)
+ free(npath);
plen += attr_len;
break;
case ATTR_NEXTHOP:
@@ -1253,10 +1268,23 @@ bad_flags:
goto bad_flags;
goto optattr;
case ATTR_AGGREGATOR:
- if (attr_len != 6)
+ if ((!rde_as4byte(peer) && attr_len != 6) ||
+ (rde_as4byte(peer) && attr_len != 8))
goto bad_len;
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
goto bad_flags;
+ if (!rde_as4byte(peer)) {
+ /* need to inflate aggregator AS to 4-byte */
+ u_char t[8];
+ t[0] = t[1] = 0;
+ UPD_READ(&t[2], p, plen, 2);
+ UPD_READ(&t[4], p, plen, 4);
+ if (attr_optadd(a, flags, type, t,
+ sizeof(t)) == -1)
+ goto bad_list;
+ break;
+ }
+ /* 4-byte ready server take the default route */
goto optattr;
case ATTR_COMMUNITIES:
if ((attr_len & 0x3) != 0)
@@ -1305,6 +1333,26 @@ bad_flags:
mpa->unreach_len = attr_len;
plen += attr_len;
break;
+ case ATTR_NEW_AGGREGATOR:
+ if (attr_len != 8)
+ goto bad_len;
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
+ goto bad_flags;
+ a->flags |= F_ATTR_AS4BYTE_NEW;
+ goto optattr;
+ case ATTR_NEW_ASPATH:
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
+ goto bad_flags;
+ if (aspath_verify(p, attr_len, 1) != 0) {
+ /* XXX draft does not specify how to handle errors */
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
+ NULL, 0);
+ return (-1);
+ }
+ a->flags |= F_ATTR_AS4BYTE_NEW;
+ goto optattr;
default:
if ((flags & ATTR_OPTIONAL) == 0) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNKNWN_WK_ATTR,
@@ -1493,31 +1541,82 @@ rde_update_log(const char *message,
const struct rde_peer *peer, const struct bgpd_addr *next,
const struct bgpd_addr *prefix, u_int8_t prefixlen)
{
- char *nexthop = NULL;
+ char *n = NULL;
char *p = NULL;
if (!(conf->log & BGPD_LOG_UPDATES))
return;
if (next != NULL)
- if (asprintf(&nexthop, " via %s",
- log_addr(next)) == -1)
- nexthop = NULL;
-
+ if (asprintf(&n, " via %s", log_addr(next)) == -1)
+ n = NULL;
if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
p = NULL;
- log_info("neighbor %s (AS%u) %s %s %s",
- log_addr(&peer->conf.remote_addr), peer->conf.remote_as, message,
- p ? p : "out of memory", nexthop ? nexthop : "");
+ log_info("%s AS%s: %s %s%s",
+ log_fmt_peer(&peer->conf), log_as(peer->conf.remote_as), message,
+ p ? p : "out of memory", n ? n : "");
- free(nexthop);
+ free(n);
free(p);
}
/*
- * route reflector helper function
+ * 4-Byte ASN helper function.
+ * Two scenarios need to be considered:
+ * - NEW session with NEW attributes present -> just remove the attributes
+ * - OLD session with NEW attributes present -> try to merge them
*/
+void
+rde_as4byte_fixup(struct rde_peer *peer, struct rde_aspath *a)
+{
+ struct attr *nasp, *naggr, *oaggr;
+ u_int32_t as;
+
+ /* first get the attributes */
+ nasp = attr_optget(a, ATTR_NEW_ASPATH);
+ naggr = attr_optget(a, ATTR_NEW_AGGREGATOR);
+
+ if (rde_as4byte(peer)) {
+ /* NEW session using 4-byte ASNs */
+ if (nasp)
+ attr_free(a, nasp);
+ if (naggr)
+ attr_free(a, naggr);
+ return;
+ }
+ /* OLD session using 2-byte ASNs */
+ /* try to merge the new attributes into the old ones */
+ 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 */
+ if (nasp)
+ attr_free(a, nasp);
+ if (naggr)
+ attr_free(a, naggr);
+ return;
+ }
+ if (naggr) {
+ /* switch over to new AGGREGATOR */
+ attr_free(a, oaggr);
+ if (attr_optadd(a, ATTR_OPTIONAL | ATTR_TRANSITIVE,
+ ATTR_AGGREGATOR, naggr->data, naggr->len))
+ fatalx("attr_optadd failed but impossible");
+ }
+ }
+ /* there is no need for NEW_AGGREGATOR any more */
+ if (naggr)
+ attr_free(a, naggr);
+ /* merge NEW_ASPATH with ASPATH */
+ if (nasp)
+ aspath_merge(a, nasp);
+}
+
+
+/*
+ * route reflector helper function
+ */
int
rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
{
@@ -2228,7 +2327,7 @@ rde_update6_queue_runner(void)
/*
* generic helper function
*/
-u_int16_t
+u_int32_t
rde_local_as(void)
{
return (conf->as);
@@ -2250,6 +2349,12 @@ rde_decisionflags(void)
return (conf->flags & BGPD_FLAG_DECISION_MASK);
}
+int
+rde_as4byte(struct rde_peer *peer)
+{
+ return (peer->capa_announced.as4byte && peer->capa_received.as4byte);
+}
+
/*
* peer functions
*/
@@ -2407,6 +2512,7 @@ peer_up(u_int32_t id, struct session_up *sup)
if (peer->state != PEER_DOWN && peer->state != PEER_NONE)
fatalx("peer_up: bad state");
peer->remote_bgpid = ntohl(sup->remote_bgpid);
+ peer->short_as = sup->short_as;
memcpy(&peer->remote_addr, &sup->remote_addr,
sizeof(peer->remote_addr));
memcpy(&peer->capa_announced, &sup->capa_announced,
@@ -2538,12 +2644,14 @@ network_init(struct network_head *net_l)
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));
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index f9492cf9abf..1340a70c8a9 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.98 2007/04/06 18:03:51 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.99 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -73,6 +73,7 @@ struct rde_peer {
u_int32_t up_nlricnt;
u_int32_t up_wcnt;
enum peer_state state;
+ u_int16_t short_as;
u_int8_t reconf_in; /* in filter changed */
u_int8_t reconf_out; /* out filter changed */
};
@@ -104,7 +105,9 @@ enum attrtypes {
ATTR_ORIGINATOR_ID,
ATTR_CLUSTER_LIST,
ATTR_MP_REACH_NLRI=14,
- ATTR_MP_UNREACH_NLRI=15
+ ATTR_MP_UNREACH_NLRI=15,
+ ATTR_NEW_ASPATH=17,
+ ATTR_NEW_AGGREGATOR=18
};
/* attribute flags. 4 low order bits reserved */
@@ -142,22 +145,23 @@ struct path_table {
LIST_HEAD(prefix_head, prefix);
-#define F_ATTR_ORIGIN 0x0001
-#define F_ATTR_ASPATH 0x0002
-#define F_ATTR_NEXTHOP 0x0004
-#define F_ATTR_LOCALPREF 0x0008
-#define F_ATTR_MED 0x0010
-#define F_ATTR_MED_ANNOUNCE 0x0020
-#define F_ATTR_MP_REACH 0x0040
-#define F_ATTR_MP_UNREACH 0x0080
-#define F_PREFIX_ANNOUNCED 0x0100
-#define F_NEXTHOP_REJECT 0x0200
-#define F_NEXTHOP_BLACKHOLE 0x0400
-#define F_NEXTHOP_NOMODIFY 0x0800
-#define F_NEXTHOP_SELF 0x1000
-#define F_ATTR_LINKED 0x2000
-#define F_LOCAL 0x4000 /* Local-RIB */
-#define F_ORIGINAL 0x8000 /* Adj-RIB-In */
+#define F_ATTR_ORIGIN 0x00001
+#define F_ATTR_ASPATH 0x00002
+#define F_ATTR_NEXTHOP 0x00004
+#define F_ATTR_LOCALPREF 0x00008
+#define F_ATTR_MED 0x00010
+#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_PREFIX_ANNOUNCED 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
@@ -179,9 +183,9 @@ struct rde_aspath {
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 */
- u_int16_t flags; /* internally used */
u_int8_t origin;
u_int8_t others_len;
};
@@ -277,9 +281,10 @@ void rde_send_pftable(u_int16_t, struct bgpd_addr *,
void rde_send_pftable_commit(void);
void rde_generate_updates(struct prefix *, struct prefix *);
-u_int16_t rde_local_as(void);
+u_int32_t rde_local_as(void);
int rde_noevaluate(void);
int rde_decisionflags(void);
+int rde_as4byte(struct rde_peer *);
/* rde_attr.c */
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
@@ -296,7 +301,7 @@ void attr_free(struct rde_aspath *, struct attr *);
#define attr_optlen(x) \
((x)->len > 255 ? (x)->len + 4 : (x)->len + 3)
-int aspath_verify(void *, u_int16_t);
+int aspath_verify(void *, u_int16_t, int);
#define AS_ERR_LEN -1
#define AS_ERR_TYPE -2
#define AS_ERR_BAD -3
@@ -304,14 +309,17 @@ void aspath_init(u_int32_t);
void aspath_shutdown(void);
struct aspath *aspath_get(void *, u_int16_t);
void aspath_put(struct aspath *);
+u_char *aspath_inflate(void *, u_int16_t, u_int16_t *);
+u_char *aspath_deflate(u_char *, u_int16_t *, int *);
+void aspath_merge(struct rde_aspath *, struct attr *);
u_char *aspath_dump(struct aspath *);
u_int16_t aspath_length(struct aspath *);
u_int16_t aspath_count(const void *, u_int16_t);
-u_int16_t aspath_neighbor(struct aspath *);
-int aspath_loopfree(struct aspath *, u_int16_t);
+u_int32_t aspath_neighbor(struct aspath *);
+int aspath_loopfree(struct aspath *, u_int32_t);
int aspath_compare(struct aspath *, struct aspath *);
-struct aspath *aspath_prepend(struct aspath *, u_int16_t, int);
-int aspath_match(struct aspath *, enum as_spec, u_int16_t);
+u_char *aspath_prepend(struct aspath *, u_int32_t, int, u_int16_t *);
+int aspath_match(struct aspath *, enum as_spec, u_int32_t);
int community_match(void *, u_int16_t, int, int);
int community_set(struct rde_aspath *, int, int);
void community_delete(struct rde_aspath *, int, int);
@@ -403,6 +411,6 @@ int rde_filter_equal(struct filter_head *, struct filter_head *,
struct rde_peer *, enum directions);
/* util.c */
-u_int16_t aspath_extract(const void *, int);
+u_int32_t aspath_extract(const void *, int);
#endif /* __RDE_H__ */
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index eaf692f5a9a..870fa1f5a93 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.70 2007/03/06 16:52:48 henning Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.71 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -361,6 +361,9 @@ attr_put(struct attr *a)
/* aspath specific functions */
+u_int16_t aspath_countlength(struct aspath *, u_int16_t, int);
+void aspath_countcopy(struct aspath *, u_int16_t, u_int8_t *,
+ u_int16_t, int);
struct aspath *aspath_lookup(const void *, u_int16_t);
struct aspath_table {
@@ -372,18 +375,21 @@ struct aspath_table {
&astable.hashtbl[(x) & astable.hashmask]
int
-aspath_verify(void *data, u_int16_t len)
+aspath_verify(void *data, u_int16_t len, int as4byte)
{
u_int8_t *seg = data;
- u_int16_t seg_size;
+ u_int16_t seg_size, as_size = 2;
u_int8_t seg_len, seg_type;
if (len & 1)
/* odd length aspath are invalid */
return (AS_ERR_BAD);
+ if (as4byte)
+ as_size = 4;
+
for (; len > 0; len -= seg_size, seg += seg_size) {
- if (len < 2)
+ if (len < 2) /* header length check */
return (AS_ERR_BAD);
seg_type = seg[0];
seg_len = seg[1];
@@ -391,7 +397,7 @@ aspath_verify(void *data, u_int16_t len)
if (seg_type != AS_SET && seg_type != AS_SEQUENCE)
return (AS_ERR_TYPE);
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + as_size * seg_len;
if (seg_size > len)
return (AS_ERR_LEN);
@@ -485,6 +491,134 @@ aspath_put(struct aspath *aspath)
}
u_char *
+aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
+{
+ u_int8_t *seg, *nseg, *ndata;
+ u_int16_t seg_size, olen, nlen;
+ u_int8_t seg_len;
+
+ /* first calculate the length of the aspath */
+ seg = data;
+ nlen = 0;
+ for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int16_t) * seg_len;
+ nlen += 2 + sizeof(u_int32_t) * seg_len;
+
+ if (seg_size > len)
+ fatalx("aspath_inflate: bula bula");
+ }
+
+ *newlen = nlen;
+ if ((ndata = malloc(nlen)) == NULL)
+ fatal("aspath_inflate");
+
+ /* then copy the aspath */
+ seg = data;
+ for (nseg = ndata; nseg < ndata + nlen; ) {
+ *nseg++ = *seg++;
+ *nseg++ = seg_len = *seg++;
+ for (; seg_len > 0; seg_len--) {
+ *nseg++ = 0;
+ *nseg++ = 0;
+ *nseg++ = *seg++;
+ *nseg++ = *seg++;
+ }
+ }
+
+ return (ndata);
+}
+
+/* convert a 4 byte aspath to a 2byte one. data is freed by aspath_deflate */
+u_char *
+aspath_deflate(u_char *data, u_int16_t *len, int *flagnew)
+{
+ u_int8_t *seg, *nseg, *ndata;
+ u_int32_t as;
+ int i;
+ u_int16_t seg_size, olen, nlen;
+ u_int8_t seg_len;
+
+ /* first calculate the length of the aspath */
+ nlen = 0;
+ seg = data;
+ olen = *len;
+ for (; olen > 0; olen -= seg_size, seg += seg_size) {
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
+ nlen += 2 + sizeof(u_int16_t) * seg_len;
+
+ if (seg_size > olen)
+ fatalx("aspath_deflate: bula bula");
+ }
+
+ if ((ndata = malloc(nlen)) == NULL)
+ fatal("aspath_deflate");
+
+ /* then copy the aspath */
+ seg = data;
+ olen = *len;
+ for (nseg = ndata; seg < data + olen; seg += seg_size) {
+ *nseg++ = seg[0];
+ *nseg++ = seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
+
+ for (i = 0; i < seg_len; i++) {
+ as = aspath_extract(seg, i);
+ if (as > USHRT_MAX) {
+ as = AS_TRANS;
+ *flagnew = 1;
+ }
+ *nseg++ = (as >> 8) & 0xff;
+ *nseg++ = as & 0xff;
+ }
+ }
+
+ free(data);
+ *len = nlen;
+ return (ndata);
+}
+
+void
+aspath_merge(struct rde_aspath *a, struct attr *attr)
+{
+ u_int8_t *np;
+ u_int16_t ascnt, diff, nlen, difflen;
+ int hroom = 0;
+
+ ascnt = aspath_count(attr->data, attr->len);
+ if (ascnt > a->aspath->ascnt) {
+ /* ASPATH is shorter then NEW_ASPATH no way to merge */
+ attr_free(a, attr);
+ return;
+ }
+
+ diff = a->aspath->ascnt - ascnt;
+ if (attr->len > 2 && attr->data[0] == AS_SEQUENCE)
+ hroom = attr->data[1];
+ difflen = aspath_countlength(a->aspath, diff, hroom);
+ nlen = attr->len + difflen;
+
+ if ((np = malloc(nlen)) == NULL)
+ fatal("aspath_merge");
+
+ /* copy head from old aspath */
+ aspath_countcopy(a->aspath, diff, np, difflen, hroom);
+
+ /* copy tail from new aspath */
+ if (hroom > 0)
+ memcpy(np + nlen - attr->len + 2, attr->data + 2,
+ attr->len - 2);
+ else
+ memcpy(np + nlen - attr->len, attr->data, attr->len);
+
+ aspath_put(a->aspath);
+ a->aspath = aspath_get(np, nlen);
+ free(np);
+ attr_free(a, attr);
+}
+
+u_char *
aspath_dump(struct aspath *aspath)
{
return (aspath->data);
@@ -508,7 +642,7 @@ aspath_count(const void *data, u_int16_t len)
for (; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
if (seg_type == AS_SET)
cnt += 1;
@@ -522,6 +656,85 @@ aspath_count(const void *data, u_int16_t len)
}
u_int16_t
+aspath_countlength(struct aspath *aspath, u_int16_t cnt, int headcnt)
+{
+ const u_int8_t *seg;
+ u_int16_t seg_size, len, clen;
+ u_int8_t seg_type = 0, seg_len = 0;
+
+ seg = aspath->data;
+ clen = 0;
+ for (len = aspath->len; len > 0 && cnt > 0;
+ len -= seg_size, seg += seg_size) {
+ seg_type = seg[0];
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
+
+ if (seg_type == AS_SET)
+ cnt -= 1;
+ else if (seg_len > cnt) {
+ seg_len = cnt;
+ clen += 2 + sizeof(u_int32_t) * cnt;
+ break;
+ } else
+ cnt -= seg_len;
+
+ clen += seg_size;
+
+ if (seg_size > len)
+ fatalx("aspath_countlenght: bula bula");
+ }
+ if (headcnt > 0 && seg_type == AS_SEQUENCE && headcnt + seg_len < 256)
+ /* no need for additional header from the new aspath. */
+ clen -= 2;
+
+ return (clen);
+}
+
+void
+aspath_countcopy(struct aspath *aspath, u_int16_t cnt, u_int8_t *buf,
+ u_int16_t size, int headcnt)
+{
+ const u_int8_t *seg;
+ u_int16_t seg_size, len;
+ u_int8_t seg_type, seg_len;
+
+ if (headcnt > 0)
+ /*
+ * additional room because we steal the segment header
+ * from the other aspath
+ */
+ size += 2;
+ seg = aspath->data;
+ for (len = aspath->len; len > 0 && cnt > 0;
+ len -= seg_size, seg += seg_size) {
+ seg_type = seg[0];
+ seg_len = seg[1];
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
+
+ if (seg_type == AS_SET)
+ cnt -= 1;
+ else if (seg_len > cnt) {
+ seg_len = cnt + headcnt;
+ seg_size = 2 + sizeof(u_int32_t) * cnt;
+ cnt = 0;
+ } else {
+ cnt -= seg_len;
+ if (cnt == 0)
+ seg_len += headcnt;
+ }
+
+ memcpy(buf, seg, seg_size);
+ buf[0] = seg_type;
+ buf[1] = seg_len;
+ buf += seg_size;
+ if (size < seg_size)
+ fatalx("aspath_countlength: would overflow");
+ size -= seg_size;
+ }
+}
+
+u_int32_t
aspath_neighbor(struct aspath *aspath)
{
/*
@@ -537,7 +750,7 @@ aspath_neighbor(struct aspath *aspath)
}
int
-aspath_loopfree(struct aspath *aspath, u_int16_t myAS)
+aspath_loopfree(struct aspath *aspath, u_int32_t myAS)
{
u_int8_t *seg;
u_int16_t len, seg_size;
@@ -547,7 +760,7 @@ aspath_loopfree(struct aspath *aspath, u_int16_t myAS)
for (len = aspath->len; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
for (i = 0; i < seg_len; i++) {
if (myAS == aspath_extract(seg, i))
@@ -598,11 +811,11 @@ aspath_lookup(const void *data, u_int16_t len)
/*
* Returns a new prepended aspath. Old needs to be freed by caller.
*/
-struct aspath *
-aspath_prepend(struct aspath *asp, u_int16_t as, int quantum)
+u_char *
+aspath_prepend(struct aspath *asp, u_int32_t as, int quantum, u_int16_t *len)
{
u_char *p;
- int len, overflow = 0, shift = 0, size, wpos = 0;
+ int l, overflow = 0, shift = 0, size, wpos = 0;
u_int8_t type;
/* lunatic prepends are blocked in the parser and limited */
@@ -620,32 +833,35 @@ aspath_prepend(struct aspath *asp, u_int16_t as, int quantum)
}
if (quantum == 0) {
- /* no change needed but increase refcnt as we return a copy */
- asp->refcnt++;
- rdemem.aspath_refs++;
- return (asp);
+ /* no change needed but return a copy */
+ p = malloc(asp->len);
+ if (p == NULL)
+ fatal("aspath_prepend");
+ memcpy(p, asp->data, asp->len);
+ *len = asp->len;
+ return (p);
} else if (type == AS_SET || size + quantum > 255) {
/* need to attach a new AS_SEQUENCE */
- len = 2 + quantum * 2 + asp->len;
+ l = 2 + quantum * sizeof(u_int32_t) + asp->len;
overflow = type == AS_SET ? quantum : (size + quantum) & 0xff;
} else
- len = quantum * 2 + asp->len;
+ l = quantum * sizeof(u_int32_t) + asp->len;
quantum -= overflow;
- p = malloc(len);
+ p = malloc(l);
if (p == NULL)
fatal("aspath_prepend");
/* first prepends */
- as = htons(as);
+ as = htonl(as);
if (overflow > 0) {
p[wpos++] = AS_SEQUENCE;
p[wpos++] = overflow;
for (; overflow > 0; overflow--) {
- memcpy(p + wpos, &as, 2);
- wpos += 2;
+ memcpy(p + wpos, &as, sizeof(u_int32_t));
+ wpos += sizeof(u_int32_t);
}
}
if (quantum > 0) {
@@ -654,24 +870,22 @@ aspath_prepend(struct aspath *asp, u_int16_t as, int quantum)
p[wpos++] = quantum + size;
for (; quantum > 0; quantum--) {
- memcpy(p + wpos, &as, 2);
- wpos += 2;
+ memcpy(p + wpos, &as, sizeof(u_int32_t));
+ wpos += sizeof(u_int32_t);
}
}
memcpy(p + wpos, asp->data + shift, asp->len - shift);
- asp = aspath_get(p, len);
- free(p);
-
- return (asp);
+ *len = l;
+ return (p);
}
/* we need to be able to search more than one as */
int
-aspath_match(struct aspath *a, enum as_spec type, u_int16_t as)
+aspath_match(struct aspath *a, enum as_spec type, u_int32_t as)
{
u_int8_t *seg;
- int final, first;
+ int final;
u_int16_t len, seg_size;
u_int8_t i, seg_type, seg_len;
@@ -683,36 +897,45 @@ aspath_match(struct aspath *a, enum as_spec type, u_int16_t as)
}
final = 0;
- first = 1;
seg = a->data;
for (len = a->len; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
final = (len == seg_size);
- if (type == AS_SOURCE && !final)
+ /* just check the first (leftmost) AS */
+ if (type == AS_PEER) {
+ if (as == aspath_extract(seg, 0))
+ return (1);
+ else
+ return (0);
+ }
+ /* just check the final (rightmost) AS */
+ if (type == AS_SOURCE) {
/* not yet in the final segment */
- continue;
+ if (!final)
+ continue;
+ if (as == aspath_extract(seg, seg_len - 1))
+ return (1);
+ else
+ return (0);
+ }
+
+ /* AS_TRANSIT or AS_ALL */
for (i = 0; i < seg_len; i++) {
if (as == aspath_extract(seg, i)) {
- if (type == AS_PEER) {
- if (first)
- return (1);
- else
- return (0);
- } else if (final && i + 1 >= seg_len)
- /* the final (rightmost) as */
- if (type == AS_TRANSIT)
- return (0);
- else
- return (1);
- else if (type != AS_SOURCE)
- return (1);
+ /*
+ * the source (rightmost) AS is excluded from
+ * AS_TRANSIT matches.
+ */
+ if (final && i == seg_len - 1 &&
+ type == AS_TRANSIT)
+ return (0);
+ return (1);
}
- first = 0;
}
}
return (0);
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index 97d4b992a32..8bb857d70f1 100644
--- a/usr.sbin/bgpd/rde_filter.c
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_filter.c,v 1.50 2006/05/28 23:24:15 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.51 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -74,9 +74,10 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
sa_family_t af, struct rde_peer *from, struct rde_peer *peer)
{
struct filter_set *set;
- struct aspath *new;
+ u_char *np;
int as, type;
- u_int16_t prep_as;
+ u_int32_t prep_as;
+ u_int16_t nl;
u_int8_t prepend;
if (asp == NULL)
@@ -141,20 +142,22 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
}
break;
case ACTION_SET_PREPEND_SELF:
- as = rde_local_as();
+ prep_as = rde_local_as();
prepend = set->action.prepend;
- new = aspath_prepend(asp->aspath, as, prepend);
+ np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
aspath_put(asp->aspath);
- asp->aspath = new;
+ asp->aspath = aspath_get(np, nl);
+ free(np);
break;
case ACTION_SET_PREPEND_PEER:
if (from == NULL)
break;
prep_as = from->conf.remote_as;
prepend = set->action.prepend;
- new = aspath_prepend(asp->aspath, prep_as, prepend);
+ np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
aspath_put(asp->aspath);
- asp->aspath = new;
+ asp->aspath = aspath_get(np, nl);
+ free(np);
break;
case ACTION_SET_NEXTHOP:
case ACTION_SET_NEXTHOP_REJECT:
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 4346fa26535..d0517d6b16f 100644
--- a/usr.sbin/bgpd/rde_update.c
+++ b/usr.sbin/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.56 2007/04/06 18:03:51 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.57 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -610,12 +610,12 @@ int
up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
struct rde_aspath *a, sa_family_t af)
{
- struct aspath *path;
struct attr *oa;
- u_int32_t tmp32;
+ u_char *pdata;
+ u_int32_t tmp32, aggr_as;
in_addr_t nexthop;
- int r, ismp = 0;
- u_int16_t len = sizeof(up_attr_buf), wlen = 0;
+ int r, ismp = 0, neednewpath = 0, neednewaggr = 0;
+ u_int16_t len = sizeof(up_attr_buf), wlen = 0, plen;
u_int8_t l;
/* origin */
@@ -627,15 +627,18 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
/* aspath */
if (!peer->conf.ebgp ||
rde_decisionflags() & BGPD_FLAG_DECISION_TRANS_AS)
- path = aspath_prepend(a->aspath, rde_local_as(), 0);
+ pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
else
- path = aspath_prepend(a->aspath, rde_local_as(), 1);
+ pdata = aspath_prepend(a->aspath, rde_local_as(), 1, &plen);
+
+ if (!rde_as4byte(peer))
+ pdata = aspath_deflate(pdata, &plen, &neednewpath);
if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,
- ATTR_ASPATH, path->data, path->len)) == -1)
+ ATTR_ASPATH, pdata, plen)) == -1)
return (-1);
- aspath_put(path);
wlen += r; len -= r;
+ free(pdata);
switch (af) {
case AF_INET:
@@ -676,6 +679,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
* dump all other path attributes. Following rules apply:
* 1. well-known attrs: ATTR_ATOMIC_AGGREGATE and ATTR_AGGREGATOR
* pass unmodified (enforce flags to correct values)
+ * Actually ATTR_AGGREGATOR may be deflated for OLD 2-byte peers.
* 2. non-transitive attrs: don't re-announce to ebgp peers
* 3. transitive known attrs: announce unmodified
* 4. transitive unknown attrs: set partial bit and re-announce
@@ -691,6 +695,34 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
return (-1);
break;
case ATTR_AGGREGATOR:
+ if (!rde_as4byte(peer)) {
+ /* need to deflate the aggregator */
+ u_int8_t t[6];
+ u_int16_t tas;
+
+ if ((!(oa->flags & ATTR_TRANSITIVE)) &&
+ peer->conf.ebgp != 0) {
+ r = 0;
+ break;
+ }
+
+ memcpy(&aggr_as, oa->data, sizeof(aggr_as));
+ if (htonl(aggr_as) > USHRT_MAX) {
+ tas = htons(AS_TRANS);
+ neednewaggr = 1;
+ } else
+ tas = htons(ntohl(aggr_as));
+
+ memcpy(t, &tas, sizeof(tas));
+ memcpy(t + sizeof(tas),
+ oa->data + sizeof(aggr_as),
+ oa->len - sizeof(aggr_as));
+ if ((r = attr_write(up_attr_buf + wlen, len,
+ oa->flags, oa->type, &t, sizeof(t))) == -1)
+ return (-1);
+ break;
+ }
+ /* FALLTHROUGH */
case ATTR_COMMUNITIES:
case ATTR_ORIGINATOR_ID:
case ATTR_CLUSTER_LIST:
@@ -724,6 +756,32 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
wlen += r; len -= r;
}
+ /* 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)
+ pdata = aspath_prepend(a->aspath, rde_local_as(), 0,
+ &plen);
+ else
+ pdata = aspath_prepend(a->aspath, rde_local_as(), 1,
+ &plen);
+ 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)
+ return (-1);
+ wlen += r; len -= r;
+ free(pdata);
+ }
+ if (neednewaggr) {
+ if ((r = attr_write(up_attr_buf + wlen, len,
+ ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_NEW_AGGREGATOR,
+ &aggr_as, sizeof(aggr_as))) == -1)
+ return (-1);
+ wlen += r; len -= r;
+ }
+
/* write mp attribute to different buffer */
if (ismp)
if (up_generate_mp_reach(peer, upa, a, AF_INET6) == -1)
diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c
index 9f8e7718d22..1f00f61a599 100644
--- a/usr.sbin/bgpd/session.c
+++ b/usr.sbin/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.272 2007/03/28 11:53:48 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.273 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <poll.h>
#include <pwd.h>
#include <signal.h>
@@ -82,7 +83,7 @@ int parse_open(struct peer *);
int parse_update(struct peer *);
int parse_refresh(struct peer *);
int parse_notification(struct peer *);
-int parse_capabilities(struct peer *, u_char *, u_int16_t);
+int parse_capabilities(struct peer *, u_char *, u_int16_t, u_int32_t *);
void session_dispatch_imsg(struct imsgbuf *, int, u_int *);
void session_up(struct peer *);
void session_down(struct peer *);
@@ -1247,6 +1248,7 @@ session_capa_ann_none(struct peer *peer)
peer->capa.ann.mp_v4 = SAFI_NONE;
peer->capa.ann.refresh = 0;
peer->capa.ann.restart = 0;
+ peer->capa.ann.as4byte = 0;
}
int
@@ -1380,6 +1382,15 @@ session_open(struct peer *p)
errs += buf_add(opb, &c, 4);
}
+ /* 4-bytes AS numbers, draft-ietf-idr-as4bytes-12 */
+ if (p->capa.ann.as4byte) { /* 4 bytes data */
+ u_int32_t nas;
+
+ nas = htonl(conf->as);
+ errs += session_capa_add(p, opb, CAPA_AS4BYTE, 4, &optparamlen);
+ errs += buf_add(opb, &nas, 4);
+ }
+
len = MSGSIZE_OPEN_MIN + optparamlen;
if (errs || (buf = session_newmsg(OPEN, len)) == NULL) {
buf_free(opb);
@@ -1388,7 +1399,10 @@ session_open(struct peer *p)
}
msg.version = 4;
- msg.myas = htons(conf->as);
+ if (conf->as > USHRT_MAX)
+ msg.myas = htons(conf->short_as);
+ else
+ msg.myas = htons(conf->as);
if (p->conf.holdtime)
msg.holdtime = htons(p->conf.holdtime);
else
@@ -1816,9 +1830,9 @@ parse_open(struct peer *peer)
{
u_char *p, *op_val;
u_int8_t version, rversion;
- u_int16_t as, msglen;
+ u_int16_t short_as, msglen;
u_int16_t holdtime, oholdtime, myholdtime;
- u_int32_t bgpid;
+ u_int32_t as, bgpid;
u_int8_t optparamlen, plen;
u_int8_t op_type, op_len;
@@ -1846,22 +1860,16 @@ parse_open(struct peer *peer)
return (-1);
}
- memcpy(&as, p, sizeof(as));
- p += sizeof(as);
+ memcpy(&short_as, p, sizeof(short_as));
+ p += sizeof(short_as);
+ as = peer->short_as = ntohs(short_as);
/* if remote-as is zero and it's a cloned neighbor, accept any */
- if (peer->conf.cloned && !peer->conf.remote_as) {
- peer->conf.remote_as = ntohs(as);
+ if (peer->conf.cloned && !peer->conf.remote_as && as != AS_TRANS) {
+ peer->conf.remote_as = as;
peer->conf.ebgp = (peer->conf.remote_as != conf->as);
}
- if (peer->conf.remote_as != ntohs(as)) {
- log_peer_warnx(&peer->conf, "peer sent wrong AS %u", ntohs(as));
- session_notification(peer, ERR_OPEN, ERR_OPEN_AS, NULL, 0);
- change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN);
- return (-1);
- }
-
memcpy(&oholdtime, p, sizeof(oholdtime));
p += sizeof(oholdtime);
@@ -1940,7 +1948,8 @@ parse_open(struct peer *peer)
switch (op_type) {
case OPT_PARAM_CAPABILITIES: /* RFC 3392 */
- if (parse_capabilities(peer, op_val, op_len) == -1) {
+ if (parse_capabilities(peer, op_val, op_len,
+ &as) == -1) {
session_notification(peer, ERR_OPEN, 0,
NULL, 0);
change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN);
@@ -1968,6 +1977,14 @@ parse_open(struct peer *peer)
}
}
+ if (peer->conf.remote_as != as) {
+ log_peer_warnx(&peer->conf, "peer sent wrong AS %s",
+ log_as(as));
+ session_notification(peer, ERR_OPEN, ERR_OPEN_AS, NULL, 0);
+ change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN);
+ return (-1);
+ }
+
return (0);
}
@@ -2103,6 +2120,11 @@ parse_notification(struct peer *peer)
log_peer_warnx(&peer->conf,
"disabling restart capability");
break;
+ case CAPA_AS4BYTE:
+ peer->capa.ann.as4byte = 0;
+ log_peer_warnx(&peer->conf,
+ "disabling 4-byte AS num capability");
+ break;
default: /* should not happen... */
log_peer_warnx(&peer->conf, "received "
"\"unsupported capability\" notification "
@@ -2126,7 +2148,7 @@ parse_notification(struct peer *peer)
}
int
-parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen)
+parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
{
u_int16_t len;
u_int8_t capa_code;
@@ -2134,6 +2156,7 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen)
u_char *capa_val;
u_int16_t mp_afi;
u_int8_t mp_safi;
+ u_int32_t remote_as;
len = dlen;
while (len > 0) {
@@ -2203,6 +2226,17 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen)
peer->capa.peer.restart = 1;
/* we don't care about the further restart capas yet */
break;
+ case CAPA_AS4BYTE:
+ if (capa_len != 4) {
+ log_peer_warnx(&peer->conf,
+ "parse_capabilities: "
+ "expect len 4, len is %u", capa_len);
+ return (-1);
+ }
+ memcpy(&remote_as, capa_val, sizeof(remote_as));
+ *as = ntohl(remote_as);
+ peer->capa.peer.as4byte = 1;
+ break;
default:
break;
}
@@ -2754,6 +2788,7 @@ session_up(struct peer *p)
}
sup.remote_bgpid = p->remote_bgpid;
+ sup.short_as = p->short_as;
memcpy(&sup.capa_announced, &p->capa.ann, sizeof(sup.capa_announced));
memcpy(&sup.capa_received, &p->capa.peer, sizeof(sup.capa_received));
p->stats.last_updown = time(NULL);
diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h
index 3bdcd721b96..f6973ef2f60 100644
--- a/usr.sbin/bgpd/session.h
+++ b/usr.sbin/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.91 2007/04/06 18:03:51 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.92 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -104,7 +104,8 @@ enum capa_codes {
CAPA_NONE,
CAPA_MP,
CAPA_REFRESH,
- CAPA_RESTART = 64
+ CAPA_RESTART = 64,
+ CAPA_AS4BYTE = 65
};
struct bgp_msg {
@@ -194,6 +195,7 @@ struct peer {
u_int32_t remote_bgpid;
enum session_state state;
enum session_state prev_state;
+ u_int16_t short_as;
u_int16_t holdtime;
u_int8_t depend_ok;
u_int8_t demoted;
@@ -215,6 +217,7 @@ int imsg_compose_parent(int, pid_t, void *, u_int16_t);
int imsg_compose_rde(int, pid_t, void *, u_int16_t);
/* log.c */
+char *log_fmt_peer(const struct peer_config *);
void log_statechange(struct peer *, enum session_state,
enum session_events);
void log_notification(const struct peer *, u_int8_t, u_int8_t,
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c
index d301dce878d..2043ca6ab29 100644
--- a/usr.sbin/bgpd/util.c
+++ b/usr.sbin/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.1 2006/01/03 22:19:59 claudio Exp $ */
+/* $OpenBSD: util.c,v 1.2 2007/04/23 13:04:24 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -74,6 +74,22 @@ log_sockaddr(struct sockaddr *sa)
return (buf);
}
+const char *
+log_as(u_int32_t as)
+{
+ static char buf[12]; /* "65000.65000\0" */
+
+ if (as < USHRT_MAX) {
+ if (snprintf(buf, sizeof(buf), "%u", as) == -1)
+ return ("?");
+ } else {
+ if (snprintf(buf, sizeof(buf), "%u.%u", as >> 16,
+ as & 0xffff) == -1)
+ return ("?");
+ }
+ return (buf);
+}
+
int
aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
{
@@ -100,7 +116,7 @@ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
for (; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
if (seg_type == AS_SET) {
if (total_size != 0)
@@ -114,7 +130,8 @@ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
}
for (i = 0; i < seg_len; i++) {
- r = snprintf(buf, size, "%hu", aspath_extract(seg, i));
+ r = snprintf(buf, size, "%s",
+ log_as(aspath_extract(seg, i)));
UPDATE();
if (i + 1 < seg_len) {
r = snprintf(buf, size, " ");
@@ -160,7 +177,8 @@ aspath_strlen(void *data, u_int16_t len)
{
u_int8_t *seg;
int total_size;
- u_int16_t as, seg_size;
+ u_int32_t as;
+ u_int16_t seg_size;
u_int8_t i, seg_type, seg_len;
total_size = 0;
@@ -168,7 +186,7 @@ aspath_strlen(void *data, u_int16_t len)
for (; len > 0; len -= seg_size, seg += seg_size) {
seg_type = seg[0];
seg_len = seg[1];
- seg_size = 2 + 2 * seg_len;
+ seg_size = 2 + sizeof(u_int32_t) * seg_len;
if (seg_type == AS_SET)
if (total_size != 0)
@@ -180,6 +198,21 @@ aspath_strlen(void *data, u_int16_t len)
for (i = 0; i < seg_len; i++) {
as = aspath_extract(seg, i);
+ if (as > USHRT_MAX) {
+ u_int32_t a = as >> 16;
+
+ if (a >= 10000)
+ total_size += 5;
+ else if (a >= 1000)
+ total_size += 4;
+ else if (a >= 100)
+ total_size += 3;
+ else if (a >= 10)
+ total_size += 2;
+ else
+ total_size += 1;
+ total_size += 1; /* dot between hi & lo */
+ }
if (as >= 10000)
total_size += 5;
else if (as >= 1000)
@@ -206,16 +239,13 @@ aspath_strlen(void *data, u_int16_t len)
* Direct access is not possible because of non-aligned reads.
* ATTENTION: no bounds check are done.
*/
-u_int16_t
+u_int32_t
aspath_extract(const void *seg, int pos)
{
const u_char *ptr = seg;
- u_int16_t as = 0;
+ u_int32_t as;
- ptr += 2 + 2 * pos;
- as = *ptr++;
- as <<= 8;
- as |= *ptr;
- return (as);
+ ptr += 2 + sizeof(u_int32_t) * pos;
+ memcpy(&as, ptr, sizeof(u_int32_t));
+ return (ntohl(as));
}
-