diff options
Diffstat (limited to 'proto/bgp')
-rw-r--r-- | proto/bgp/attrs.c | 42 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/bgp/config.Y | 4 |
3 files changed, 44 insertions, 3 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index b8371f32..6fe34e56 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -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; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index b1cca2d9..d5747c18 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -308,6 +308,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi #define BA_EXT_COMMUNITY 0x10 /* [RFC4360] */ #define BA_AS4_PATH 0x11 /* [RFC4893] */ #define BA_AS4_AGGREGATOR 0x12 +#define BA_LARGE_COMMUNITY 0x1e /* [draft-ietf-idr-large-community] */ /* BGP connection states */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index f3ba0e16..32ae88a3 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -27,7 +27,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, - CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY) + CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY) CF_GRAMMAR @@ -159,6 +159,8 @@ 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_ADDTO(dynamic_attr, BGP_LARGE_COMMUNITY + { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(EAP_BGP, BA_LARGE_COMMUNITY)); }) |