diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-03-11 17:12:52 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-03-11 17:12:52 +0000 |
commit | b21c2c568e1f969a0ca76f191c92856223ff303d (patch) | |
tree | c7a28663b294b4c9aa62c2be89dee73c6ec3534d /usr.sbin | |
parent | 01eec010699fb17fab1f9d2ec7b12f15330fd2b9 (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.h | 14 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 55 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 14 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 8 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_attr.c | 82 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 20 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_update.c | 44 |
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, |