diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-03-05 15:25:01 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-03-05 15:25:01 +0000 |
commit | e588841a37c4827ec10abcfa7533e356f1eb7e32 (patch) | |
tree | 6a3bd38f03bcc2f9b7a902f8eda4669ad163c044 /usr.sbin | |
parent | c305baaf13d88ae8b5cc03c8663520d3054d1338 (diff) |
Allow to filter for ext-community attributes. Currently only perfect matches
work but that's already better then nothing. OK sthen@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.conf.5 | 29 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 21 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 18 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_attr.c | 113 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 7 |
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) |