]> git.ipfire.org Git - thirdparty/bird.git/blob - filter/config.Y
7c077b6570d7ea59a3de985d09aa39fc0e812978
[thirdparty/bird.git] / filter / config.Y
1 /*
2 * BIRD - filters
3 *
4 * Copyright 1998--2000 Pavel Machek
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 *
8 FIXME: priority of ! should be lower
9 */
10
11 CF_HDR
12
13 CF_DEFINES
14
15 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
16 static inline u32 pair_a(u32 p) { return p >> 16; }
17 static 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 */
26 static int
27 f_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:
37 case T_LC:
38 return 1;
39
40 default:
41 return 0;
42 }
43 }
44
45 static inline struct f_tree *
46 f_new_item(struct f_val from, struct f_val to)
47 {
48 struct f_tree *t = f_new_tree();
49 t->right = t;
50 t->from = from;
51 t->to = to;
52 return t;
53 }
54
55 static inline struct f_tree *
56 f_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 }
64
65 static inline struct f_tree *
66 f_new_pair_item(int fa, int ta, int fb, int tb)
67 {
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
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;
82 }
83
84 static inline struct f_tree *
85 f_new_pair_set(int fa, int ta, int fb, int tb)
86 {
87 check_u16(fa);
88 check_u16(ta);
89 check_u16(fb);
90 check_u16(tb);
91
92 if ((ta < fa) || (tb < fb))
93 cf_error( "From value cannot be higher that To value in pair sets");
94
95 struct f_tree *lst = NULL;
96 int i;
97
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;
102 }
103
104 #define CC_ALL 0xFFFF
105 #define EC_ALL 0xFFFFFFFF
106 #define LC_ALL 0xFFFFFFFF
107
108 static struct f_tree *
109 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
110 {
111 u64 fm, to;
112
113 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
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
146 static struct f_tree *
147 f_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
157 static inline struct f_inst *
158 f_generate_empty(struct f_dynamic_attr dyn)
159 {
160 struct f_inst *e = f_new_inst(FI_EMPTY);
161
162 switch (dyn.type & EAF_TYPE_MASK) {
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;
172 case EAF_TYPE_LC_SET:
173 e->aux = T_LCLIST;
174 break;
175 default:
176 cf_error("Can't empty that attribute");
177 }
178
179 struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
180 s->a1.p = e;
181 return s;
182 }
183
184
185 static inline struct f_inst *
186 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
187 {
188 struct f_inst *rv;
189
190 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
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
197 rv = f_new_inst(FI_CONSTANT);
198 rv->aux = T_PAIR;
199 rv->a2.i = pair(t1->a2.i, t2->a2.i);
200 }
201 else {
202 rv = f_new_inst(FI_PAIR_CONSTRUCT);
203 rv->a1.p = t1;
204 rv->a2.p = t2;
205 }
206
207 return rv;
208 }
209
210 static inline struct f_inst *
211 f_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
217 if (tk->fi_code == FI_CONSTANT) {
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 */
232 else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
233 c1 = 1;
234 struct f_val *val = tk->a1.p;
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) {
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
250 if (tv->fi_code == FI_CONSTANT) {
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;
259
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;
276 rv = f_new_inst(FI_CONSTANT_INDIRECT);
277 rv->a1.p = val;
278 val->type = T_EC;
279 val->val.ec = ec;
280 }
281 else {
282 rv = f_new_inst(FI_EC_CONSTRUCT);
283 rv->aux = kind;
284 rv->a1.p = tk;
285 rv->a2.p = tv;
286 }
287
288 return rv;
289 }
290
291 static inline struct f_inst *
292 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
293 {
294 struct f_inst *rv;
295
296 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
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
300 rv = f_new_inst(FI_CONSTANT_INDIRECT);
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;
311 rv->fi_code = FI_LC_CONSTRUCT;
312 rv->a1.p = t1;
313 rv->a2.p = t2;
314 INST3(rv).p = t3;
315 }
316
317 return rv;
318 }
319
320 static inline struct f_inst *
321 f_generate_path_mask(struct f_path_mask *t)
322 {
323 for (struct f_path_mask *tt = t; tt; tt = tt->next) {
324 if (tt->kind == PM_ASN_EXPR) {
325 struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
326 mrv->a1.p = t;
327 return mrv;
328 }
329 }
330
331 NEW_F_VAL;
332 val->type = T_PATH_MASK;
333 val->val.path_mask = t;
334
335 struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
336 rv->a1.p = val;
337
338 return rv;
339 }
340
341
342 CF_DECLS
343
344 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
345 ACCEPT, REJECT, ERROR, QUITBIRD,
346 INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
347 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
348 IF, THEN, ELSE, CASE,
349 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
350 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
351 PREFERENCE,
352 LEN,
353 DEFINED,
354 ADD, DELETE, CONTAINS, RESET,
355 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
356 ROA_CHECK,
357 EMPTY,
358 FILTER, WHERE, EVAL)
359
360 %nonassoc THEN
361 %nonassoc ELSE
362
363 %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
364 %type <fda> dynamic_attr
365 %type <fsa> static_attr
366 %type <f> filter filter_body where_filter
367 %type <i> type break_command ec_kind
368 %type <i32> cnum
369 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
370 %type <trie> fprefix_set
371 %type <v> set_atom switch_atom fprefix fprefix_s fipa
372 %type <s> decls declsn one_decl function_params
373 %type <h> bgp_path bgp_path_tail1 bgp_path_tail2
374
375 CF_GRAMMAR
376
377 CF_ADDTO(conf, filter_def)
378 filter_def:
379 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
380 filter_body {
381 $2->def = $4;
382 $4->name = $2->name;
383 DBG( "We have new filter defined (%s)\n", $2->name );
384 cf_pop_scope();
385 }
386 ;
387
388 CF_ADDTO(conf, filter_eval)
389 filter_eval:
390 EVAL term { f_eval_int($2); }
391 ;
392
393 type:
394 INT { $$ = T_INT; }
395 | BOOL { $$ = T_BOOL; }
396 | IP { $$ = T_IP; }
397 | PREFIX { $$ = T_PREFIX; }
398 | PAIR { $$ = T_PAIR; }
399 | QUAD { $$ = T_QUAD; }
400 | EC { $$ = T_EC; }
401 | LC { $$ = T_LC; }
402 | STRING { $$ = T_STRING; }
403 | BGPMASK { $$ = T_PATH_MASK; }
404 | BGPPATH { $$ = T_PATH; }
405 | CLIST { $$ = T_CLIST; }
406 | ECLIST { $$ = T_ECLIST; }
407 | LCLIST { $$ = T_LCLIST; }
408 | type SET {
409 switch ($1) {
410 case T_INT:
411 case T_PAIR:
412 case T_QUAD:
413 case T_EC:
414 case T_LC:
415 case T_IP:
416 $$ = T_SET;
417 break;
418
419 case T_PREFIX:
420 $$ = T_PREFIX_SET;
421 break;
422
423 default:
424 cf_error( "You can't create sets of this type." );
425 }
426 }
427 ;
428
429 one_decl:
430 type SYM {
431 struct f_val * val = cfg_alloc(sizeof(struct f_val));
432 val->type = T_VOID;
433 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
434 DBG( "New variable %s type %x\n", $2->name, $1 );
435 $2->aux2 = NULL;
436 $$=$2;
437 }
438 ;
439
440 /* Decls with ';' at the end */
441 decls: /* EMPTY */ { $$ = NULL; }
442 | one_decl ';' decls {
443 $$ = $1;
444 $$->aux2 = $3;
445 }
446 ;
447
448 /* Declarations that have no ';' at the end. */
449 declsn: one_decl { $$ = $1; }
450 | one_decl ';' declsn {
451 $$ = $1;
452 $$->aux2 = $3;
453 }
454 ;
455
456 filter_body:
457 function_body {
458 struct filter *f = cfg_alloc(sizeof(struct filter));
459 f->name = NULL;
460 f->root = $1;
461 $$ = f;
462 }
463 ;
464
465 filter:
466 SYM {
467 if ($1->class != SYM_FILTER) cf_error("No such filter.");
468 $$ = $1->def;
469 }
470 | filter_body
471 ;
472
473 where_filter:
474 WHERE term {
475 /* Construct 'IF term THEN ACCEPT; REJECT;' */
476 struct filter *f = cfg_alloc(sizeof(struct filter));
477 struct f_inst *i, *acc, *rej;
478 acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
479 acc->a1.p = NULL;
480 acc->a2.i = F_ACCEPT;
481 rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
482 rej->a1.p = NULL;
483 rej->a2.i = F_REJECT;
484 i = f_new_inst(FI_CONDITION); /* IF */
485 i->a1.p = $2;
486 i->a2.p = acc;
487 i->next = rej;
488 f->name = NULL;
489 f->root = i;
490 $$ = f;
491 }
492 ;
493
494 function_params:
495 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
496 | '(' ')' { $$=NULL; }
497 ;
498
499 function_body:
500 decls '{' cmds '}' {
501 if ($1) {
502 /* Prepend instruction to clear local variables */
503 $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
504 $$->a1.p = $1;
505 $$->next = $3;
506 } else
507 $$ = $3;
508 }
509 ;
510
511 CF_ADDTO(conf, function_def)
512 function_def:
513 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
514 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
515 cf_push_scope($2);
516 } function_params function_body {
517 $2->def = $5;
518 $2->aux2 = $4;
519 DBG("Hmm, we've got one function here - %s\n", $2->name);
520 cf_pop_scope();
521 }
522 ;
523
524 /* Programs */
525
526 /* Hack: $$ of cmds_int is the last node.
527 $$->next of cmds_int is temporary used for the first node */
528
529 cmds: /* EMPTY */ { $$ = NULL; }
530 | cmds_int { $$ = $1->next; $1->next = NULL; }
531 ;
532
533 cmds_int: cmd { $$ = $1; $1->next = $1; }
534 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
535 ;
536
537 block:
538 cmd {
539 $$=$1;
540 }
541 | '{' cmds '}' {
542 $$=$2;
543 }
544 ;
545
546 /*
547 * Complex types, their bison value is struct f_val
548 */
549 fipa:
550 IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
551 ;
552
553
554
555 /*
556 * Set constants. They are also used in switch cases. We use separate
557 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
558 * to elude a collision between symbol (in expr) in set_atom and symbol
559 * as a function call in switch case cmds.
560 */
561
562 set_atom:
563 NUM { $$.type = T_INT; $$.val.i = $1; }
564 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
565 | fipa { $$ = $1; }
566 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
567 | '(' term ')' {
568 $$ = f_eval($2, cfg_mem);
569 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
570 }
571 | SYM {
572 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
573 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
574 $$ = *(struct f_val *)($1->def);
575 }
576 ;
577
578 switch_atom:
579 NUM { $$.type = T_INT; $$.val.i = $1; }
580 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
581 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
582 | fipa { $$ = $1; }
583 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
584 ;
585
586 cnum:
587 term { $$ = f_eval_int($1); }
588
589 pair_item:
590 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
591 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
592 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
593 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
594 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
595 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
596 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
597 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
598 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
599 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
600 { $$ = f_new_pair_item($2, $8, $4, $10); }
601 ;
602
603 ec_kind:
604 RT { $$ = EC_RT; }
605 | RO { $$ = EC_RO; }
606 | UNKNOWN NUM { $$ = $2; }
607 | GENERIC { $$ = EC_GENERIC; }
608 ;
609
610 ec_item:
611 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
612 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
613 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
614 ;
615
616 lc_item:
617 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
618 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
619 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
620 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
621 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
622 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
623 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
624 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
625 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
626 ;
627
628 set_item:
629 pair_item
630 | ec_item
631 | lc_item
632 | set_atom { $$ = f_new_item($1, $1); }
633 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
634 ;
635
636 switch_item:
637 pair_item
638 | ec_item
639 | lc_item
640 | switch_atom { $$ = f_new_item($1, $1); }
641 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
642 ;
643
644 set_items:
645 set_item
646 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
647 ;
648
649 switch_items:
650 switch_item
651 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
652 ;
653
654 fprefix_s:
655 IPA '/' NUM %prec '/' {
656 if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
657 $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
658 }
659 ;
660
661 fprefix:
662 fprefix_s { $$ = $1; }
663 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
664 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
665 | fprefix_s '{' NUM ',' NUM '}' {
666 if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
667 $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
668 }
669 ;
670
671 fprefix_set:
672 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
673 | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
674 ;
675
676 switch_body: /* EMPTY */ { $$ = NULL; }
677 | switch_body switch_items ':' cmds {
678 /* Fill data fields */
679 struct f_tree *t;
680 for (t = $2; t; t = t->left)
681 t->data = $4;
682 $$ = f_merge_items($1, $2);
683 }
684 | switch_body ELSECOL cmds {
685 struct f_tree *t = f_new_tree();
686 t->from.type = t->to.type = T_VOID;
687 t->right = t;
688 t->data = $3;
689 $$ = f_merge_items($1, t);
690 }
691 ;
692
693 /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
694
695 bgp_path_expr:
696 symbol { $$ = $1; }
697 | '(' term ')' { $$ = $2; }
698 ;
699
700 bgp_path:
701 PO bgp_path_tail1 PC { $$ = $2; }
702 | '/' bgp_path_tail2 '/' { $$ = $2; }
703 ;
704
705 bgp_path_tail1:
706 NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
707 | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
708 | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
709 | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
710 | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
711 | { $$ = NULL; }
712 ;
713
714 bgp_path_tail2:
715 NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
716 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
717 | { $$ = NULL; }
718 ;
719
720 constant:
721 NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
722 | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
723 | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
724 | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
725 | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
726 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
727 | RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
728 | '[' 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" ); }
729 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
730 | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
731 ;
732
733 constructor:
734 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
735 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
736 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
737 | bgp_path { $$ = f_generate_path_mask($1); }
738 ;
739
740
741 /*
742 * Maybe there are no dynamic attributes defined by protocols.
743 * For such cases, we force the dynamic_attr list to contain
744 * at least an invalid token, so it is syntantically correct.
745 */
746 CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
747
748 rtadot: /* EMPTY, we are not permitted RTA. prefix */
749 ;
750
751 function_call:
752 SYM '(' var_list ')' {
753 struct symbol *sym;
754 struct f_inst *inst = $3;
755 if ($1->class != SYM_FUNCTION)
756 cf_error("You can't call something which is not a function. Really.");
757 DBG("You are calling function %s\n", $1->name);
758 $$ = f_new_inst(FI_CALL);
759 $$->a1.p = inst;
760 $$->a2.p = $1->def;
761 sym = $1->aux2;
762 while (sym || inst) {
763 if (!sym || !inst)
764 cf_error("Wrong number of arguments for function %s.", $1->name);
765 DBG( "You should pass parameter called %s\n", sym->name);
766 inst->a1.p = sym;
767 sym = sym->aux2;
768 inst = inst->next;
769 }
770 }
771 ;
772
773 symbol:
774 SYM {
775 switch ($1->class & 0xff00) {
776 case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
777 case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
778 default: cf_error("%s: variable expected.", $1->name);
779 }
780
781 $$->a1.p = $1->def;
782 $$->a2.p = $1->name;
783 }
784
785 static_attr:
786 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
787 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
788 | NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); }
789 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
790 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
791 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
792 | CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
793 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
794 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
795 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
796 ;
797
798 term:
799 '(' term ')' { $$ = $2; }
800 | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
801 | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
802 | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
803 | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
804 | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
805 | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
806 | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
807 | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
808 | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
809 | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
810 | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
811 | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
812 | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
813 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
814 | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
815 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
816
817 | symbol { $$ = $1; }
818 | constant { $$ = $1; }
819 | constructor { $$ = $1; }
820
821 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
822
823 | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
824
825 | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
826
827 | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
828 | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
829 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
830 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
831 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
832 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
833
834 /* Communities */
835 /* This causes one shift/reduce conflict
836 | rtadot dynamic_attr '.' ADD '(' term ')' { }
837 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
838 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
839 | rtadot dynamic_attr '.' RESET{ }
840 */
841
842 | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
843 | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
844 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
845 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
846 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
847 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
848 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
849 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
850
851 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
852 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
853
854 /* function_call is inlined here */
855 | SYM '(' var_list ')' {
856 struct symbol *sym;
857 struct f_inst *inst = $3;
858 if ($1->class != SYM_FUNCTION)
859 cf_error("You can't call something which is not a function. Really.");
860 DBG("You are calling function %s\n", $1->name);
861 $$ = f_new_inst(FI_CALL);
862 $$->a1.p = inst;
863 $$->a2.p = $1->def;
864 sym = $1->aux2;
865 while (sym || inst) {
866 if (!sym || !inst)
867 cf_error("Wrong number of arguments for function %s.", $1->name);
868 DBG( "You should pass parameter called %s\n", sym->name);
869 inst->a1.p = sym;
870 sym = sym->aux2;
871 inst = inst->next;
872 }
873 }
874 ;
875
876 break_command:
877 QUITBIRD { $$ = F_QUITBIRD; }
878 | ACCEPT { $$ = F_ACCEPT; }
879 | REJECT { $$ = F_REJECT; }
880 | ERROR { $$ = F_ERROR; }
881 | PRINT { $$ = F_NOP; }
882 | PRINTN { $$ = F_NONL; }
883 ;
884
885 print_one:
886 term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
887 ;
888
889 print_list: /* EMPTY */ { $$ = NULL; }
890 | print_one { $$ = $1; }
891 | print_one ',' print_list {
892 if ($1) {
893 $1->next = $3;
894 $$ = $1;
895 } else $$ = $3;
896 }
897 ;
898
899 var_listn: term {
900 $$ = f_new_inst(FI_SET);
901 $$->a1.p = NULL;
902 $$->a2.p = $1;
903 $$->next = NULL;
904 }
905 | term ',' var_listn {
906 $$ = f_new_inst(FI_SET);
907 $$->a1.p = NULL;
908 $$->a2.p = $1;
909 $$->next = $3;
910 }
911 ;
912
913 var_list: /* EMPTY */ { $$ = NULL; }
914 | var_listn { $$ = $1; }
915 ;
916
917 cmd:
918 IF term THEN block {
919 $$ = f_new_inst(FI_CONDITION);
920 $$->a1.p = $2;
921 $$->a2.p = $4;
922 }
923 | IF term THEN block ELSE block {
924 struct f_inst *i = f_new_inst(FI_CONDITION);
925 i->a1.p = $2;
926 i->a2.p = $4;
927 $$ = f_new_inst(FI_CONDITION);
928 $$->a1.p = i;
929 $$->a2.p = $6;
930 }
931 | SYM '=' term ';' {
932 DBG( "Ook, we'll set value\n" );
933 if (($1->class & ~T_MASK) != SYM_VARIABLE)
934 cf_error( "You may set only variables." );
935 $$ = f_new_inst(FI_SET);
936 $$->a1.p = $1;
937 $$->a2.p = $3;
938 }
939 | RETURN term ';' {
940 DBG( "Ook, we'll return the value\n" );
941 $$ = f_new_inst(FI_RETURN);
942 $$->a1.p = $2;
943 }
944 | rtadot dynamic_attr '=' term ';' {
945 $$ = f_new_inst_da(FI_EA_SET, $2);
946 $$->a1.p = $4;
947 }
948 | rtadot static_attr '=' term ';' {
949 $$ = f_new_inst_sa(FI_RTA_SET, $2);
950 if (!$$->a1.i)
951 cf_error( "This static attribute is read-only.");
952 $$->a1.p = $4;
953 }
954 | PREFERENCE '=' term ';' {
955 $$ = f_new_inst(FI_PREF_SET);
956 $$->a1.p = $3;
957 }
958 | UNSET '(' rtadot dynamic_attr ')' ';' {
959 $$ = f_new_inst_da(FI_EA_SET, $4);
960 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
961 $$->a1.p = NULL;
962 }
963 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
964 | function_call ';' { $$ = $1; }
965 | CASE term '{' switch_body '}' {
966 $$ = f_new_inst(FI_SWITCH);
967 $$->a1.p = $2;
968 $$->a2.p = build_tree( $4 );
969 }
970
971
972 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
973 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
974 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
975 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
976 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
977 ;
978
979 CF_END