4 * Copyright 1998--2000 Pavel Machek
6 * Can be freely distributed and used under the terms of the GNU GPL.
8 FIXME: priority of ! should be lower
13 #include "filter/f-inst.h"
14 #include "filter/data.h"
18 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
19 static inline u32 pair_a(u32 p) { return p >> 16; }
20 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
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)
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().
32 f_valid_set_type(int type)
51 static inline struct f_tree *
52 f_new_item(struct f_val from, struct f_val to)
54 struct f_tree *t = f_new_tree();
61 static inline struct f_tree *
62 f_merge_items(struct f_tree *a, struct f_tree *b)
71 static inline struct f_tree *
72 f_new_pair_item(int fa, int ta, int fb, int tb)
79 if ((ta < fa) || (tb < fb))
80 cf_error( "From value cannot be higher that To value in pair sets");
82 struct f_tree *t = f_new_tree();
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);
90 static inline struct f_tree *
91 f_new_pair_set(int fa, int ta, int fb, int tb)
98 if ((ta < fa) || (tb < fb))
99 cf_error( "From value cannot be higher that To value in pair sets");
101 struct f_tree *lst = NULL;
104 for (i = fa; i <= ta; i++)
105 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
110 #define CC_ALL 0xFFFF
111 #define EC_ALL 0xFFFFFFFF
112 #define LC_ALL 0xFFFFFFFF
114 static struct f_tree *
115 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
119 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
127 if (kind == EC_GENERIC) {
128 fm = ec_generic(key, vf);
129 to = ec_generic(key, vt);
131 else if (ipv4_used) {
132 fm = ec_ip4(kind, key, vf);
133 to = ec_ip4(kind, key, vt);
135 else if (key < 0x10000) {
136 fm = ec_as2(kind, key, vf);
137 to = ec_as2(kind, key, vt);
140 fm = ec_as4(kind, key, vf);
141 to = ec_as4(kind, key, vt);
144 struct f_tree *t = f_new_tree();
146 t->from.type = t->to.type = T_EC;
152 static struct f_tree *
153 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
155 struct f_tree *t = f_new_tree();
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};
163 static inline struct f_inst *
164 f_generate_empty(struct f_dynamic_attr dyn)
168 switch (dyn.type & EAF_TYPE_MASK) {
169 case EAF_TYPE_AS_PATH:
170 empty = f_const_empty_path;
172 case EAF_TYPE_INT_SET:
173 empty = f_const_empty_clist;
175 case EAF_TYPE_EC_SET:
176 empty = f_const_empty_eclist;
178 case EAF_TYPE_LC_SET:
179 empty = f_const_empty_lclist;
182 cf_error("Can't empty that attribute");
185 return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
190 static inline struct f_inst *
191 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
195 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
196 if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
197 cf_error( "Can't operate with value of non-integer type in pair constructor");
199 check_u16(t1->a[1].i);
200 check_u16(t2->a[1].i);
202 rv = f_new_inst(FI_CONSTANT);
203 rv->val = (struct f_val) {
205 .val.i = pair(t1->a[1].i, t2->a[1].i),
209 rv = f_new_inst(FI_PAIR_CONSTRUCT);
217 static inline struct f_inst *
218 f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
221 int c1 = 0, c2 = 0, ipv4_used = 0;
222 u32 key = 0, val2 = 0;
224 if (tk->fi_code == FI_CONSTANT) {
226 struct f_val *val = &(tk->val);
228 if (val->type == T_INT) {
229 ipv4_used = 0; key = val->val.i;
231 else if (tk->val.type == T_QUAD) {
232 ipv4_used = 1; key = val->val.i;
234 else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
235 ipv4_used = 1; key = ipa_to_u32(val->val.ip);
238 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
241 if (tv->fi_code == FI_CONSTANT) {
242 if (tv->val.type != T_INT)
243 cf_error("Can't operate with value of non-integer type in EC constructor");
245 val2 = tv->val.val.i;
251 if (kind == EC_GENERIC) {
252 ec = ec_generic(key, val2);
254 else if (ipv4_used) {
256 ec = ec_ip4(kind, key, val2);
258 else if (key < 0x10000) {
259 ec = ec_as2(kind, key, val2);
263 ec = ec_as4(kind, key, val2);
266 rv = f_new_inst(FI_CONSTANT);
267 rv->val = (struct f_val) {
273 rv = f_new_inst(FI_EC_CONSTRUCT);
282 static inline struct f_inst *
283 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
287 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
288 if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
289 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
291 rv = f_new_inst(FI_CONSTANT);
292 rv->val = (struct f_val) {
294 .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
299 rv = f_new_inst(FI_LC_CONSTRUCT);
308 static inline struct f_inst *
309 f_generate_path_mask(struct f_inst *t)
313 for (const struct f_inst *tt = t; tt; tt = tt->next) {
314 if (tt->fi_code != FI_CONSTANT)
320 struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
326 struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
329 for (const struct f_inst *tt = t; tt; tt = tt->next)
330 pm->item[i++] = tt->val.val.pmi;
333 struct f_inst *pmc = f_new_inst(FI_CONSTANT);
334 pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
342 * Remove all new lines and doubled whitespaces
343 * and convert all tabulators to spaces
344 * and return a copy of string
347 assert_copy_expr(const char *start, size_t len)
349 /* XXX: Allocates maybe a little more memory than we really finally need */
350 char *str = cfg_alloc(len + 1);
353 const char *src = start - 1;
354 const char *end = start + len;
360 /* Skip doubled whitespaces */
363 const char *prev = src - 1;
364 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
381 * assert_done - create f_instruction of bt_assert
382 * @expr: expression in bt_assert()
383 * @start: pointer to first char of test expression
384 * @end: pointer to the last char of test expression
386 static struct f_inst *
387 assert_done(struct f_inst *expr, const char *start, const char *end)
389 return f_new_inst(FI_ASSERT, expr,
391 assert_copy_expr(start, end - start + 1)
395 static struct f_inst *
396 assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
398 struct f_inst *setter, *getter, *checker;
399 switch (lval->type) {
400 case F_LVAL_VARIABLE:
401 setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
402 getter = f_new_inst(FI_VAR_GET, lval->sym);
404 case F_LVAL_PREFERENCE:
405 setter = f_new_inst(FI_PREF_SET, expr);
406 getter = f_new_inst(FI_PREF_GET);
409 setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
410 getter = f_new_inst(FI_RTA_GET, lval->sa);
413 setter = f_new_inst(FI_EA_SET, expr, lval->da);
414 getter = f_new_inst(FI_EA_GET, lval->da);
417 bug("Unknown lval type");
420 checker = f_new_inst(FI_EQ, expr, getter);
421 setter->next = checker;
423 return assert_done(setter, start, end);
428 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
429 ACCEPT, REJECT, ERROR, QUITBIRD,
430 INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
431 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
432 IF, THEN, ELSE, CASE,
433 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
434 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
440 ADD, DELETE, CONTAINS, RESET,
441 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
443 FILTER, WHERE, EVAL, ATTRIBUTE,
444 BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
450 %type <x> term block cmd cmds constant constructor print_one print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
451 %type <fda> dynamic_attr
452 %type <fsa> static_attr
453 %type <f> filter where_filter
454 %type <fl> filter_body function_body
456 %type <i> type function_params declsn decls
458 %type <fret> break_command
460 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
461 %type <trie> fprefix_set
462 %type <v> set_atom switch_atom fipa
464 %type <t> get_cf_position
470 FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
472 struct filter *f = cfg_alloc(sizeof(struct filter));
473 *f = (struct filter) { .sym = $2, .root = $4 };
482 EVAL term { f_eval_int(f_linearize($2)); }
486 custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
487 cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
490 conf: bt_test_suite ;
492 BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
493 cf_assert_symbol($3, SYM_FUNCTION);
494 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
495 t->fn = $3->function;
496 t->fn_name = $3->name;
499 add_tail(&new_config->tests, &t->n);
505 BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
506 cf_assert_symbol($3, SYM_FUNCTION);
507 cf_assert_symbol($5, SYM_FUNCTION);
508 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
509 t->fn = $3->function;
510 t->cmp = $5->function;
512 t->fn_name = $3->name;
514 add_tail(&new_config->tests, &t->n);
520 | BOOL { $$ = T_BOOL; }
523 | PREFIX { $$ = T_NET; }
524 | PAIR { $$ = T_PAIR; }
525 | QUAD { $$ = T_QUAD; }
528 | STRING { $$ = T_STRING; }
529 | BGPMASK { $$ = T_PATH_MASK; }
530 | BGPPATH { $$ = T_PATH; }
531 | CLIST { $$ = T_CLIST; }
532 | ECLIST { $$ = T_ECLIST; }
533 | LCLIST { $$ = T_LCLIST; }
551 cf_error( "You can't create sets of this type." );
556 /* Declarations with ';' at the end */
558 /* EMPTY */ { $$ = 0; }
559 | declsn ';' { $$ = $1; }
562 /* Declarations that have no ';' at the end. */
565 cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++);
566 $$ = $2->scope->slots;
568 | declsn ';' type CF_SYM_VOID {
569 if ($4->scope->slots >= 0xff) cf_error("Too many declarations, at most 255 allowed");
570 cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
571 $$ = $4->scope->slots;
575 filter_body: function_body ;
579 cf_assert_symbol($1, SYM_FILTER);
583 struct filter *f = cfg_alloc(sizeof(struct filter));
584 *f = (struct filter) { .root = $1 };
591 /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
592 $$ = f_new_where($2);
597 '(' declsn ')' { $$ = $2; }
598 | '(' ')' { $$ = 0; }
603 $$ = f_linearize($3);
610 FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
611 $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
613 } function_params function_body {
623 cmds: /* EMPTY */ { $$ = NULL; }
624 | cmds_int { $$ = $1[0]; }
627 cmds_int: cmd { $$[0] = $$[1] = $1; }
628 | cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; }
641 * Complex types, their bison value is struct f_val
644 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
645 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
651 * Set constants. They are also used in switch cases. We use separate
652 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
653 * to elude a collision between symbol (in expr) in set_atom and symbol
654 * as a function call in switch case cmds.
658 NUM { $$.type = T_INT; $$.val.i = $1; }
660 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
661 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
663 if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
664 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
667 cf_assert_symbol($1, SYM_CONSTANT);
668 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
674 NUM { $$.type = T_INT; $$.val.i = $1; }
675 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
677 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
681 term { $$ = f_eval_int(f_linearize($1)); }
684 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
685 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
686 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
687 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
688 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
689 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
690 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
691 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
692 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
693 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
694 { $$ = f_new_pair_item($2, $8, $4, $10); }
700 | UNKNOWN NUM { $$ = $2; }
701 | GENERIC { $$ = EC_GENERIC; }
705 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
706 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
707 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
711 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
712 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
713 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
714 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
715 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
716 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
717 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
718 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
719 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
726 | set_atom { $$ = f_new_item($1, $1); }
727 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
734 | switch_atom { $$ = f_new_item($1, $1); }
735 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
740 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
745 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
749 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
750 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
751 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
752 | net_ip_ '{' NUM ',' NUM '}' {
753 $$.net = $1; $$.lo = $3; $$.hi = $5;
754 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
755 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
760 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
761 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
764 switch_body: /* EMPTY */ { $$ = NULL; }
765 | switch_body switch_items ':' cmds {
766 /* Fill data fields */
768 struct f_line *line = f_linearize($4);
769 for (t = $2; t; t = t->left)
771 $$ = f_merge_items($1, $2);
773 | switch_body ELSECOL cmds {
774 struct f_tree *t = f_new_tree();
775 t->from.type = t->to.type = T_VOID;
777 t->data = f_linearize($3);
778 $$ = f_merge_items($1, t);
783 symbol_value { $$ = $1; }
784 | '(' term ')' { $$ = $2; }
788 PO bgp_path_tail PC { $$ = $2; }
792 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; }
793 | 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; }
794 | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
795 | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
796 | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
801 NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
802 | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
803 | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
804 | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
805 | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
806 | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
807 | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
808 | '[' set_items ']' {
809 DBG( "We've got a set here..." );
810 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
813 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
814 | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
818 '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
819 | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
820 | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
821 | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); }
825 /* This generates the function_call variable list backwards. */
826 var_list: /* EMPTY */ { $$ = NULL; }
828 | var_list ',' term { $$ = $3; $$->next = $1; }
831 CF_SYM_KNOWN '(' var_list ')' {
832 if ($1->class != SYM_FUNCTION)
833 cf_error("You can't call something which is not a function. Really.");
835 struct f_inst *fc = f_new_inst(FI_CALL, $1);
839 struct f_inst *tmp = $3->next;
846 if (args != $1->function->args)
847 cf_error("Function call '%s' got %u arguments, need %u arguments.",
848 $1->name, args, $1->function->args);
850 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
855 symbol_value: CF_SYM_KNOWN
858 case SYM_CONSTANT_RANGE:
859 $$ = f_new_inst(FI_CONSTANT, *($1->val));
861 case SYM_VARIABLE_RANGE:
862 $$ = f_new_inst(FI_VAR_GET, $1);
865 $$ = f_new_inst(FI_EA_GET, *$1->attribute);
868 cf_error("Can't get value of symbol %s", $1->name);
874 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
875 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
876 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
877 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
878 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
879 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
880 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
881 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
882 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
886 '(' term ')' { $$ = $2; }
887 | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
888 | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
889 | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
890 | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
891 | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
892 | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
893 | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
894 | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
895 | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
896 | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
897 | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
898 | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
899 | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
900 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
901 | '!' term { $$ = f_new_inst(FI_NOT, $2); }
902 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
904 | symbol_value { $$ = $1; }
905 | constant { $$ = $1; }
906 | constructor { $$ = $1; }
908 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
910 | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
912 | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
914 | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
915 | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
916 | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
917 | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
918 | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
919 | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
920 | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
921 | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
922 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
923 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
924 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
925 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
928 /* This causes one shift/reduce conflict
929 | dynamic_attr '.' ADD '(' term ')' { }
930 | dynamic_attr '.' DELETE '(' term ')' { }
931 | dynamic_attr '.' CONTAINS '(' term ')' { }
932 | dynamic_attr '.' RESET{ }
935 | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
936 | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
937 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
938 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
939 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
940 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
941 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
942 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
944 | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
945 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
947 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
949 /* | term '.' LEN { $$->code = P('P','l'); } */
955 QUITBIRD { $$ = F_QUITBIRD; }
956 | ACCEPT { $$ = F_ACCEPT; }
957 | REJECT { $$ = F_REJECT; }
958 | ERROR { $$ = F_ERROR; }
959 | PRINT { $$ = F_NOP; }
960 | PRINTN { $$ = F_NONL; }
964 term { $$ = f_new_inst(FI_PRINT, $1); }
967 print_list: /* EMPTY */ { $$ = NULL; }
968 | print_one { $$ = $1; }
969 | print_one ',' print_list {
979 $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
981 | IF term THEN block ELSE block {
982 $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
984 | CF_SYM_KNOWN '=' term ';' {
986 case SYM_VARIABLE_RANGE:
987 $$ = f_new_inst(FI_VAR_SET, $3, $1);
990 $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
993 cf_error("Can't assign to symbol %s", $1->name);
997 DBG( "Ook, we'll return the value\n" );
998 $$ = f_new_inst(FI_RETURN, $2);
1000 | dynamic_attr '=' term ';' {
1001 $$ = f_new_inst(FI_EA_SET, $3, $1);
1003 | static_attr '=' term ';' {
1005 cf_error( "This static attribute is read-only.");
1006 $$ = f_new_inst(FI_RTA_SET, $3, $1);
1008 | PREFERENCE '=' term ';' {
1009 $$ = f_new_inst(FI_PREF_SET, $3);
1011 | UNSET '(' dynamic_attr ')' ';' {
1012 $$ = f_new_inst(FI_EA_UNSET, $3);
1014 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
1015 | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
1016 | CASE term '{' switch_body '}' {
1017 $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
1020 | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
1021 | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
1022 | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
1023 | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
1024 | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
1025 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
1026 | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
1035 CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
1036 | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
1037 | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
1038 | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };