]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Flowspec: Fix values for true/false operators
[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,
8cc5bb09 281 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT,
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,
132529ce 291 BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
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
f851f0d7 315conf: filter_def ;
e0f2e42f 316filter_def:
2de1e206 317 FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
b2b7bbfc 318 filter_body {
0b39b1cb 319 struct filter *f = cfg_alloc(sizeof(struct filter));
f249d0b8 320 *f = (struct filter) { .sym = $2, .root = $4 };
0b39b1cb
MM
321 $2->filter = f;
322
ae3e1af2 323 cf_pop_scope();
b9d70dc8
PM
324 }
325 ;
326
f851f0d7 327conf: filter_eval ;
1c20608e 328filter_eval:
23e3b1e6 329 EVAL term { f_eval_int(f_linearize($2)); }
1c20608e
MM
330 ;
331
265419a3 332conf: custom_attr ;
2de1e206 333custom_attr: ATTRIBUTE type symbol ';' {
0b39b1cb 334 cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
265419a3
MM
335};
336
f851f0d7 337conf: bt_test_suite ;
9b0a0ba9 338bt_test_suite:
9eef9c64
MM
339 BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
340 cf_assert_symbol($3, SYM_FUNCTION);
132529ce 341 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
0b39b1cb 342 t->fn = $3->function;
9b0a0ba9
OZ
343 t->fn_name = $3->name;
344 t->dsc = $5;
345
346 add_tail(&new_config->tests, &t->n);
347 }
348 ;
349
132529ce
MM
350conf: bt_test_same ;
351bt_test_same:
9eef9c64
MM
352 BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
353 cf_assert_symbol($3, SYM_FUNCTION);
354 cf_assert_symbol($5, SYM_FUNCTION);
132529ce 355 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
0b39b1cb
MM
356 t->fn = $3->function;
357 t->cmp = $5->function;
132529ce
MM
358 t->result = $7;
359 t->fn_name = $3->name;
360 t->dsc = $5->name;
361 add_tail(&new_config->tests, &t->n);
362 }
363 ;
364
ba921648
PM
365type:
366 INT { $$ = T_INT; }
367 | BOOL { $$ = T_BOOL; }
368 | IP { $$ = T_IP; }
8c9986d3 369 | RD { $$ = T_RD; }
5e173e9f 370 | PREFIX { $$ = T_NET; }
ba921648 371 | PAIR { $$ = T_PAIR; }
126683fe 372 | QUAD { $$ = T_QUAD; }
42a0c054 373 | EC { $$ = T_EC; }
66dbdbd9 374 | LC { $$ = T_LC; }
ba921648 375 | STRING { $$ = T_STRING; }
10a53608
PM
376 | BGPMASK { $$ = T_PATH_MASK; }
377 | BGPPATH { $$ = T_PATH; }
378 | CLIST { $$ = T_CLIST; }
42a0c054 379 | ECLIST { $$ = T_ECLIST; }
66dbdbd9 380 | LCLIST { $$ = T_LCLIST; }
c8cafc8e 381 | type SET {
ba921648 382 switch ($1) {
b1a597e0 383 case T_INT:
b1a597e0 384 case T_PAIR:
126683fe 385 case T_QUAD:
42a0c054 386 case T_EC:
66dbdbd9 387 case T_LC:
83715aa8 388 case T_RD:
126683fe 389 case T_IP:
b1a597e0
OZ
390 $$ = T_SET;
391 break;
392
5e173e9f 393 case T_NET:
b1a597e0
OZ
394 $$ = T_PREFIX_SET;
395 break;
396
ba921648 397 default:
a5a947d4 398 cf_error( "You can't create sets of this type." );
ba921648 399 }
b1a597e0 400 }
ba921648
PM
401 ;
402
c29d73a0
MM
403function_argsn:
404 /* EMPTY */
2de1e206 405 | function_argsn type symbol ';' {
c29d73a0
MM
406 if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
407 cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
408 }
6dc7a0cb
PM
409 ;
410
c29d73a0
MM
411function_args:
412 '(' ')' { $$ = 0; }
2de1e206 413 | '(' function_argsn type symbol ')' {
63e76204
MM
414 cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
415 $$ = $4->scope->slots;
e0f2e42f
MM
416 }
417 ;
418
c29d73a0
MM
419function_vars:
420 /* EMPTY */ { $$ = 0; }
2de1e206 421 | function_vars type symbol ';' {
c29d73a0
MM
422 cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
423 $$ = $1 + 1;
424 }
425 ;
426
63e76204 427filter_body: function_body ;
96d757c1 428
e0f2e42f 429filter:
9eef9c64
MM
430 CF_SYM_KNOWN {
431 cf_assert_symbol($1, SYM_FILTER);
0b39b1cb
MM
432 $$ = $1->filter;
433 }
434 | filter_body {
435 struct filter *f = cfg_alloc(sizeof(struct filter));
436 *f = (struct filter) { .root = $1 };
437 $$ = f;
e0f2e42f 438 }
e0f2e42f
MM
439 ;
440
430da60f
MM
441where_filter:
442 WHERE term {
224b77d4 443 /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
9b46748d 444 $$ = f_new_where($2);
4c553c5a 445 }
430da60f
MM
446 ;
447
ba921648 448function_body:
c29d73a0 449 function_vars '{' cmds '}' {
23e3b1e6 450 $$ = f_linearize($3);
63e76204 451 $$->vars = $1;
84c7e194 452 }
ba921648
PM
453 ;
454
f851f0d7 455conf: function_def ;
ba921648 456function_def:
2de1e206 457 FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name );
0b39b1cb 458 $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
bf3eb98e 459 cf_push_scope($2);
c29d73a0
MM
460 } function_args function_body {
461 DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars);
96d757c1
JMM
462 $5->args = $4;
463 $2->function = $5;
ae3e1af2 464 cf_pop_scope();
ba921648
PM
465 }
466 ;
467
468/* Programs */
469
470cmds: /* EMPTY */ { $$ = NULL; }
0206c070 471 | cmds_int { $$ = $1.begin; }
5f47c4c1
OZ
472 ;
473
dfe63ed8 474cmd_prep: cmd {
0206c070 475 $$.begin = $$.end = $1;
dfe63ed8
MM
476 if ($1)
477 while ($$.end->next)
478 $$.end = $$.end->next;
479}
480 ;
481
482cmds_int: cmd_prep
483 | cmds_int cmd_prep {
484 if (!$1.begin)
485 $$ = $2;
486 else if (!$2.begin)
487 $$ = $1;
488 else {
489 $$.begin = $1.begin;
490 $$.end = $2.end;
491 $1.end->next = $2.begin;
0206c070 492 }
0206c070 493 }
84c7e194
PM
494 ;
495
2575593e 496block:
ba921648 497 cmd {
2575593e
PM
498 $$=$1;
499 }
500 | '{' cmds '}' {
501 $$=$2;
502 }
503 ;
504
d3dd620b
PM
505/*
506 * Complex types, their bison value is struct f_val
507 */
e3f2d5fc 508fipa:
04632fd7
OZ
509 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
510 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
d3dd620b
PM
511 ;
512
b8cc390e
OZ
513
514
515/*
516 * Set constants. They are also used in switch cases. We use separate
517 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
518 * to elude a collision between symbol (in expr) in set_atom and symbol
519 * as a function call in switch case cmds.
520 */
521
38506f71 522set_atom:
83715aa8
OZ
523 NUM { $$.type = T_INT; $$.val.i = $1; }
524 | fipa { $$ = $1; }
525 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
526 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
b2f00837 527 | '(' term ')' {
23e3b1e6 528 if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
b2f00837
OZ
529 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
530 }
9eef9c64
MM
531 | CF_SYM_KNOWN {
532 cf_assert_symbol($1, SYM_CONSTANT);
b2f00837 533 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
0b39b1cb 534 $$ = *$1->val;
b2f00837 535 }
b8cc390e 536 ;
38506f71 537
b8cc390e
OZ
538switch_atom:
539 NUM { $$.type = T_INT; $$.val.i = $1; }
23e3b1e6 540 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
b8cc390e
OZ
541 | fipa { $$ = $1; }
542 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
543 ;
544
60566c5c 545cnum:
23e3b1e6 546 term { $$ = f_eval_int(f_linearize($1)); }
b8cc390e
OZ
547
548pair_item:
60566c5c
OZ
549 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
550 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
551 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
552 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
553 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
554 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
555 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
556 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
557 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
558 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
559 { $$ = f_new_pair_item($2, $8, $4, $10); }
38506f71
PM
560 ;
561
42a0c054
OZ
562ec_kind:
563 RT { $$ = EC_RT; }
564 | RO { $$ = EC_RO; }
565 | UNKNOWN NUM { $$ = $2; }
566 | GENERIC { $$ = EC_GENERIC; }
567 ;
568
569ec_item:
60566c5c
OZ
570 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
571 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
572 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
42a0c054
OZ
573 ;
574
60566c5c
OZ
575lc_item:
576 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
577 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
578 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
579 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
580 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
581 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
582 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
583 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
584 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
585;
42a0c054 586
b8cc390e
OZ
587set_item:
588 pair_item
42a0c054 589 | ec_item
60566c5c 590 | lc_item
b8cc390e
OZ
591 | set_atom { $$ = f_new_item($1, $1); }
592 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
593 ;
594
595switch_item:
596 pair_item
42a0c054 597 | ec_item
60566c5c 598 | lc_item
b8cc390e
OZ
599 | switch_atom { $$ = f_new_item($1, $1); }
600 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
601 ;
602
38506f71 603set_items:
b8cc390e
OZ
604 set_item
605 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
606 ;
607
608switch_items:
609 switch_item
610 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
38506f71
PM
611 ;
612
b1a597e0 613fprefix:
04632fd7
OZ
614 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
615 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
616 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
617 | net_ip_ '{' NUM ',' NUM '}' {
5e173e9f 618 $$.net = $1; $$.lo = $3; $$.hi = $5;
6aaaa635
OZ
619 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
620 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
b1a597e0
OZ
621 }
622 ;
623
624fprefix_set:
27550028
OZ
625 fprefix { $$ = f_new_trie(cfg_mem, 0); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
626 | 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
627 ;
628
41be4444 629switch_body: /* EMPTY */ { $$ = NULL; }
b8cc390e
OZ
630 | switch_body switch_items ':' cmds {
631 /* Fill data fields */
632 struct f_tree *t;
23e3b1e6 633 struct f_line *line = f_linearize($4);
b8cc390e 634 for (t = $2; t; t = t->left)
4c553c5a 635 t->data = line;
b8cc390e 636 $$ = f_merge_items($1, $2);
41be4444 637 }
5e173e9f 638 | switch_body ELSECOL cmds {
b8cc390e
OZ
639 struct f_tree *t = f_new_tree();
640 t->from.type = t->to.type = T_VOID;
641 t->right = t;
23e3b1e6 642 t->data = f_linearize($3);
b8cc390e
OZ
643 $$ = f_merge_items($1, t);
644 }
41be4444 645 ;
d3dd620b 646
92a72a4c 647bgp_path_expr:
c0e958e0 648 symbol_value { $$ = $1; }
92a72a4c
OZ
649 | '(' term ')' { $$ = $2; }
650 ;
651
f9491630 652bgp_path:
3e52d112 653 PO bgp_path_tail PC { $$ = $2; }
f9491630
OZ
654 ;
655
3e52d112 656bgp_path_tail:
4f082dfa
MM
657 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; }
658 | 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
659 | '[' set_items ']' bgp_path_tail {
660 if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
661 $$ = 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;
662 }
4f082dfa
MM
663 | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
664 | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
ec430a7f 665 | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
4f082dfa 666 | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
122deb6d 667 | { $$ = NULL; }
f9491630 668 ;
77de6882 669
23b1539b 670constant:
9b46748d
MM
671 NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
672 | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
673 | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
674 | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
675 | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
676 | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
677 | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
ca2ee91a
MM
678 | '[' set_items ']' {
679 DBG( "We've got a set here..." );
9b46748d 680 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
ca2ee91a
MM
681 DBG( "ook\n" );
682 }
9b46748d
MM
683 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
684 | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
23b1539b
PM
685 ;
686
42a0c054 687constructor:
9b46748d
MM
688 '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
689 | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
690 | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
c0999a14 691 | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); }
42a0c054
OZ
692 ;
693
92a72a4c 694
96d757c1
JMM
695/* This generates the function_call variable list backwards. */
696var_list: /* EMPTY */ { $$ = NULL; }
697 | term { $$ = $1; }
698 | var_list ',' term { $$ = $3; $$->next = $1; }
699
2d496d20 700function_call:
9eef9c64 701 CF_SYM_KNOWN '(' var_list ')' {
96d757c1
JMM
702 if ($1->class != SYM_FUNCTION)
703 cf_error("You can't call something which is not a function. Really.");
704
705 struct f_inst *fc = f_new_inst(FI_CALL, $1);
706 uint args = 0;
707 while ($3) {
708 args++;
709 struct f_inst *tmp = $3->next;
710 $3->next = fc;
711
712 fc = $3;
713 $3 = tmp;
714 }
715
716 if (args != $1->function->args)
717 cf_error("Function call '%s' got %u arguments, need %u arguments.",
718 $1->name, args, $1->function->args);
719
720 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
721 $$->next = fc;
2d496d20
PM
722 }
723 ;
724
9eef9c64
MM
725symbol_value: CF_SYM_KNOWN
726 {
727 switch ($1->class) {
728 case SYM_CONSTANT_RANGE:
30667d50 729 $$ = f_new_inst(FI_CONSTANT, *($1->val));
96d757c1 730 break;
9eef9c64 731 case SYM_VARIABLE_RANGE:
96d757c1 732 $$ = f_new_inst(FI_VAR_GET, $1);
9eef9c64
MM
733 break;
734 case SYM_ATTRIBUTE:
735 $$ = f_new_inst(FI_EA_GET, *$1->attribute);
736 break;
737 default:
738 cf_error("Can't get value of symbol %s", $1->name);
739 }
740 }
c0e958e0 741 ;
92a72a4c 742
2bdb5e00 743static_attr:
4c553c5a
MM
744 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
745 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
746 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
747 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
748 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
749 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
750 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
751 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
752 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
8cc5bb09 753 | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
2bdb5e00
PM
754 ;
755
84c7e194 756term:
5a14df39 757 '(' term ')' { $$ = $2; }
9b46748d
MM
758 | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
759 | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
760 | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
761 | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
762 | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
763 | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
764 | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
765 | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
766 | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
767 | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
768 | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
769 | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
770 | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
771 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
772 | '!' term { $$ = f_new_inst(FI_NOT, $2); }
773 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
23b1539b 774
c0e958e0 775 | symbol_value { $$ = $1; }
1183b6b2 776 | constant { $$ = $1; }
42a0c054 777 | constructor { $$ = $1; }
4515bdba 778
5a14df39 779 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
2bdb5e00 780
c0e958e0 781 | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
fe613ecd 782
c0e958e0 783 | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
36bbfc70 784
9b46748d
MM
785 | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
786 | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
787 | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
788 | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
789 | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
790 | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
791 | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
ff2ca10c
OZ
792 | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
793 | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
9b46748d
MM
794 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
795 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
796 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
797 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
7f77e250
PM
798
799/* Communities */
10a53608 800/* This causes one shift/reduce conflict
c0e958e0
MM
801 | dynamic_attr '.' ADD '(' term ')' { }
802 | dynamic_attr '.' DELETE '(' term ')' { }
803 | dynamic_attr '.' CONTAINS '(' term ')' { }
804 | dynamic_attr '.' RESET{ }
10a53608 805*/
7f77e250 806
9b46748d
MM
807 | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
808 | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
809 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
810 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
811 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
812 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
813 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
814 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
afc54517 815
9b46748d
MM
816 | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
817 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
af582c48 818
9b46748d 819 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
9b0a0ba9 820
a2d15746 821/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 822
4c553c5a 823 | function_call
ba921648
PM
824 ;
825
826break_command:
82bfee76 827 ACCEPT { $$ = F_ACCEPT; }
03e3d184
MM
828 | REJECT { $$ = F_REJECT; }
829 | ERROR { $$ = F_ERROR; }
ba921648
PM
830 ;
831
23b1539b 832print_list: /* EMPTY */ { $$ = NULL; }
0206c070
MM
833 | term { $$ = $1; }
834 | term ',' print_list {
835 ASSERT($1);
836 ASSERT($1->next == NULL);
837 $1->next = $3;
838 $$ = $1;
23b1539b
PM
839 }
840 ;
841
842cmd:
49955645 843 IF term THEN block {
9b46748d 844 $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
23b1539b 845 }
49955645 846 | IF term THEN block ELSE block {
9b46748d 847 $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
23b1539b 848 }
9eef9c64
MM
849 | CF_SYM_KNOWN '=' term ';' {
850 switch ($1->class) {
851 case SYM_VARIABLE_RANGE:
a84b8b6e 852 $$ = f_new_inst(FI_VAR_SET, $3, $1);
9eef9c64
MM
853 break;
854 case SYM_ATTRIBUTE:
a84b8b6e 855 $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
9eef9c64
MM
856 break;
857 default:
858 cf_error("Can't assign to symbol %s", $1->name);
859 }
b9d70dc8 860 }
2d496d20 861 | RETURN term ';' {
d4d75628 862 DBG( "Ook, we'll return the value\n" );
a84b8b6e 863 $$ = f_new_inst(FI_RETURN, $2);
2d496d20 864 }
c0e958e0 865 | dynamic_attr '=' term ';' {
a84b8b6e 866 $$ = f_new_inst(FI_EA_SET, $3, $1);
f31156ca 867 }
c0e958e0
MM
868 | static_attr '=' term ';' {
869 if ($1.readonly)
0dc4431c 870 cf_error( "This static attribute is read-only.");
a84b8b6e 871 $$ = f_new_inst(FI_RTA_SET, $3, $1);
0dc4431c
PM
872 }
873 | PREFERENCE '=' term ';' {
a84b8b6e 874 $$ = f_new_inst(FI_PREF_SET, $3);
c8cafc8e 875 }
c0e958e0
MM
876 | UNSET '(' dynamic_attr ')' ';' {
877 $$ = f_new_inst(FI_EA_UNSET, $3);
c7b43f33 878 }
0206c070 879 | break_command print_list ';' {
efd7c87b
MM
880 struct f_inst *breaker = f_new_inst(FI_DIE, $1);
881 if ($2) {
882 struct f_inst *printer = f_new_inst(FI_PRINT, $2);
883 struct f_inst *flusher = f_new_inst(FI_FLUSH);
884 printer->next = flusher;
885 flusher->next = breaker;
0206c070 886 $$ = printer;
efd7c87b 887 } else
0206c070
MM
888 $$ = breaker;
889 }
efd7c87b
MM
890 | PRINT print_list ';' {
891 $$ = f_new_inst(FI_PRINT, $2);
892 $$->next = f_new_inst(FI_FLUSH);
893 }
894 | PRINTN print_list ';' {
895 $$ = f_new_inst(FI_PRINT, $2);
896 }
9b46748d 897 | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
7db7b7db 898 | CASE term '{' switch_body '}' {
9b46748d 899 $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
7db7b7db 900 }
7d6eebae 901
c0e958e0
MM
902 | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
903 | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
904 | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
905 | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
906 | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
3ec0bedc 907 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
c0e958e0 908 | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
9b0a0ba9
OZ
909 ;
910
911get_cf_position:
912{
913 $$ = cf_text;
914};
915
c0e958e0 916lvalue:
9eef9c64 917 CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
c0e958e0
MM
918 | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
919 | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
920 | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
9b0a0ba9 921
b9d70dc8 922CF_END