summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2010-03-05 15:25:01 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2010-03-05 15:25:01 +0000
commite588841a37c4827ec10abcfa7533e356f1eb7e32 (patch)
tree6a3bd38f03bcc2f9b7a902f8eda4669ad163c044
parentc305baaf13d88ae8b5cc03c8663520d3054d1338 (diff)
Allow to filter for ext-community attributes. Currently only perfect matches
work but that's already better then nothing. OK sthen@
-rw-r--r--usr.sbin/bgpd/bgpd.conf.529
-rw-r--r--usr.sbin/bgpd/bgpd.h13
-rw-r--r--usr.sbin/bgpd/parse.y21
-rw-r--r--usr.sbin/bgpd/printconf.c18
-rw-r--r--usr.sbin/bgpd/rde.h4
-rw-r--r--usr.sbin/bgpd/rde_attr.c113
-rw-r--r--usr.sbin/bgpd/rde_filter.c7
7 files changed, 182 insertions, 23 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index be84b281a26..8114b853152 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.103 2009/12/16 15:40:55 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.104 2010/03/05 15:25:00 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: December 16 2009 $
+.Dd $Mdocdate: March 5 2010 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -951,6 +951,31 @@ may be set to
which is expanded to the current neighbor remote AS number.
.Pp
.It Xo
+.Ic ext-community
+.Ar subtype Ar as-number Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community
+.Ar subtype Ar IP Ns Li : Ns Ar local
+.Xc
+.It Xo
+.Ic ext-community
+.Ar subtype Ar numvalue
+.Xc
+This rule applies only to
+.Em UPDATES
+where the
+.Em extended community
+path attribute is present and matches.
+Extended Communities are specified by a
+.Ar subtype
+and normally two values, a globally unique part (e.g. the AS number) and a
+local part.
+See also the
+.Sx ATTRIBUTE SET
+section for further information about the encoding.
+.Pp
+.It Xo
.Pq Ic from Ns \&| Ns Ic to
.Ar peer
.Xc
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 16e82ea8ae7..3e466fde63f 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.252 2010/01/13 06:02:37 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.253 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -567,6 +567,7 @@ struct filter_community {
};
struct filter_extcommunity {
+ u_int16_t flags;
u_int8_t type;
u_int8_t subtype; /* if extended type */
union {
@@ -666,6 +667,7 @@ struct filter_peers {
#define EXT_COMMUNITY_BGP_COLLECT 8 /* RFC 4384 */
/* other handy defines */
#define EXT_COMMUNITY_OPAQUE_MAX 0xffffffffffffULL
+#define EXT_COMMUNITY_FLAG_VALID 0x01
struct ext_comm_pairs {
u_int8_t type;
@@ -700,10 +702,11 @@ struct filter_prefixlen {
};
struct filter_match {
- struct filter_prefix prefix;
- struct filter_prefixlen prefixlen;
- struct filter_as as;
- struct filter_community community;
+ struct filter_prefix prefix;
+ struct filter_prefixlen prefixlen;
+ struct filter_as as;
+ struct filter_community community;
+ struct filter_extcommunity ext_community;
};
TAILQ_HEAD(filter_head, filter_rule);
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 11b5742445f..975682bdb35 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.248 2010/01/13 06:02:37 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.249 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -1473,6 +1473,24 @@ filter_elm : filter_prefix_h {
}
free($2);
}
+ | EXTCOMMUNITY STRING STRING {
+ if (fmopts.m.ext_community.flags &
+ EXT_COMMUNITY_FLAG_VALID) {
+ yyerror("\"ext-community\" already specified");
+ free($2);
+ free($3);
+ YYERROR;
+ }
+
+ if (parseextcommunity(&fmopts.m.ext_community,
+ $2, $3) == -1) {
+ free($2);
+ free($3);
+ YYERROR;
+ }
+ free($2);
+ free($3);
+ }
| IPV4 {
if (fmopts.aid) {
yyerror("address family already specified");
@@ -2741,6 +2759,7 @@ parseextcommunity(struct filter_extcommunity *c, char *t, char *s)
if (iana[i].type == type && iana[i].subtype == subtype) {
if (iana[i].transitive)
c->type |= EXT_COMMUNITY_TRANSITIVE;
+ c->flags |= EXT_COMMUNITY_FLAG_VALID;
return (0);
}
}
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 388acdc9de4..54d8d51626d 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.78 2010/03/03 22:09:08 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.79 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -100,23 +100,23 @@ print_extcommunity(struct filter_extcommunity *c)
{
switch (c->type & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TWO_AS:
- printf("%s %i:%i", log_ext_subtype(c->subtype),
+ printf("%s %i:%i ", log_ext_subtype(c->subtype),
c->data.ext_as.as, c->data.ext_as.val);
break;
case EXT_COMMUNITY_IPV4:
- printf("%s %s:%i", log_ext_subtype(c->subtype),
+ printf("%s %s:%i ", log_ext_subtype(c->subtype),
inet_ntoa(c->data.ext_ip.addr), c->data.ext_ip.val);
break;
case EXT_COMMUNITY_FOUR_AS:
- printf("%s %s:%i", log_ext_subtype(c->subtype),
+ printf("%s %s:%i ", log_ext_subtype(c->subtype),
log_as(c->data.ext_as4.as4), c->data.ext_as.val);
break;
case EXT_COMMUNITY_OPAQUE:
- printf("%s 0x%llx", log_ext_subtype(c->subtype),
+ printf("%s 0x%llx ", log_ext_subtype(c->subtype),
c->data.ext_opaq);
break;
default:
- printf("0x%x 0x%llx", c->type, c->data.ext_opaq);
+ printf("0x%x 0x%llx ", c->type, c->data.ext_opaq);
break;
}
}
@@ -214,12 +214,10 @@ print_set(struct filter_set_head *set)
case ACTION_SET_EXT_COMMUNITY:
printf("ext-community ");
print_extcommunity(&s->action.ext_community);
- printf(" ");
break;
case ACTION_DEL_EXT_COMMUNITY:
printf("ext-community delete ");
print_extcommunity(&s->action.ext_community);
- printf(" ");
break;
}
}
@@ -554,6 +552,10 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
print_community(r->match.community.as,
r->match.community.type);
}
+ if (r->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID) {
+ printf("ext-community ");
+ print_extcommunity(&r->match.ext_community);
+ }
print_set(&r->set);
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index a22050fc26c..f7dbb0bd025 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.130 2010/03/03 13:52:39 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.131 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -350,6 +350,8 @@ int aspath_match(struct aspath *, enum as_spec, u_int32_t);
int community_match(struct rde_aspath *, int, int);
int community_set(struct rde_aspath *, int, int);
void community_delete(struct rde_aspath *, int, int);
+int community_ext_match(struct rde_aspath *,
+ struct filter_extcommunity *, u_int16_t);
int community_ext_set(struct rde_aspath *,
struct filter_extcommunity *, u_int16_t);
void community_ext_delete(struct rde_aspath *,
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index c83a3d2736d..6f73d9a6537 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.81 2009/12/18 15:51:37 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.82 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -976,6 +976,7 @@ aspath_match(struct aspath *a, enum as_spec type, u_int32_t as)
*/
int community_ext_conv(struct filter_extcommunity *, u_int16_t, u_int64_t *);
+int community_ext_matchone(struct filter_extcommunity *, u_int16_t, u_int64_t);
int
community_match(struct rde_aspath *asp, int as, int type)
@@ -989,10 +990,8 @@ community_match(struct rde_aspath *asp, int as, int type)
/* no communities, no match */
return (0);
- len = a->len / 4;
p = a->data;
-
- for (; len > 0; len--) {
+ for (len = a->len / 4; len > 0; len--) {
eas = *p++;
eas <<= 8;
eas |= *p++;
@@ -1118,6 +1117,31 @@ community_delete(struct rde_aspath *asp, int as, int type)
}
int
+community_ext_match(struct rde_aspath *asp, struct filter_extcommunity *c,
+ u_int16_t neighas)
+{
+ struct attr *attr;
+ u_int8_t *p;
+ u_int64_t ec;
+ u_int16_t len;
+
+ attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
+ if (attr == NULL)
+ /* no communities, no match */
+ return (0);
+
+ p = attr->data;
+ for (len = attr->len / sizeof(ec); len > 0; len--) {
+ memcpy(&ec, p, sizeof(ec));
+ if (community_ext_matchone(c, neighas, ec))
+ return (1);
+ p += sizeof(ec);
+ }
+
+ return (0);
+}
+
+int
community_ext_set(struct rde_aspath *asp, struct filter_extcommunity *c,
u_int16_t neighas)
{
@@ -1133,7 +1157,7 @@ community_ext_set(struct rde_aspath *asp, struct filter_extcommunity *c,
attr = attr_optget(asp, ATTR_EXT_COMMUNITIES);
if (attr != NULL) {
p = attr->data;
- ncommunities = attr->len / 8; /* 64bit per ext-community */
+ ncommunities = attr->len / sizeof(community);
}
/* first check if the community is not already set */
@@ -1254,3 +1278,82 @@ community_ext_conv(struct filter_extcommunity *c, u_int16_t neighas,
return (0);
}
+
+int
+community_ext_matchone(struct filter_extcommunity *c, u_int16_t neighas,
+ u_int64_t community)
+{
+ u_int64_t com, mask;
+ u_int32_t ip;
+
+ community = betoh64(community);
+
+ com = (u_int64_t)c->type << 56;
+ mask = 0xffULL << 56;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ case EXT_COMMUNITY_IPV4:
+ case EXT_COMMUNITY_FOUR_AS:
+ case EXT_COMMUNITY_OPAQUE:
+ com = (u_int64_t)c->subtype << 48;
+ mask = 0xffULL << 48;
+ if ((com & mask) != (community & mask))
+ return (0);
+ break;
+ default:
+ com = c->data.ext_opaq & 0xffffffffffffffULL;
+ mask = 0xffffffffffffffULL;
+ if ((com & mask) == (community & mask))
+ return (1);
+ return (0);
+ }
+
+
+ switch (c->type & EXT_COMMUNITY_VALUE) {
+ case EXT_COMMUNITY_TWO_AS:
+ com = (u_int64_t)c->data.ext_as.as << 32;
+ mask = 0xffffULL << 32;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_as.val;
+ mask = 0xffffffffULL;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_IPV4:
+ ip = ntohl(c->data.ext_ip.addr.s_addr);
+ com = (u_int64_t)ip << 16;
+ mask = 0xffffffff0000ULL;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_ip.val;
+ mask = 0xffff;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ com = (u_int64_t)c->data.ext_as4.as4 << 16;
+ mask = 0xffffffffULL << 16;
+ if ((com & mask) != (community & mask))
+ return (0);
+
+ com = c->data.ext_as4.val;
+ mask = 0xffff;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ case EXT_COMMUNITY_OPAQUE:
+ com = c->data.ext_opaq & EXT_COMMUNITY_OPAQUE_MAX;
+ mask = EXT_COMMUNITY_OPAQUE_MAX;
+ if ((com & mask) == (community & mask))
+ return (1);
+ break;
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index f6e3a179048..994e4d15b5d 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.61 2009/12/18 15:51:37 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.62 2010/03/05 15:25:00 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -302,6 +302,11 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
if (community_match(asp, as, type) == 0)
return (0);
}
+ if (asp != NULL &&
+ (f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID))
+ if (community_ext_match(asp, &f->match.ext_community,
+ peer->conf.remote_as) == 0)
+ return (0);
if (f->match.prefix.addr.aid != 0) {
if (f->match.prefix.addr.aid != prefix->aid)