summaryrefslogtreecommitdiffstats
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-08-12 21:03:43 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2011-08-14 13:55:02 +0200
commit42a0c05408c4151442e6a0ec1c6889acbcfe9c17 (patch)
tree5a4992c5fa66256987e335ffe94ee960ed1ff9db /proto
parentbde872bba745e5596bdb066df6ef323b7cabcfdd (diff)
downloadbird-42a0c05408c4151442e6a0ec1c6889acbcfe9c17.tar
bird-42a0c05408c4151442e6a0ec1c6889acbcfe9c17.zip
BGP Extended communities.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/attrs.c76
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y13
3 files changed, 75 insertions, 16 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 83ca249..59d8a8c 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -247,7 +247,6 @@ bgp_check_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
return ((len % 4) == 0) ? 0 : WITHDRAW;
}
-
static int
bgp_check_cluster_list(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
{
@@ -281,6 +280,13 @@ bgp_check_unreach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSE
return IGNORE;
}
+static int
+bgp_check_ext_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
+{
+ return ((len % 8) == 0) ? 0 : WITHDRAW;
+}
+
+
static struct attr_desc bgp_attr_table[] = {
{ NULL, -1, 0, 0, 0, /* Undefined */
NULL, NULL },
@@ -311,7 +317,8 @@ static struct attr_desc bgp_attr_table[] = {
bgp_check_reach_nlri, NULL },
{ "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_UNREACH_NLRI */
bgp_check_unreach_nlri, NULL },
- { .name = NULL }, /* BA_EXTENDED_COMM */
+ { "ext_community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_EC_SET, 1, /* BA_EXT_COMMUNITY */
+ bgp_check_ext_community, NULL },
{ "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */
NULL, NULL },
{ "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */
@@ -468,7 +475,7 @@ bgp_get_attr_len(eattr *a)
unsigned int
bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
{
- unsigned int i, code, flags;
+ unsigned int i, code, type, flags;
byte *start = w;
int len, rv;
@@ -477,6 +484,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
eattr *a = &attrs->attrs[i];
ASSERT(EA_PROTO(a->id) == EAP_BGP);
code = EA_ID(a->id);
+
#ifdef IPV6
/* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
if (code == BA_NEXT_HOP)
@@ -559,11 +567,12 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
/* Standard path continues here ... */
+ type = a->type & EAF_TYPE_MASK;
flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
len = bgp_get_attr_len(a);
- /* Skip empty int sets */
- if (((a->type & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) && (len == 0))
+ /* Skip empty sets */
+ if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET)) && (len == 0))
continue;
if (remains < len + 4)
@@ -572,7 +581,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
rv = bgp_encode_attr_hdr(w, flags, code, len);
ADVANCE(w, remains, rv);
- switch (a->type & EAF_TYPE_MASK)
+ switch (type)
{
case EAF_TYPE_INT:
case EAF_TYPE_ROUTER_ID:
@@ -589,8 +598,9 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
break;
}
case EAF_TYPE_INT_SET:
+ case EAF_TYPE_EC_SET:
{
- u32 *z = (u32 *)a->u.ptr->data;
+ u32 *z = int_set_get_data(a->u.ptr);
int i;
for(i=0; i<len; i+=4)
put_u32(w+i, *z++);
@@ -624,13 +634,50 @@ bgp_compare_u32(const u32 *x, const u32 *y)
return (*x < *y) ? -1 : (*x > *y) ? 1 : 0;
}
-static void
-bgp_normalize_set(u32 *dest, u32 *src, unsigned cnt)
+static inline void
+bgp_normalize_int_set(u32 *dest, u32 *src, unsigned cnt)
{
memcpy(dest, src, sizeof(u32) * cnt);
qsort(dest, cnt, sizeof(u32), (int(*)(const void *, const void *)) bgp_compare_u32);
}
+static int
+bgp_compare_ec(const u32 *xp, const u32 *yp)
+{
+ u64 x = ec_get(xp, 0);
+ u64 y = ec_get(yp, 0);
+ return (x < y) ? -1 : (x > y) ? 1 : 0;
+}
+
+static inline void
+bgp_normalize_ec_set(struct adata *ad, u32 *src, int internal)
+{
+ u32 *dst = int_set_get_data(ad);
+
+ /* Remove non-transitive communities (EC_TBIT active) on external sessions */
+ if (! internal)
+ {
+ int len = int_set_get_size(ad);
+ u32 *t = dst;
+ int i;
+
+ for (i=0; i < len; i += 2)
+ {
+ if (src[i] & EC_TBIT)
+ continue;
+
+ *t++ = src[i];
+ *t++ = src[i+1];
+ }
+
+ ad->length = (t - dst) * 4;
+ }
+ else
+ memcpy(dst, src, ad->length);
+
+ qsort(dst, ad->length / 8, 8, (int(*)(const void *, const void *)) bgp_compare_ec);
+}
+
static void
bgp_rehash_buckets(struct bgp_proto *p)
{
@@ -763,7 +810,15 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
{
struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
z->length = d->u.ptr->length;
- bgp_normalize_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
+ bgp_normalize_int_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
+ d->u.ptr = z;
+ break;
+ }
+ case EAF_TYPE_EC_SET:
+ {
+ struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
+ z->length = d->u.ptr->length;
+ bgp_normalize_ec_set(z, (u32 *) d->u.ptr->data, p->is_internal);
d->u.ptr = z;
break;
}
@@ -1447,6 +1502,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
ipa_ntoh(*(ip_addr *)ad->data);
break;
case EAF_TYPE_INT_SET:
+ case EAF_TYPE_EC_SET:
{
u32 *z = (u32 *) ad->data;
for(i=0; i<ad->length/4; i++)
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 097faa6..1247870 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -236,7 +236,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
#define BA_RCID_PATH 0x0d
#define BA_MP_REACH_NLRI 0x0e /* [RFC2283] */
#define BA_MP_UNREACH_NLRI 0x0f
-#define BA_EXTENDED_COMM 0x10 /* draft-ramachandra-bgp-ext-communities */
+#define BA_EXT_COMMUNITY 0x10 /* [RFC4360] */
#define BA_AS4_PATH 0x11 /* [RFC4893] */
#define BA_AS4_AGGREGATOR 0x12
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 93f832a..93cc85f 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -21,11 +21,11 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
PATH, METRIC, ERROR, START, DELAY, FORGET, WAIT, ENABLE,
DISABLE, AFTER, BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN,
BGP_NEXT_HOP, BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY,
- SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4,
- ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER,
- MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET,
- COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE,
- GATEWAY, DIRECT, RECURSIVE, MED)
+ BGP_EXT_COMMUNITY, SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT,
+ CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE,
+ PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
+ INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
+ TABLE, GATEWAY, DIRECT, RECURSIVE, MED)
CF_GRAMMAR
@@ -120,6 +120,9 @@ CF_ADDTO(dynamic_attr, BGP_ORIGINATOR_ID
{ $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); })
CF_ADDTO(dynamic_attr, BGP_CLUSTER_LIST
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); })
+CF_ADDTO(dynamic_attr, BGP_EXT_COMMUNITY
+ { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(EAP_BGP, BA_EXT_COMMUNITY)); })
+
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)