]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Filters: Removed FI_COMMA, not used for 19 years.
[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
2edb31b0
MM
13CF_DEFINES
14
b8cc390e
OZ
15static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
16static inline u32 pair_a(u32 p) { return p >> 16; }
17static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
18
19
20/*
21 * Sets and their items are during parsing handled as lists, linked
22 * through left ptr. The first item in a list also contains a pointer
23 * to the last item in a list (right ptr). For convenience, even items
24 * are handled as one-item lists. Lists are merged by f_merge_items().
25 */
b2f00837
OZ
26static int
27f_valid_set_type(int type)
28{
29 switch (type)
30 {
31 case T_INT:
32 case T_PAIR:
33 case T_QUAD:
34 case T_ENUM:
35 case T_IP:
36 case T_EC:
66dbdbd9 37 case T_LC:
b2f00837
OZ
38 return 1;
39
40 default:
41 return 0;
42 }
43}
b8cc390e
OZ
44
45static inline struct f_tree *
46f_new_item(struct f_val from, struct f_val to)
92a72a4c 47{
b8cc390e
OZ
48 struct f_tree *t = f_new_tree();
49 t->right = t;
50 t->from = from;
51 t->to = to;
52 return t;
53}
92a72a4c 54
b8cc390e
OZ
55static inline struct f_tree *
56f_merge_items(struct f_tree *a, struct f_tree *b)
57{
58 if (!a) return b;
59 a->right->left = b;
60 a->right = b->right;
61 b->right = NULL;
62 return a;
63}
92a72a4c 64
b8cc390e
OZ
65static inline struct f_tree *
66f_new_pair_item(int fa, int ta, int fb, int tb)
67{
60566c5c
OZ
68 check_u16(fa);
69 check_u16(ta);
70 check_u16(fb);
71 check_u16(tb);
72
73 if ((ta < fa) || (tb < fb))
74 cf_error( "From value cannot be higher that To value in pair sets");
75
b8cc390e
OZ
76 struct f_tree *t = f_new_tree();
77 t->right = t;
78 t->from.type = t->to.type = T_PAIR;
79 t->from.val.i = pair(fa, fb);
80 t->to.val.i = pair(ta, tb);
81 return t;
92a72a4c
OZ
82}
83
b8cc390e
OZ
84static inline struct f_tree *
85f_new_pair_set(int fa, int ta, int fb, int tb)
4fc36f39 86{
60566c5c
OZ
87 check_u16(fa);
88 check_u16(ta);
89 check_u16(fb);
90 check_u16(tb);
c454872f 91
b8cc390e
OZ
92 if ((ta < fa) || (tb < fb))
93 cf_error( "From value cannot be higher that To value in pair sets");
c454872f 94
60566c5c
OZ
95 struct f_tree *lst = NULL;
96 int i;
97
b8cc390e
OZ
98 for (i = fa; i <= ta; i++)
99 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
100
101 return lst;
4fc36f39
OF
102}
103
60566c5c 104#define CC_ALL 0xFFFF
42a0c054 105#define EC_ALL 0xFFFFFFFF
60566c5c 106#define LC_ALL 0xFFFFFFFF
42a0c054
OZ
107
108static struct f_tree *
109f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
110{
111 u64 fm, to;
112
e46128fb 113 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
42a0c054
OZ
114 check_u16(vf);
115 if (vt == EC_ALL)
116 vt = 0xFFFF;
117 else
118 check_u16(vt);
119 }
120
121 if (kind == EC_GENERIC) {
122 fm = ec_generic(key, vf);
123 to = ec_generic(key, vt);
124 }
125 else if (ipv4_used) {
126 fm = ec_ip4(kind, key, vf);
127 to = ec_ip4(kind, key, vt);
128 }
129 else if (key < 0x10000) {
130 fm = ec_as2(kind, key, vf);
131 to = ec_as2(kind, key, vt);
132 }
133 else {
134 fm = ec_as4(kind, key, vf);
135 to = ec_as4(kind, key, vt);
136 }
137
138 struct f_tree *t = f_new_tree();
139 t->right = t;
140 t->from.type = t->to.type = T_EC;
141 t->from.val.ec = fm;
142 t->to.val.ec = to;
143 return t;
144}
145
60566c5c
OZ
146static struct f_tree *
147f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
148{
149 struct f_tree *t = f_new_tree();
150 t->right = t;
151 t->from.type = t->to.type = T_LC;
152 t->from.val.lc = (lcomm) {f1, f2, f3};
153 t->to.val.lc = (lcomm) {t1, t2, t3};
154 return t;
155}
156
42a0c054 157static inline struct f_inst *
5a14df39 158f_generate_empty(struct f_dynamic_attr dyn)
c8cafc8e 159{
5a14df39 160 struct f_inst *e = f_new_inst(FI_EMPTY);
42a0c054 161
5a14df39 162 switch (dyn.type & EAF_TYPE_MASK) {
42a0c054
OZ
163 case EAF_TYPE_AS_PATH:
164 e->aux = T_PATH;
165 break;
166 case EAF_TYPE_INT_SET:
167 e->aux = T_CLIST;
168 break;
169 case EAF_TYPE_EC_SET:
170 e->aux = T_ECLIST;
171 break;
66dbdbd9
OZ
172 case EAF_TYPE_LC_SET:
173 e->aux = T_LCLIST;
174 break;
42a0c054
OZ
175 default:
176 cf_error("Can't empty that attribute");
177 }
178
5a14df39
MJM
179 struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
180 s->a1.p = e;
181 return s;
42a0c054
OZ
182}
183
184
185static inline struct f_inst *
186f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
187{
188 struct f_inst *rv;
189
5a14df39 190 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
42a0c054
OZ
191 if ((t1->aux != T_INT) || (t2->aux != T_INT))
192 cf_error( "Can't operate with value of non-integer type in pair constructor");
193
194 check_u16(t1->a2.i);
195 check_u16(t2->a2.i);
196
5a14df39 197 rv = f_new_inst(FI_CONSTANT);
42a0c054
OZ
198 rv->aux = T_PAIR;
199 rv->a2.i = pair(t1->a2.i, t2->a2.i);
200 }
201 else {
5a14df39 202 rv = f_new_inst(FI_PAIR_CONSTRUCT);
42a0c054
OZ
203 rv->a1.p = t1;
204 rv->a2.p = t2;
205 }
206
207 return rv;
208}
209
210static inline struct f_inst *
211f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
212{
213 struct f_inst *rv;
214 int c1 = 0, c2 = 0, ipv4_used = 0;
215 u32 key = 0, val2 = 0;
216
5a14df39 217 if (tk->fi_code == FI_CONSTANT) {
42a0c054
OZ
218 c1 = 1;
219
220 if (tk->aux == T_INT) {
221 ipv4_used = 0; key = tk->a2.i;
222 }
223 else if (tk->aux == T_QUAD) {
224 ipv4_used = 1; key = tk->a2.i;
225 }
226 else
227 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
228 }
229
230#ifndef IPV6
231 /* IP->Quad implicit conversion */
5a14df39 232 else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
42a0c054
OZ
233 c1 = 1;
234 struct f_val *val = tk->a1.p;
1103b32e
OZ
235
236 if (val->type == T_INT) {
237 ipv4_used = 0; key = val->val.i;
238 }
239 else if (val->type == T_QUAD) {
240 ipv4_used = 1; key = val->val.i;
241 }
242 else if (val->type == T_IP) {
42a0c054
OZ
243 ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
244 }
245 else
246 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
247 }
248#endif
249
5a14df39 250 if (tv->fi_code == FI_CONSTANT) {
42a0c054
OZ
251 if (tv->aux != T_INT)
252 cf_error("Can't operate with value of non-integer type in EC constructor");
253 c2 = 1;
254 val2 = tv->a2.i;
255 }
256
257 if (c1 && c2) {
258 u64 ec;
c8cafc8e 259
42a0c054
OZ
260 if (kind == EC_GENERIC) {
261 ec = ec_generic(key, val2);
262 }
263 else if (ipv4_used) {
264 check_u16(val2);
265 ec = ec_ip4(kind, key, val2);
266 }
267 else if (key < 0x10000) {
268 ec = ec_as2(kind, key, val2);
269 }
270 else {
271 check_u16(val2);
272 ec = ec_as4(kind, key, val2);
273 }
274
275 NEW_F_VAL;
5a14df39 276 rv = f_new_inst(FI_CONSTANT_INDIRECT);
c8cafc8e 277 rv->a1.p = val;
42a0c054
OZ
278 val->type = T_EC;
279 val->val.ec = ec;
280 }
281 else {
5a14df39 282 rv = f_new_inst(FI_EC_CONSTRUCT);
42a0c054
OZ
283 rv->aux = kind;
284 rv->a1.p = tk;
285 rv->a2.p = tv;
286 }
287
288 return rv;
78e33c29 289}
42a0c054 290
66dbdbd9
OZ
291static inline struct f_inst *
292f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
293{
294 struct f_inst *rv;
295
5a14df39 296 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
66dbdbd9
OZ
297 if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
298 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
299
5a14df39 300 rv = f_new_inst(FI_CONSTANT_INDIRECT);
66dbdbd9
OZ
301
302 NEW_F_VAL;
303 rv->a1.p = val;
304 val->type = T_LC;
305 val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
306 }
307 else
308 {
309 rv = cfg_allocz(sizeof(struct f_inst3));
310 rv->lineno = ifs->lino;
5a14df39 311 rv->fi_code = FI_LC_CONSTRUCT;
66dbdbd9
OZ
312 rv->a1.p = t1;
313 rv->a2.p = t2;
314 INST3(rv).p = t3;
315 }
316
317 return rv;
318}
319
42a0c054
OZ
320
321
b9d70dc8
PM
322CF_DECLS
323
e4a73dbf 324CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ba921648 325 ACCEPT, REJECT, ERROR, QUITBIRD,
66dbdbd9
OZ
326 INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
327 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
7db7b7db 328 IF, THEN, ELSE, CASE,
42a0c054 329 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
a5fc5958
OZ
330 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
331 PREFERENCE,
36bbfc70 332 LEN,
f4536657 333 DEFINED,
7f77e250 334 ADD, DELETE, CONTAINS, RESET,
9c9cc35c 335 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
af582c48 336 ROA_CHECK,
afc54517 337 EMPTY,
1c20608e 338 FILTER, WHERE, EVAL)
b9d70dc8 339
f4536657 340%nonassoc THEN
4ed8718a 341%nonassoc ELSE
f4536657 342
5a14df39
MJM
343%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
344%type <fda> dynamic_attr
345%type <fsa> static_attr
430da60f 346%type <f> filter filter_body where_filter
60566c5c
OZ
347%type <i> type break_command ec_kind
348%type <i32> cnum
349%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
b1a597e0 350%type <trie> fprefix_set
b8cc390e 351%type <v> set_atom switch_atom fprefix fprefix_s fipa
c8cafc8e 352%type <s> decls declsn one_decl function_params
f9491630 353%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
b9d70dc8
PM
354
355CF_GRAMMAR
356
e0f2e42f
MM
357CF_ADDTO(conf, filter_def)
358filter_def:
b2b7bbfc
OZ
359 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
360 filter_body {
361 $2->def = $4;
ae3e1af2 362 $4->name = $2->name;
d4d75628 363 DBG( "We have new filter defined (%s)\n", $2->name );
ae3e1af2 364 cf_pop_scope();
b9d70dc8
PM
365 }
366 ;
367
1c20608e
MM
368CF_ADDTO(conf, filter_eval)
369filter_eval:
370 EVAL term { f_eval_int($2); }
371 ;
372
ba921648
PM
373type:
374 INT { $$ = T_INT; }
375 | BOOL { $$ = T_BOOL; }
376 | IP { $$ = T_IP; }
377 | PREFIX { $$ = T_PREFIX; }
378 | PAIR { $$ = T_PAIR; }
126683fe 379 | QUAD { $$ = T_QUAD; }
42a0c054 380 | EC { $$ = T_EC; }
66dbdbd9 381 | LC { $$ = T_LC; }
ba921648 382 | STRING { $$ = T_STRING; }
10a53608
PM
383 | BGPMASK { $$ = T_PATH_MASK; }
384 | BGPPATH { $$ = T_PATH; }
385 | CLIST { $$ = T_CLIST; }
42a0c054 386 | ECLIST { $$ = T_ECLIST; }
66dbdbd9 387 | LCLIST { $$ = T_LCLIST; }
c8cafc8e 388 | type SET {
ba921648 389 switch ($1) {
b1a597e0 390 case T_INT:
b1a597e0 391 case T_PAIR:
126683fe 392 case T_QUAD:
42a0c054 393 case T_EC:
66dbdbd9 394 case T_LC:
126683fe 395 case T_IP:
b1a597e0
OZ
396 $$ = T_SET;
397 break;
398
399 case T_PREFIX:
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
6dc7a0cb
PM
409one_decl:
410 type SYM {
4ee39ff2
OZ
411 struct f_val * val = cfg_alloc(sizeof(struct f_val));
412 val->type = T_VOID;
083c43e2 413 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
d4d75628 414 DBG( "New variable %s type %x\n", $2->name, $1 );
083c43e2 415 $2->aux2 = NULL;
6542ece9 416 $$=$2;
ba921648
PM
417 }
418 ;
419
6dc7a0cb
PM
420/* Decls with ';' at the end */
421decls: /* EMPTY */ { $$ = NULL; }
422 | one_decl ';' decls {
423 $$ = $1;
083c43e2 424 $$->aux2 = $3;
6dc7a0cb
PM
425 }
426 ;
427
3c989eb4 428/* Declarations that have no ';' at the end. */
6dc7a0cb 429declsn: one_decl { $$ = $1; }
736fd730 430 | one_decl ';' declsn {
4515bdba 431 $$ = $1;
083c43e2 432 $$->aux2 = $3;
6dc7a0cb
PM
433 }
434 ;
435
e0f2e42f 436filter_body:
ba921648 437 function_body {
e0f2e42f
MM
438 struct filter *f = cfg_alloc(sizeof(struct filter));
439 f->name = NULL;
ba921648 440 f->root = $1;
e0f2e42f
MM
441 $$ = f;
442 }
443 ;
444
445filter:
446 SYM {
a5a947d4 447 if ($1->class != SYM_FILTER) cf_error("No such filter.");
e0f2e42f
MM
448 $$ = $1->def;
449 }
450 | filter_body
451 ;
452
430da60f
MM
453where_filter:
454 WHERE term {
455 /* Construct 'IF term THEN ACCEPT; REJECT;' */
456 struct filter *f = cfg_alloc(sizeof(struct filter));
457 struct f_inst *i, *acc, *rej;
5a14df39 458 acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
430da60f
MM
459 acc->a1.p = NULL;
460 acc->a2.i = F_ACCEPT;
5a14df39 461 rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
430da60f
MM
462 rej->a1.p = NULL;
463 rej->a2.i = F_REJECT;
5a14df39 464 i = f_new_inst(FI_CONDITION); /* IF */
430da60f
MM
465 i->a1.p = $2;
466 i->a2.p = acc;
467 i->next = rej;
468 f->name = NULL;
469 f->root = i;
470 $$ = f;
471 }
472 ;
473
ba921648 474function_params:
d4d75628 475 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 476 | '(' ')' { $$=NULL; }
ba921648 477 ;
b9d70dc8 478
ba921648
PM
479function_body:
480 decls '{' cmds '}' {
aa461248
OZ
481 if ($1) {
482 /* Prepend instruction to clear local variables */
5a14df39 483 $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
aa461248
OZ
484 $$->a1.p = $1;
485 $$->next = $3;
486 } else
487 $$ = $3;
84c7e194 488 }
ba921648
PM
489 ;
490
491CF_ADDTO(conf, function_def)
492function_def:
bf3eb98e
MM
493 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
494 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
495 cf_push_scope($2);
496 } function_params function_body {
497 $2->def = $5;
083c43e2 498 $2->aux2 = $4;
c8cafc8e 499 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 500 cf_pop_scope();
ba921648
PM
501 }
502 ;
503
504/* Programs */
505
5f47c4c1
OZ
506/* Hack: $$ of cmds_int is the last node.
507 $$->next of cmds_int is temporary used for the first node */
508
ba921648 509cmds: /* EMPTY */ { $$ = NULL; }
5f47c4c1
OZ
510 | cmds_int { $$ = $1->next; $1->next = NULL; }
511 ;
512
513cmds_int: cmd { $$ = $1; $1->next = $1; }
514 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
84c7e194
PM
515 ;
516
2575593e 517block:
ba921648 518 cmd {
2575593e
PM
519 $$=$1;
520 }
521 | '{' cmds '}' {
522 $$=$2;
523 }
524 ;
525
d3dd620b
PM
526/*
527 * Complex types, their bison value is struct f_val
528 */
e3f2d5fc 529fipa:
60de3356 530 IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
d3dd620b
PM
531 ;
532
b8cc390e
OZ
533
534
535/*
536 * Set constants. They are also used in switch cases. We use separate
537 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
538 * to elude a collision between symbol (in expr) in set_atom and symbol
539 * as a function call in switch case cmds.
540 */
541
38506f71 542set_atom:
b2f00837 543 NUM { $$.type = T_INT; $$.val.i = $1; }
126683fe 544 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
92a72a4c 545 | fipa { $$ = $1; }
b8cc390e 546 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
b2f00837
OZ
547 | '(' term ')' {
548 $$ = f_eval($2, cfg_mem);
549 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
550 }
551 | SYM {
552 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
553 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
554 $$ = *(struct f_val *)($1->def);
555 }
b8cc390e 556 ;
38506f71 557
b8cc390e
OZ
558switch_atom:
559 NUM { $$.type = T_INT; $$.val.i = $1; }
560 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
561 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
562 | fipa { $$ = $1; }
563 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
564 ;
565
60566c5c
OZ
566cnum:
567 term { $$ = f_eval_int($1); }
b8cc390e
OZ
568
569pair_item:
60566c5c
OZ
570 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
571 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
572 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
573 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
574 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
575 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
576 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
577 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
578 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
579 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
580 { $$ = f_new_pair_item($2, $8, $4, $10); }
38506f71
PM
581 ;
582
42a0c054
OZ
583ec_kind:
584 RT { $$ = EC_RT; }
585 | RO { $$ = EC_RO; }
586 | UNKNOWN NUM { $$ = $2; }
587 | GENERIC { $$ = EC_GENERIC; }
588 ;
589
590ec_item:
60566c5c
OZ
591 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
592 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
593 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
42a0c054
OZ
594 ;
595
60566c5c
OZ
596lc_item:
597 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
598 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
599 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
600 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
601 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
602 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
603 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
604 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
605 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
606;
607
b8cc390e
OZ
608set_item:
609 pair_item
42a0c054 610 | ec_item
60566c5c 611 | lc_item
b8cc390e
OZ
612 | set_atom { $$ = f_new_item($1, $1); }
613 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
614 ;
615
616switch_item:
617 pair_item
42a0c054 618 | ec_item
60566c5c 619 | lc_item
b8cc390e
OZ
620 | switch_atom { $$ = f_new_item($1, $1); }
621 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
622 ;
623
38506f71 624set_items:
b8cc390e
OZ
625 set_item
626 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
627 ;
628
629switch_items:
630 switch_item
631 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
38506f71
PM
632 ;
633
b1a597e0
OZ
634fprefix_s:
635 IPA '/' NUM %prec '/' {
636 if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
637 $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
638 }
639 ;
640
641fprefix:
642 fprefix_s { $$ = $1; }
643 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
644 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
c8cafc8e 645 | fprefix_s '{' NUM ',' NUM '}' {
b1a597e0
OZ
646 if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
647 $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
648 }
649 ;
650
651fprefix_set:
51762a45 652 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
7f0d245a 653 | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
b1a597e0
OZ
654 ;
655
41be4444 656switch_body: /* EMPTY */ { $$ = NULL; }
b8cc390e
OZ
657 | switch_body switch_items ':' cmds {
658 /* Fill data fields */
659 struct f_tree *t;
660 for (t = $2; t; t = t->left)
661 t->data = $4;
662 $$ = f_merge_items($1, $2);
41be4444 663 }
c8cafc8e 664 | switch_body ELSECOL cmds {
b8cc390e
OZ
665 struct f_tree *t = f_new_tree();
666 t->from.type = t->to.type = T_VOID;
667 t->right = t;
668 t->data = $3;
669 $$ = f_merge_items($1, t);
670 }
41be4444 671 ;
d3dd620b 672
5a14df39 673/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
e4a73dbf 674
92a72a4c 675bgp_path_expr:
c8cafc8e 676 symbol { $$ = $1; }
92a72a4c
OZ
677 | '(' term ')' { $$ = $2; }
678 ;
679
f9491630 680bgp_path:
cf186034 681 PO bgp_path_tail1 PC { $$ = $2; }
f9491630 682 | '/' bgp_path_tail2 '/' { $$ = $2; }
f9491630
OZ
683 ;
684
685bgp_path_tail1:
122deb6d
OZ
686 NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
687 | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
688 | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
689 | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
690 | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
691 | { $$ = NULL; }
f9491630 692 ;
77de6882 693
f9491630 694bgp_path_tail2:
122deb6d
OZ
695 NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
696 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
f9491630 697 | { $$ = NULL; }
77de6882
PM
698 ;
699
23b1539b 700constant:
5a14df39
MJM
701 NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
702 | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
703 | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
704 | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
705 | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
706 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
707 | RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
708 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
709 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
710 | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
711 | bgp_path { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
23b1539b
PM
712 ;
713
42a0c054 714constructor:
78e33c29
OZ
715 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
716 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
66dbdbd9 717 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
42a0c054
OZ
718 ;
719
92a72a4c 720
db1326aa
MM
721/*
722 * Maybe there are no dynamic attributes defined by protocols.
723 * For such cases, we force the dynamic_attr list to contain
b8cc390e 724 * at least an invalid token, so it is syntantically correct.
db1326aa 725 */
5a14df39 726CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
f4536657 727
2e18b87d 728rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 729 ;
f4536657 730
2d496d20
PM
731function_call:
732 SYM '(' var_list ')' {
733 struct symbol *sym;
734 struct f_inst *inst = $3;
735 if ($1->class != SYM_FUNCTION)
a5a947d4 736 cf_error("You can't call something which is not a function. Really.");
d4d75628 737 DBG("You are calling function %s\n", $1->name);
5a14df39 738 $$ = f_new_inst(FI_CALL);
2d496d20 739 $$->a1.p = inst;
083c43e2
OZ
740 $$->a2.p = $1->def;
741 sym = $1->aux2;
2d496d20
PM
742 while (sym || inst) {
743 if (!sym || !inst)
a5a947d4 744 cf_error("Wrong number of arguments for function %s.", $1->name);
d4d75628 745 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20 746 inst->a1.p = sym;
083c43e2 747 sym = sym->aux2;
2d496d20
PM
748 inst = inst->next;
749 }
750 }
751 ;
752
92a72a4c
OZ
753symbol:
754 SYM {
1103b32e 755 switch ($1->class & 0xff00) {
5a14df39
MJM
756 case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
757 case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
1103b32e 758 default: cf_error("%s: variable expected.", $1->name);
92a72a4c 759 }
1103b32e
OZ
760
761 $$->a1.p = $1->def;
762 $$->a2.p = $1->name;
92a72a4c
OZ
763 }
764
2bdb5e00 765static_attr:
5a14df39
MJM
766 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
767 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
768 | NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); }
769 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
770 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
771 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
772 | CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
773 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
774 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
775 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
2bdb5e00
PM
776 ;
777
84c7e194 778term:
5a14df39
MJM
779 '(' term ')' { $$ = $2; }
780 | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
781 | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
782 | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
783 | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
784 | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
785 | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
786 | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
787 | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
788 | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
789 | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
790 | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
791 | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
792 | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
793 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
794 | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
795 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
23b1539b 796
92a72a4c 797 | symbol { $$ = $1; }
1183b6b2 798 | constant { $$ = $1; }
42a0c054 799 | constructor { $$ = $1; }
4515bdba 800
5a14df39 801 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
2bdb5e00 802
5a14df39 803 | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
fe613ecd 804
5a14df39 805 | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
36bbfc70 806
5a14df39
MJM
807 | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
808 | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
809 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
810 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
811 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
812 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
7f77e250
PM
813
814/* Communities */
10a53608
PM
815/* This causes one shift/reduce conflict
816 | rtadot dynamic_attr '.' ADD '(' term ')' { }
817 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
818 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
a2d15746 819 | rtadot dynamic_attr '.' RESET{ }
10a53608 820*/
7f77e250 821
5a14df39
MJM
822 | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
823 | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
824 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
825 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
826 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
827 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
828 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
829 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
afc54517 830
af582c48
OZ
831 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
832 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
833
995e5894
PM
834/* function_call is inlined here */
835 | SYM '(' var_list ')' {
836 struct symbol *sym;
837 struct f_inst *inst = $3;
838 if ($1->class != SYM_FUNCTION)
a5a947d4 839 cf_error("You can't call something which is not a function. Really.");
995e5894 840 DBG("You are calling function %s\n", $1->name);
5a14df39 841 $$ = f_new_inst(FI_CALL);
995e5894 842 $$->a1.p = inst;
083c43e2
OZ
843 $$->a2.p = $1->def;
844 sym = $1->aux2;
995e5894
PM
845 while (sym || inst) {
846 if (!sym || !inst)
a5a947d4 847 cf_error("Wrong number of arguments for function %s.", $1->name);
995e5894
PM
848 DBG( "You should pass parameter called %s\n", sym->name);
849 inst->a1.p = sym;
083c43e2 850 sym = sym->aux2;
995e5894
PM
851 inst = inst->next;
852 }
853 }
ba921648
PM
854 ;
855
856break_command:
03e3d184
MM
857 QUITBIRD { $$ = F_QUITBIRD; }
858 | ACCEPT { $$ = F_ACCEPT; }
859 | REJECT { $$ = F_REJECT; }
860 | ERROR { $$ = F_ERROR; }
861 | PRINT { $$ = F_NOP; }
862 | PRINTN { $$ = F_NONL; }
ba921648
PM
863 ;
864
23b1539b 865print_one:
5a14df39 866 term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
867 ;
868
869print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
870 | print_one { $$ = $1; }
871 | print_one ',' print_list {
23b1539b 872 if ($1) {
995e5894 873 $1->next = $3;
23b1539b 874 $$ = $1;
995e5894 875 } else $$ = $3;
23b1539b
PM
876 }
877 ;
878
c8cafc8e 879var_listn: term {
5a14df39 880 $$ = f_new_inst(FI_SET);
d3dd620b
PM
881 $$->a1.p = NULL;
882 $$->a2.p = $1;
883 $$->next = NULL;
884 }
6dc7a0cb 885 | term ',' var_listn {
5a14df39 886 $$ = f_new_inst(FI_SET);
6542ece9
PM
887 $$->a1.p = NULL;
888 $$->a2.p = $1;
889 $$->next = $3;
890 }
891 ;
892
6dc7a0cb
PM
893var_list: /* EMPTY */ { $$ = NULL; }
894 | var_listn { $$ = $1; }
895 ;
896
23b1539b 897cmd:
49955645 898 IF term THEN block {
5a14df39 899 $$ = f_new_inst(FI_CONDITION);
49955645
MM
900 $$->a1.p = $2;
901 $$->a2.p = $4;
23b1539b 902 }
49955645 903 | IF term THEN block ELSE block {
5a14df39 904 struct f_inst *i = f_new_inst(FI_CONDITION);
49955645
MM
905 i->a1.p = $2;
906 i->a2.p = $4;
5a14df39 907 $$ = f_new_inst(FI_CONDITION);
49955645
MM
908 $$->a1.p = i;
909 $$->a2.p = $6;
23b1539b 910 }
ba921648 911 | SYM '=' term ';' {
d4d75628 912 DBG( "Ook, we'll set value\n" );
ba921648 913 if (($1->class & ~T_MASK) != SYM_VARIABLE)
a5a947d4 914 cf_error( "You may set only variables." );
5a14df39 915 $$ = f_new_inst(FI_SET);
2db3b288
PM
916 $$->a1.p = $1;
917 $$->a2.p = $3;
b9d70dc8 918 }
2d496d20 919 | RETURN term ';' {
d4d75628 920 DBG( "Ook, we'll return the value\n" );
5a14df39 921 $$ = f_new_inst(FI_RETURN);
2d496d20
PM
922 $$->a1.p = $2;
923 }
db1326aa 924 | rtadot dynamic_attr '=' term ';' {
5a14df39 925 $$ = f_new_inst_da(FI_EA_SET, $2);
6c14255d 926 $$->a1.p = $4;
f31156ca 927 }
0dc4431c 928 | rtadot static_attr '=' term ';' {
5a14df39 929 $$ = f_new_inst_sa(FI_RTA_SET, $2);
0dc4431c
PM
930 if (!$$->a1.i)
931 cf_error( "This static attribute is read-only.");
0dc4431c
PM
932 $$->a1.p = $4;
933 }
934 | PREFERENCE '=' term ';' {
5a14df39 935 $$ = f_new_inst(FI_PREF_SET);
0dc4431c 936 $$->a1.p = $3;
c8cafc8e 937 }
db1326aa 938 | UNSET '(' rtadot dynamic_attr ')' ';' {
5a14df39 939 $$ = f_new_inst_da(FI_EA_SET, $4);
9f4929e7 940 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
48f9e019 941 $$->a1.p = NULL;
c7b43f33 942 }
5a14df39 943 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
2d496d20 944 | function_call ';' { $$ = $1; }
7db7b7db 945 | CASE term '{' switch_body '}' {
5a14df39 946 $$ = f_new_inst(FI_SWITCH);
7db7b7db 947 $$->a1.p = $2;
41be4444 948 $$->a2.p = build_tree( $4 );
7db7b7db 949 }
7d6eebae
PM
950
951
42a0c054 952 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
5a14df39
MJM
953 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
954 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
955 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
956 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
b9d70dc8
PM
957 ;
958
959CF_END