summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2004-03-11 17:12:52 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2004-03-11 17:12:52 +0000
commitb21c2c568e1f969a0ca76f191c92856223ff303d (patch)
treec7a28663b294b4c9aa62c2be89dee73c6ec3534d /usr.sbin
parent01eec010699fb17fab1f9d2ec7b12f15330fd2b9 (diff)
Add basic support for communities. Currently it is only possible to filter
on communities, e.g match from any community 24640:* set localpref 666 OK henning@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bgpd/bgpd.h14
-rw-r--r--usr.sbin/bgpd/parse.y55
-rw-r--r--usr.sbin/bgpd/printconf.c14
-rw-r--r--usr.sbin/bgpd/rde.h8
-rw-r--r--usr.sbin/bgpd/rde_attr.c82
-rw-r--r--usr.sbin/bgpd/rde_filter.c20
-rw-r--r--usr.sbin/bgpd/rde_update.c44
7 files changed, 197 insertions, 40 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index fd1fc8de1a0..95db970c195 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.105 2004/03/10 11:38:32 henning Exp $ */
+/* $OpenBSD: bgpd.h,v 1.106 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -394,6 +394,14 @@ struct filter_peers {
u_int32_t groupid;
};
+/* special community type */
+#define COMMUNITY_ERROR -1
+#define COMMUNITY_ANY -2
+#define COMMUNITY_WELLKNOWN 0xffff
+#define COMMUNITY_NO_EXPORT 0xff01
+#define COMMUNITY_NO_ADVERTISE 0xff02
+#define COMMUNITY_NO_EXPSUBCONFED 0xff03
+
struct filter_match {
struct {
struct bgpd_addr addr;
@@ -406,6 +414,10 @@ struct filter_match {
u_int8_t len_max;
} prefixlen;
struct as_filter as;
+ struct {
+ int as;
+ int type;
+ } community;
};
TAILQ_HEAD(filter_head, filter_rule);
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 56922153782..c30a1db47f3 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.75 2004/03/10 11:40:33 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.76 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -81,6 +81,7 @@ struct sym {
int symset(const char *, const char *, int);
char *symget(const char *);
int atoul(char *, u_long *);
+int getcommunity(char *);
typedef struct {
union {
@@ -111,11 +112,11 @@ typedef struct {
%token ALLOW DENY MATCH
%token QUICK
%token FROM TO ANY
-%token PREFIX PREFIXLEN SOURCEAS TRANSITAS
+%token PREFIX PREFIXLEN SOURCEAS TRANSITAS COMMUNITY
%token SET LOCALPREF MED NEXTHOP PREPEND
%token ERROR
%token <v.string> STRING
-%type <v.number> number asnumber optnumber yesno inout
+%type <v.number> number asnumber optnumber cnumber yesno inout
%type <v.string> string
%type <v.addr> address
%type <v.prefix> prefix
@@ -625,15 +626,32 @@ filter_match : /* empty */ { bzero(&$$, sizeof($$)); }
$$.prefixlen = $2.prefixlen;
$$.prefixlen.af = AF_INET;
}
- | filter_as number {
+ | filter_as asnumber {
bzero(&$$, sizeof($$));
- if ($2 > 0xffff) {
- yyerror("AS out of range, max %u", 0xffff);
- YYERROR;
- }
$$.as.as = $2;
$$.as.type = $1;
}
+ | COMMUNITY STRING {
+ char *p;
+ int i;
+
+ bzero(&$$, sizeof($$));
+ if ((p = strchr($2, ':')) == NULL) {
+ yyerror("Bad community syntax");
+ YYERROR;
+ }
+ *p++ = 0;
+ if ((i = getcommunity($2)) == COMMUNITY_ERROR)
+ YYERROR;
+ if (i == 0 || i == USHRT_MAX) {
+ yyerror("Bad community as number");
+ YYERROR;
+ }
+ $$.community.as = i;
+ if ((i = getcommunity(p)) == COMMUNITY_ERROR)
+ YYERROR;
+ $$.community.type = i;
+ }
;
prefixlenop : unaryop number {
@@ -771,6 +789,7 @@ lookup(char *s)
{ "announce", ANNOUNCE},
{ "any", ANY},
{ "capabilities", CAPABILITIES},
+ { "community", COMMUNITY},
{ "deny", DENY},
{ "descr", DESCR},
{ "dump", DUMP},
@@ -992,7 +1011,7 @@ top:
x != '!' && x != '=' && x != '/' && x != '#' && \
x != ','))
- if (isalnum(c) || c == ':' || c == '_') {
+ if (isalnum(c) || c == ':' || c == '_' || c == '*') {
do {
*p++ = c;
if ((unsigned)(p-buf) >= sizeof(buf)) {
@@ -1184,6 +1203,24 @@ atoul(char *s, u_long *ulvalp)
return (0);
}
+int
+getcommunity(char *s)
+{
+ u_long ulval;
+
+ if (strcmp(s, "*") == 0)
+ return (COMMUNITY_ANY);
+ if (atoul(s, &ulval) == -1) {
+ yyerror("\"%s\" is not a number", s);
+ return (COMMUNITY_ERROR);
+ }
+ if (ulval > USHRT_MAX) {
+ yyerror("Community too big: max %u", USHRT_MAX);
+ return (COMMUNITY_ERROR);
+ }
+ return (ulval);
+}
+
struct peer *
alloc_peer(void)
{
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 97d0a0d4d43..077696c0828 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.8 2004/03/01 23:00:03 henning Exp $ */
+/* $OpenBSD: printconf.c,v 1.9 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -240,6 +240,18 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
printf("unfluffy-AS %u ", r->match.as.as);
}
+ if (r->match.community.as != 0) {
+ if (r->match.community.as == COMMUNITY_ANY)
+ printf("*:");
+ else
+ printf("%d:", r->match.community.as);
+
+ if (r->match.community.type == COMMUNITY_ANY)
+ printf("* ");
+ else
+ printf("%d ", r->match.community.type);
+ }
+
print_set(&r->set);
printf("\n");
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 6911a1556a7..bd5eacb6014 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.35 2004/03/11 14:22:23 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.36 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -106,7 +106,8 @@ enum attrtypes {
ATTR_MED,
ATTR_LOCALPREF,
ATTR_ATOMIC_AGGREGATE,
- ATTR_AGGREGATOR
+ ATTR_AGGREGATOR,
+ ATTR_COMMUNITIES
};
/* attribute flags. 4 low order bits reserved */
@@ -232,6 +233,7 @@ int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
int attr_optadd(struct attr_flags *, u_int8_t, u_int8_t,
u_char *, u_int16_t);
+struct attr *attr_optget(struct attr_flags *, u_int8_t);
void attr_optfree(struct attr_flags *);
int aspath_verify(void *, u_int16_t);
@@ -253,6 +255,7 @@ 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);
int aspath_match(struct aspath *, enum as_spec, u_int16_t);
+int community_match(void *, u_int16_t, int, int);
/* rde_rib.c */
void path_init(u_int32_t);
@@ -306,5 +309,6 @@ void pt_dump(void (*)(struct pt_entry *, void *), void *);
enum filter_actions rde_filter(struct rde_peer *, struct attr_flags *,
struct bgpd_addr *, u_int8_t, enum directions);
void rde_apply_set(struct attr_flags *, struct filter_set *);
+int rde_filter_community(struct attr_flags *, int, int);
#endif /* __RDE_H__ */
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index fd3279aee64..d6aced91aba 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.19 2004/03/11 16:38:23 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.20 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -37,8 +37,8 @@
plen += n; \
} while (0)
-#define CHECK_FLAGS(s, t) \
- (((s) & ~ATTR_EXTLEN) == (t))
+#define CHECK_FLAGS(s, t, m) \
+ (((s) & ~(ATTR_EXTLEN | (m))) == (t))
#define F_ATTR_ORIGIN 0x01
#define F_ATTR_ASPATH 0x02
@@ -97,7 +97,7 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_ORIGIN:
if (attr_len != 1)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN))
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
return (-1);
UPD_READ(&a->origin, p, plen, 1);
if (a->origin > ORIGIN_INCOMPLETE)
@@ -105,7 +105,7 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
WFLAG(a->wflags, F_ATTR_ORIGIN);
break;
case ATTR_ASPATH:
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN))
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
return (-1);
if (aspath_verify(p, attr_len) != 0)
return (-1);
@@ -120,7 +120,7 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_NEXTHOP:
if (attr_len != 4)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN))
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
return (-1);
WFLAG(a->wflags, F_ATTR_NEXTHOP);
UPD_READ(&a->nexthop, p, plen, 4); /* network byte order */
@@ -136,7 +136,7 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_MED:
if (attr_len != 4)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL))
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
return (-1);
WFLAG(a->wflags, F_ATTR_MED);
UPD_READ(&tmp32, p, plen, 4);
@@ -145,7 +145,7 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_LOCALPREF:
if (attr_len != 4)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN))
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
return (-1);
if (ebgp) {
/* ignore local-pref attr for non ibgp peers */
@@ -160,13 +160,20 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
case ATTR_ATOMIC_AGGREGATE:
if (attr_len != 0)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN))
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
return (-1);
goto optattr;
case ATTR_AGGREGATOR:
if (attr_len != 6)
return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE))
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_COMMUNITIES:
+ if ((attr_len & 0x3) != 0)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
return (-1);
goto optattr;
default:
@@ -238,7 +245,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
*size = 0;
return (NULL);
}
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN)) {
+ if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
/* malformed aspath detected by exclusion method */
*size = 0;
*suberr = ERR_UPD_ASPATH;
@@ -253,7 +260,7 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
*size = 0;
return (NULL);
}
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN)) {
+ if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
/* malformed nexthop detected by exclusion method */
*suberr = ERR_UPD_NETWORK;
return (p);
@@ -285,15 +292,15 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
if (attr_len != 6)
return (p);
break;
+ case ATTR_COMMUNITIES:
+ if ((attr_len & 0x3) != 0)
+ return (p);
+ /* FALLTHROUGH */
default:
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN)) {
+ if ((flags & ATTR_OPTIONAL) == 0) {
*suberr = ERR_UPD_UNKNWN_WK_ATTR;
return (p);
}
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL)) {
- *suberr = ERR_UPD_ATTRFLAGS;
- return (p);
- }
TAILQ_FOREACH(a, &attr->others, attr_l)
if (type == a->type) {
*size = NULL;
@@ -497,6 +504,21 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
return (0);
}
+struct attr *
+attr_optget(struct attr_flags *attr, u_int8_t type)
+{
+ struct attr *a;
+
+ TAILQ_FOREACH(a, &attr->others, attr_l) {
+ if (type == a->type)
+ return (a);
+ if (type < a->type)
+ /* list is sorted */
+ break;
+ }
+ return (NULL);
+}
+
void
attr_optfree(struct attr_flags *attr)
{
@@ -821,7 +843,10 @@ aspath_snprint(char *buf, size_t size, void *data, u_int16_t len)
seg_size = 2 + 2 * seg_len;
if (seg_type == AS_SET) {
- r = snprintf(buf, size, "{ ");
+ if (total_size != 0)
+ r = snprintf(buf, size, " { ");
+ else
+ r = snprintf(buf, size, "{ ");
UPDATE();
} else if (total_size != 0) {
r = snprintf(buf, size, " ");
@@ -948,3 +973,24 @@ aspath_match(struct aspath *a, enum as_spec type, u_int16_t as)
}
return (0);
}
+
+int
+community_match(void *data, u_int16_t len, int as, int type)
+{
+ u_int8_t *p = data;
+ u_int16_t eas, etype, l;
+
+ for (l = 0; l + 3 < len; len +=4) {
+ eas = *p++;
+ eas <<= 8;
+ eas |= *p++;
+ etype = *p++;
+ etype <<= 8;
+ etype |= *p++;
+ if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) &&
+ (type == COMMUNITY_ANY || type == etype))
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index 328283df97f..1e36d67e1da 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.6 2004/03/02 19:29:01 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.7 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -87,6 +87,11 @@ rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
f->match.as.as) == 0)
return (0);
+ if (attrs != NULL && f->match.community.as != 0)
+ if (rde_filter_community(attrs, f->match.community.as,
+ f->match.community.type) == 0)
+ return (0);
+
if (f->match.prefix.addr.af != 0 &&
f->match.prefix.addr.af == prefix->af) {
switch (f->match.prefix.addr.af) {
@@ -160,3 +165,16 @@ rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
/* matched somewhen or is anymatch rule */
return (1);
}
+
+int
+rde_filter_community(struct attr_flags *attr, int as, int type)
+{
+ struct attr *a;
+
+ a = attr_optget(attr, ATTR_COMMUNITIES);
+ if (a == NULL)
+ /* no communities, no match */
+ return (0);
+
+ return (community_match(a->data, a->len, as, type));
+}
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index afd677e24ba..07087600991 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.13 2004/03/09 13:51:16 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.14 2004/03/11 17:12:51 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -252,6 +252,17 @@ up_generate_updates(struct rde_peer *peer,
break;
}
+ /* well known communites */
+ if (rde_filter_community(&old->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE))
+ return;
+ if (peer->conf.ebgp && rde_filter_community(&old->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT))
+ return;
+ if (peer->conf.ebgp && rde_filter_community(&old->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED))
+ return;
+
/* copy attributes for output filter */
attr_copy(&attrs, &old->aspath->flags);
@@ -317,6 +328,23 @@ up_generate_updates(struct rde_peer *peer,
break;
}
+ /* well known communites */
+ if (rde_filter_community(&new->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE)) {
+ up_generate_updates(peer, NULL, old);
+ return;
+ }
+ if (peer->conf.ebgp && rde_filter_community(&new->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT)) {
+ up_generate_updates(peer, NULL, old);
+ return;
+ }
+ if (peer->conf.ebgp && rde_filter_community(&new->aspath->flags,
+ COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED)) {
+ up_generate_updates(peer, NULL, old);
+ return;
+ }
+
/* copy attributes for output filter */
attr_copy(&attrs, &new->aspath->flags);
@@ -457,17 +485,17 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
break;
case ATTR_AGGREGATOR:
if ((r = attr_write(up_attr_buf + wlen, len,
- ATTR_OPTIONAL | ATTR_TRANSITIVE, ATTR_AGGREGATOR,
- oa->data, oa->len)) == -1)
+ oa->flags, oa->type, oa->data, oa->len)) == -1)
+ return (-1);
+ break;
+ case ATTR_COMMUNITIES:
+ if ((r = attr_write(up_attr_buf + wlen, len,
+ oa->flags, oa->type, oa->data, oa->len)) == -1)
return (-1);
break;
- /*
- * currently there are no non-transitive or transitive known
- * attributes.
- */
default:
/* unknown attribute */
- if (!(oa->flags & ATTR_OPTIONAL))
+ if (!(oa->flags & ATTR_TRANSITIVE))
/* somehow a non-transitive slipped through */
break;
if ((r = attr_write(up_attr_buf + wlen, len,