summaryrefslogtreecommitdiff
path: root/proto/aggregator/config.Y
diff options
context:
space:
mode:
Diffstat (limited to 'proto/aggregator/config.Y')
-rw-r--r--proto/aggregator/config.Y134
1 files changed, 134 insertions, 0 deletions
diff --git a/proto/aggregator/config.Y b/proto/aggregator/config.Y
new file mode 100644
index 00000000..44b7752f
--- /dev/null
+++ b/proto/aggregator/config.Y
@@ -0,0 +1,134 @@
+/*
+ * BIRD -- Aggregator configuration
+ *
+ * (c) 2023 Igor Putovny <igor.putovny@nic.cz>
+ * (c) 2023 Maria Matejka <mq@ucw.cz>
+ * (c) 2023 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+CF_HDR
+
+#include "proto/aggregator/aggregator.h"
+
+CF_DEFINES
+
+#define AGGREGATOR_CFG ((struct aggregator_config *) this_proto)
+#define AGGR_ITEM_ALLOC ((struct aggr_item_node *) cfg_allocz(sizeof(struct aggr_item_node)))
+
+
+CF_DECLS
+
+CF_KEYWORDS(AGGREGATOR, AGGREGATE, ON, MERGE, BY)
+
+%type <ai> aggr_item aggr_list
+
+CF_GRAMMAR
+
+proto: aggregator_proto ;
+
+aggregator_proto_start: proto_start AGGREGATOR
+{
+ this_proto = proto_config_new(&proto_aggregator, $1);
+ this_channel = AGGREGATOR_CFG->src = channel_config_new(NULL, "source", 0, this_proto);
+ AGGREGATOR_CFG->dst = channel_config_new(NULL, "destination", 0, this_proto);
+
+ AGGREGATOR_CFG->src->ra_mode = AGGREGATOR_CFG->dst->ra_mode = RA_ANY;
+};
+
+aggregator_proto_item:
+ proto_item
+ | channel_item_
+ | PEER TABLE rtable { AGGREGATOR_CFG->dst->table = $3; }
+ | AGGREGATE ON aggr_list {
+ if (AGGREGATOR_CFG->aggr_on)
+ cf_error("Only one aggregate on clause allowed");
+
+ _Bool net_present = 0;
+ int count = 0;
+
+ for (const struct aggr_item_node *item = $3; item; item = item->next) {
+// log(L_WARN "type %d sacode %d", item->i.type, item->i.sa.sa_code);
+ if (item->i.type == AGGR_ITEM_STATIC_ATTR && item->i.sa.sa_code == SA_NET)
+ net_present = 1;
+
+ count++;
+ }
+
+ if (!net_present)
+ cf_error("'NET' must be present");
+
+ AGGREGATOR_CFG->aggr_on = cfg_alloc(sizeof(struct aggr_item) * count);
+
+ int pos = 0;
+ for (const struct aggr_item_node *item = $3; item; item = item->next) {
+ if (item->i.type == AGGR_ITEM_DYNAMIC_ATTR)
+ AGGREGATOR_CFG->aggr_on_da_count++;
+
+ AGGREGATOR_CFG->aggr_on[pos++] = item->i;
+ }
+
+ AGGREGATOR_CFG->aggr_on_count = pos;
+ }
+ | MERGE BY {
+ cf_push_block_scope(new_config);
+ cf_create_symbol(new_config, "routes", SYM_VARIABLE | T_ROUTES_BLOCK, offset, f_new_var(sym_->scope));
+ } function_body {
+ cf_pop_block_scope(new_config);
+ $4->args++;
+ AGGREGATOR_CFG->merge_by = $4;
+ }
+;
+
+aggregator_proto_opts: /* empty */ | aggregator_proto_opts aggregator_proto_item ';' ;
+aggregator_proto: aggregator_proto_start proto_name '{' aggregator_proto_opts '}' ;
+
+
+aggr_list:
+ aggr_item
+ | aggr_list ',' aggr_item {
+ if ($3 == NULL) {
+ $$ = $1;
+ } else {
+ $$ = $3;
+ $$->next = $1;
+ }
+ }
+ ;
+
+aggr_item:
+ '(' term ')' {
+ $$ = AGGR_ITEM_ALLOC;
+ $$->i.type = AGGR_ITEM_TERM;
+ $$->i.line = f_linearize($2, 1);
+ }
+ | CF_SYM_KNOWN {
+ switch ($1->class) {
+ case SYM_ATTRIBUTE:
+ $$ = AGGR_ITEM_ALLOC;
+ $$->i.type = AGGR_ITEM_DYNAMIC_ATTR;
+ $$->i.da = *$1->attribute;
+ break;
+ case SYM_CONSTANT_RANGE:
+ $$ = NULL;
+ break;
+ default:
+ cf_error("Can't aggregate on symbol type %s.", cf_symbol_class_name($1));
+ }
+ }
+ | dynamic_attr {
+ $$ = AGGR_ITEM_ALLOC;
+ $$->i.type = AGGR_ITEM_DYNAMIC_ATTR;
+ $$->i.da = $1;
+ }
+ | static_attr {
+ $$ = AGGR_ITEM_ALLOC;
+ $$->i.type = AGGR_ITEM_STATIC_ATTR;
+ $$->i.sa = $1;
+ }
+ ;
+
+CF_CODE
+
+CF_END