--- filter/data.h +++ filter/data.h @@ -28,6 +28,7 @@ T_BOOL = 0x11, T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ T_QUAD = 0x13, + T_AGGREGATOR = 0x14, /* Put enumerational types in 0x30..0x3f range */ T_ENUM_LO = 0x30, @@ -83,6 +84,10 @@ enum f_type type; /* T_* */ union { uint i; + struct { + u32 asn; + u32 rid; + } aggregator; u64 ec; lcomm lc; vpn_rd rd; --- filter/data.c +++ filter/data.c @@ -32,6 +32,7 @@ [T_INT] = "int", [T_BOOL] = "bool", [T_PAIR] = "pair", + [T_AGGREGATOR] = "aggregator", [T_QUAD] = "quad", [T_ENUM_RTS] = "enum rts", @@ -163,6 +164,16 @@ return 0; } +static inline int +aggregator_cmp(const struct f_val *v1, const struct f_val *v2) +{ + if (v1->val.aggregator.asn != v2->val.aggregator.asn) + return (v1->val.aggregator.asn > v2->val.aggregator.asn) ? 1 : -1; + if (v1->val.aggregator.rid != v2->val.aggregator.rid) + return (v1->val.aggregator.rid > v2->val.aggregator.rid) ? 1 : -1; + return 0; +} + /** * val_compare - compare two values * @v1: first value @@ -205,6 +216,8 @@ return u64_cmp(v1->val.ec, v2->val.ec); case T_LC: return lcomm_cmp(v1->val.lc, v2->val.lc); + case T_AGGREGATOR: + return aggregator_cmp(v1, v2); case T_IP: return ipa_compare(v1->val.ip, v2->val.ip); case T_NET: @@ -631,6 +644,7 @@ case T_IP: buffer_print(buf, "%I", v->val.ip); return; case T_NET: buffer_print(buf, "%N", v->val.net); return; case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return; + case T_AGGREGATOR: buffer_print(buf, "aggregator(%u, %R)", v->val.aggregator.asn, v->val.aggregator.rid); return; case T_QUAD: buffer_print(buf, "%R", v->val.i); return; case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return; case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return; --- filter/config.Y +++ filter/config.Y @@ -458,6 +458,7 @@ | RD { $$ = T_RD; } | PREFIX { $$ = T_NET; } | PAIR { $$ = T_PAIR; } + | AGGREGATOR { $$ = T_AGGREGATOR; } | QUAD { $$ = T_QUAD; } | EC { $$ = T_EC; } | LC { $$ = T_LC; } @@ -821,6 +822,7 @@ constructor: '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } + | AGGREGATOR '(' term ',' term ')' { $$ = f_new_inst(FI_AGGREGATOR_CONSTRUCT, $3, $5); } | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); } | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); } --- filter/f-inst.c +++ filter/f-inst.c @@ -335,6 +335,22 @@ RESULT(T_PAIR, i, (u1 << 16) | u2); } + INST(FI_AGGREGATOR_CONSTRUCT, 2, 1) { + ARG(1, T_INT); + ARG_ANY(2); + + u32 rid; + + if (v2.type == T_QUAD) + rid = v2.val.i; + else if (val_is_ip4(&v2)) + rid = ipa_to_u32(v2.val.ip); + else + runtime("Argument 2 of aggregator constructor must be router ID or IPv4 address, got 0x%02x", v2.type); + + RESULT(T_AGGREGATOR, aggregator, ((typeof(v1.val.aggregator)) { .asn = v1.val.i, .rid = rid })); + } + INST(FI_EC_CONSTRUCT, 2, 1) { ARG_ANY(1); ARG(2, T_INT); @@ -880,6 +896,12 @@ case EAF_TYPE_OPAQUE: if (da.f_type == T_ENUM_EMPTY) RESULT_(T_ENUM_EMPTY, i, 0); + else if (da.f_type == T_AGGREGATOR) + RESULT_(T_AGGREGATOR, aggregator, + ((typeof(v1.val.aggregator)) { + .asn = get_u32(e->u.ptr->data + 0), + .rid = get_u32(e->u.ptr->data + 4), + })); else RESULT_(T_BYTESTRING, ad, e->u.ptr); break; @@ -950,6 +972,15 @@ break; case EAF_TYPE_OPAQUE: + if (da.f_type == T_AGGREGATOR) + { + struct adata *ad = lp_alloc_adata(fs->pool, 8); + put_u32(ad->data + 0, v1.val.aggregator.asn); + put_u32(ad->data + 4, v1.val.aggregator.rid); + l->attrs[0].u.ptr = ad; + break; + } + /* Fall through */ case EAF_TYPE_AS_PATH: case EAF_TYPE_INT_SET: case EAF_TYPE_EC_SET: @@ -1120,6 +1151,12 @@ /* Get data part from the standard community */ METHOD_R(T_PAIR, data, T_INT, i, v1.val.i & 0xFFFF); + /* Get ASN part from aggregator */ + METHOD_R(T_AGGREGATOR, asn, T_INT, i, v1.val.aggregator.asn); + + /* Get router ID part from aggregator */ + METHOD_R(T_AGGREGATOR, router_id, T_QUAD, i, v1.val.aggregator.rid); + /* Get ASN part from the large community */ METHOD_R(T_LC, asn, T_INT, i, v1.val.lc.asn); --- proto/bgp/config.Y +++ proto/bgp/config.Y @@ -511,7 +511,7 @@ dynamic_attr: BGP_ATOMIC_AGGR { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); $$.flags = BAF_TRANSITIVE; } ; dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); $$.flags = BAF_OPTIONAL | BAF_TRANSITIVE; } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_AGGREGATOR, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); $$.flags = BAF_OPTIONAL | BAF_TRANSITIVE; } ; dynamic_attr: BGP_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); $$.flags = BAF_OPTIONAL | BAF_TRANSITIVE; } ; dynamic_attr: BGP_ORIGINATOR_ID --- filter/test.conf +++ filter/test.conf @@ -1056,6 +1056,29 @@ /* + * Testing Aggregator + * ------------------ + */ + +function t_aggregator() +aggregator a; +{ + a = aggregator(64512, 192.0.2.1); + bt_assert(format(a) = "aggregator(64512, 192.0.2.1)"); + bt_assert(a.asn = 64512); + bt_assert(a.router_id = 192.0.2.1); + + a = aggregator(64513, 10.20.30.40); + bt_assert(a.asn = 64513); + bt_assert(a.router_id = 10.20.30.40); +} + +bt_test_suite(t_aggregator, "Testing aggregator"); + + + + +/* * Testing Community List * ---------------------- */ @@ -2633,6 +2656,7 @@ bt_check_assign(from, 10.20.30.40); # bt_check_assign(gw, 55.55.55.44); + bt_check_assign(bgp_aggregator, aggregator(64512, 10.20.30.40)); bgp_community.add((3,5)); bgp_ext_community.add((ro, 135, 999)); --- doc/bird.sgml +++ doc/bird.sgml @@ -4102,10 +4102,11 @@ presence of which indicates that the route has been aggregated from multiple routes by some router on the path from the originator. - + This is an optional attribute specifying AS number and IP address of the BGP router that created the route by aggregating multiple BGP routes. - Currently, the attribute is not accessible from filters. + It is accessible from filters and can be set using + . List of community values associated with the route. Each such value is a