]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Preexport: No route modification, no linpool needed
[thirdparty/bird.git] / filter / config.Y
CommitLineData
b9d70dc8
PM
1/*
2 * BIRD - filters
3 *
1c20608e 4 * Copyright 1998--2000 Pavel Machek
b9d70dc8
PM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
c9f8c1a8 7 *
1877dab2 8 FIXME: priority of ! should be lower
b9d70dc8
PM
9 */
10
11CF_HDR
12
8bdb05ed 13#include "filter/f-inst.h"
4f082dfa 14#include "filter/data.h"
8bdb05ed 15
2edb31b0
MM
16CF_DEFINES
17
b8cc390e
OZ
18static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
19static inline u32 pair_a(u32 p) { return p >> 16; }
20static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
21
a84b8b6e
MM
22#define f_generate_complex(fi_code, da, arg) \
23 f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
24
b8cc390e
OZ
25/*
26 * Sets and their items are during parsing handled as lists, linked
27 * through left ptr. The first item in a list also contains a pointer
28 * to the last item in a list (right ptr). For convenience, even items
29 * are handled as one-item lists. Lists are merged by f_merge_items().
30 */
b2f00837
OZ
31static int
32f_valid_set_type(int type)
33{
34 switch (type)
35 {
36 case T_INT:
37 case T_PAIR:
38 case T_QUAD:
39 case T_ENUM:
40 case T_IP:
41 case T_EC:
66dbdbd9 42 case T_LC:
83715aa8 43 case T_RD:
b2f00837
OZ
44 return 1;
45
46 default:
47 return 0;
48 }
49}
b8cc390e
OZ
50
51static inline struct f_tree *
52f_new_item(struct f_val from, struct f_val to)
92a72a4c 53{
b8cc390e
OZ
54 struct f_tree *t = f_new_tree();
55 t->right = t;
56 t->from = from;
57 t->to = to;
58 return t;
59}
92a72a4c 60
b8cc390e
OZ
61static inline struct f_tree *
62f_merge_items(struct f_tree *a, struct f_tree *b)
63{
64 if (!a) return b;
65 a->right->left = b;
66 a->right = b->right;
67 b->right = NULL;
68 return a;
69}
92a72a4c 70
b8cc390e
OZ
71static inline struct f_tree *
72f_new_pair_item(int fa, int ta, int fb, int tb)
73{
60566c5c
OZ
74 check_u16(fa);
75 check_u16(ta);
76 check_u16(fb);
77 check_u16(tb);
78
79 if ((ta < fa) || (tb < fb))
80 cf_error( "From value cannot be higher that To value in pair sets");
81
b8cc390e
OZ
82 struct f_tree *t = f_new_tree();
83 t->right = t;
84 t->from.type = t->to.type = T_PAIR;
85 t->from.val.i = pair(fa, fb);
86 t->to.val.i = pair(ta, tb);
87 return t;
92a72a4c
OZ
88}
89
b8cc390e
OZ
90static inline struct f_tree *
91f_new_pair_set(int fa, int ta, int fb, int tb)
4fc36f39 92{
60566c5c
OZ
93 check_u16(fa);
94 check_u16(ta);
95 check_u16(fb);
96 check_u16(tb);
c454872f 97
b8cc390e
OZ
98 if ((ta < fa) || (tb < fb))
99 cf_error( "From value cannot be higher that To value in pair sets");
c454872f 100
60566c5c
OZ
101 struct f_tree *lst = NULL;
102 int i;
103
b8cc390e
OZ
104 for (i = fa; i <= ta; i++)
105 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
106
107 return lst;
4fc36f39
OF
108}
109
60566c5c 110#define CC_ALL 0xFFFF
42a0c054 111#define EC_ALL 0xFFFFFFFF
60566c5c 112#define LC_ALL 0xFFFFFFFF
42a0c054
OZ
113
114static struct f_tree *
115f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
116{
117 u64 fm, to;
118
e46128fb 119 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
42a0c054
OZ
120 check_u16(vf);
121 if (vt == EC_ALL)
122 vt = 0xFFFF;
123 else
124 check_u16(vt);
125 }
126
127 if (kind == EC_GENERIC) {
128 fm = ec_generic(key, vf);
129 to = ec_generic(key, vt);
130 }
131 else if (ipv4_used) {
132 fm = ec_ip4(kind, key, vf);
133 to = ec_ip4(kind, key, vt);
134 }
135 else if (key < 0x10000) {
136 fm = ec_as2(kind, key, vf);
137 to = ec_as2(kind, key, vt);
138 }
139 else {
140 fm = ec_as4(kind, key, vf);
141 to = ec_as4(kind, key, vt);
142 }
143
144 struct f_tree *t = f_new_tree();
145 t->right = t;
146 t->from.type = t->to.type = T_EC;
147 t->from.val.ec = fm;
148 t->to.val.ec = to;
149 return t;
150}
151
60566c5c
OZ
152static struct f_tree *
153f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
154{
155 struct f_tree *t = f_new_tree();
156 t->right = t;
157 t->from.type = t->to.type = T_LC;
158 t->from.val.lc = (lcomm) {f1, f2, f3};
159 t->to.val.lc = (lcomm) {t1, t2, t3};
160 return t;
161}
162
42a0c054 163static inline struct f_inst *
5a14df39 164f_generate_empty(struct f_dynamic_attr dyn)
5e173e9f 165{
9b46748d 166 struct f_val empty;
42a0c054 167
5a14df39 168 switch (dyn.type & EAF_TYPE_MASK) {
42a0c054 169 case EAF_TYPE_AS_PATH:
9b46748d 170 empty = f_const_empty_path;
42a0c054
OZ
171 break;
172 case EAF_TYPE_INT_SET:
9b46748d 173 empty = f_const_empty_clist;
42a0c054
OZ
174 break;
175 case EAF_TYPE_EC_SET:
9b46748d 176 empty = f_const_empty_eclist;
42a0c054 177 break;
66dbdbd9 178 case EAF_TYPE_LC_SET:
9b46748d 179 empty = f_const_empty_lclist;
66dbdbd9 180 break;
42a0c054
OZ
181 default:
182 cf_error("Can't empty that attribute");
183 }
184
a84b8b6e 185 return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
42a0c054
OZ
186}
187
9b0a0ba9
OZ
188/*
189 * Remove all new lines and doubled whitespaces
190 * and convert all tabulators to spaces
191 * and return a copy of string
192 */
193char *
194assert_copy_expr(const char *start, size_t len)
195{
196 /* XXX: Allocates maybe a little more memory than we really finally need */
197 char *str = cfg_alloc(len + 1);
198
199 char *dst = str;
200 const char *src = start - 1;
201 const char *end = start + len;
202 while (++src < end)
203 {
204 if (*src == '\n')
205 continue;
206
207 /* Skip doubled whitespaces */
208 if (src != start)
209 {
210 const char *prev = src - 1;
211 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
212 continue;
213 }
214
215 if (*src == '\t')
216 *dst = ' ';
217 else
218 *dst = *src;
219
220 dst++;
221 }
222 *dst = '\0';
223
224 return str;
225}
226
227/*
228 * assert_done - create f_instruction of bt_assert
229 * @expr: expression in bt_assert()
230 * @start: pointer to first char of test expression
231 * @end: pointer to the last char of test expression
232 */
233static struct f_inst *
234assert_done(struct f_inst *expr, const char *start, const char *end)
235{
9b46748d
MM
236 return f_new_inst(FI_ASSERT, expr,
237 (end >= start) ?
238 assert_copy_expr(start, end - start + 1)
239 : "???");
9b0a0ba9 240}
42a0c054 241
c0e958e0
MM
242static struct f_inst *
243assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
244{
a84b8b6e 245 struct f_inst *setter, *getter, *checker;
c0e958e0
MM
246 switch (lval->type) {
247 case F_LVAL_VARIABLE:
a84b8b6e 248 setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
96d757c1 249 getter = f_new_inst(FI_VAR_GET, lval->sym);
c0e958e0
MM
250 break;
251 case F_LVAL_PREFERENCE:
a84b8b6e 252 setter = f_new_inst(FI_PREF_SET, expr);
c0e958e0
MM
253 getter = f_new_inst(FI_PREF_GET);
254 break;
255 case F_LVAL_SA:
a84b8b6e 256 setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
c0e958e0
MM
257 getter = f_new_inst(FI_RTA_GET, lval->sa);
258 break;
259 case F_LVAL_EA:
a84b8b6e 260 setter = f_new_inst(FI_EA_SET, expr, lval->da);
c0e958e0
MM
261 getter = f_new_inst(FI_EA_GET, lval->da);
262 break;
a84b8b6e
MM
263 default:
264 bug("Unknown lval type");
c0e958e0
MM
265 }
266
a84b8b6e 267 checker = f_new_inst(FI_EQ, expr, getter);
4f082dfa 268 setter->next = checker;
a84b8b6e 269
c0e958e0
MM
270 return assert_done(setter, start, end);
271}
272
b9d70dc8
PM
273CF_DECLS
274
e4a73dbf 275CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
82bfee76 276 ACCEPT, REJECT, ERROR,
8c9986d3 277 INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
66dbdbd9 278 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
7db7b7db 279 IF, THEN, ELSE, CASE,
42a0c054 280 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
e5468d16 281 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
a5fc5958 282 PREFERENCE,
ff2ca10c 283 ROA_CHECK, ASN, SRC, DST,
61e501da 284 IS_V4, IS_V6,
e58f8c28 285 LEN, MAXLEN,
f4536657 286 DEFINED,
7f77e250 287 ADD, DELETE, CONTAINS, RESET,
9c9cc35c 288 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
afc54517 289 EMPTY,
265419a3 290 FILTER, WHERE, EVAL, ATTRIBUTE,
2c137591 291 BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
b9d70dc8 292
f4536657 293%nonassoc THEN
4ed8718a 294%nonassoc ELSE
f4536657 295
dfe63ed8 296%type <xp> cmds_int cmd_prep
0206c070 297%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
5a14df39
MJM
298%type <fda> dynamic_attr
299%type <fsa> static_attr
0b39b1cb 300%type <f> filter where_filter
96d757c1 301%type <fl> filter_body function_body
c0e958e0 302%type <flv> lvalue
c29d73a0 303%type <i> type function_args function_vars
9b46748d
MM
304%type <ecs> ec_kind
305%type <fret> break_command
60566c5c
OZ
306%type <i32> cnum
307%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
b1a597e0 308%type <trie> fprefix_set
5e173e9f
JMM
309%type <v> set_atom switch_atom fipa
310%type <px> fprefix
9b0a0ba9 311%type <t> get_cf_position
b9d70dc8
PM
312
313CF_GRAMMAR
314
2c137591
MM
315conf: FILTER STACKS expr expr ';' {
316 new_config->filter_vstk = $3;
317 new_config->filter_estk = $4;
318 }
319 ;
320
f851f0d7 321conf: filter_def ;
e0f2e42f 322filter_def:
2de1e206 323 FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
b2b7bbfc 324 filter_body {
0b39b1cb 325 struct filter *f = cfg_alloc(sizeof(struct filter));
f249d0b8 326 *f = (struct filter) { .sym = $2, .root = $4 };
0b39b1cb
MM
327 $2->filter = f;
328
ae3e1af2 329 cf_pop_scope();
b9d70dc8
PM
330 }
331 ;
332
f851f0d7 333conf: filter_eval ;
1c20608e 334filter_eval:
23e3b1e6 335 EVAL term { f_eval_int(f_linearize($2)); }
1c20608e
MM
336 ;
337
265419a3 338conf: custom_attr ;
2de1e206 339custom_attr: ATTRIBUTE type symbol ';' {
0b39b1cb 340 cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
265419a3
MM
341};
342
f851f0d7 343conf: bt_test_suite ;
9b0a0ba9 344bt_test_suite:
9eef9c64
MM
345 BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
346 cf_assert_symbol($3, SYM_FUNCTION);
132529ce 347 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
0b39b1cb 348 t->fn = $3->function;
9b0a0ba9
OZ
349 t->fn_name = $3->name;
350 t->dsc = $5;
351
352 add_tail(&new_config->tests, &t->n);
353 }
354 ;
355
132529ce
MM
356conf: bt_test_same ;
357bt_test_same:
9eef9c64
MM
358 BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
359 cf_assert_symbol($3, SYM_FUNCTION);
360 cf_assert_symbol($5, SYM_FUNCTION);
132529ce 361 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
0b39b1cb
MM
362 t->fn = $3->function;
363 t->cmp = $5->function;
132529ce
MM
364 t->result = $7;
365 t->fn_name = $3->name;
366 t->dsc = $5->name;
367 add_tail(&new_config->tests, &t->n);
368 }
369 ;
370
ba921648
PM
371type:
372 INT { $$ = T_INT; }
373 | BOOL { $$ = T_BOOL; }
374 | IP { $$ = T_IP; }
8c9986d3 375 | RD { $$ = T_RD; }
5e173e9f 376 | PREFIX { $$ = T_NET; }
ba921648 377 | PAIR { $$ = T_PAIR; }
126683fe 378 | QUAD { $$ = T_QUAD; }
42a0c054 379 | EC { $$ = T_EC; }
66dbdbd9 380 | LC { $$ = T_LC; }
ba921648 381 | STRING { $$ = T_STRING; }
10a53608
PM
382 | BGPMASK { $$ = T_PATH_MASK; }
383 | BGPPATH { $$ = T_PATH; }
384 | CLIST { $$ = T_CLIST; }
42a0c054 385 | ECLIST { $$ = T_ECLIST; }
66dbdbd9 386 | LCLIST { $$ = T_LCLIST; }
c8cafc8e 387 | type SET {
ba921648 388 switch ($1) {
b1a597e0 389 case T_INT:
b1a597e0 390 case T_PAIR:
126683fe 391 case T_QUAD:
42a0c054 392 case T_EC:
66dbdbd9 393 case T_LC:
83715aa8 394 case T_RD:
126683fe 395 case T_IP:
b1a597e0
OZ
396 $$ = T_SET;
397 break;
398
5e173e9f 399 case T_NET:
b1a597e0
OZ
400 $$ = T_PREFIX_SET;
401 break;
402
ba921648 403 default:
a5a947d4 404 cf_error( "You can't create sets of this type." );
ba921648 405 }
b1a597e0 406 }
ba921648
PM
407 ;
408
c29d73a0
MM
409function_argsn:
410 /* EMPTY */
2de1e206 411 | function_argsn type symbol ';' {
c29d73a0
MM
412 if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
413 cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
414 }
6dc7a0cb
PM
415 ;
416
c29d73a0
MM
417function_args:
418 '(' ')' { $$ = 0; }
2de1e206 419 | '(' function_argsn type symbol ')' {
63e76204
MM
420 cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
421 $$ = $4->scope->slots;
e0f2e42f
MM
422 }
423 ;
424
c29d73a0
MM
425function_vars:
426 /* EMPTY */ { $$ = 0; }
2de1e206 427 | function_vars type symbol ';' {
c29d73a0
MM
428 cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
429 $$ = $1 + 1;
430 }
431 ;
432
63e76204 433filter_body: function_body ;
96d757c1 434
e0f2e42f 435filter:
9eef9c64
MM
436 CF_SYM_KNOWN {
437 cf_assert_symbol($1, SYM_FILTER);
0b39b1cb
MM
438 $$ = $1->filter;
439 }
440 | filter_body {
441 struct filter *f = cfg_alloc(sizeof(struct filter));
442 *f = (struct filter) { .root = $1 };
443 $$ = f;
e0f2e42f 444 }
e0f2e42f
MM
445 ;
446
430da60f
MM
447where_filter:
448 WHERE term {
224b77d4 449 /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
9b46748d 450 $$ = f_new_where($2);
4c553c5a 451 }
430da60f
MM
452 ;
453
ba921648 454function_body:
c29d73a0 455 function_vars '{' cmds '}' {
23e3b1e6 456 $$ = f_linearize($3);
63e76204 457 $$->vars = $1;
84c7e194 458 }
ba921648
PM
459 ;
460
f851f0d7 461conf: function_def ;
ba921648 462function_def:
2de1e206 463 FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name );
0b39b1cb 464 $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
bf3eb98e 465 cf_push_scope($2);
c29d73a0
MM
466 } function_args function_body {
467 DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars);
96d757c1
JMM
468 $5->args = $4;
469 $2->function = $5;
ae3e1af2 470 cf_pop_scope();
ba921648
PM
471 }
472 ;
473
474/* Programs */
475
476cmds: /* EMPTY */ { $$ = NULL; }
0206c070 477 | cmds_int { $$ = $1.begin; }
5f47c4c1
OZ
478 ;
479
dfe63ed8 480cmd_prep: cmd {
0206c070 481 $$.begin = $$.end = $1;
dfe63ed8
MM
482 if ($1)
483 while ($$.end->next)
484 $$.end = $$.end->next;
485}
486 ;
487
488cmds_int: cmd_prep
489 | cmds_int cmd_prep {
490 if (!$1.begin)
491 $$ = $2;
492 else if (!$2.begin)
493 $$ = $1;
494 else {
495 $$.begin = $1.begin;
496 $$.end = $2.end;
497 $1.end->next = $2.begin;
0206c070 498 }
0206c070 499 }
84c7e194
PM
500 ;
501
2575593e 502block:
ba921648 503 cmd {
2575593e
PM
504 $$=$1;
505 }
506 | '{' cmds '}' {
507 $$=$2;
508 }
509 ;
510
d3dd620b
PM
511/*
512 * Complex types, their bison value is struct f_val
513 */
e3f2d5fc 514fipa:
04632fd7
OZ
515 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
516 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
d3dd620b
PM
517 ;
518
b8cc390e
OZ
519
520
521/*
522 * Set constants. They are also used in switch cases. We use separate
523 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
524 * to elude a collision between symbol (in expr) in set_atom and symbol
525 * as a function call in switch case cmds.
526 */
527
38506f71 528set_atom:
83715aa8
OZ
529 NUM { $$.type = T_INT; $$.val.i = $1; }
530 | fipa { $$ = $1; }
531 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
532 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
b2f00837 533 | '(' term ')' {
23e3b1e6 534 if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
b2f00837
OZ
535 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
536 }
9eef9c64
MM
537 | CF_SYM_KNOWN {
538 cf_assert_symbol($1, SYM_CONSTANT);
b2f00837 539 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
0b39b1cb 540 $$ = *$1->val;
b2f00837 541 }
b8cc390e 542 ;
38506f71 543
b8cc390e
OZ
544switch_atom:
545 NUM { $$.type = T_INT; $$.val.i = $1; }
23e3b1e6 546 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
b8cc390e
OZ
547 | fipa { $$ = $1; }
548 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
549 ;
550
60566c5c 551cnum:
23e3b1e6 552 term { $$ = f_eval_int(f_linearize($1)); }
b8cc390e
OZ
553
554pair_item:
60566c5c
OZ
555 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
556 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
557 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
558 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
559 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
560 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
561 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
562 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
563 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
564 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
565 { $$ = f_new_pair_item($2, $8, $4, $10); }
38506f71
PM
566 ;
567
42a0c054
OZ
568ec_kind:
569 RT { $$ = EC_RT; }
570 | RO { $$ = EC_RO; }
571 | UNKNOWN NUM { $$ = $2; }
572 | GENERIC { $$ = EC_GENERIC; }
573 ;
574
575ec_item:
60566c5c
OZ
576 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
577 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
578 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
42a0c054
OZ
579 ;
580
60566c5c
OZ
581lc_item:
582 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
583 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
584 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
585 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
586 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
587 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
588 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
589 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
590 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
591;
42a0c054 592
b8cc390e
OZ
593set_item:
594 pair_item
42a0c054 595 | ec_item
60566c5c 596 | lc_item
b8cc390e
OZ
597 | set_atom { $$ = f_new_item($1, $1); }
598 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
599 ;
600
601switch_item:
602 pair_item
42a0c054 603 | ec_item
60566c5c 604 | lc_item
b8cc390e
OZ
605 | switch_atom { $$ = f_new_item($1, $1); }
606 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
607 ;
608
38506f71 609set_items:
b8cc390e
OZ
610 set_item
611 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
612 ;
613
614switch_items:
615 switch_item
616 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
38506f71
PM
617 ;
618
b1a597e0 619fprefix:
04632fd7
OZ
620 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
621 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
622 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
623 | net_ip_ '{' NUM ',' NUM '}' {
5e173e9f 624 $$.net = $1; $$.lo = $3; $$.hi = $5;
6aaaa635
OZ
625 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
626 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
b1a597e0
OZ
627 }
628 ;
629
630fprefix_set:
27550028
OZ
631 fprefix { $$ = f_new_trie(cfg_mem, 0); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
632 | fprefix_set ',' fprefix { $$ = $1; if (!trie_add_prefix($$, &($3.net), $3.lo, $3.hi)) cf_error("Mixed IPv4/IPv6 prefixes in prefix set"); }
b1a597e0
OZ
633 ;
634
41be4444 635switch_body: /* EMPTY */ { $$ = NULL; }
b8cc390e
OZ
636 | switch_body switch_items ':' cmds {
637 /* Fill data fields */
638 struct f_tree *t;
23e3b1e6 639 struct f_line *line = f_linearize($4);
b8cc390e 640 for (t = $2; t; t = t->left)
4c553c5a 641 t->data = line;
b8cc390e 642 $$ = f_merge_items($1, $2);
41be4444 643 }
5e173e9f 644 | switch_body ELSECOL cmds {
b8cc390e
OZ
645 struct f_tree *t = f_new_tree();
646 t->from.type = t->to.type = T_VOID;
647 t->right = t;
23e3b1e6 648 t->data = f_linearize($3);
b8cc390e
OZ
649 $$ = f_merge_items($1, t);
650 }
41be4444 651 ;
d3dd620b 652
92a72a4c 653bgp_path_expr:
c0e958e0 654 symbol_value { $$ = $1; }
92a72a4c
OZ
655 | '(' term ')' { $$ = $2; }
656 ;
657
f9491630 658bgp_path:
3e52d112 659 PO bgp_path_tail PC { $$ = $2; }
f9491630
OZ
660 ;
661
3e52d112 662bgp_path_tail:
4f082dfa
MM
663 NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; }
664 | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; }
ef113c6f
OZ
665 | '[' set_items ']' bgp_path_tail {
666 if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
667 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = build_tree($2), .kind = PM_ASN_SET }, }); $$->next = $4;
668 }
4f082dfa
MM
669 | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
670 | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
ec430a7f 671 | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
4f082dfa 672 | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
122deb6d 673 | { $$ = NULL; }
f9491630 674 ;
77de6882 675
23b1539b 676constant:
9b46748d
MM
677 NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
678 | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
679 | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
680 | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
681 | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
682 | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
683 | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
ca2ee91a
MM
684 | '[' set_items ']' {
685 DBG( "We've got a set here..." );
9b46748d 686 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
ca2ee91a
MM
687 DBG( "ook\n" );
688 }
9b46748d
MM
689 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
690 | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
23b1539b
PM
691 ;
692
42a0c054 693constructor:
9b46748d
MM
694 '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
695 | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
696 | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
c0999a14 697 | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); }
42a0c054
OZ
698 ;
699
92a72a4c 700
96d757c1
JMM
701/* This generates the function_call variable list backwards. */
702var_list: /* EMPTY */ { $$ = NULL; }
703 | term { $$ = $1; }
704 | var_list ',' term { $$ = $3; $$->next = $1; }
705
2d496d20 706function_call:
9eef9c64 707 CF_SYM_KNOWN '(' var_list ')' {
96d757c1
JMM
708 if ($1->class != SYM_FUNCTION)
709 cf_error("You can't call something which is not a function. Really.");
710
711 struct f_inst *fc = f_new_inst(FI_CALL, $1);
712 uint args = 0;
713 while ($3) {
714 args++;
715 struct f_inst *tmp = $3->next;
716 $3->next = fc;
717
718 fc = $3;
719 $3 = tmp;
720 }
721
722 if (args != $1->function->args)
723 cf_error("Function call '%s' got %u arguments, need %u arguments.",
724 $1->name, args, $1->function->args);
725
726 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
727 $$->next = fc;
2d496d20
PM
728 }
729 ;
730
9eef9c64
MM
731symbol_value: CF_SYM_KNOWN
732 {
733 switch ($1->class) {
734 case SYM_CONSTANT_RANGE:
30667d50 735 $$ = f_new_inst(FI_CONSTANT, *($1->val));
96d757c1 736 break;
9eef9c64 737 case SYM_VARIABLE_RANGE:
96d757c1 738 $$ = f_new_inst(FI_VAR_GET, $1);
9eef9c64
MM
739 break;
740 case SYM_ATTRIBUTE:
741 $$ = f_new_inst(FI_EA_GET, *$1->attribute);
742 break;
743 default:
744 cf_error("Can't get value of symbol %s", $1->name);
745 }
746 }
c0e958e0 747 ;
92a72a4c 748
2bdb5e00 749static_attr:
4c553c5a
MM
750 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
751 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
752 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
753 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
754 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
755 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
756 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
757 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
758 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
8cc5bb09 759 | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
e5468d16 760 | GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
2bdb5e00
PM
761 ;
762
84c7e194 763term:
5a14df39 764 '(' term ')' { $$ = $2; }
9b46748d
MM
765 | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
766 | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
767 | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
768 | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
769 | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
770 | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
771 | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
772 | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
773 | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
774 | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
775 | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
776 | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
777 | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
778 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
779 | '!' term { $$ = f_new_inst(FI_NOT, $2); }
780 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
23b1539b 781
c0e958e0 782 | symbol_value { $$ = $1; }
1183b6b2 783 | constant { $$ = $1; }
42a0c054 784 | constructor { $$ = $1; }
4515bdba 785
5a14df39 786 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
2bdb5e00 787
c0e958e0 788 | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
fe613ecd 789
c0e958e0 790 | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
36bbfc70 791
9b46748d
MM
792 | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
793 | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
794 | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
795 | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
796 | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
797 | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
798 | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
ff2ca10c
OZ
799 | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
800 | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
9b46748d
MM
801 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
802 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
803 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
804 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
7f77e250
PM
805
806/* Communities */
10a53608 807/* This causes one shift/reduce conflict
c0e958e0
MM
808 | dynamic_attr '.' ADD '(' term ')' { }
809 | dynamic_attr '.' DELETE '(' term ')' { }
810 | dynamic_attr '.' CONTAINS '(' term ')' { }
811 | dynamic_attr '.' RESET{ }
10a53608 812*/
7f77e250 813
9b46748d
MM
814 | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
815 | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
816 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
817 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
818 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
819 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
820 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
821 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
afc54517 822
9b46748d
MM
823 | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
824 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
af582c48 825
9b46748d 826 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
9b0a0ba9 827
a2d15746 828/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 829
4c553c5a 830 | function_call
ba921648
PM
831 ;
832
833break_command:
82bfee76 834 ACCEPT { $$ = F_ACCEPT; }
03e3d184
MM
835 | REJECT { $$ = F_REJECT; }
836 | ERROR { $$ = F_ERROR; }
ba921648
PM
837 ;
838
23b1539b 839print_list: /* EMPTY */ { $$ = NULL; }
0206c070
MM
840 | term { $$ = $1; }
841 | term ',' print_list {
842 ASSERT($1);
843 ASSERT($1->next == NULL);
844 $1->next = $3;
845 $$ = $1;
23b1539b
PM
846 }
847 ;
848
849cmd:
49955645 850 IF term THEN block {
9b46748d 851 $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
23b1539b 852 }
49955645 853 | IF term THEN block ELSE block {
9b46748d 854 $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
23b1539b 855 }
9eef9c64
MM
856 | CF_SYM_KNOWN '=' term ';' {
857 switch ($1->class) {
858 case SYM_VARIABLE_RANGE:
a84b8b6e 859 $$ = f_new_inst(FI_VAR_SET, $3, $1);
9eef9c64
MM
860 break;
861 case SYM_ATTRIBUTE:
a84b8b6e 862 $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
9eef9c64
MM
863 break;
864 default:
865 cf_error("Can't assign to symbol %s", $1->name);
866 }
b9d70dc8 867 }
2d496d20 868 | RETURN term ';' {
d4d75628 869 DBG( "Ook, we'll return the value\n" );
a84b8b6e 870 $$ = f_new_inst(FI_RETURN, $2);
2d496d20 871 }
c0e958e0 872 | dynamic_attr '=' term ';' {
a84b8b6e 873 $$ = f_new_inst(FI_EA_SET, $3, $1);
f31156ca 874 }
c0e958e0
MM
875 | static_attr '=' term ';' {
876 if ($1.readonly)
0dc4431c 877 cf_error( "This static attribute is read-only.");
a84b8b6e 878 $$ = f_new_inst(FI_RTA_SET, $3, $1);
0dc4431c
PM
879 }
880 | PREFERENCE '=' term ';' {
a84b8b6e 881 $$ = f_new_inst(FI_PREF_SET, $3);
c8cafc8e 882 }
c0e958e0
MM
883 | UNSET '(' dynamic_attr ')' ';' {
884 $$ = f_new_inst(FI_EA_UNSET, $3);
c7b43f33 885 }
0206c070 886 | break_command print_list ';' {
efd7c87b
MM
887 struct f_inst *breaker = f_new_inst(FI_DIE, $1);
888 if ($2) {
889 struct f_inst *printer = f_new_inst(FI_PRINT, $2);
890 struct f_inst *flusher = f_new_inst(FI_FLUSH);
891 printer->next = flusher;
892 flusher->next = breaker;
0206c070 893 $$ = printer;
efd7c87b 894 } else
0206c070
MM
895 $$ = breaker;
896 }
efd7c87b
MM
897 | PRINT print_list ';' {
898 $$ = f_new_inst(FI_PRINT, $2);
899 $$->next = f_new_inst(FI_FLUSH);
900 }
901 | PRINTN print_list ';' {
902 $$ = f_new_inst(FI_PRINT, $2);
903 }
9b46748d 904 | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
7db7b7db 905 | CASE term '{' switch_body '}' {
9b46748d 906 $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
7db7b7db 907 }
7d6eebae 908
c0e958e0
MM
909 | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
910 | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
911 | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
912 | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
913 | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
3ec0bedc 914 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
c0e958e0 915 | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
9b0a0ba9
OZ
916 ;
917
918get_cf_position:
919{
920 $$ = cf_text;
921};
922
c0e958e0 923lvalue:
9eef9c64 924 CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
c0e958e0
MM
925 | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
926 | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
927 | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
9b0a0ba9 928
b9d70dc8 929CF_END