aboutsummaryrefslogtreecommitdiffstats
path: root/proto/aggregator/config.Y
blob: 44b7752f14a398e4c78a8d345da5ccf6b10d941f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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