summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2004-05-17 12:39:33 +0000
committerDamien Miller <djm@cvs.openbsd.org>2004-05-17 12:39:33 +0000
commita74d240e1f035cf15ade49b9233080a0dd32ad05 (patch)
treefed5bf61ab95bfca13f112c19059765153821251 /usr.sbin/bgpd
parent4126f8f2d4e3ed383225cb8d06c0724ff7698c95 (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.518
-rw-r--r--usr.sbin/bgpd/bgpd.h7
-rw-r--r--usr.sbin/bgpd/parse.y102
-rw-r--r--usr.sbin/bgpd/rde.h3
-rw-r--r--usr.sbin/bgpd/rde_attr.c33
-rw-r--r--usr.sbin/bgpd/rde_filter.c13
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