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 uint decls_count;
20 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
21 static inline u32 pair_a(u32 p) { return p >> 16; }
22 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
24 #define f_generate_complex(fi_code, da, arg) \
25 f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
28 * Sets and their items are during parsing handled as lists, linked
29 * through left ptr. The first item in a list also contains a pointer
30 * to the last item in a list (right ptr). For convenience, even items
31 * are handled as one-item lists. Lists are merged by f_merge_items().
34 f_valid_set_type(int type)
53 static inline struct f_tree *
54 f_new_item(struct f_val from, struct f_val to)
56 struct f_tree *t = f_new_tree();
63 static inline struct f_tree *
64 f_merge_items(struct f_tree *a, struct f_tree *b)
73 static inline struct f_tree *
74 f_new_pair_item(int fa, int ta, int fb, int tb)
81 if ((ta < fa) || (tb < fb))
82 cf_error( "From value cannot be higher that To value in pair sets");
84 struct f_tree *t = f_new_tree();
86 t->from.type = t->to.type = T_PAIR;
87 t->from.val.i = pair(fa, fb);
88 t->to.val.i = pair(ta, tb);
92 static inline struct f_tree *
93 f_new_pair_set(int fa, int ta, int fb, int tb)
100 if ((ta < fa) || (tb < fb))
101 cf_error( "From value cannot be higher that To value in pair sets");
103 struct f_tree *lst = NULL;
106 for (i = fa; i <= ta; i++)
107 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
112 #define CC_ALL 0xFFFF
113 #define EC_ALL 0xFFFFFFFF
114 #define LC_ALL 0xFFFFFFFF
116 static struct f_tree *
117 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
121 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
129 if (kind == EC_GENERIC) {
130 fm = ec_generic(key, vf);
131 to = ec_generic(key, vt);
133 else if (ipv4_used) {
134 fm = ec_ip4(kind, key, vf);
135 to = ec_ip4(kind, key, vt);
137 else if (key < 0x10000) {
138 fm = ec_as2(kind, key, vf);
139 to = ec_as2(kind, key, vt);
142 fm = ec_as4(kind, key, vf);
143 to = ec_as4(kind, key, vt);
146 struct f_tree *t = f_new_tree();
148 t->from.type = t->to.type = T_EC;
154 static struct f_tree *
155 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
157 struct f_tree *t = f_new_tree();
159 t->from.type = t->to.type = T_LC;
160 t->from.val.lc = (lcomm) {f1, f2, f3};
161 t->to.val.lc = (lcomm) {t1, t2, t3};
165 static inline struct f_inst *
166 f_generate_empty(struct f_dynamic_attr dyn)
170 switch (dyn.type & EAF_TYPE_MASK) {
171 case EAF_TYPE_AS_PATH:
172 empty = f_const_empty_path;
174 case EAF_TYPE_INT_SET:
175 empty = f_const_empty_clist;
177 case EAF_TYPE_EC_SET:
178 empty = f_const_empty_eclist;
180 case EAF_TYPE_LC_SET:
181 empty = f_const_empty_lclist;
184 cf_error("Can't empty that attribute");
187 return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
192 static inline struct f_inst *
193 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
197 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
198 if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
199 cf_error( "Can't operate with value of non-integer type in pair constructor");
201 check_u16(t1->a[1].i);
202 check_u16(t2->a[1].i);
204 rv = f_new_inst(FI_CONSTANT);
205 rv->val = (struct f_val) {
207 .val.i = pair(t1->a[1].i, t2->a[1].i),
211 rv = f_new_inst(FI_PAIR_CONSTRUCT);
219 static inline struct f_inst *
220 f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
223 int c1 = 0, c2 = 0, ipv4_used = 0;
224 u32 key = 0, val2 = 0;
226 if (tk->fi_code == FI_CONSTANT) {
228 struct f_val *val = &(tk->val);
230 if (val->type == T_INT) {
231 ipv4_used = 0; key = val->val.i;
233 else if (tk->val.type == T_QUAD) {
234 ipv4_used = 1; key = val->val.i;
236 else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
237 ipv4_used = 1; key = ipa_to_u32(val->val.ip);
240 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
243 if (tv->fi_code == FI_CONSTANT) {
244 if (tv->val.type != T_INT)
245 cf_error("Can't operate with value of non-integer type in EC constructor");
247 val2 = tv->val.val.i;
253 if (kind == EC_GENERIC) {
254 ec = ec_generic(key, val2);
256 else if (ipv4_used) {
258 ec = ec_ip4(kind, key, val2);
260 else if (key < 0x10000) {
261 ec = ec_as2(kind, key, val2);
265 ec = ec_as4(kind, key, val2);
268 rv = f_new_inst(FI_CONSTANT);
269 rv->val = (struct f_val) {
275 rv = f_new_inst(FI_EC_CONSTRUCT);
284 static inline struct f_inst *
285 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
289 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
290 if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
291 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
293 rv = f_new_inst(FI_CONSTANT);
294 rv->val = (struct f_val) {
296 .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
301 rv = f_new_inst(FI_LC_CONSTRUCT);
310 static inline struct f_inst *
311 f_generate_path_mask(struct f_inst *t)
315 for (const struct f_inst *tt = t; tt; tt = tt->next) {
316 if (tt->fi_code != FI_CONSTANT)
322 struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
328 struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
331 for (const struct f_inst *tt = t; tt; tt = tt->next)
332 pm->item[i++] = tt->val.val.pmi;
335 struct f_inst *pmc = f_new_inst(FI_CONSTANT);
336 pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
344 * Remove all new lines and doubled whitespaces
345 * and convert all tabulators to spaces
346 * and return a copy of string
349 assert_copy_expr(const char *start, size_t len)
351 /* XXX: Allocates maybe a little more memory than we really finally need */
352 char *str = cfg_alloc(len + 1);
355 const char *src = start - 1;
356 const char *end = start + len;
362 /* Skip doubled whitespaces */
365 const char *prev = src - 1;
366 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
383 * assert_done - create f_instruction of bt_assert
384 * @expr: expression in bt_assert()
385 * @start: pointer to first char of test expression
386 * @end: pointer to the last char of test expression
388 static struct f_inst *
389 assert_done(struct f_inst *expr, const char *start, const char *end)
391 return f_new_inst(FI_ASSERT, expr,
393 assert_copy_expr(start, end - start + 1)
397 static struct f_inst *
398 assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
400 struct f_inst *setter, *getter, *checker;
401 switch (lval->type) {
402 case F_LVAL_VARIABLE:
403 setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
404 getter = f_new_inst(FI_VAR_GET, lval->sym);
406 case F_LVAL_PREFERENCE:
407 setter = f_new_inst(FI_PREF_SET, expr);
408 getter = f_new_inst(FI_PREF_GET);
411 setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
412 getter = f_new_inst(FI_RTA_GET, lval->sa);
415 setter = f_new_inst(FI_EA_SET, expr, lval->da);
416 getter = f_new_inst(FI_EA_GET, lval->da);
419 bug("Unknown lval type");
422 checker = f_new_inst(FI_EQ, expr, getter);
423 setter->next = checker;
425 return assert_done(setter, start, end);
430 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
431 ACCEPT, REJECT, ERROR, QUITBIRD,
432 INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
433 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
434 IF, THEN, ELSE, CASE,
435 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
436 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
442 ADD, DELETE, CONTAINS, RESET,
443 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
445 FILTER, WHERE, EVAL, ATTRIBUTE,
446 BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
452 %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
453 %type <fda> dynamic_attr
454 %type <fsa> static_attr
455 %type <f> filter where_filter
456 %type <fl> filter_body function_body
458 %type <i> type function_params
460 %type <fret> break_command
462 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
463 %type <trie> fprefix_set
464 %type <v> set_atom switch_atom fipa
466 %type <t> get_cf_position
472 FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
474 struct filter *f = cfg_alloc(sizeof(struct filter));
475 *f = (struct filter) { .sym = $2, .root = $4 };
484 EVAL term { f_eval_int(f_linearize($2)); }
488 custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
489 cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
492 conf: bt_test_suite ;
494 BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
495 cf_assert_symbol($3, SYM_FUNCTION);
496 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
497 t->fn = $3->function;
498 t->fn_name = $3->name;
501 add_tail(&new_config->tests, &t->n);
507 BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
508 cf_assert_symbol($3, SYM_FUNCTION);
509 cf_assert_symbol($5, SYM_FUNCTION);
510 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
511 t->fn = $3->function;
512 t->cmp = $5->function;
514 t->fn_name = $3->name;
516 add_tail(&new_config->tests, &t->n);
522 | BOOL { $$ = T_BOOL; }
525 | PREFIX { $$ = T_NET; }
526 | PAIR { $$ = T_PAIR; }
527 | QUAD { $$ = T_QUAD; }
530 | STRING { $$ = T_STRING; }
531 | BGPMASK { $$ = T_PATH_MASK; }
532 | BGPPATH { $$ = T_PATH; }
533 | CLIST { $$ = T_CLIST; }
534 | ECLIST { $$ = T_ECLIST; }
535 | LCLIST { $$ = T_LCLIST; }
553 cf_error( "You can't create sets of this type." );
558 /* Declarations with ';' at the end */
564 /* Declarations that have no ';' at the end. */
567 cf_define_symbol($2, SYM_VARIABLE | $1, offset, decls_count++);
569 | declsn ';' type CF_SYM_VOID {
570 if (decls_count >= 0xff) cf_error("Too many declarations, at most 255 allowed");
571 cf_define_symbol($4, SYM_VARIABLE | $3, offset, decls_count++);
575 filter_body: { decls_count = 0; } function_body { $$ = $2; } ;
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 ')' { $$ = decls_count; }
598 | '(' ')' { $$ = 0; }
603 $$ = f_linearize($3);
604 $$->vars = decls_count;
610 FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
611 $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
614 } function_params function_body {
624 cmds: /* EMPTY */ { $$ = NULL; }
625 | cmds_int { $$ = $1[0]; }
628 cmds_int: cmd { $$[0] = $$[1] = $1; }
629 | cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; }
642 * Complex types, their bison value is struct f_val
645 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
646 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
652 * Set constants. They are also used in switch cases. We use separate
653 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
654 * to elude a collision between symbol (in expr) in set_atom and symbol
655 * as a function call in switch case cmds.
659 NUM { $$.type = T_INT; $$.val.i = $1; }
661 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
662 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
664 if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
665 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
668 cf_assert_symbol($1, SYM_CONSTANT);
669 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
675 NUM { $$.type = T_INT; $$.val.i = $1; }
676 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
678 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
682 term { $$ = f_eval_int(f_linearize($1)); }
685 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
686 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
687 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
688 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
689 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
690 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
691 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
692 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
693 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
694 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
695 { $$ = f_new_pair_item($2, $8, $4, $10); }
701 | UNKNOWN NUM { $$ = $2; }
702 | GENERIC { $$ = EC_GENERIC; }
706 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
707 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
708 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
712 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
713 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
714 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
715 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
716 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
717 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
718 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
719 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
720 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
727 | set_atom { $$ = f_new_item($1, $1); }
728 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
735 | switch_atom { $$ = f_new_item($1, $1); }
736 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
741 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
746 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
750 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
751 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
752 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
753 | net_ip_ '{' NUM ',' NUM '}' {
754 $$.net = $1; $$.lo = $3; $$.hi = $5;
755 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
756 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
761 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
762 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
765 switch_body: /* EMPTY */ { $$ = NULL; }
766 | switch_body switch_items ':' cmds {
767 /* Fill data fields */
769 struct f_line *line = f_linearize($4);
770 for (t = $2; t; t = t->left)
772 $$ = f_merge_items($1, $2);
774 | switch_body ELSECOL cmds {
775 struct f_tree *t = f_new_tree();
776 t->from.type = t->to.type = T_VOID;
778 t->data = f_linearize($3);
779 $$ = f_merge_items($1, t);
784 symbol_value { $$ = $1; }
785 | '(' term ')' { $$ = $2; }
789 PO bgp_path_tail PC { $$ = $2; }
793 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; }
794 | 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; }
795 | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
796 | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
797 | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
802 NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
803 | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
804 | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
805 | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
806 | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
807 | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
808 | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
809 | '[' set_items ']' {
810 DBG( "We've got a set here..." );
811 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
814 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
815 | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
819 '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
820 | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
821 | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
822 | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); }
826 /* This generates the function_call variable list backwards. */
827 var_list: /* EMPTY */ { $$ = NULL; }
829 | var_list ',' term { $$ = $3; $$->next = $1; }
832 CF_SYM_KNOWN '(' var_list ')' {
833 if ($1->class != SYM_FUNCTION)
834 cf_error("You can't call something which is not a function. Really.");
836 struct f_inst *fc = f_new_inst(FI_CALL, $1);
840 struct f_inst *tmp = $3->next;
847 if (args != $1->function->args)
848 cf_error("Function call '%s' got %u arguments, need %u arguments.",
849 $1->name, args, $1->function->args);
851 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
856 symbol_value: CF_SYM_KNOWN
859 case SYM_CONSTANT_RANGE:
860 $$ = f_new_inst(FI_CONSTANT_DEFINED, $1);
862 case SYM_VARIABLE_RANGE:
863 $$ = f_new_inst(FI_VAR_GET, $1);
866 $$ = f_new_inst(FI_EA_GET, *$1->attribute);
869 cf_error("Can't get value of symbol %s", $1->name);
875 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
876 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
877 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
878 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
879 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
880 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
881 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
882 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
883 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
887 '(' term ')' { $$ = $2; }
888 | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
889 | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
890 | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
891 | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
892 | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
893 | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
894 | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
895 | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
896 | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
897 | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
898 | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
899 | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
900 | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
901 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
902 | '!' term { $$ = f_new_inst(FI_NOT, $2); }
903 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
905 | symbol_value { $$ = $1; }
906 | constant { $$ = $1; }
907 | constructor { $$ = $1; }
909 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
911 | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
913 | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
915 | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
916 | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
917 | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
918 | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
919 | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
920 | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
921 | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
922 | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
923 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
924 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
925 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
926 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
929 /* This causes one shift/reduce conflict
930 | dynamic_attr '.' ADD '(' term ')' { }
931 | dynamic_attr '.' DELETE '(' term ')' { }
932 | dynamic_attr '.' CONTAINS '(' term ')' { }
933 | dynamic_attr '.' RESET{ }
936 | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
937 | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
938 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
939 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
940 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
941 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
942 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
943 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
945 | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
946 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
948 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
950 /* | term '.' LEN { $$->code = P('P','l'); } */
956 QUITBIRD { $$ = F_QUITBIRD; }
957 | ACCEPT { $$ = F_ACCEPT; }
958 | REJECT { $$ = F_REJECT; }
959 | ERROR { $$ = F_ERROR; }
960 | PRINT { $$ = F_NOP; }
961 | PRINTN { $$ = F_NONL; }
965 term { $$ = f_new_inst(FI_PRINT, $1); }
968 print_list: /* EMPTY */ { $$ = NULL; }
969 | print_one { $$ = $1; }
970 | print_one ',' print_list {
980 $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
982 | IF term THEN block ELSE block {
983 $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
985 | CF_SYM_KNOWN '=' term ';' {
987 case SYM_VARIABLE_RANGE:
988 $$ = f_new_inst(FI_VAR_SET, $3, $1);
991 $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
994 cf_error("Can't assign to symbol %s", $1->name);
998 DBG( "Ook, we'll return the value\n" );
999 $$ = f_new_inst(FI_RETURN, $2);
1001 | dynamic_attr '=' term ';' {
1002 $$ = f_new_inst(FI_EA_SET, $3, $1);
1004 | static_attr '=' term ';' {
1006 cf_error( "This static attribute is read-only.");
1007 $$ = f_new_inst(FI_RTA_SET, $3, $1);
1009 | PREFERENCE '=' term ';' {
1010 $$ = f_new_inst(FI_PREF_SET, $3);
1012 | UNSET '(' dynamic_attr ')' ';' {
1013 $$ = f_new_inst(FI_EA_UNSET, $3);
1015 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
1016 | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
1017 | CASE term '{' switch_body '}' {
1018 $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
1021 | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
1022 | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
1023 | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
1024 | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
1025 | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
1026 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
1027 | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
1036 CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
1037 | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
1038 | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
1039 | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };