--- lib/type.h
+++ lib/type.h
@@ -12,6 +12,11 @@
#include "lib/birdlib.h"
#include "lib/attrs.h"
+struct f_aggregator {
+ u32 asn;
+ u32 rid;
+};
+
union bval {
#define BVAL_ITEMS \
struct { \
@@ -36,6 +41,7 @@
u64 ec;
lcomm lc;
vpn_rd rd;
+ struct f_aggregator aggregator;
ip_addr ip;
const net_addr *net;
const char *s;
@@ -87,6 +93,7 @@
/* Other user visible types which fit in int */
T_BOOL = 0xa0,
T_PAIR = 0xa4, /* Notice that pair is stored as integer: first << 16 | second */
+ T_AGGREGATOR = 0xa8, /* BGP aggregator tuple: ASN + router ID */
/* Put enumerational types in 0x20..0x3f range */
T_ENUM_LO = 0x12,
--- filter/data.c
+++ filter/data.c
@@ -36,6 +36,7 @@
[T_INT] = "int",
[T_BOOL] = "bool",
[T_PAIR] = "pair",
+ [T_AGGREGATOR] = "aggregator",
[T_QUAD] = "quad",
[T_ENUM_RTS] = "enum rts",
@@ -159,6 +160,16 @@
return 0;
}
+static inline int
+aggregator_cmp(struct f_aggregator v1, struct f_aggregator v2)
+{
+ if (v1.asn != v2.asn)
+ return (v1.asn > v2.asn) ? 1 : -1;
+ if (v1.rid != v2.rid)
+ return (v1.rid > v2.rid) ? 1 : -1;
+ return 0;
+}
+
/**
* val_compare - compare two values
* @v1: first value
@@ -201,6 +212,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->val.aggregator, v2->val.aggregator);
case T_IP:
return ipa_compare(v1->val.ip, v2->val.ip);
case T_NET:
@@ -612,6 +625,9 @@
case T_ENUM:
MX(i);
break;
+ case T_AGGREGATOR:
+ MX(aggregator);
+ break;
case T_EC:
case T_RD:
MX(ec);
@@ -705,6 +721,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;
@@ -754,6 +771,7 @@
case T_INT:
case T_IP:
case T_PAIR:
+ case T_AGGREGATOR:
case T_QUAD:
case T_EC:
case T_LC:
--- filter/config.Y
+++ filter/config.Y
@@ -374,6 +374,7 @@
ADD, DELETE, RESET,
PREPEND,
APPEND,
+ AGGREGATOR,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
FROM_HEX,
@@ -484,6 +485,7 @@
| RD { $$ = T_RD; }
| PREFIX { $$ = T_NET; }
| PAIR { $$ = T_PAIR; }
+ | AGGREGATOR { $$ = T_AGGREGATOR; }
| QUAD { $$ = T_QUAD; }
| EC { $$ = T_EC; }
| LC { $$ = T_LC; }
@@ -858,6 +860,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
@@ -342,6 +342,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, ((struct f_aggregator) { .asn = v1.val.i, .rid = rid }));
+ }
+
INST(FI_EC_CONSTRUCT, 2, 1) {
ARG_ANY(1);
ARG(2, T_INT);
@@ -911,6 +927,14 @@
RESULT_(T_IP, ip, *((const ip_addr *) e->u.ptr->data));
break;
+ case T_AGGREGATOR:
+ RESULT_(T_AGGREGATOR, aggregator,
+ ((struct f_aggregator) {
+ .asn = get_u32(e->u.ptr->data + 0),
+ .rid = get_u32(e->u.ptr->data + 4),
+ }));
+ break;
+
case T_STRING:
RESULT_(T_STRING, s, (const char *) e->u.ptr->data);
break;
@@ -956,6 +980,16 @@
EA_LITERAL_STORE_ADATA(da, da->flags, &v1.val.ip, sizeof(ip_addr)));
break;
+ case T_AGGREGATOR:
+ {
+ byte data[8];
+ put_u32(data + 0, v1.val.aggregator.asn);
+ put_u32(data + 4, v1.val.aggregator.rid);
+ a = ea_set_attr(&fs->rte->attrs,
+ EA_LITERAL_STORE_ADATA(da, da->flags, data, sizeof(data)));
+ }
+ break;
+
case T_STRING:
a = ea_set_attr(&fs->rte->attrs,
EA_LITERAL_STORE_ADATA(da, da->flags, v1.val.s, strlen(v1.val.s) + 1));
@@ -1117,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/attrs.c
+++ proto/bgp/attrs.c
@@ -1111,7 +1111,7 @@
[BA_AGGREGATOR] = {
.name = "bgp_aggregator",
.legacy_name = "BGP.aggregator",
- .type = T_OPAQUE,
+ .type = T_AGGREGATOR,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.encode = bgp_encode_aggregator,
.decode = bgp_decode_aggregator,
--- filter/test.conf
+++ filter/test.conf
@@ -1181,6 +1181,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
* ----------------------
*/
@@ -2952,6 +2975,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
@@ -4236,10 +4236,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