summaryrefslogtreecommitdiff
path: root/proto/bgp/attrs.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-08 19:27:58 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-08 19:27:58 +0100
commit8860e991f6650e47cfe6c1af595fe4fe92a4edfd (patch)
tree18f49bb3a21739a1a596b54d9f65e82cff4fc09f /proto/bgp/attrs.c
parentcc5b93f72db80abd1262a0a5e1d8400ceef54385 (diff)
parentc8cafc8ebb5320ac7c6117c17e6460036f0fdf62 (diff)
Merge branch 'master' into int-new
Diffstat (limited to 'proto/bgp/attrs.c')
-rw-r--r--proto/bgp/attrs.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index b8371f32..0309c1f7 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -191,7 +191,7 @@ validate_as4_path(struct bgp_proto *p, struct adata *path)
}
static int
-bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len)
+bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a UNUSED6, int len UNUSED6)
{
#ifdef IPV6
return IGNORE;
@@ -289,6 +289,12 @@ bgp_check_ext_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
return ((len % 8) == 0) ? 0 : WITHDRAW;
}
+static int
+bgp_check_large_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
+{
+ return ((len % 12) == 0) ? 0 : WITHDRAW;
+}
+
static struct attr_desc bgp_attr_table[] = {
{ NULL, -1, 0, 0, 0, /* Undefined */
@@ -325,7 +331,10 @@ static struct attr_desc bgp_attr_table[] = {
{ "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 */
- NULL, NULL }
+ NULL, NULL },
+ [BA_LARGE_COMMUNITY] =
+ { "large_community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_LC_SET, 1,
+ bgp_check_large_community, NULL }
};
/* BA_AS4_PATH is type EAF_TYPE_OPAQUE and not type EAF_TYPE_AS_PATH.
@@ -575,7 +584,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
len = bgp_get_attr_len(a);
/* Skip empty sets */
- if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET)) && (len == 0))
+ if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET) || (type == EAF_TYPE_LC_SET)) && (len == 0))
continue;
if (remains < len + 4)
@@ -601,6 +610,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
break;
}
case EAF_TYPE_INT_SET:
+ case EAF_TYPE_LC_SET:
case EAF_TYPE_EC_SET:
{
u32 *z = int_set_get_data(a->u.ptr);
@@ -683,6 +693,25 @@ bgp_normalize_ec_set(struct adata *ad, u32 *src, int internal)
qsort(dst, ad->length / 8, 8, (int(*)(const void *, const void *)) bgp_compare_ec);
}
+static int
+bgp_compare_lc(const u32 *x, const u32 *y)
+{
+ if (x[0] != y[0])
+ return (x[0] > y[0]) ? 1 : -1;
+ if (x[1] != y[1])
+ return (x[1] > y[1]) ? 1 : -1;
+ if (x[2] != y[2])
+ return (x[2] > y[2]) ? 1 : -1;
+ return 0;
+}
+
+static inline void
+bgp_normalize_lc_set(u32 *dest, u32 *src, unsigned cnt)
+{
+ memcpy(dest, src, LCOMM_LENGTH * cnt);
+ qsort(dest, cnt, LCOMM_LENGTH, (int(*)(const void *, const void *)) bgp_compare_lc);
+}
+
static void
bgp_rehash_buckets(struct bgp_proto *p)
{
@@ -827,6 +856,14 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
d->u.ptr = z;
break;
}
+ case EAF_TYPE_LC_SET:
+ {
+ struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
+ z->length = d->u.ptr->length;
+ bgp_normalize_lc_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / LCOMM_LENGTH);
+ d->u.ptr = z;
+ break;
+ }
default: ;
}
d++;
@@ -1797,6 +1834,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, uint len, struct linpool *po
ipa_ntoh(*(ip_addr *)ad->data);
break;
case EAF_TYPE_INT_SET:
+ case EAF_TYPE_LC_SET:
case EAF_TYPE_EC_SET:
{
u32 *z = (u32 *) ad->data;