--- 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