summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2019-02-26 10:49:16 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2019-02-26 10:49:16 +0000
commitd70cbcf1ecef9eafe8d77b451466b5edb728ba01 (patch)
tree7f0227f504be95673e1cb96813aa6ffdd3f20464 /usr.sbin
parent8b7c44fdfd62544312b38cf7248eb584f04c5271 (diff)
Add support for '*', local-as and neighbor-as for ext-community matching
and setting. This allows rules like: ext-community * * # delete any ext-community ext-community ovs * # delete any ext-community of specified type ext-community rt 1.2.3.4:* and ext-community rt 65001:local-as ext-community rt local-as:11111 Note: Sometimes the type of the ext-community is underspecified when using wildchars or expands. So 'ext-community rt *' or 'ext-community soo *' will match for any of the 3 possible types (2-byte AS, 4-byte AS and IP address). If local-as/neighbor-as is used as an expand of as-number like ext-community rt local-as:11111 then bgpd will default to the 4-byte AS type to encode the community. OK benno@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bgpd/bgpd.conf.553
-rw-r--r--usr.sbin/bgpd/bgpd.h12
-rw-r--r--usr.sbin/bgpd/parse.y77
-rw-r--r--usr.sbin/bgpd/printconf.c60
-rw-r--r--usr.sbin/bgpd/rde.h4
-rw-r--r--usr.sbin/bgpd/rde_attr.c273
-rw-r--r--usr.sbin/bgpd/util.c6
7 files changed, 348 insertions, 137 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index 377efd1cdfd..a6f975e935d 100644
--- a/usr.sbin/bgpd/bgpd.conf.5
+++ b/usr.sbin/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.185 2019/02/11 17:45:59 jmc Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.186 2019/02/26 10:49:15 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: February 11 2019 $
+.Dd $Mdocdate: February 26 2019 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -1354,14 +1354,9 @@ and
.Ar local
may be set to
.Sq *
-to do wildcard matching.
-Both
-.Ar as-number
-and
-.Ar local
-may be set to
+to do wildcard matching,
.Ic neighbor-as ,
-which is expanded to the current neighbor remote AS number,
+which is expanded to the current neighbor remote AS number, or
.Ic local-as ,
which is expanded to the locally assigned AS number.
.Pp
@@ -1379,7 +1374,7 @@ which is expanded to the locally assigned AS number.
.Xc
.It Xo
.Ic ext-community
-.Ar ovs
+.Ic ovs
.Pq Ic valid | not-found | invalid
.Xc
This rule applies only to
@@ -1391,6 +1386,26 @@ Extended Communities are specified by a
.Ar subtype
and normally two values, a globally unique part (e.g. the AS number) and a
local part.
+Both
+.Ar as-number
+and
+.Ar local
+may be set to
+.Ic neighbor-as ,
+which is expanded to the current neighbor remote AS number, or
+.Ic local-as ,
+which is expanded to the locally assigned AS number.
+Wildcard matching is supported for
+.Ar local ,
+.Ar numvalue
+and
+.Ar subtype .
+If wildcard matching is used on the
+.Ar subtype
+then
+.Ar numvalue
+also needs to be set to
+.Sq * .
See also the
.Sx ATTRIBUTE SET
section for further information about the encoding.
@@ -1689,7 +1704,7 @@ to do wildcard matching.
.Xc
.It Xo
.Ic ext-community Op Ar delete
-.Ar ovs
+.Ic ovs
.Pq Ic valid | not-found | invalid
.Xc
Set or delete the
@@ -1737,6 +1752,22 @@ vrfri VRF Route Import
Not all type and subtype value pairs are allowed by IANA and the parser
will ensure that no invalid combination is created.
.Pp
+For
+.Cm delete ,
+.Ar subtype ,
+.Ar numvalue ,
+or
+.Ar local ,
+may be set to
+.Sq *
+to do wildcard matching.
+If wildcard matching is used on the
+.Ar subtype
+then
+.Ar numvalue
+also needs to be set to
+.Sq * .
+.Pp
.It Ic localpref Ar number
Set the
.Em LOCAL_PREF
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 07a57e44f81..d3a868d0ccf 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.374 2019/02/21 11:17:22 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.375 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -784,7 +784,7 @@ struct filter_community {
struct ext {
u_int32_t data1;
u_int64_t data2;
- u_int8_t type;
+ short type;
u_int8_t subtype; /* if extended type */
} e;
} c;
@@ -877,8 +877,10 @@ struct filter_peers {
#define EXT_COMMUNITY_NON_TRANS_IPV4 0x41 /* IPv4 specific */
#define EXT_COMMUNITY_NON_TRANS_FOUR_AS 0x42 /* 4 octet AS specific */
#define EXT_COMMUNITY_NON_TRANS_OPAQUE 0x43 /* opaque ext community */
+#define EXT_COMMUNITY_UNKNOWN -1
/* BGP Origin Validation State Extended Community RFC8097 */
+#define EXT_COMMUNITY_SUBTYPE_OVS 0
#define EXT_COMMUNITY_OVS_VALID 0
#define EXT_COMMUNITY_OVS_NOTFOUND 1
#define EXT_COMMUNITY_OVS_INVALID 2
@@ -888,7 +890,7 @@ struct filter_peers {
#define EXT_COMMUNITY_FLAG_VALID 0x01
struct ext_comm_pairs {
- u_int8_t type;
+ short type;
u_int8_t subtype;
const char *subname;
};
@@ -917,7 +919,7 @@ struct ext_comm_pairs {
{ EXT_COMMUNITY_TRANS_OPAQUE, 0x06, "ort" }, \
{ EXT_COMMUNITY_TRANS_OPAQUE, 0x0d, "defgw" }, \
\
- { EXT_COMMUNITY_NON_TRANS_OPAQUE, 0x00, "ovs" }, \
+ { EXT_COMMUNITY_NON_TRANS_OPAQUE, EXT_COMMUNITY_SUBTYPE_OVS, "ovs" }, \
\
{ EXT_COMMUNITY_TRANS_EVPN, 0x00, "mac-mob" }, \
{ EXT_COMMUNITY_TRANS_EVPN, 0x01, "esi-lab" }, \
@@ -1269,7 +1271,7 @@ const char *log_in6addr(const struct in6_addr *);
const char *log_sockaddr(struct sockaddr *, socklen_t);
const char *log_as(u_int32_t);
const char *log_rd(u_int64_t);
-const char *log_ext_subtype(u_int8_t, u_int8_t);
+const char *log_ext_subtype(short, u_int8_t);
const char *log_shutcomm(const char *);
int aspath_snprint(char *, size_t, void *, u_int16_t);
int aspath_asprint(char **, void *, u_int16_t);
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 3b89e5b48e9..1738f9e055f 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.379 2019/02/18 16:31:46 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.380 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -1100,6 +1100,7 @@ l3vpnopts : RD STRING {
struct filter_community ext;
u_int64_t rd;
+ memset(&ext, 0, sizeof(ext));
if (parseextcommunity(&ext, "rt", $2) == -1) {
free($2);
YYERROR;
@@ -1109,7 +1110,7 @@ l3vpnopts : RD STRING {
* RD is almost encode like an ext-community,
* but only almost so convert here.
*/
- if (community_ext_conv(&ext, 0, &rd)) {
+ if (community_ext_conv(&ext, NULL, &rd, NULL)) {
yyerror("bad encoding of rd");
YYERROR;
}
@@ -3598,7 +3599,7 @@ parsesubtype(char *name, int *type, int *subtype)
}
static int
-parseextvalue(int type, char *s, u_int32_t *v)
+parseextvalue(int type, char *s, u_int32_t *v, u_int8_t *flag)
{
const char *errstr;
char *p;
@@ -3607,6 +3608,14 @@ parseextvalue(int type, char *s, u_int32_t *v)
if (type != -1) {
/* nothing */
+ } else if (strcmp(s, "neighbor-as") == 0) {
+ *flag = COMMUNITY_NEIGHBOR_AS;
+ *v = 0;
+ return EXT_COMMUNITY_TRANS_FOUR_AS;
+ } else if (strcmp(s, "local-as") == 0) {
+ *flag = COMMUNITY_LOCAL_AS;
+ *v = 0;
+ return EXT_COMMUNITY_TRANS_FOUR_AS;
} else if ((p = strchr(s, '.')) == NULL) {
/* AS_PLAIN number (4 or 2 byte) */
strtonum(s, 0, USHRT_MAX, &errstr);
@@ -3672,12 +3681,16 @@ int
parseextcommunity(struct filter_community *c, char *t, char *s)
{
const struct ext_comm_pairs *cp;
- const char *errstr;
u_int64_t ullval;
- u_int32_t uval;
+ u_int32_t uval, uval2;
char *p, *ep;
int type = 0, subtype = 0;
+ if (strcmp(t, "*") == 0 && strcmp(s, "*") == 0) {
+ c->type = COMMUNITY_TYPE_EXT;
+ c->dflag3 = COMMUNITY_ANY;
+ return (0);
+ }
if (parsesubtype(t, &type, &subtype) == 0) {
yyerror("Bad ext-community unknown type");
return (-1);
@@ -3688,33 +3701,39 @@ parseextcommunity(struct filter_community *c, char *t, char *s)
case EXT_COMMUNITY_TRANS_FOUR_AS:
case EXT_COMMUNITY_TRANS_IPV4:
case -1:
+ if (strcmp(s, "*") == 0) {
+ c->dflag1 = COMMUNITY_ANY;
+ break;
+ }
if ((p = strchr(s, ':')) == NULL) {
yyerror("Bad ext-community %s", s);
return (-1);
}
*p++ = '\0';
- if ((type = parseextvalue(type, s, &uval)) == -1)
+ if ((type = parseextvalue(type, s, &uval, &c->dflag1)) == -1)
return (-1);
switch (type) {
case EXT_COMMUNITY_TRANS_TWO_AS:
- ullval = strtonum(p, 0, UINT_MAX, &errstr);
+ if (getcommunity(p, 1, &uval2, &c->dflag2) == -1)
+ return (-1);
break;
case EXT_COMMUNITY_TRANS_IPV4:
case EXT_COMMUNITY_TRANS_FOUR_AS:
- ullval = strtonum(p, 0, USHRT_MAX, &errstr);
+ if (getcommunity(p, 0, &uval2, &c->dflag2) == -1)
+ return (-1);
break;
default:
fatalx("parseextcommunity: unexpected result");
}
- if (errstr) {
- yyerror("Bad ext-community %s is %s", p, errstr);
- return (-1);
- }
c->c.e.data1 = uval;
- c->c.e.data2 = ullval;
+ c->c.e.data2 = uval2;
break;
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
+ if (strcmp(s, "*") == 0) {
+ c->dflag1 = COMMUNITY_ANY;
+ break;
+ }
errno = 0;
ullval = strtoull(s, &ep, 0);
if (s[0] == '\0' || *ep != '\0') {
@@ -3728,21 +3747,33 @@ parseextcommunity(struct filter_community *c, char *t, char *s)
c->c.e.data2 = ullval;
break;
case EXT_COMMUNITY_NON_TRANS_OPAQUE:
- if (strcmp(s, "valid") == 0)
- c->c.e.data2 = EXT_COMMUNITY_OVS_VALID;
- else if (strcmp(s, "invalid") == 0)
- c->c.e.data2 = EXT_COMMUNITY_OVS_INVALID;
- else if (strcmp(s, "not-found") == 0)
- c->c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND;
- else {
- yyerror("Bad ext-community %s", s);
- return (-1);
+ if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
+ if (strcmp(s, "valid") == 0) {
+ c->c.e.data2 = EXT_COMMUNITY_OVS_VALID;
+ break;
+ } else if (strcmp(s, "invalid") == 0) {
+ c->c.e.data2 = EXT_COMMUNITY_OVS_INVALID;
+ break;
+ } else if (strcmp(s, "not-found") == 0) {
+ c->c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND;
+ break;
+ } else if (strcmp(s, "*") == 0) {
+ c->dflag1 = COMMUNITY_ANY;
+ break;
+ }
}
- break;
+ yyerror("Bad ext-community %s", s);
+ return (-1);
}
c->c.e.type = type;
c->c.e.subtype = subtype;
+ /* special handling of ext-community rt * since type is not known */
+ if (c->dflag1 == COMMUNITY_ANY && c->c.e.type == -1) {
+ c->type = COMMUNITY_TYPE_EXT;
+ return (0);
+ }
+
/* verify type/subtype combo */
for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
if (cp->type == type && cp->subtype == subtype) {
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index bd042334974..80f733a5f2a 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.131 2019/02/18 11:43:44 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.132 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -200,34 +200,66 @@ print_community(struct filter_community *c)
}
break;
case COMMUNITY_TYPE_EXT:
+ if (c->dflag3 == COMMUNITY_ANY) {
+ printf("* * ");
+ break;
+ }
printf("%s ", log_ext_subtype(c->c.e.type, c->c.e.subtype));
+ if (c->dflag1 == COMMUNITY_ANY) {
+ printf("* ");
+ break;
+ }
+
switch (c->c.e.type) {
case EXT_COMMUNITY_TRANS_TWO_AS:
case EXT_COMMUNITY_TRANS_FOUR_AS:
- printf("%s:%llu ", log_as(c->c.e.data1),
- (unsigned long long)c->c.e.data2);
+ if (c->dflag1 == COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as:");
+ else if (c->dflag1 == COMMUNITY_LOCAL_AS)
+ printf("local-as:");
+ else
+ printf("%s:", log_as(c->c.e.data1));
break;
case EXT_COMMUNITY_TRANS_IPV4:
addr.s_addr = htonl(c->c.e.data1);
- printf("%s:%llu ", inet_ntoa(addr),
- (unsigned long long)c->c.e.data2);
+ printf("%s:", inet_ntoa(addr));
+ break;
+ }
+
+ switch (c->c.e.type) {
+ case EXT_COMMUNITY_TRANS_TWO_AS:
+ case EXT_COMMUNITY_TRANS_FOUR_AS:
+ case EXT_COMMUNITY_TRANS_IPV4:
+ if (c->dflag2 == COMMUNITY_ANY)
+ printf("* ");
+ else if (c->dflag2 == COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as ");
+ else if (c->dflag2 == COMMUNITY_LOCAL_AS)
+ printf("local-as ");
+ else
+ printf("%llu ",
+ (unsigned long long)c->c.e.data2);
break;
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
printf("0x%llx ", (unsigned long long)c->c.e.data2);
break;
case EXT_COMMUNITY_NON_TRANS_OPAQUE:
- switch (c->c.e.data2) {
- case EXT_COMMUNITY_OVS_VALID:
- printf("valid ");
- break;
- case EXT_COMMUNITY_OVS_NOTFOUND:
- printf("not-found ");
- break;
- case EXT_COMMUNITY_OVS_INVALID:
- printf("invalid ");
+ if (c->c.e.subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
+ switch (c->c.e.data2) {
+ case EXT_COMMUNITY_OVS_VALID:
+ printf("valid ");
+ break;
+ case EXT_COMMUNITY_OVS_NOTFOUND:
+ printf("not-found ");
+ break;
+ case EXT_COMMUNITY_OVS_INVALID:
+ printf("invalid ");
+ break;
+ }
break;
}
+ printf("0x%llx ", (unsigned long long)c->c.e.data2);
break;
default:
printf("0x%llx ", (unsigned long long)c->c.e.data2);
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 1e4fb6fccbb..8eb453f617a 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.209 2019/02/04 18:53:10 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.210 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -393,7 +393,7 @@ int community_ext_set(struct rde_aspath *,
void community_ext_delete(struct rde_aspath *,
struct filter_community *, struct rde_peer *);
int community_ext_conv(struct filter_community *, struct rde_peer *,
- u_int64_t *);
+ u_int64_t *, u_int64_t *);
u_char *community_ext_delete_non_trans(u_char *, u_int16_t, u_int16_t *);
/* rde_decide.c */
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index fa8086842f0..d1743197d24 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.118 2019/02/15 09:55:21 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.119 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -1155,26 +1155,42 @@ aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen)
static int
community_extract(struct filter_community *fc, struct rde_peer *peer,
- int field, int large, u_int32_t *value)
+ int field, u_int32_t *value)
{
u_int32_t data;
u_int8_t flag;
switch (field) {
case 1:
flag = fc->dflag1;
- if (large)
- data = fc->c.l.data1;
- else
+ switch (fc->type) {
+ case COMMUNITY_TYPE_BASIC:
data = fc->c.b.data1;
+ break;
+ case COMMUNITY_TYPE_LARGE:
+ data = fc->c.l.data1;
+ break;
+ case COMMUNITY_TYPE_EXT:
+ data = fc->c.e.data1;
+ break;
+ }
break;
case 2:
flag = fc->dflag2;
- if (large)
- data = fc->c.l.data2;
- else
+ switch (fc->type) {
+ case COMMUNITY_TYPE_BASIC:
data = fc->c.b.data2;
+ break;
+ case COMMUNITY_TYPE_LARGE:
+ data = fc->c.l.data2;
+ break;
+ case COMMUNITY_TYPE_EXT:
+ data = fc->c.e.data2;
+ break;
+ }
break;
case 3:
+ if (fc->type != COMMUNITY_TYPE_LARGE)
+ fatalx("%s: bad field %d", __func__, field);
flag = fc->dflag3;
data = fc->c.l.data3;
break;
@@ -1194,7 +1210,7 @@ community_extract(struct filter_community *fc, struct rde_peer *peer,
default:
*value = data;
}
- if (!large && *value > USHRT_MAX)
+ if (fc->type == COMMUNITY_TYPE_BASIC && *value > USHRT_MAX)
return -1;
return 0;
}
@@ -1203,10 +1219,24 @@ static int
community_ext_matchone(struct filter_community *c, struct rde_peer *peer,
u_int64_t community)
{
+ u_int32_t val;
u_int64_t com, mask;
community = be64toh(community);
+ if (c->dflag3 == COMMUNITY_ANY)
+ /* handle 'ext-community *', etc */
+ return (1);
+
+ /* special handling of ext-community rt * since type is not known */
+ if (c->dflag1 == COMMUNITY_ANY && c->c.e.type == -1) {
+ u_int8_t type = community >> 56;
+ if (type == EXT_COMMUNITY_TRANS_TWO_AS ||
+ type == EXT_COMMUNITY_TRANS_FOUR_AS ||
+ type == EXT_COMMUNITY_TRANS_IPV4)
+ goto subtype;
+ }
+
com = (u_int64_t)c->c.e.type << 56;
mask = 0xffULL << 56;
if ((com & mask) != (community & mask))
@@ -1214,9 +1244,11 @@ community_ext_matchone(struct filter_community *c, struct rde_peer *peer,
switch (c->c.e.type & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
- case EXT_COMMUNITY_TRANS_IPV4:
case EXT_COMMUNITY_TRANS_FOUR_AS:
+ case EXT_COMMUNITY_TRANS_IPV4:
case EXT_COMMUNITY_TRANS_OPAQUE:
+ case EXT_COMMUNITY_NON_TRANS_OPAQUE:
+subtype:
com = (u_int64_t)c->c.e.subtype << 48;
mask = 0xffULL << 48;
if ((com & mask) != (community & mask))
@@ -1230,39 +1262,48 @@ community_ext_matchone(struct filter_community *c, struct rde_peer *peer,
return (0);
}
+ if (c->dflag1 == COMMUNITY_ANY)
+ /* handle 'ext-community rt *', etc */
+ return (1);
switch (c->c.e.type & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
- com = (u_int64_t)c->c.e.data1 << 32;
+ if (community_extract(c, peer, 1, &val) == -1)
+ return (0);
+ com = (u_int64_t)val << 32;
mask = 0xffffULL << 32;
if ((com & mask) != (community & mask))
return (0);
- com = c->c.e.data2;
+ if (community_extract(c, peer, 2, &val) == -1)
+ return (0);
+ com = val;
mask = 0xffffffffULL;
- if ((com & mask) == (community & mask))
- return (1);
break;
case EXT_COMMUNITY_TRANS_IPV4:
case EXT_COMMUNITY_TRANS_FOUR_AS:
- com = (u_int64_t)c->c.e.data1 << 16;
+ if (community_extract(c, peer, 1, &val) == -1)
+ return (0);
+ com = (u_int64_t)val << 16;
mask = 0xffffffffULL << 16;
if ((com & mask) != (community & mask))
return (0);
- com = c->c.e.data2;
+ if (community_extract(c, peer, 2, &val) == -1)
+ return (0);
+ com = val;
mask = 0xffff;
- if ((com & mask) == (community & mask))
- return (1);
break;
case EXT_COMMUNITY_TRANS_OPAQUE:
+ case EXT_COMMUNITY_NON_TRANS_OPAQUE:
com = c->c.e.data2;
mask = EXT_COMMUNITY_OPAQUE_MAX;
- if ((com & mask) == (community & mask))
- return (1);
break;
}
+ if (c->dflag2 == COMMUNITY_ANY ||
+ (com & mask) == (community & mask))
+ return (1);
return (0);
}
@@ -1280,8 +1321,8 @@ community_match(struct rde_aspath *asp, struct filter_community *fc,
/* no communities, no match */
return (0);
- if (community_extract(fc, peer, 1, 0, &as) == -1 ||
- community_extract(fc, peer, 2, 0, &type) == -1)
+ if (community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &type) == -1)
/* can't match community */
return (0);
@@ -1311,8 +1352,8 @@ community_set(struct rde_aspath *asp, struct filter_community *fc,
u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY ||
- community_extract(fc, peer, 1, 0, &as) == -1 ||
- community_extract(fc, peer, 2, 0, &type) == -1)
+ community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &type) == -1)
/* bad community */
return (0);
@@ -1370,8 +1411,8 @@ community_delete(struct rde_aspath *asp, struct filter_community *fc,
/* no attr nothing to do */
return;
- if (community_extract(fc, peer, 1, 0, &as) == -1 ||
- community_extract(fc, peer, 2, 0, &type) == -1)
+ if (community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &type) == -1)
/* bad community, nothing to do */
return;
@@ -1460,7 +1501,7 @@ community_ext_set(struct rde_aspath *asp, struct filter_community *c,
unsigned int i, ncommunities = 0;
u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
- if (community_ext_conv(c, peer, &community))
+ if (community_ext_conv(c, peer, &community, NULL))
return (0);
attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
@@ -1504,12 +1545,15 @@ community_ext_delete(struct rde_aspath *asp, struct filter_community *c,
{
struct attr *attr;
u_int8_t *p, *n;
- u_int64_t community;
+ u_int64_t community, mask, test;
u_int16_t l, len = 0;
u_int8_t f;
+ int check_type = 0;
- if (community_ext_conv(c, peer, &community))
+ if (community_ext_conv(c, peer, &community, &mask))
return;
+ if (mask != 0 && betoh64(mask) >> 56 == 0)
+ check_type = 1;
attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
if (attr == NULL)
@@ -1518,7 +1562,19 @@ community_ext_delete(struct rde_aspath *asp, struct filter_community *c,
p = attr->data;
for (l = 0; l < attr->len; l += sizeof(community)) {
- if (memcmp(&community, p + l, sizeof(community)) == 0)
+ memcpy(&test, p + l, sizeof(community));
+ /* special handling of ext-community rt *, type is not known */
+ if (check_type) {
+ u_int8_t type = betoh64(test) >> 56;
+ if (type != EXT_COMMUNITY_TRANS_TWO_AS &&
+ type != EXT_COMMUNITY_TRANS_FOUR_AS &&
+ type != EXT_COMMUNITY_TRANS_IPV4) {
+ /* no match */
+ len += sizeof(community);
+ continue;
+ }
+ }
+ if ((test & mask) == (community & mask))
/* match */
continue;
len += sizeof(community);
@@ -1535,9 +1591,23 @@ community_ext_delete(struct rde_aspath *asp, struct filter_community *c,
p = attr->data;
for (l = 0; l < len && p < attr->data + attr->len;
p += sizeof(community)) {
- if (memcmp(&community, p, sizeof(community)) == 0)
+ memcpy(&test, p, sizeof(community));
+ /* special handling of ext-community rt *, type is not known */
+ if (check_type) {
+ u_int8_t type = betoh64(test) >> 56;
+ if (type != EXT_COMMUNITY_TRANS_TWO_AS &&
+ type != EXT_COMMUNITY_TRANS_FOUR_AS &&
+ type != EXT_COMMUNITY_TRANS_IPV4) {
+ /* no match */
+ memcpy(n + l, p, sizeof(community));
+ l += sizeof(community);
+ continue;
+ }
+ }
+ if ((test & mask) == (community & mask)) {
/* match */
continue;
+ }
memcpy(n + l, p, sizeof(community));
l += sizeof(community);
}
@@ -1551,25 +1621,65 @@ community_ext_delete(struct rde_aspath *asp, struct filter_community *c,
int
community_ext_conv(struct filter_community *c, struct rde_peer *peer,
- u_int64_t *community)
+ u_int64_t *community, u_int64_t *mask)
{
- u_int64_t com;
+ u_int64_t com = 0, m = 0;
+ u_int32_t val;
+
+ if (c->dflag3 == COMMUNITY_ANY) {
+ m = ~m;
+ goto done;
+ }
+ /* special handling of ext-community rt * since type is not known */
+ if (c->dflag1 == COMMUNITY_ANY && c->c.e.type == -1) {
+ m |= 0xffULL << 56;
+ goto subtype;
+ }
com = (u_int64_t)c->c.e.type << 56;
switch (c->c.e.type & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
+ case EXT_COMMUNITY_TRANS_FOUR_AS:
+ case EXT_COMMUNITY_TRANS_IPV4:
+ case EXT_COMMUNITY_TRANS_OPAQUE:
+subtype:
com |= (u_int64_t)c->c.e.subtype << 48;
- com |= (u_int64_t)c->c.e.data1 << 32;
- com |= c->c.e.data2 & 0xffffffff;
+ if (c->dflag1 == COMMUNITY_ANY) {
+ m |= 0xffffffffffffULL;
+ goto done;
+ }
+ break;
+ }
+
+ switch (c->c.e.type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TRANS_TWO_AS:
+ if (community_extract(c, peer, 1, &val) == -1)
+ return (-1);
+ com |= (u_int64_t)val << 32;
+
+ if (c->dflag2 == COMMUNITY_ANY) {
+ m |= 0xffffffffULL;
+ goto done;
+ }
+ if (community_extract(c, peer, 2, &val) == -1)
+ return (-1);
+ com |= (u_int64_t)val & 0xffffffffULL;
break;
case EXT_COMMUNITY_TRANS_IPV4:
case EXT_COMMUNITY_TRANS_FOUR_AS:
- com |= (u_int64_t)c->c.e.subtype << 48;
- com |= (u_int64_t)c->c.e.data1 << 16;
- com |= c->c.e.data2 & 0xffff;
+ if (community_extract(c, peer, 1, &val) == -1)
+ return (-1);
+ com |= (u_int64_t)val << 16;
+
+ if (c->dflag2 == COMMUNITY_ANY) {
+ m |= 0xffffULL;
+ goto done;
+ }
+ if (community_extract(c, peer, 2, &val) == -1)
+ return (-1);
+ com |= (u_int64_t)val & 0xffffULL;
break;
case EXT_COMMUNITY_TRANS_OPAQUE:
- com |= (u_int64_t)c->c.e.subtype << 48;
com |= c->c.e.data2 & EXT_COMMUNITY_OPAQUE_MAX;
break;
default:
@@ -1577,11 +1687,47 @@ community_ext_conv(struct filter_community *c, struct rde_peer *peer,
break;
}
+done:
*community = htobe64(com);
+ if (mask)
+ *mask = htobe64(~m);
+ else if (m != 0)
+ return (-1);
return (0);
}
+u_char *
+community_ext_delete_non_trans(u_char *data, u_int16_t len, u_int16_t *newlen)
+{
+ u_int8_t *ext = data, *newdata;
+ u_int16_t l, nlen = 0;
+
+ for (l = 0; l < len; l += sizeof(u_int64_t)) {
+ if (!(ext[l] & EXT_COMMUNITY_TRANSITIVE))
+ nlen += sizeof(u_int64_t);
+ }
+
+ if (nlen == 0) {
+ *newlen = 0;
+ return NULL;
+ }
+
+ newdata = malloc(nlen);
+ if (newdata == NULL)
+ fatal("%s", __func__);
+
+ for (l = 0, nlen = 0; l < len; l += sizeof(u_int64_t)) {
+ if (!(ext[l] & EXT_COMMUNITY_TRANSITIVE)) {
+ memcpy(newdata + nlen, ext + l, sizeof(u_int64_t));
+ nlen += sizeof(u_int64_t);
+ }
+ }
+
+ *newlen = nlen;
+ return newdata;
+}
+
struct wire_largecommunity {
uint32_t as;
uint32_t ld1;
@@ -1603,9 +1749,9 @@ community_large_match(struct rde_aspath *asp, struct filter_community *fc,
/* no communities, no match */
return (0);
- if (community_extract(fc, peer, 1, 1, &as) == -1 ||
- community_extract(fc, peer, 2, 1, &ld1) == -1 ||
- community_extract(fc, peer, 3, 1, &ld2) == -1)
+ if (community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &ld1) == -1 ||
+ community_extract(fc, peer, 3, &ld2) == -1)
/* can't match community */
return (0);
@@ -1639,9 +1785,9 @@ community_large_set(struct rde_aspath *asp, struct filter_community *fc,
if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY ||
fc->dflag3 == COMMUNITY_ANY ||
- community_extract(fc, peer, 1, 1, &as) == -1 ||
- community_extract(fc, peer, 2, 1, &ld1) == -1 ||
- community_extract(fc, peer, 3, 1, &ld2) == -1)
+ community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &ld1) == -1 ||
+ community_extract(fc, peer, 3, &ld2) == -1)
/* can't match community */
return (0);
@@ -1704,9 +1850,9 @@ community_large_delete(struct rde_aspath *asp, struct filter_community *fc,
/* no attr nothing to do */
return;
- if (community_extract(fc, peer, 1, 1, &as) == -1 ||
- community_extract(fc, peer, 2, 1, &ld1) == -1 ||
- community_extract(fc, peer, 3, 1, &ld2) == -1)
+ if (community_extract(fc, peer, 1, &as) == -1 ||
+ community_extract(fc, peer, 2, &ld1) == -1 ||
+ community_extract(fc, peer, 3, &ld2) == -1)
/* can't match community */
return;
@@ -1755,34 +1901,3 @@ community_large_delete(struct rde_aspath *asp, struct filter_community *fc,
attr_optadd(asp, f, ATTR_LARGE_COMMUNITIES, n, len);
free(n);
}
-
-u_char *
-community_ext_delete_non_trans(u_char *data, u_int16_t len, u_int16_t *newlen)
-{
- u_int8_t *ext = data, *newdata;
- u_int16_t l, nlen = 0;
-
- for (l = 0; l < len; l += sizeof(u_int64_t)) {
- if (!(ext[l] & EXT_COMMUNITY_TRANSITIVE))
- nlen += sizeof(u_int64_t);
- }
-
- if (nlen == 0) {
- *newlen = 0;
- return NULL;
- }
-
- newdata = malloc(nlen);
- if (newdata == NULL)
- fatal("%s", __func__);
-
- for (l = 0, nlen = 0; l < len; l += sizeof(u_int64_t)) {
- if (!(ext[l] & EXT_COMMUNITY_TRANSITIVE)) {
- memcpy(newdata + nlen, ext + l, sizeof(u_int64_t));
- nlen += sizeof(u_int64_t);
- }
- }
-
- *newlen = nlen;
- return newdata;
-}
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c
index ed1e406662d..c97c9b7f216 100644
--- a/usr.sbin/bgpd/util.c
+++ b/usr.sbin/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.46 2019/02/21 11:17:22 claudio Exp $ */
+/* $OpenBSD: util.c,v 1.47 2019/02/26 10:49:15 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -146,13 +146,13 @@ const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
/* NOTE: this function does not check if the type/subtype combo is
* actually valid. */
const char *
-log_ext_subtype(u_int8_t type, u_int8_t subtype)
+log_ext_subtype(short type, u_int8_t subtype)
{
static char etype[6];
const struct ext_comm_pairs *cp;
for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
- if (type == cp->type && subtype == cp->subtype)
+ if ((type == cp->type || type == -1) && subtype == cp->subtype)
return (cp->subname);
}
snprintf(etype, sizeof(etype), "[%u]", subtype);