diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2004-05-17 12:39:33 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2004-05-17 12:39:33 +0000 |
commit | a74d240e1f035cf15ade49b9233080a0dd32ad05 (patch) | |
tree | fed5bf61ab95bfca13f112c19059765153821251 /usr.sbin/bgpd | |
parent | 4126f8f2d4e3ed383225cb8d06c0724ff7698c95 (diff) |
extend filter language to allow basic setting of COMMUNITIES attribute.
ok claudio@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/bgpd.conf.5 | 18 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 102 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 3 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_attr.c | 33 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 13 |
6 files changed, 147 insertions, 29 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5 index 00e1aca6e99..51ffdc06084 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.24 2004/05/08 20:18:45 henning Exp $ +.\" $OpenBSD: bgpd.conf.5,v 1.25 2004/05/17 12:39:32 djm Exp $ .\" .\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -611,6 +611,22 @@ The following attributes can be modified: Set the .Em LOCAL_PREF .Em AS path attribute . +.It Ar community +Set the +.Em COMMUNITIES +.Em AS path attribute . +Communities are specified as +.Ar asnum:local , +where +.Ar asnum +is an AS number and +.Ar local +is a locally-significant number between zero and 0xffff. +Alternately, well-known communities may be specified by name: +.Em NO_EXPORT , +.Em NO_ADVERTISE , +or +.Em NO_EXPORT_SUBCONFED . .It Ar med Set the .Em MULTI_EXIT_DISC diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 84bf565b866..d8f54b081fe 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.122 2004/05/07 10:06:15 djm Exp $ */ +/* $OpenBSD: bgpd.h,v 1.123 2004/05/17 12:39:32 djm Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -146,6 +146,10 @@ struct filter_set { struct in6_addr nexthop6; u_int8_t prepend; char pftable[PFTABLE_LEN]; + struct { + int as; + int type; + } community; }; enum auth_method { @@ -438,6 +442,7 @@ enum comp_ops { #define SET_NEXTHOP6 0x08 #define SET_PREPEND 0x10 #define SET_PFTABLE 0x20 +#define SET_COMMUNITY 0x40 struct filter_peers { u_int32_t peerid; diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 91647e5b16f..92f73b5ff0a 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.110 2004/05/08 20:58:00 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.111 2004/05/17 12:39:32 djm Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -84,6 +84,7 @@ int symset(const char *, const char *, int); char *symget(const char *); int atoul(char *, u_long *); int getcommunity(char *); +int parsecommunity(char *, int *, int *); typedef struct { union { @@ -791,32 +792,13 @@ filter_match : /* empty */ { bzero(&$$, sizeof($$)); } $$.as.type = $1; } | COMMUNITY STRING { - char *p; - int i; - bzero(&$$, sizeof($$)); - if ((p = strchr($2, ':')) == NULL) { - free($2); - yyerror("Bad community syntax"); - YYERROR; - } - *p++ = 0; - if ((i = getcommunity($2)) == COMMUNITY_ERROR) { - free($2); - YYERROR; - } - if (i == 0 || i == USHRT_MAX) { - free($2); - yyerror("Bad community AS number"); - YYERROR; - } - $$.community.as = i; - if ((i = getcommunity(p)) == COMMUNITY_ERROR) { + if (parsecommunity($2, &$$.community.as, + &$$.community.type) == -1) { free($2); YYERROR; } free($2); - $$.community.type = i; } ; @@ -876,6 +858,10 @@ filter_set_l : filter_set_l comma filter_set_opt { if ($3.flags & SET_PFTABLE) strlcpy($$.pftable, $3.pftable, sizeof($$.pftable)); + if ($3.flags & SET_COMMUNITY) { + $$.community.as = $3.community.as; + $$.community.type = $3.community.type; + } } | filter_set_opt ; @@ -917,6 +903,34 @@ filter_set_opt : LOCALPREF number { YYERROR; } } + | COMMUNITY STRING { + $$.flags = SET_COMMUNITY; + if (parsecommunity($2, &$$.community.as, + &$$.community.type) == -1) { + free($2); + YYERROR; + } + free($2); + if ($$.community.as <= 0 || $$.community.as > 0xffff) { + yyerror("Invalid comminity"); + YYERROR; + } + /* Don't allow setting of unknown well-known types */ + if ($$.community.as == COMMUNITY_WELLKNOWN) { + switch ($$.community.type) { + case COMMUNITY_NO_EXPORT: + case COMMUNITY_NO_ADVERTISE: + case COMMUNITY_NO_EXPSUBCONFED: + /* valid */ + break; + default: + /* unknown */ + yyerror("Invalid well-known community"); + YYERROR; + break; + } + } + } ; comma : "," @@ -1418,6 +1432,48 @@ getcommunity(char *s) return (ulval); } +int +parsecommunity(char *s, int *as, int *type) +{ + char *p; + int i; + + /* Well-known communities */ + if (strcasecmp(s, "NO_EXPORT") == 0) { + *as = COMMUNITY_WELLKNOWN; + *type = COMMUNITY_NO_EXPORT; + return (0); + } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { + *as = COMMUNITY_WELLKNOWN; + *type = COMMUNITY_NO_ADVERTISE; + return (0); + } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { + *as = COMMUNITY_WELLKNOWN; + *type = COMMUNITY_NO_EXPSUBCONFED; + return (0); + } + + if ((p = strchr(s, ':')) == NULL) { + yyerror("Bad community syntax"); + return (-1); + } + *p++ = 0; + + if ((i = getcommunity(s)) == COMMUNITY_ERROR) + return (-1); + if (i == 0 || i == USHRT_MAX) { + yyerror("Bad community AS number"); + return (-1); + } + *as = i; + + if ((i = getcommunity(p)) == COMMUNITY_ERROR) + return (-1); + *type = i; + + return (0); +} + struct peer * alloc_peer(void) { @@ -1621,4 +1677,4 @@ neighbor_consistent(struct peer *p) } return (0); -}
\ No newline at end of file +} diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index cb6a249359b..6b37632841e 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.38 2004/05/07 10:06:15 djm Exp $ */ +/* $OpenBSD: rde.h,v 1.39 2004/05/17 12:39:32 djm Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -251,6 +251,7 @@ 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); +int community_set(struct attr *, int, int); /* rde_rib.c */ void path_init(u_int32_t); diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c index 8ec8450c942..772aa5bd2f3 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.29 2004/05/07 10:06:15 djm Exp $ */ +/* $OpenBSD: rde_attr.c,v 1.30 2004/05/17 12:39:32 djm Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -993,7 +993,7 @@ community_match(void *data, u_int16_t len, int as, int type) u_int16_t eas, etype; ENSURE((len & 0x3) == 0); - len >>= 2; /* devide by four */ + len >>= 2; /* divide by four */ for (; len > 0; len--) { eas = *p++; @@ -1009,3 +1009,32 @@ community_match(void *data, u_int16_t len, int as, int type) return 0; } +int +community_set(struct attr *attr, int as, int type) +{ + u_int32_t *cdata = (u_int32_t*)attr->data; + unsigned int i, ncommunities = attr->len; + + ENSURE((as & ~0xffff) == 0); + ENSURE((type & ~0xffff) == 0); + ENSURE((ncommunities & 0x3) == 0); + ncommunities >>= 2; /* divide by four */ + + for (i = 0; i < ncommunities; i++) { + if ((ntohl(cdata[i]) & 0xffff0000) == (unsigned)as << 16) + break; + } + + if (i >= ncommunities) { + if (attr->len + 4 > 0xffff) /* overflow */ + return (0); + attr->len += 4; + if ((cdata = realloc(attr->data, attr->len)) == NULL) + return (0); + attr->data = (void*)cdata; + } + cdata[i] = htonl(as << 16 | type); + + return (1); +} + diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c index 5a8a0923651..619dfc9dc74 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.8 2004/05/07 10:06:15 djm Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.9 2004/05/17 12:39:32 djm Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -78,6 +78,17 @@ rde_apply_set(struct attr_flags *attrs, struct filter_set *set) } if (set->flags & SET_PFTABLE) strlcpy(attrs->pftable, set->pftable, sizeof(attrs->pftable)); + if (set->flags & SET_COMMUNITY) { + struct attr *a; + + if ((a = attr_optget(attrs, ATTR_COMMUNITIES)) == NULL) { + attr_optadd(attrs, ATTR_OPTIONAL|ATTR_TRANSITIVE, + ATTR_COMMUNITIES, NULL, 0); + if ((a = attr_optget(attrs, ATTR_COMMUNITIES)) == NULL) + fatalx("internal community bug"); + } + community_set(a, set->community.as, set->community.type); + } } int |