summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/rde_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd/rde_attr.c')
-rw-r--r--usr.sbin/bgpd/rde_attr.c113
1 files changed, 108 insertions, 5 deletions
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);
+}