summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
Diffstat (limited to 'filter')
-rw-r--r--filter/Makefile16
-rw-r--r--filter/config.Y185
-rw-r--r--filter/dump.m443
-rw-r--r--filter/f-inst.c983
-rw-r--r--filter/f-util.c29
-rw-r--r--filter/filter.c544
-rw-r--r--filter/filter.h325
-rw-r--r--filter/filter_test.c7
-rw-r--r--filter/interpret.m457
-rw-r--r--filter/line-size.m430
-rw-r--r--filter/postfixify.m455
-rw-r--r--filter/same.m456
-rw-r--r--filter/tree.c30
-rw-r--r--filter/tree_test.c10
-rw-r--r--filter/trie.c14
15 files changed, 1402 insertions, 982 deletions
diff --git a/filter/Makefile b/filter/Makefile
index 0979a34f..c74ba2f3 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -5,10 +5,22 @@ $(cf-local)
M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS))
-$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c
+$(o)f-inst-line-size.c: $(s)line-size.m4 $(s)f-inst.c $(objdir)/.dir-stamp
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
-$(o)filter.o: $(o)f-inst-interpret.c
+$(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c
tests_src := tree_test.c filter_test.c trie_test.c
tests_targets := $(tests_targets) $(tests-target-files)
diff --git a/filter/config.Y b/filter/config.Y
index e1f3fec8..a79b1582 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -158,20 +158,20 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
static inline struct f_inst *
f_generate_empty(struct f_dynamic_attr dyn)
{
- struct f_inst *e = f_new_inst(FI_EMPTY);
+ struct f_inst *e = f_new_inst(FI_CONSTANT);
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
- e->aux = T_PATH;
+ e->val = f_const_empty_path;
break;
case EAF_TYPE_INT_SET:
- e->aux = T_CLIST;
+ e->val = f_const_empty_clist;
break;
case EAF_TYPE_EC_SET:
- e->aux = T_ECLIST;
+ e->val = f_const_empty_eclist;
break;
case EAF_TYPE_LC_SET:
- e->aux = T_LCLIST;
+ e->val = f_const_empty_lclist;
break;
default:
cf_error("Can't empty that attribute");
@@ -302,23 +302,34 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
}
static inline struct f_inst *
-f_generate_path_mask(struct f_path_mask *t)
+f_generate_path_mask(struct f_inst *t)
{
- for (struct f_path_mask *tt = t; tt; tt = tt->next) {
- if (tt->kind == PM_ASN_EXPR) {
- struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
- mrv->a[0].p = t;
- return mrv;
- }
+ uint len = 0;
+ uint dyn = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next) {
+ if (tt->fi_code != FI_CONSTANT)
+ dyn++;
+ len++;
+ }
+
+ if (dyn) {
+ struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
+ pmc->a[0].p = t;
+ pmc->a[1].i = len;
+ return pmc;
}
- struct f_inst *rv = f_new_inst(FI_CONSTANT);
- rv->val = (struct f_val) {
- .type = T_PATH_MASK,
- .val.path_mask = t,
- };
+ struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
- return rv;
+ uint i = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next)
+ pm->item[i++] = tt->val.val.pmi;
+
+ pm->len = i;
+ struct f_inst *pmc = f_new_inst(FI_CONSTANT);
+ pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
+
+ return pmc;
}
/*
@@ -409,7 +420,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN
%nonassoc ELSE
-%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
+%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 bgp_path bgp_path_tail
%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter filter_body where_filter
@@ -420,7 +431,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom switch_atom fipa
%type <px> fprefix
%type <s> decls declsn one_decl function_params
-%type <h> bgp_path bgp_path_tail
%type <t> get_cf_position
CF_GRAMMAR
@@ -438,7 +448,7 @@ filter_def:
conf: filter_eval ;
filter_eval:
- EVAL term { f_eval_int($2); }
+ EVAL term { f_eval_int(f_postfixify($2)); }
;
conf: custom_attr ;
@@ -530,7 +540,7 @@ filter_body:
function_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
f->name = NULL;
- f->root = $1;
+ f->root = f_postfixify($1);
$$ = f;
}
;
@@ -547,21 +557,25 @@ where_filter:
WHERE term {
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
struct filter *f = cfg_alloc(sizeof(struct filter));
- struct f_inst *i, *acc, *rej;
- acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
- acc->a[0].p = NULL;
- acc->a[1].i = F_ACCEPT;
- rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
- rej->a[0].p = NULL;
- rej->a[1].i = F_REJECT;
- i = f_new_inst(FI_CONDITION); /* IF */
- i->a[0].p = $2;
- i->a[1].p = acc;
- i->a[2].p = rej;
+ struct f_inst acc = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .a = { { .p = NULL }, { .i = F_ACCEPT } },
+ .lineno = ifs->lino,
+ };
+ struct f_inst rej = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .a = { { .p = NULL }, { .i = F_REJECT } },
+ .lineno = ifs->lino,
+ };
+ struct f_inst i = {
+ .fi_code = FI_CONDITION,
+ .a = { { .p = $2 }, { .p = &acc }, { .p = &rej } },
+ .lineno = ifs->lino,
+ };
f->name = NULL;
- f->root = i;
+ f->root = f_postfixify(&i);
$$ = f;
- }
+ }
;
function_params:
@@ -587,7 +601,9 @@ function_def:
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
cf_push_scope($2);
} function_params function_body {
- $2->def = $5;
+ struct f_inst *vc = f_new_inst(FI_CONSTANT);
+ vc->val = (struct f_val) { .type = T_VOID };
+ $2->def = f_postfixify_concat($5, vc, NULL);
$2->aux2 = $4;
DBG("Hmm, we've got one function here - %s\n", $2->name);
cf_pop_scope();
@@ -639,7 +655,7 @@ set_atom:
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
- if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
+ if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
| SYM {
@@ -651,13 +667,13 @@ set_atom:
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
cnum:
- term { $$ = f_eval_int($1); }
+ term { $$ = f_eval_int(f_postfixify($1)); }
pair_item:
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
@@ -744,15 +760,16 @@ switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body switch_items ':' cmds {
/* Fill data fields */
struct f_tree *t;
+ struct f_line *line = f_postfixify($4);
for (t = $2; t; t = t->left)
- t->data = $4;
+ t->data = line;
$$ = f_merge_items($1, $2);
}
| switch_body ELSECOL cmds {
struct f_tree *t = f_new_tree();
t->from.type = t->to.type = T_VOID;
t->right = t;
- t->data = $3;
+ t->data = f_postfixify($3);
$$ = f_merge_items($1, t);
}
;
@@ -767,11 +784,11 @@ bgp_path:
;
bgp_path_tail:
- NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
- | NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
- | '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
- | '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
- | bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
+ NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; }
+ | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; }
+ | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; }
+ | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; }
+ | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
@@ -831,12 +848,11 @@ symbol:
switch ($1->class & 0xffff) {
case SYM_CONSTANT_RANGE:
$$ = f_new_inst(FI_CONSTANT_INDIRECT);
- goto cv_common;
+ $$->a[0].p = $1;
+ break;
case SYM_VARIABLE_RANGE:
$$ = f_new_inst(FI_VARIABLE);
- cv_common:
- $$->a[0].p = $1->def;
- $$->a[1].p = $1->name;
+ $$->a[0].p = $1;
break;
case SYM_ATTRIBUTE:
$$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
@@ -847,15 +863,15 @@ symbol:
}
static_attr:
- FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
- | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
- | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
- | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
- | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
- | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
- | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
- | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); }
- | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
+ FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
+ | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
+ | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
+ | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
+ | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
+ | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
+ | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
+ | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
+ | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
;
term:
@@ -908,42 +924,23 @@ term:
| rtadot dynamic_attr '.' RESET{ }
*/
- | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
- | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
- | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; }
- | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; }
- | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; }
- | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; }
- | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
- | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+ | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; }
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
/* | term '.' LEN { $$->code = P('P','l'); } */
-/* function_call is inlined here */
- | SYM '(' var_list ')' {
- struct symbol *sym;
- struct f_inst *inst = $3;
- if ($1->class != SYM_FUNCTION)
- cf_error("You can't call something which is not a function. Really.");
- DBG("You are calling function %s\n", $1->name);
- $$ = f_new_inst(FI_CALL);
- $$->a[0].p = inst;
- $$->a[1].p = $1->def;
- sym = $1->aux2;
- while (sym || inst) {
- if (!sym || !inst)
- cf_error("Wrong number of arguments for function %s.", $1->name);
- DBG( "You should pass parameter called %s\n", sym->name);
- inst->a[0].p = sym;
- sym = sym->aux2;
- inst = inst->next;
- }
- }
+ | function_call
;
break_command:
@@ -1022,7 +1019,7 @@ cmd:
}
| rtadot static_attr '=' term ';' {
$$ = f_new_inst_sa(FI_RTA_SET, $2);
- if (!$$->a[0].i)
+ if ($$->sa.readonly)
cf_error( "This static attribute is read-only.");
$$->a[0].p = $4;
}
@@ -1036,7 +1033,7 @@ cmd:
$$->a[0].p = NULL;
}
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
- | function_call ';' { $$ = $1; }
+ | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; }
| CASE term '{' switch_body '}' {
$$ = f_new_inst(FI_SWITCH);
$$->a[0].p = $2;
@@ -1044,10 +1041,10 @@ cmd:
}
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
+ | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
+ | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
+ | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
+ | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
;
diff --git a/filter/dump.m4 b/filter/dump.m4
new file mode 100644
index 00000000..913a7652
--- /dev/null
+++ b/filter/dump.m4
@@ -0,0 +1,43 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Dumping instruction lines
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1:
+m4_divert(-1)'))
+m4_define(LINE, `m4_divert(1)f_dump_line(item->lines[$2], indent + 1);
+m4_divert(-1)')
+m4_define(LINEP, `LINE($@)')
+m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name);
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
+m4_divert(-1)')
+m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret);
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)debug("%sec subtype %d\n", INDENT, item->ecs);
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)debug("%sroute table %s\n", INDENT, item->rtc->name);
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly);
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code);
+m4_divert(-1)')
+m4_define(DUMP, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/f-inst.c b/filter/f-inst.c
index ef5d4f06..02c88409 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -10,269 +10,282 @@
*/
/* Binary operators */
- INST(FI_ADD) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i += v1.val.i;
- }
- INST(FI_SUBTRACT) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i -= v1.val.i;
- }
- INST(FI_MULTIPLY) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i *= v1.val.i;
- }
- INST(FI_DIVIDE) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- if (v1.val.i == 0) runtime( "Mother told me not to divide by 0" );
- res.val.i /= v1.val.i;
- }
- INST(FI_AND) {
- ARG_T(1,0,T_BOOL);
+ INST(FI_ADD, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i += v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_SUBTRACT, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i -= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_MULTIPLY, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i *= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_DIVIDE, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
+ res.val.i /= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_AND, 1, 1) {
+ ARG(1,T_BOOL);
if (res.val.i)
- ARG_T(2,0,T_BOOL);
+ LINE(2,0);
+ else
+ RESULT_OK;
}
- INST(FI_OR) {
- ARG_T(1,0,T_BOOL);
+ INST(FI_OR, 1, 1) {
+ ARG(1,T_BOOL);
if (!res.val.i)
- ARG_T(2,0,T_BOOL);
+ LINE(2,0);
+ else
+ RESULT_OK;
}
- INST(FI_PAIR_CONSTRUCT) {
+ INST(FI_PAIR_CONSTRUCT, 2, 1) {
ARG(1,T_INT);
ARG(2,T_INT);
- u1 = v1.val.i;
- u2 = v2.val.i;
+ uint u1 = v1.val.i;
+ uint u2 = v2.val.i;
if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
runtime( "Can't operate with value out of bounds in pair constructor" );
- res.val.i = (u1 << 16) | u2;
- res.type = T_PAIR;
+ RESULT(T_PAIR, i, (u1 << 16) | u2);
}
+ INST(FI_EC_CONSTRUCT, 2, 1) {
+ ARG_ANY(1);
+ ARG(2, T_INT);
+ ECS;
- INST(FI_EC_CONSTRUCT) {
- {
- ARG_ANY(1);
- ARG(2, T_INT);
-
- int check, ipv4_used;
- u32 key, val;
-
- if (v1.type == T_INT) {
- ipv4_used = 0; key = v1.val.i;
- }
- else if (v1.type == T_QUAD) {
- ipv4_used = 1; key = v1.val.i;
- }
- /* IP->Quad implicit conversion */
- else if (val_is_ip4(v1)) {
- ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
- }
- else
- runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
-
- val = v2.val.i;
-
- /* XXXX */
- res.type = T_EC;
+ int check, ipv4_used;
+ u32 key, val;
- if (what->aux == EC_GENERIC) {
- check = 0; res.val.ec = ec_generic(key, val);
- }
- else if (ipv4_used) {
- check = 1; res.val.ec = ec_ip4(what->aux, key, val);
- }
- else if (key < 0x10000) {
- check = 0; res.val.ec = ec_as2(what->aux, key, val);
- }
- else {
- check = 1; res.val.ec = ec_as4(what->aux, key, val);
- }
+ if (v1.type == T_INT) {
+ ipv4_used = 0; key = v1.val.i;
+ }
+ else if (v1.type == T_QUAD) {
+ ipv4_used = 1; key = v1.val.i;
+ }
+ /* IP->Quad implicit conversion */
+ else if (val_is_ip4(&v1)) {
+ ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
+ }
+ else
+ runtime("Argument 1 of instruction FI_EC_CONSTRUCT must be integer or IPv4 address, got 0x%02x");
- if (check && (val > 0xFFFF))
- runtime("Can't operate with value out of bounds in EC constructor");
+ val = v2.val.i;
+ if (ecs == EC_GENERIC) {
+ check = 0; RESULT(T_EC, ec, ec_generic(key, val));
+ }
+ else if (ipv4_used) {
+ check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
}
+ else if (key < 0x10000) {
+ check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
+ }
+ else {
+ check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
}
- INST(FI_LC_CONSTRUCT) {
- {
- ARG(1, T_INT);
- ARG(2, T_INT);
- ARG(3, T_INT);
+ if (check && (val > 0xFFFF))
+ runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
+ }
- res.type = T_LC;
- res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
+ INST(FI_LC_CONSTRUCT, 3, 1) {
+ ARG(1, T_INT);
+ ARG(2, T_INT);
+ ARG(3, T_INT);
+ RESULT(T_LC, lc, [[(lcomm) { v1.val.i, v2.val.i, v3.val.i }]]);
+ }
- }
+ INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
+ ARG_ANY(1);
+ COUNT(2);
+ if (vstk.cnt < what->count) /* TODO: make this check systematic */
+ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count);
+
+ struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item));
+ for (uint i=0; i<what->count; i++) {
+//#define pv vstk.val[vstk.cnt-i-1]
+#define pv vstk.val[vstk.cnt - what->count + i]
+ switch (pv.type) {
+ case T_PATH_MASK_ITEM:
+ pm->item[i] = pv.val.pmi;
+ break;
+ case T_INT:
+ pm->item[i] = (struct f_path_mask_item) {
+ .asn = pv.val.i,
+ .kind = PM_ASN,
+ };
+ break;
+ default:
+ runtime( "Error resolving path mask template: value not an integer" );
+ }
}
- INST(FI_PATHMASK_CONSTRUCT) {
- {
- struct f_path_mask *tt = what->a[0].p, *vbegin, **vv = &vbegin;
-
- while (tt) {
- *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask));
- if (tt->kind == PM_ASN_EXPR) {
- INTERPRET((struct f_inst *) tt->val, 0);
- (*vv)->kind = PM_ASN;
- if (res.type != T_INT) {
- runtime( "Error resolving path mask template: value not an integer" );
- return F_ERROR;
- }
-
- (*vv)->val = res.val.i;
- } else {
- **vv = *tt;
- }
- tt = tt->next;
- vv = &((*vv)->next);
- }
+ vstk.cnt -= what->count;
+ pm->len = what->count;
- res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin };
- }
- }
+ RESULT(T_PATH_MASK, path_mask, pm);
+ }
/* Relational operators */
- INST(FI_NEQ) {
+ INST(FI_NEQ, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = !val_same(v1, v2);
+ RESULT(T_BOOL, i, !val_same(&v1, &v2));
}
- INST(FI_EQ) {
+ INST(FI_EQ, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_same(v1, v2);
+ RESULT(T_BOOL, i, val_same(&v1, &v2));
}
- INST(FI_LT) {
+ INST(FI_LT, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- i = val_compare(v1, v2);
- if (i==CMP_ERROR)
+ int i = val_compare(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
- res.type = T_BOOL;
- res.val.i = (i == -1);
+ RESULT(T_BOOL, i, (i == -1));
}
- INST(FI_LTE) {
+ INST(FI_LTE, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- i = val_compare(v1, v2);
- if (i==CMP_ERROR)
+ int i = val_compare(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
- res.type = T_BOOL;
- res.val.i = (i != 1);
+ RESULT(T_BOOL, i, (i != 1));
}
- INST(FI_NOT) {
- ARG_T(1,0,T_BOOL);
- res.val.i = !res.val.i;
+ INST(FI_NOT, 1, 1) {
+ ARG(1,T_BOOL);
+ RESULT(T_BOOL, i, !v1.val.i);
}
- INST(FI_MATCH) {
+ INST(FI_MATCH, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_in_range(v1, v2);
- if (res.val.i == CMP_ERROR)
+ int i = val_in_range(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "~ applied on unknown type pair" );
- res.val.i = !!res.val.i;
+ RESULT(T_BOOL, i, !!i);
}
- INST(FI_NOT_MATCH) {
+ INST(FI_NOT_MATCH, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_in_range(v1, v2);
+ int i = val_in_range(&v1, &v2);
if (res.val.i == CMP_ERROR)
runtime( "!~ applied on unknown type pair" );
- res.val.i = !res.val.i;
+ RESULT(T_BOOL, i, !i);
}
- INST(FI_DEFINED) {
+ INST(FI_DEFINED, 1, 1) {
ARG_ANY(1);
- res.type = T_BOOL;
- res.val.i = (v1.type != T_VOID) && !undef_value(v1);
+ RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
}
- INST(FI_TYPE) {
+
+ INST(FI_TYPE, 1, 1) {
ARG_ANY(1); /* There may be more types supporting this operation */
switch (v1.type)
{
case T_NET:
- res.type = T_ENUM_NETTYPE;
- res.val.i = v1.val.net->type;
+ RESULT(T_ENUM_NETTYPE, i, v1.val.net->type);
break;
default:
runtime( "Can't determine type of this item" );
}
}
- INST(FI_IS_V4) {
+
+ INST(FI_IS_V4, 1, 1) {
ARG(1, T_IP);
- res.type = T_BOOL;
- res.val.i = ipa_is_ip4(v1.val.ip);
+ RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip));
}
- /* Set to indirect value, a[0] = variable, a[1] = value */
- INST(FI_SET) {
+ /* Set to indirect value prepared in v1 */
+ INST(FI_SET, 1, 0) {
ARG_ANY(2);
- sym = what->a[0].p;
- vp = sym->def;
- if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID))
+ SYMBOL(1);
+ if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
{
/* IP->Quad implicit conversion */
- if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(v2))
+ if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
{
- vp->type = T_QUAD;
- vp->val.i = ipa_to_u32(v2.val.ip);
+ *((struct f_val *) sym->def) = (struct f_val) {
+ .type = T_QUAD,
+ .val.i = ipa_to_u32(v1.val.ip),
+ };
break;
}
runtime( "Assigning to variable of incompatible type" );
}
- *vp = v2;
+ *((struct f_val *) sym->def) = v1;
}
/* some constants have value in a[1], some in *a[0].p, strange. */
- INST(FI_CONSTANT) { /* integer (or simple type) constant, string, set, or prefix_set */
- res = what->val;
+ INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */
+ VALI; // res = what->val;
+ RESULT_OK;
}
- INST(FI_VARIABLE) {
- res = * ((struct f_val *) what->a[0].p);
+ INST(FI_VARIABLE, 0, 1) {
+ VALP(1); // res = * ((struct f_val *) what->a[0].p);
+ SAME([[if (strcmp(f1->sym->name, f2->sym->name)) return 0; ]]);
+ RESULT_OK;
}
- INST(FI_CONSTANT_INDIRECT) {
- res = * ((struct f_val *) what->a[0].p);
+ INST(FI_CONSTANT_INDIRECT, 0, 1) {
+ VALP(1);
+ SAME([[if (!val_same(f1->vp, f2->vp)) return 0; ]]);
+ RESULT_OK;
}
- INST(FI_PRINT) {
+ INST(FI_PRINT, 1, 0) {
ARG_ANY(1);
- val_format(v1, &fs->buf);
+ val_format(&(v1), &fs->buf);
}
- INST(FI_CONDITION) {
- ARG_T(1, 0, T_BOOL);
+ INST(FI_CONDITION, 1, 0) {
+ ARG(1, T_BOOL);
if (res.val.i)
- ARG_ANY_T(2,0);
+ LINE(2,0);
else
- ARG_ANY_T(3,0);
+ LINE(3,1);
}
- INST(FI_PRINT_AND_DIE) {
- ARG_ANY(1);
- if ((what->a[1].i == F_NOP || (what->a[1].i != F_NONL && what->a[0].p)) &&
+ INST(FI_PRINT_AND_DIE, 0, 0) {
+ POSTFIXIFY([[
+ if (what->a[0].p) {
+ pos = postfixify(dest, what->a[0].p, pos);
+ dest->items[pos].flags |= FIF_PRINTED;
+ }
+ ]]);
+ LINE_SIZE([[
+ if (what->a[0].p) {
+ cnt += inst_line_size(what->a[0].p);
+ }
+ ]]);
+
+ FRET(2);
+
+ if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) &&
!(fs->flags & FF_SILENT))
log_commit(*L_INFO, &fs->buf);
- switch (what->a[1].i) {
+ switch (fret) {
case F_QUITBIRD:
die( "Filter asked me to die" );
case F_ACCEPT:
/* Should take care about turning ACCEPT into MODIFY */
case F_ERROR:
case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
- return what->a[1].i; /* We have to return now, no more processing. */
+ return fret; /* We have to return now, no more processing. */
case F_NONL:
case F_NOP:
break;
@@ -280,40 +293,43 @@
bug( "unknown return type: Can't happen");
}
}
- INST(FI_RTA_GET) { /* rta access */
+
+ INST(FI_RTA_GET, 0, 1) { /* rta access */
{
+ STATIC_ATTR;
ACCESS_RTE;
struct rta *rta = (*fs->rte)->attrs;
- res.type = what->aux;
- switch (what->a[1].i)
+ switch (sa.sa_code)
{
- case SA_FROM: res.val.ip = rta->from; break;
- case SA_GW: res.val.ip = rta->nh.gw; break;
- case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break;
- case SA_PROTO: res.val.s = rta->src->proto->name; break;
- case SA_SOURCE: res.val.i = rta->source; break;
- case SA_SCOPE: res.val.i = rta->scope; break;
- case SA_DEST: res.val.i = rta->dest; break;
- case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break;
- case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break;
+ case SA_FROM: RESULT(sa.f_type, ip, rta->from); break;
+ case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break;
+ case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
+ case SA_PROTO: RESULT(sa.f_type, s, rta->src->proto->name); break;
+ case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break;
+ case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break;
+ case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
+ case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
+ case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
default:
- bug("Invalid static attribute access (%x)", res.type);
+ bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
}
}
- INST(FI_RTA_SET) {
+
+ INST(FI_RTA_SET, 1, 0) {
+ STATIC_ATTR;
ACCESS_RTE;
ARG_ANY(1);
- if (what->aux != v1.type)
+ if (sa.f_type != v1.type)
runtime( "Attempt to set static attribute to incompatible type" );
f_rta_cow(fs);
{
struct rta *rta = (*fs->rte)->attrs;
- switch (what->a[1].i)
+ switch (sa.sa_code)
{
case SA_FROM:
rta->from = v1.val.ip;
@@ -339,15 +355,17 @@
break;
case SA_DEST:
- i = v1.val.i;
- if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
- runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
-
- rta->dest = i;
- rta->nh.gw = IPA_NONE;
- rta->nh.iface = NULL;
- rta->nh.next = NULL;
- rta->hostentry = NULL;
+ {
+ int i = v1.val.i;
+ if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
+ runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
+
+ rta->dest = i;
+ rta->nh.gw = IPA_NONE;
+ rta->nh.iface = NULL;
+ rta->nh.next = NULL;
+ rta->hostentry = NULL;
+ }
break;
case SA_IFNAME:
@@ -365,124 +383,112 @@
break;
default:
- bug("Invalid static attribute access (%x)", res.type);
+ bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
}
}
- INST(FI_EA_GET) { /* Access to extended attributes */
+
+ INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */
+ DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
{
- u16 code = what->a[1].i;
- int f_type = what->aux >> 8;
- eattr *e = ea_find(*fs->eattrs, code);
+ eattr *e = ea_find(*fs->eattrs, da.ea_code);
if (!e) {
/* A special case: undefined as_path looks like empty as_path */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) {
- res.type = T_PATH;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_AS_PATH) {
+ RESULT(T_PATH, ad, &null_adata);
break;
}
/* The same special case for int_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
- res.type = T_CLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_INT_SET) {
+ RESULT(T_CLIST, ad, &null_adata);
break;
}
/* The same special case for ec_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
- res.type = T_ECLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_EC_SET) {
+ RESULT(T_ECLIST, ad, &null_adata);
break;
}
/* The same special case for lc_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
- res.type = T_LCLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_LC_SET) {
+ RESULT(T_LCLIST, ad, &null_adata);
break;
}
/* Undefined value */
res.type = T_VOID;
+ RESULT_OK;
break;
}
switch (e->type & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
- res.type = f_type;
- res.val.i = e->u.data;
+ RESULT(da.f_type, i, e->u.data);
break;
case EAF_TYPE_ROUTER_ID:
- res.type = T_QUAD;
- res.val.i = e->u.data;
+ RESULT(T_QUAD, i, e->u.data);
break;
case EAF_TYPE_OPAQUE:
- res.type = T_ENUM_EMPTY;
- res.val.i = 0;
+ RESULT(T_ENUM_EMPTY, i, 0);
break;
case EAF_TYPE_IP_ADDRESS:
- res.type = T_IP;
- struct adata * ad = e->u.ptr;
- res.val.ip = * (ip_addr *) ad->data;
+ RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
break;
case EAF_TYPE_AS_PATH:
- res.type = T_PATH;
- res.val.ad = e->u.ptr;
+ RESULT(T_PATH, ad, e->u.ptr);
break;
case EAF_TYPE_BITFIELD:
- res.type = T_BOOL;
- res.val.i = !!(e->u.data & BITFIELD_MASK(what));
+ RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
break;
case EAF_TYPE_INT_SET:
- res.type = T_CLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_CLIST, ad, e->u.ptr);
break;
case EAF_TYPE_EC_SET:
- res.type = T_ECLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_ECLIST, ad, e->u.ptr);
break;
case EAF_TYPE_LC_SET:
- res.type = T_LCLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_LCLIST, ad, e->u.ptr);
break;
case EAF_TYPE_UNDEF:
res.type = T_VOID;
+ RESULT_OK;
break;
default:
- bug("Unknown type in e,a");
+ bug("Unknown dynamic attribute type");
}
}
}
- INST(FI_EA_SET) {
+
+ INST(FI_EA_SET, 1, 0) {
+ DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
ARG_ANY(1);
{
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
- u16 code = what->a[1].i;
- int f_type = what->aux >> 8;
l->next = NULL;
l->flags = EALF_SORTED;
l->count = 1;
- l->attrs[0].id = code;
+ l->attrs[0].id = da.ea_code;
l->attrs[0].flags = 0;
- l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH;
+ l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
- switch (what->aux & EAF_TYPE_MASK) {
+ switch (da.type) {
case EAF_TYPE_INT:
- if (v1.type != f_type)
+ if (v1.type != da.f_type)
runtime( "Setting int attribute to non-int value" );
l->attrs[0].u.data = v1.val.i;
break;
case EAF_TYPE_ROUTER_ID:
/* IP->Quad implicit conversion */
- if (val_is_ip4(v1)) {
+ if (val_is_ip4(&v1)) {
l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
break;
}
@@ -514,13 +520,13 @@
runtime( "Setting bit in bitfield attribute to non-bool value" );
{
/* First, we have to find the old value */
- eattr *e = ea_find(*fs->eattrs, code);
+ eattr *e = ea_find(*fs->eattrs, da.ea_code);
u32 data = e ? e->u.data : 0;
if (v1.val.i)
- l->attrs[0].u.data = data | BITFIELD_MASK(what);
+ l->attrs[0].u.data = data | (1u << da.bit);
else
- l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
+ l->attrs[0].u.data = data & ~(1u << da.bit);
}
break;
case EAF_TYPE_INT_SET:
@@ -551,12 +557,13 @@
*fs->eattrs = l;
}
}
- INST(FI_PREF_GET) {
+
+ INST(FI_PREF_GET, 0, 1) {
ACCESS_RTE;
- res.type = T_INT;
- res.val.i = (*fs->rte)->pref;
+ RESULT(T_INT, i, (*fs->rte)->pref);
}
- INST(FI_PREF_SET) {
+
+ INST(FI_PREF_SET, 1, 0) {
ACCESS_RTE;
ARG(1,T_INT);
if (v1.val.i > 0xFFFF)
@@ -564,149 +571,221 @@
f_rte_cow(fs);
(*fs->rte)->pref = v1.val.i;
}
- INST(FI_LENGTH) { /* Get length of */
+
+ INST(FI_LENGTH, 1, 1) { /* Get length of */
ARG_ANY(1);
- res.type = T_INT;
switch(v1.type) {
- case T_NET: res.val.i = net_pxlen(v1.val.net); break;
- case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
- case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
- case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
- case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
+ case T_NET: RESULT(T_INT, i, net_pxlen(v1.val.net)); break;
+ case T_PATH: RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break;
+ case T_CLIST: RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break;
+ case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break;
+ case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break;
default: runtime( "Prefix, path, clist or eclist expected" );
}
}
- INST(FI_SADR_SRC) { /* Get SADR src prefix */
+
+ INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */
ARG(1, T_NET);
if (!net_is_sadr(v1.val.net))
runtime( "SADR expected" );
- {
- net_addr_ip6_sadr *net = (void *) v1.val.net;
- net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6));
- net_fill_ip6(src, net->src_prefix, net->src_pxlen);
+ net_addr_ip6_sadr *net = (void *) v1.val.net;
+ net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6));
+ net_fill_ip6(src, net->src_prefix, net->src_pxlen);
- res.type = T_NET;
- res.val.net = src;
- }
+ RESULT(T_NET, net, src);
}
- INST(FI_ROA_MAXLEN) { /* Get ROA max prefix length */
+
+ INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
runtime( "ROA expected" );
- res.type = T_INT;
- res.val.i = (v1.val.net->type == NET_ROA4) ?
+ RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
((net_addr_roa4 *) v1.val.net)->max_pxlen :
- ((net_addr_roa6 *) v1.val.net)->max_pxlen;
+ ((net_addr_roa6 *) v1.val.net)->max_pxlen);
}
- INST(FI_ROA_ASN) { /* Get ROA ASN */
+
+ INST(FI_ROA_ASN, 1, 1) { /* Get ROA ASN */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
runtime( "ROA expected" );
- res.type = T_INT;
- res.val.i = (v1.val.net->type == NET_ROA4) ?
+ RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
((net_addr_roa4 *) v1.val.net)->asn :
- ((net_addr_roa6 *) v1.val.net)->asn;
+ ((net_addr_roa6 *) v1.val.net)->asn);
}
- INST(FI_IP) { /* Convert prefix to ... */
+
+ INST(FI_IP, 1, 1) { /* Convert prefix to ... */
ARG(1, T_NET);
- res.type = T_IP;
- res.val.ip = net_prefix(v1.val.net);
+ RESULT(T_IP, ip, net_prefix(v1.val.net));
}
- INST(FI_ROUTE_DISTINGUISHER) {
+
+ INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
ARG(1, T_NET);
if (!net_is_vpn(v1.val.net))
runtime( "VPN address expected" );
- res.type = T_RD;
- res.val.ec = net_rd(v1.val.net);
+ RESULT(T_RD, ec, net_rd(v1.val.net));
}
- INST(FI_AS_PATH_FIRST) { /* Get first ASN from AS PATH */
- ARG(1, T_PATH);
- as = 0;
+ INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */
+ ARG(1, T_PATH);
+ int as = 0;
as_path_get_first(v1.val.ad, &as);
- res.type = T_INT;
- res.val.i = as;
+ RESULT(T_INT, i, as);
}
- INST(FI_AS_PATH_LAST) { /* Get last ASN from AS PATH */
- ARG(1, T_PATH);
- as = 0;
+ INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */
+ ARG(1, T_PATH);
+ int as = 0;
as_path_get_last(v1.val.ad, &as);
- res.type = T_INT;
- res.val.i = as;
+ RESULT(T_INT, i, as);
}
- INST(FI_AS_PATH_LAST_NAG) { /* Get last ASN from non-aggregated part of AS PATH */
+
+ INST(FI_AS_PATH_LAST_NAG, 1, 1) { /* Get last ASN from non-aggregated part of AS PATH */
ARG(1, T_PATH);
+ RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
+ }
- res.type = T_INT;
- res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
+ INST(FI_RETURN, 1, 1) {
+ /* Acquire the return value */
+ ARG_ANY(1);
+ uint retpos = vstk.cnt;
+
+ /* Drop every sub-block including ourselves */
+ while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN))
+ ;
+
+ /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
+ if (!estk.cnt)
+ if (vstk.val[retpos].type == T_BOOL)
+ if (vstk.val[retpos].val.i)
+ return F_ACCEPT;
+ else
+ return F_REJECT;
+ else
+ runtime("Can't return non-bool from non-function");
+
+ /* Set the value stack position */
+ vstk.cnt = estk.item[estk.cnt].ventry;
+
+ /* Copy the return value */
+ RESULT_VAL(vstk.val[retpos]);
}
- INST(FI_RETURN) {
- ARG_ANY_T(1,0);
- return F_RETURN;
+
+ INST(FI_CALL, 0, 1) {
+ /* First push the code */
+ LINEP(2,0);
+ curline.emask |= FE_RETURN;
+
+ /* Then push the arguments */
+ LINE(1,1);
}
- INST(FI_CALL) {
- ARG_ANY_T(1,0);
- fret = interpret(fs, what->a[1].p);
- if (fret > F_RETURN)
- return fret;
+
+ INST(FI_DROP_RESULT, 1, 0) {
+ ARG_ANY(1);
}
- INST(FI_CLEAR_LOCAL_VARS) { /* Clear local variables */
- for (sym = what->a[0].p; sym != NULL; sym = sym->aux2)
+
+ INST(FI_CLEAR_LOCAL_VARS, 0, 0) { /* Clear local variables */
+ SYMBOL(1);
+ for ( ; sym != NULL; sym = sym->aux2)
((struct f_val *) sym->def)->type = T_VOID;
}
- INST(FI_SWITCH) {
+ INST(FI_SWITCH, 1, 0) {
ARG_ANY(1);
- {
- struct f_tree *t = find_tree(what->a[1].p, v1);
+ POSTFIXIFY([[
+ dest->items[pos].tree = what->a[1].p;
+ ]]);
+ const struct f_tree *t = find_tree(what->tree, &v1);
+ if (!t) {
+ v1.type = T_VOID;
+ t = find_tree(what->tree, &v1);
if (!t) {
- v1.type = T_VOID;
- t = find_tree(what->a[1].p, v1);
- if (!t) {
- debug( "No else statement?\n");
- break;
- }
+ debug( "No else statement?\n");
+ break;
}
- /* It is actually possible to have t->data NULL */
-
- fret = interpret(fs, t->data);
- if (fret >= F_RETURN)
- return fret;
}
+ /* It is actually possible to have t->data NULL */
+
+ LINEX(t->data);
}
- INST(FI_IP_MASK) { /* IP.MASK(val) */
+
+ INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */
ARG(1, T_IP);
ARG(2, T_INT);
-
- res.type = T_IP;
- res.val.ip = ipa_is_ip4(v1.val.ip) ?
+ RESULT(T_IP, ip, [[ ipa_is_ip4(v1.val.ip) ?
ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
- ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
+ ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]);
}
- INST(FI_EMPTY) { /* Create empty attribute */
- res.type = what->aux;
- res.val.ad = adata_empty(fs->pool, 0);
- }
- INST(FI_PATH_PREPEND) { /* Path prepend */
+ INST(FI_PATH_PREPEND, 2, 1) { /* Path prepend */
ARG(1, T_PATH);
ARG(2, T_INT);
+ RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]);
+ }
+
+ INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */
+ ARG_ANY(1);
+ ARG_ANY(2);
+ if (v1.type == T_PATH)
+ runtime("Can't add to path");
+
+ else if (v1.type == T_CLIST)
+ {
+ /* Community (or cluster) list */
+ struct f_val dummy;
+
+ if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
+ RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, v2.val.i) ]]);
+ /* IP->Quad implicit conversion */
+ else if (val_is_ip4(&v2))
+ RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
+ runtime("Can't add set");
+ else if (v2.type == T_CLIST)
+ RESULT(T_CLIST, ad, [[ int_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else
+ runtime("Can't add non-pair");
+ }
- res.type = T_PATH;
- res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i);
+ else if (v1.type == T_ECLIST)
+ {
+ /* v2.val is either EC or EC-set */
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
+ runtime("Can't add set");
+ else if (v2.type == T_ECLIST)
+ RESULT(T_ECLIST, ad, [[ ec_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else if (v2.type != T_EC)
+ runtime("Can't add non-ec");
+ else
+ RESULT(T_ECLIST, ad, [[ ec_set_add(fs->pool, v1.val.ad, v2.val.ec) ]]);
+ }
+
+ else if (v1.type == T_LCLIST)
+ {
+ /* v2.val is either LC or LC-set */
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
+ runtime("Can't add set");
+ else if (v2.type == T_LCLIST)
+ RESULT(T_LCLIST, ad, [[ lc_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else if (v2.type != T_LC)
+ runtime("Can't add non-lc");
+ else
+ RESULT(T_LCLIST, ad, [[ lc_set_add(fs->pool, v1.val.ad, v2.val.lc) ]]);
+
+ }
+
+ else
+ runtime("Can't add to non-[e|l]clist");
}
- INST(FI_CLIST_ADD_DEL) { /* (Extended) Community list add or delete */
+ INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
if (v1.type == T_PATH)
{
- struct f_tree *set = NULL;
+ const struct f_tree *set = NULL;
u32 key = 0;
- int pos;
if (v2.type == T_INT)
key = v2.val.i;
@@ -715,210 +794,154 @@
else
runtime("Can't delete non-integer (set)");
- switch (what->aux)
- {
- case 'a': runtime("Can't add to path");
- case 'd': pos = 0; break;
- case 'f': pos = 1; break;
- default: bug("unknown Ca operation");
- }
-
- if (pos && !set)
- runtime("Can't filter integer");
-
- res.type = T_PATH;
- res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos);
+ RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, set, key, 0) ]]);
}
+
else if (v1.type == T_CLIST)
{
/* Community (or cluster) list */
struct f_val dummy;
- int arg_set = 0;
- uint n = 0;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- n = v2.val.i;
+ RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
- else if (val_is_ip4(v2))
- n = ipa_to_u32(v2.val.ip);
- else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
- arg_set = 1;
- else if (v2.type == T_CLIST)
- arg_set = 2;
+ else if (val_is_ip4(&v2))
+ RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
+ RESULT(T_CLIST, ad, [[ clist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else
- runtime("Can't add/delete non-pair");
-
- res.type = T_CLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = int_set_add(fs->pool, v1.val.ad, n);
- else
- res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
-
- case 'd':
- if (!arg_set)
- res.val.ad = int_set_del(fs->pool, v1.val.ad, n);
- else
- res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
-
- case 'f':
- if (!arg_set)
- runtime("Can't filter pair");
- res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
-
- default:
- bug("unknown Ca operation");
- }
+ runtime("Can't delete non-pair");
}
+
else if (v1.type == T_ECLIST)
{
- /* Extended community list */
- int arg_set = 0;
-
/* v2.val is either EC or EC-set */
- if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
- arg_set = 1;
- else if (v2.type == T_ECLIST)
- arg_set = 2;
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_EC)
- runtime("Can't add/delete non-ec");
-
- res.type = T_ECLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec);
- else
- res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
-
- case 'd':
- if (!arg_set)
- res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec);
- else
- res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
-
- case 'f':
- if (!arg_set)
- runtime("Can't filter ec");
- res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
-
- default:
- bug("unknown Ca operation");
- }
+ runtime("Can't delete non-ec");
+ else
+ RESULT(T_ECLIST, ad, [[ ec_set_del(fs->pool, v1.val.ad, v2.val.ec) ]]);
}
+
else if (v1.type == T_LCLIST)
{
- /* Large community list */
- int arg_set = 0;
-
/* v2.val is either LC or LC-set */
- if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
- arg_set = 1;
- else if (v2.type == T_LCLIST)
- arg_set = 2;
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_LC)
- runtime("Can't add/delete non-lc");
-
- res.type = T_LCLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc);
- else
- res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
+ runtime("Can't delete non-lc");
+ else
+ RESULT(T_LCLIST, ad, [[ lc_set_del(fs->pool, v1.val.ad, v2.val.lc) ]]);
+ }
- case 'd':
- if (!arg_set)
- res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc);
- else
- res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
+ else
+ runtime("Can't delete in non-[e|l]clist");
+ }
- case 'f':
- if (!arg_set)
- runtime("Can't filter lc");
- res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
+ INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */
+ ARG_ANY(1);
+ ARG_ANY(2);
+ if (v1.type == T_PATH)
+ {
+ u32 key = 0;
- default:
- bug("unknown Ca operation");
- }
+ if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
+ RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, v2.val.t, key, 1) ]]);
+ else
+ runtime("Can't filter integer");
}
- else
- runtime("Can't add/delete to non-[e|l]clist");
- }
+ else if (v1.type == T_CLIST)
+ {
+ /* Community (or cluster) list */
+ struct f_val dummy;
- INST(FI_ROA_CHECK) { /* ROA Check */
- if (what->arg1)
+ if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
+ RESULT(T_CLIST, ad, [[ clist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter pair");
+ }
+
+ else if (v1.type == T_ECLIST)
{
- ARG(1, T_NET);
- ARG(2, T_INT);
+ /* v2.val is either EC or EC-set */
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter ec");
+ }
- as = v2.val.i;
+ else if (v1.type == T_LCLIST)
+ {
+ /* v2.val is either LC or LC-set */
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter lc");
}
+
else
- {
- ACCESS_RTE;
- ACCESS_EATTRS;
- v1.val.net = (*fs->rte)->net->n.addr;
+ runtime("Can't filter non-[e|l]clist");
+ }
- /* We ignore temporary attributes, probably not a problem here */
- /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
- eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
+ INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */
+ RTC(1);
+ ACCESS_RTE;
+ ACCESS_EATTRS;
+ const net_addr *net = (*fs->rte)->net->n.addr;
- if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
- runtime("Missing AS_PATH attribute");
+ /* We ignore temporary attributes, probably not a problem here */
+ /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
+ eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
- as_path_get_last(e->u.ptr, &as);
- }
+ if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
+ runtime("Missing AS_PATH attribute");
+
+ u32 as = 0;
+ as_path_get_last(e->u.ptr, &as);
- struct rtable *table = what->a[2].rtc->table;
if (!table)
runtime("Missing ROA table");
if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
runtime("Table type must be either ROA4 or ROA6");
- res.type = T_ENUM_ROA;
+ if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
+ RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
+ else
+ RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]);
+ }
+
+ INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */
+ ARG(1, T_NET);
+ ARG(2, T_INT);
+ RTC(3);
+
+ u32 as = v2.val.i;
+
+ if (!table)
+ runtime("Missing ROA table");
+
+ if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
+ runtime("Table type must be either ROA4 or ROA6");
if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
- res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */
+ RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
else
- res.val.i = net_roa_check(table, v1.val.net, as);
+ RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, v1.val.net, as) ]]);
}
- INST(FI_FORMAT) { /* Format */
+ INST(FI_FORMAT, 1, 0) { /* Format */
ARG_ANY(1);
-
- res.type = T_STRING;
- res.val.s = val_format_str(fs, v1);
+ RESULT(T_STRING, s, val_format_str(fs, &v1));
}
- INST(FI_ASSERT) { /* Birdtest Assert */
+ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
ARG(1, T_BOOL);
-
- res.type = v1.type;
- res.val = v1.val;
-
+ POSTFIXIFY([[
+ dest->items[pos].s = what->a[1].p;
+ ]]);
CALL(bt_assert_hook, res.val.i, what);
}
-
diff --git a/filter/f-util.c b/filter/f-util.c
index 11a5e97e..4f11a6d9 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -30,8 +30,7 @@ struct f_inst *
f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
{
struct f_inst *ret = f_new_inst(fi_code);
- ret->aux = (da.f_type << 8) | da.type;
- ret->a[1].i = da.ea_code;
+ ret->da = da;
return ret;
}
@@ -39,9 +38,7 @@ struct f_inst *
f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
{
struct f_inst *ret = f_new_inst(fi_code);
- ret->aux = sa.f_type;
- ret->a[1].i = sa.sa_code;
- ret->a[0].i = sa.readonly;
+ ret->sa = sa;
return ret;
}
@@ -49,13 +46,12 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
* Generate set_dynamic( operation( get_dynamic(), argument ) )
*/
struct f_inst *
-f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
+f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument)
{
struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
- *oper = f_new_inst(operation),
+ *oper = f_new_inst(fi_code),
*get_dyn = f_new_inst_da(FI_EA_GET, da);
- oper->aux = operation_aux;
oper->a[0].p = get_dyn;
oper->a[1].p = argument;
@@ -63,21 +59,6 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s
return set_dyn;
}
-struct f_inst *
-f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
-{
- struct f_inst *ret = f_new_inst(FI_ROA_CHECK);
- ret->arg1 = prefix;
- ret->arg2 = asn;
- /* prefix == NULL <-> asn == NULL */
-
- if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
- cf_error("%s is not a ROA table", table->name);
- ret->arg3 = table;
-
- return ret;
-}
-
static const char * const f_instruction_name_str[] = {
#define F(c,a,b) \
[c] = #c,
@@ -219,7 +200,7 @@ ca_lookup(pool *p, const char *name, int f_type)
}
cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1);
- cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id));
+ cas->fda = f_new_dynamic_attr(ea_type, 0, f_type, EA_CUSTOM(id));
cas->uc = 1;
strcpy(cas->name, name);
diff --git a/filter/filter.c b/filter/filter.c
index 308792b9..858d5fc5 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -50,15 +50,6 @@
#define CMP_ERROR 999
-#define FILTER_STACK_DEPTH 16384
-
-/* Filter interpreter stack. Make this thread local after going parallel. */
-struct filter_stack {
- struct f_val val;
-};
-
-static struct filter_stack filter_stack[FILTER_STACK_DEPTH];
-
/* Internal filter state, to be allocated on stack when executing filters */
struct filter_state {
struct rte **rte;
@@ -66,14 +57,10 @@ struct filter_state {
struct ea_list **eattrs;
struct linpool *pool;
struct buffer buf;
- struct filter_stack *stack;
- int stack_ptr;
int flags;
};
-void (*bt_assert_hook)(int result, struct f_inst *assert);
-
-static struct adata undef_adata; /* adata of length 0 used for undefined */
+void (*bt_assert_hook)(int result, const struct f_line_item *assert);
/* Special undef value for paths and clists */
static inline int
@@ -81,9 +68,23 @@ undef_value(struct f_val v)
{
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
- (v.val.ad == &undef_adata);
+ (v.val.ad == &null_adata);
}
+const struct f_val f_const_empty_path = {
+ .type = T_PATH,
+ .val.ad = &null_adata,
+}, f_const_empty_clist = {
+ .type = T_CLIST,
+ .val.ad = &null_adata,
+}, f_const_empty_eclist = {
+ .type = T_ECLIST,
+ .val.ad = &null_adata,
+}, f_const_empty_lclist = {
+ .type = T_LCLIST,
+ .val.ad = &null_adata,
+};
+
static struct adata *
adata_empty(struct linpool *pool, int l)
{
@@ -93,16 +94,16 @@ adata_empty(struct linpool *pool, int l)
}
static void
-pm_format(struct f_path_mask *p, buffer *buf)
+pm_format(const struct f_path_mask *p, buffer *buf)
{
buffer_puts(buf, "[= ");
- while (p)
+ for (uint i=0; i<p->len; i++)
{
- switch(p->kind)
+ switch(p->item[i].kind)
{
case PM_ASN:
- buffer_print(buf, "%u ", p->val);
+ buffer_print(buf, "%u ", p->item[i].asn);
break;
case PM_QUESTION:
@@ -114,21 +115,20 @@ pm_format(struct f_path_mask *p, buffer *buf)
break;
case PM_ASN_RANGE:
- buffer_print(buf, "%u..%u ", p->val, p->val2);
+ buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
break;
case PM_ASN_EXPR:
ASSERT(0);
}
- p = p->next;
}
buffer_puts(buf, "=]");
}
-static inline int val_is_ip4(const struct f_val v)
-{ return (v.type == T_IP) && ipa_is_ip4(v.val.ip); }
+static inline int val_is_ip4(const struct f_val *v)
+{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
static inline int
lcomm_cmp(lcomm v1, lcomm v2)
@@ -152,25 +152,25 @@ lcomm_cmp(lcomm v1, lcomm v2)
* that it can be used for building balanced trees.
*/
int
-val_compare(struct f_val v1, struct f_val v2)
+val_compare(const struct f_val *v1, const struct f_val *v2)
{
- if (v1.type != v2.type) {
- if (v1.type == T_VOID) /* Hack for else */
+ if (v1->type != v2->type) {
+ if (v1->type == T_VOID) /* Hack for else */
return -1;
- if (v2.type == T_VOID)
+ if (v2->type == T_VOID)
return 1;
/* IP->Quad implicit conversion */
- if ((v1.type == T_QUAD) && val_is_ip4(v2))
- return uint_cmp(v1.val.i, ipa_to_u32(v2.val.ip));
- if (val_is_ip4(v1) && (v2.type == T_QUAD))
- return uint_cmp(ipa_to_u32(v1.val.ip), v2.val.i);
+ if ((v1->type == T_QUAD) && val_is_ip4(v2))
+ return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
+ if (val_is_ip4(v1) && (v2->type == T_QUAD))
+ return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
debug( "Types do not match in val_compare\n" );
return CMP_ERROR;
}
- switch (v1.type) {
+ switch (v1->type) {
case T_VOID:
return 0;
case T_ENUM:
@@ -178,47 +178,52 @@ val_compare(struct f_val v1, struct f_val v2)
case T_BOOL:
case T_PAIR:
case T_QUAD:
- return uint_cmp(v1.val.i, v2.val.i);
+ return uint_cmp(v1->val.i, v2->val.i);
case T_EC:
case T_RD:
- return u64_cmp(v1.val.ec, v2.val.ec);
+ return u64_cmp(v1->val.ec, v2->val.ec);
case T_LC:
- return lcomm_cmp(v1.val.lc, v2.val.lc);
+ return lcomm_cmp(v1->val.lc, v2->val.lc);
case T_IP:
- return ipa_compare(v1.val.ip, v2.val.ip);
+ return ipa_compare(v1->val.ip, v2->val.ip);
case T_NET:
- return net_compare(v1.val.net, v2.val.net);
+ return net_compare(v1->val.net, v2->val.net);
case T_STRING:
- return strcmp(v1.val.s, v2.val.s);
+ return strcmp(v1->val.s, v2->val.s);
default:
return CMP_ERROR;
}
}
static int
-pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
+pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
{
- while (m1 && m2)
+ if (m1->len != m2->len)
+
+ for (uint i=0; i<m1->len; i++)
{
- if (m1->kind != m2->kind)
+ if (m1->item[i].kind != m2->item[i].kind)
return 0;
- if (m1->kind == PM_ASN_EXPR)
- {
- if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
- return 0;
- }
- else
- {
- if ((m1->val != m2->val) || (m1->val2 != m2->val2))
- return 0;
+ switch (m1->item[i].kind) {
+ case PM_ASN:
+ if (m1->item[i].asn != m2->item[i].asn)
+ return 0;
+ break;
+ case PM_ASN_EXPR:
+ if (!f_same(m1->item[i].expr, m2->item[i].expr))
+ return 0;
+ break;
+ case PM_ASN_RANGE:
+ if (m1->item[i].from != m2->item[i].from)
+ return 0;
+ if (m1->item[i].to != m2->item[i].to)
+ return 0;
+ break;
}
-
- m1 = m1->next;
- m2 = m2->next;
}
- return !m1 && !m2;
+ return 1;
}
/**
@@ -230,7 +235,7 @@ pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
* Comparison of values of different types is valid and returns 0.
*/
int
-val_same(struct f_val v1, struct f_val v2)
+val_same(const struct f_val *v1, const struct f_val *v2)
{
int rc;
@@ -238,28 +243,28 @@ val_same(struct f_val v1, struct f_val v2)
if (rc != CMP_ERROR)
return !rc;
- if (v1.type != v2.type)
+ if (v1->type != v2->type)
return 0;
- switch (v1.type) {
+ switch (v1->type) {
case T_PATH_MASK:
- return pm_same(v1.val.path_mask, v2.val.path_mask);
+ return pm_same(v1->val.path_mask, v2->val.path_mask);
case T_PATH:
case T_CLIST:
case T_ECLIST:
case T_LCLIST:
- return adata_same(v1.val.ad, v2.val.ad);
+ return adata_same(v1->val.ad, v2->val.ad);
case T_SET:
- return same_tree(v1.val.t, v2.val.t);
+ return same_tree(v1->val.t, v2->val.t);
case T_PREFIX_SET:
- return trie_same(v1.val.ti, v2.val.ti);
+ return trie_same(v1->val.ti, v2->val.ti);
default:
- bug("Invalid type in val_same(): %x", v1.type);
+ bug("Invalid type in val_same(): %x", v1->type);
}
}
static int
-clist_set_type(struct f_tree *set, struct f_val *v)
+clist_set_type(const struct f_tree *set, struct f_val *v)
{
switch (set->from.type)
{
@@ -272,7 +277,7 @@ clist_set_type(struct f_tree *set, struct f_val *v)
return 1;
case T_IP:
- if (val_is_ip4(set->from) && val_is_ip4(set->to))
+ if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
{
v->type = T_QUAD;
return 1;
@@ -285,15 +290,15 @@ clist_set_type(struct f_tree *set, struct f_val *v)
}
static inline int
-eclist_set_type(struct f_tree *set)
+eclist_set_type(const struct f_tree *set)
{ return set->from.type == T_EC; }
static inline int
-lclist_set_type(struct f_tree *set)
+lclist_set_type(const struct f_tree *set)
{ return set->from.type == T_LC; }
static int
-clist_match_set(struct adata *clist, struct f_tree *set)
+clist_match_set(const struct adata *clist, const struct f_tree *set)
{
if (!clist)
return 0;
@@ -307,14 +312,14 @@ clist_match_set(struct adata *clist, struct f_tree *set)
while (l < end) {
v.val.i = *l++;
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
return 0;
}
static int
-eclist_match_set(struct adata *list, struct f_tree *set)
+eclist_match_set(const struct adata *list, const struct f_tree *set)
{
if (!list)
return 0;
@@ -330,7 +335,7 @@ eclist_match_set(struct adata *list, struct f_tree *set)
v.type = T_EC;
for (i = 0; i < len; i += 2) {
v.val.ec = ec_get(l, i);
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
@@ -338,7 +343,7 @@ eclist_match_set(struct adata *list, struct f_tree *set)
}
static int
-lclist_match_set(struct adata *list, struct f_tree *set)
+lclist_match_set(const struct adata *list, const struct f_tree *set)
{
if (!list)
return 0;
@@ -354,23 +359,23 @@ lclist_match_set(struct adata *list, struct f_tree *set)
v.type = T_LC;
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
return 0;
}
-static struct adata *
-clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
if (tree)
- clist_set_type(set.val.t, &v);
+ clist_set_type(set->val.t, &v);
else
v.type = T_PAIR;
@@ -383,7 +388,7 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos
while (l < end) {
v.val.i = *l++;
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
+ if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
*k++ = v.val.i;
}
@@ -396,13 +401,13 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos
return res;
}
-static struct adata *
-eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
@@ -415,7 +420,7 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
for (i = 0; i < len; i += 2) {
v.val.ec = ec_get(l, i);
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
+ if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
*k++ = l[i];
*k++ = l[i+1];
}
@@ -430,13 +435,13 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
return res;
}
-static struct adata *
-lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
@@ -449,7 +454,7 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
+ if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
k = lc_copy(k, l+i);
}
@@ -470,57 +475,57 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
* Checks if @v1 is element (|~| operator) of @v2.
*/
static int
-val_in_range(struct f_val v1, struct f_val v2)
+val_in_range(const struct f_val *v1, const struct f_val *v2)
{
- if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
- return as_path_match(v1.val.ad, v2.val.path_mask);
+ if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
+ return as_path_match(v1->val.ad, v2->val.path_mask);
- if ((v1.type == T_INT) && (v2.type == T_PATH))
- return as_path_contains(v2.val.ad, v1.val.i, 1);
+ if ((v1->type == T_INT) && (v2->type == T_PATH))
+ return as_path_contains(v2->val.ad, v1->val.i, 1);
- if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
- return int_set_contains(v2.val.ad, v1.val.i);
+ if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
+ return int_set_contains(v2->val.ad, v1->val.i);
/* IP->Quad implicit conversion */
- if (val_is_ip4(v1) && (v2.type == T_CLIST))
- return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
+ if (val_is_ip4(v1) && (v2->type == T_CLIST))
+ return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
- if ((v1.type == T_EC) && (v2.type == T_ECLIST))
- return ec_set_contains(v2.val.ad, v1.val.ec);
+ if ((v1->type == T_EC) && (v2->type == T_ECLIST))
+ return ec_set_contains(v2->val.ad, v1->val.ec);
- if ((v1.type == T_LC) && (v2.type == T_LCLIST))
- return lc_set_contains(v2.val.ad, v1.val.lc);
+ if ((v1->type == T_LC) && (v2->type == T_LCLIST))
+ return lc_set_contains(v2->val.ad, v1->val.lc);
- if ((v1.type == T_STRING) && (v2.type == T_STRING))
- return patmatch(v2.val.s, v1.val.s);
+ if ((v1->type == T_STRING) && (v2->type == T_STRING))
+ return patmatch(v2->val.s, v1->val.s);
- if ((v1.type == T_IP) && (v2.type == T_NET))
- return ipa_in_netX(v1.val.ip, v2.val.net);
+ if ((v1->type == T_IP) && (v2->type == T_NET))
+ return ipa_in_netX(v1->val.ip, v2->val.net);
- if ((v1.type == T_NET) && (v2.type == T_NET))
- return net_in_netX(v1.val.net, v2.val.net);
+ if ((v1->type == T_NET) && (v2->type == T_NET))
+ return net_in_netX(v1->val.net, v2->val.net);
- if ((v1.type == T_NET) && (v2.type == T_PREFIX_SET))
- return trie_match_net(v2.val.ti, v1.val.net);
+ if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
+ return trie_match_net(v2->val.ti, v1->val.net);
- if (v2.type != T_SET)
+ if (v2->type != T_SET)
return CMP_ERROR;
/* With integrated Quad<->IP implicit conversion */
- if ((v1.type == v2.val.t->from.type) ||
- ((v1.type == T_QUAD) && val_is_ip4(v2.val.t->from) && val_is_ip4(v2.val.t->to)))
- return !!find_tree(v2.val.t, v1);
+ if ((v1->type == v2->val.t->from.type) ||
+ ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
+ return !!find_tree(v2->val.t, v1);
- if (v1.type == T_CLIST)
- return clist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_CLIST)
+ return clist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_ECLIST)
- return eclist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_ECLIST)
+ return eclist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_LCLIST)
- return lclist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_LCLIST)
+ return lclist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_PATH)
- return as_path_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_PATH)
+ return as_path_match_set(v1->val.ad, v2->val.t);
return CMP_ERROR;
}
@@ -529,31 +534,31 @@ val_in_range(struct f_val v1, struct f_val v2)
* val_format - format filter value
*/
void
-val_format(struct f_val v, buffer *buf)
+val_format(const struct f_val *v, buffer *buf)
{
char buf2[1024];
- switch (v.type)
+ switch (v->type)
{
case T_VOID: buffer_puts(buf, "(void)"); return;
- case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
- case T_INT: buffer_print(buf, "%u", v.val.i); return;
- case T_STRING: buffer_print(buf, "%s", v.val.s); return;
- case T_IP: buffer_print(buf, "%I", v.val.ip); return;
- case T_NET: buffer_print(buf, "%N", v.val.net); return;
- case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
- case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
- case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
- case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
- case T_RD: rd_format(v.val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
- case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
- case T_SET: tree_format(v.val.t, buf); return;
- case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
- case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
- case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
- case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
- case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
- case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
- default: buffer_print(buf, "[unknown type %x]", v.type); return;
+ case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
+ case T_INT: buffer_print(buf, "%u", v->val.i); return;
+ case T_STRING: buffer_print(buf, "%s", v->val.s); return;
+ case T_IP: buffer_print(buf, "%I", v->val.ip); return;
+ case T_NET: buffer_print(buf, "%N", v->val.net); return;
+ case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
+ case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
+ case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
+ case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
+ case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
+ case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
+ case T_SET: tree_format(v->val.t, buf); return;
+ case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
+ case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
+ case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
+ case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
+ case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
+ case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
+ default: buffer_print(buf, "[unknown type %x]", v->type); return;
}
}
@@ -599,7 +604,7 @@ f_rta_cow(struct filter_state *fs)
}
static char *
-val_format_str(struct filter_state *fs, struct f_val v) {
+val_format_str(struct filter_state *fs, struct f_val *v) {
buffer b;
LOG_BUFFER_INIT(b);
val_format(v, &b);
@@ -608,6 +613,98 @@ val_format_str(struct filter_state *fs, struct f_val v) {
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
+static uint
+inst_line_size(const struct f_inst *what)
+{
+ uint cnt = 0;
+ for ( ; what; what = what->next) {
+ switch (what->fi_code) {
+#include "filter/f-inst-line-size.c"
+ }
+ }
+ return cnt;
+}
+
+#if DEBUGGING
+#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
+static const char f_dump_line_indent_str[] = " ";
+
+static char val_dump_buffer[1024];
+
+static const char *
+val_dump(const struct f_val *v) {
+ static buffer b = {
+ .start = val_dump_buffer,
+ .end = val_dump_buffer + 1024,
+ };
+ b.pos = b.start;
+ val_format(v, &b);
+ return val_dump_buffer;
+}
+
+static void f_dump_line(const struct f_line *dest, int indent);
+
+static void
+f_dump_line_item(const struct f_line_item *item, int indent)
+{
+ debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno);
+ switch (item->fi_code) {
+#include "filter/f-inst-dump.c"
+ }
+}
+
+static void
+f_dump_line(const struct f_line *dest, int indent)
+{
+ if (!dest) {
+ debug("%sNo filter line (NULL)\n", INDENT);
+ return;
+ }
+ debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
+ for (uint i=0; i<dest->len; i++)
+ f_dump_line_item(&dest->items[i], indent+1);
+ debug("%sFilter line %p dump done\n", INDENT, dest);
+#undef INDENT
+}
+#else
+#define f_dump_line(...)
+#endif
+
+static uint
+postfixify(struct f_line *dest, const struct f_inst *what, uint pos)
+{
+ for ( ; what; what = what->next) {
+ switch (what->fi_code) {
+#include "filter/f-inst-postfixify.c"
+ }
+ pos++;
+ }
+ return pos;
+}
+
+struct f_line *
+f_postfixify_concat(struct f_inst *first, ...)
+{
+ va_list args;
+ va_list argd;
+ va_start(args, first);
+ va_copy(argd, args);
+
+ uint len = 0;
+ for (struct f_inst *what = first; what; what = va_arg(args, struct f_inst *))
+ len += inst_line_size(what);
+
+ va_end(args);
+
+ struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len);
+
+ for (struct f_inst *what = first; what; what = va_arg(argd, struct f_inst *))
+ out->len = postfixify(out, what, out->len);
+
+ f_dump_line(out, 0);
+ return out;
+}
+
/**
* interpret
* @fs: filter state
@@ -624,26 +721,28 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
* TWOARGS macro to get both of them evaluated.
*/
static enum filter_return
-interpret(struct filter_state *fs, struct f_inst *what)
+interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
{
- struct symbol *sym;
- struct f_val *vp;
- unsigned u1, u2;
- enum filter_return fret;
- int i;
- u32 as;
+ struct f_val_stack vstk;
+ vstk.cnt = 0;
-#define res fs->stack[fs->stack_ptr].val
-#define v0 res
-#define v1 fs->stack[fs->stack_ptr + 1].val
-#define v2 fs->stack[fs->stack_ptr + 2].val
-#define v3 fs->stack[fs->stack_ptr + 3].val
+ struct f_exec_stack estk;
+ estk.cnt = 1;
+ estk.item[0].line = line;
+ estk.item[0].pos = 0;
- res = (struct f_val) { .type = T_VOID };
+#define curline estk.item[estk.cnt-1]
+
+ while (estk.cnt > 0) {
+ while (curline.pos < curline.line->len) {
+ const struct f_line_item *what = &(curline.line->items[curline.pos++]);
- for ( ; what; what = what->next) {
- res = (struct f_val) { .type = T_VOID };
- switch (what->fi_code) {
+
+ switch (what->fi_code) {
+#define res vstk.val[vstk.cnt]
+#define v1 vstk.val[vstk.cnt]
+#define v2 vstk.val[vstk.cnt + 1]
+#define v3 vstk.val[vstk.cnt + 2]
#define runtime(fmt, ...) do { \
if (!(fs->flags & FF_SILENT)) \
@@ -651,84 +750,70 @@ interpret(struct filter_state *fs, struct f_inst *what)
return F_ERROR; \
} while(0)
-#define ARG_ANY_T(n, tt) INTERPRET(what->a[n-1].p, tt)
-#define ARG_ANY(n) ARG_ANY_T(n, n)
-
-#define ARG_T(n,tt,t) do { \
- ARG_ANY_T(n,tt); \
- if (v##tt.type != t) \
- runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
- n, f_instruction_name(what->fi_code), t, v##tt.type); \
-} while (0)
-
-#define ARG(n,t) ARG_T(n,n,t)
-
-#define INTERPRET(what_, n) do { \
- fs->stack_ptr += n; \
- fret = interpret(fs, what_); \
- fs->stack_ptr -= n; \
- if (fret == F_RETURN) \
- bug("This shall not happen"); \
- if (fret > F_RETURN) \
- return fret; \
-} while (0)
-
#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
-
#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
-#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i))
-
- case FI_NOP:
- bug("This shall not happen");
-
#include "filter/f-inst-interpret.c"
-
- break;
- default:
- bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
-
#undef res
+#undef v1
+#undef v2
+#undef v3
#undef runtime
-#undef ARG_ANY
-#undef ARG
-#undef INTERPRET
#undef ACCESS_RTE
#undef ACCESS_EATTRS
+ }
}
+ estk.cnt--;
}
- return F_NOP;
-}
+ switch (vstk.cnt) {
+ case 0:
+ if (val) {
+ log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack");
+ return F_ERROR;
+ }
+ return F_NOP;
+ case 1:
+ if (val) {
+ *val = vstk.val[0];
+ return F_NOP;
+ }
+ /* fallthrough */
+ default:
+ log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt);
+ return F_ERROR;
+ }
+}
-#define ARG(n) \
- if (!i_same(f1->a[n-1].p, f2->a[n-1].p)) \
- return 0;
-
-#define ONEARG ARG(1);
-#define TWOARGS ONEARG; ARG(2);
-#define THREEARGS TWOARGS; ARG(3);
-
-#define A2_SAME if (f1->a[1].i != f2->a[1].i) return 0;
/*
- * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
+ * f_same - function that does real comparing of instruction trees, you should call filter_same from outside
*/
int
-i_same(struct f_inst *f1, struct f_inst *f2)
+f_same(const struct f_line *fl1, const struct f_line *fl2)
{
- if ((!!f1) != (!!f2))
- return 0;
- if (!f1)
+ if ((!fl1) && (!fl2))
return 1;
- if (f1->aux != f2->aux)
+ if ((!fl1) || (!fl2))
return 0;
- if (f1->fi_code != f2->fi_code)
+ if (fl1->len != fl2->len)
return 0;
- if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
- return 1;
+ for (uint i=0; i<fl1->len; i++) {
+#define f1 (&(fl1->items[i]))
+#define f2 (&(fl2->items[i]))
+ if (f1->fi_code != f2->fi_code)
+ return 0;
+ if (f1->flags != f2->flags)
+ return 0;
- switch(f1->fi_code) {
+ switch(f1->fi_code) {
+#include "filter/f-inst-same.c"
+ }
+ }
+ return 1;
+}
+
+#if 0
case FI_ADD: /* fall through */
case FI_SUBTRACT:
case FI_MULTIPLY:
@@ -842,9 +927,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case FI_ASSERT: ONEARG; break;
default:
bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
- }
- return i_same(f1->next, f2->next);
-}
+#endif
/**
* f_run - run a filter for a route
@@ -871,7 +954,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
* modified in place, old cached rta is possibly freed.
*/
enum filter_return
-f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
+f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
{
if (filter == FILTER_ACCEPT)
return F_ACCEPT;
@@ -886,12 +969,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
.rte = rte,
.pool = tmp_pool,
.flags = flags,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
- enum filter_return fret = interpret(&fs, filter->root);
+ enum filter_return fret = interpret(&fs, filter->root, NULL);
if (fs.old_rta) {
/*
@@ -925,54 +1007,52 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
enum filter_return
-f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
+f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
{
struct filter_state fs = {
.rte = rte,
.pool = tmp_pool,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
/* Note that in this function we assume that rte->attrs is private / uncached */
- return interpret(&fs, expr);
+ return interpret(&fs, expr, NULL);
}
enum filter_return
-f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres)
+f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
{
struct filter_state fs = {
.pool = tmp_pool,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
- enum filter_return fret = interpret(&fs, expr);
- *pres = filter_stack[0].val;
+ enum filter_return fret = interpret(&fs, expr, pres);
return fret;
}
uint
-f_eval_int(struct f_inst *expr)
+f_eval_int(const struct f_line *expr)
{
/* Called independently in parse-time to eval expressions */
struct filter_state fs = {
.pool = cfg_mem,
- .stack = filter_stack,
};
+ struct f_val val;
+
LOG_BUFFER_INIT(fs.buf);
- if (interpret(&fs, expr) > F_RETURN)
+ if (interpret(&fs, expr, &val) > F_RETURN)
cf_error("Runtime error while evaluating expression");
- if (filter_stack[0].val.type != T_INT)
+ if (val.type != T_INT)
cf_error("Integer expression expected");
- return filter_stack[0].val.val.i;
+ return val.val.i;
}
/**
@@ -993,5 +1073,5 @@ filter_same(struct filter *new, struct filter *old)
if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
new == FILTER_ACCEPT || new == FILTER_REJECT)
return 0;
- return i_same(new->root, old->root);
+ return f_same(new->root, old->root);
}
diff --git a/filter/filter.h b/filter/filter.h
index 594c9511..87bd2c36 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -14,13 +14,65 @@
#include "nest/route.h"
#include "nest/attrs.h"
+/* IP prefix range structure */
struct f_prefix {
- net_addr net;
- u8 lo, hi;
+ net_addr net; /* The matching prefix must match this net */
+ u8 lo, hi; /* And its length must fit between lo and hi */
};
+/* Type numbers must be in 0..0xff range */
+#define T_MASK 0xff
+
+/* Internal types */
+enum f_type {
+/* Do not use type of zero, that way we'll see errors easier. */
+ T_VOID = 1,
+
+/* User visible types, which fit in int */
+ T_INT = 0x10,
+ T_BOOL = 0x11,
+ T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */
+ T_QUAD = 0x13,
+
+/* Put enumerational types in 0x30..0x3f range */
+ T_ENUM_LO = 0x30,
+ T_ENUM_HI = 0x3f,
+
+ T_ENUM_RTS = 0x30,
+ T_ENUM_BGP_ORIGIN = 0x31,
+ T_ENUM_SCOPE = 0x32,
+ T_ENUM_RTC = 0x33,
+ T_ENUM_RTD = 0x34,
+ T_ENUM_ROA = 0x35,
+ T_ENUM_NETTYPE = 0x36,
+ T_ENUM_RA_PREFERENCE = 0x37,
+
+/* new enums go here */
+ T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
+
+#define T_ENUM T_ENUM_LO ... T_ENUM_HI
+
+/* Bigger ones */
+ T_IP = 0x20,
+ T_NET = 0x21,
+ T_STRING = 0x22,
+ T_PATH_MASK = 0x23, /* mask for BGP path */
+ T_PATH = 0x24, /* BGP path */
+ T_CLIST = 0x25, /* Community list */
+ T_EC = 0x26, /* Extended community value, u64 */
+ T_ECLIST = 0x27, /* Extended community list */
+ T_LC = 0x28, /* Large community value, lcomm */
+ T_LCLIST = 0x29, /* Large community list */
+ T_RD = 0x2a, /* Route distinguisher for VPN addresses */
+ T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */
+
+ T_SET = 0x80,
+ T_PREFIX_SET = 0x81,
+} PACKED;
+
+/* Filter value; size of this affects filter memory consumption */
struct f_val {
- int type; /* T_* */
+ enum f_type type; /* T_* */
union {
uint i;
u64 ec;
@@ -28,27 +80,42 @@ struct f_val {
ip_addr ip;
const net_addr *net;
char *s;
- struct f_tree *t;
- struct f_trie *ti;
- struct adata *ad;
- struct f_path_mask *path_mask;
+ const struct f_tree *t;
+ const struct f_trie *ti;
+ const struct adata *ad;
+ const struct f_path_mask *path_mask;
+ struct f_path_mask_item pmi;
} val;
};
+/* Dynamic attribute definition (eattrs) */
struct f_dynamic_attr {
- int type;
- int f_type;
- int ea_code;
+ u8 type; /* EA type (EAF_*) */
+ u8 bit; /* For bitfield accessors */
+ enum f_type f_type; /* Filter type */
+ uint ea_code; /* EA code */
};
+enum f_sa_code {
+ SA_FROM = 1,
+ SA_GW,
+ SA_NET,
+ SA_PROTO,
+ SA_SOURCE,
+ SA_SCOPE,
+ SA_DEST,
+ SA_IFNAME,
+ SA_IFINDEX,
+} PACKED;
+
+/* Static attribute definition (members of struct rta) */
struct f_static_attr {
- int f_type;
- int sa_code;
- int readonly;
+ enum f_type f_type; /* Filter type */
+ enum f_sa_code sa_code; /* Static attribute id */
+ int readonly:1; /* Don't allow writing */
};
-/* Filter instruction types */
-
+/* Filter instruction words */
#define FI__TWOCHAR(a,b) ((a<<8) | b)
#define FI__LIST \
F(FI_NOP, 0, '0') \
@@ -96,16 +163,20 @@ struct f_static_attr {
F(FI_AS_PATH_LAST_NAG, 'a', 'L') \
F(FI_RETURN, 0, 'r') \
F(FI_CALL, 'c', 'a') \
+ F(FI_DROP_RESULT, 'd', 'r') \
F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \
F(FI_SWITCH, 'S', 'W') \
F(FI_IP_MASK, 'i', 'M') \
- F(FI_EMPTY, 0, 'E') \
F(FI_PATH_PREPEND, 'A', 'p') \
- F(FI_CLIST_ADD_DEL, 'C', 'a') \
- F(FI_ROA_CHECK, 'R', 'C') \
+ F(FI_CLIST_ADD, 'C', 'a') \
+ F(FI_CLIST_DEL, 'C', 'd') \
+ F(FI_CLIST_FILTER, 'C', 'f') \
+ F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \
+ F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \
F(FI_FORMAT, 0, 'F') \
F(FI_ASSERT, 'a', 's')
+/* The enum itself */
enum f_instruction_code {
#define F(c,a,b) \
c,
@@ -114,145 +185,165 @@ FI__LIST
FI__MAX,
} PACKED;
+/* Convert the instruction back to the enum name */
const char *f_instruction_name(enum f_instruction_code fi);
-struct f_inst { /* Instruction */
- struct f_inst *next; /* Structure is 16 bytes, anyway */
- enum f_instruction_code fi_code;
+enum f_instruction_flags {
+ FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */
+};
+
+union f_inst_attr {
+ uint i;
+ void *p;
+ struct rtable_config *rtc;
+};
+
+/* Instruction structure for config */
+struct f_inst {
+ struct f_inst *next; /* Next instruction to be executed */
+ enum f_instruction_code fi_code; /* The instruction itself */
u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union {
- union {
- uint i;
- void *p;
- struct rtable_config *rtc;
- } a[3]; /* The three arguments */
+ union f_inst_attr a[3]; /* The three arguments */
struct f_val val; /* The value if FI_CONSTANT */
+ struct {
+ union f_inst_attr sa_a[1];
+ struct f_static_attr sa; /* Static attribute def for FI_RTA_* */
+ };
+ struct {
+ union f_inst_attr da_a[1];
+ struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */
+ };
};
int lineno;
};
-#define arg1 a[0].p
-#define arg2 a[1].p
-#define arg3 a[2].p
+/* Possible return values of filter execution */
+enum filter_return {
+ F_NOP = 0,
+ F_NONL,
+ F_RETURN,
+ F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */
+ F_REJECT,
+ F_ERROR,
+ F_QUITBIRD,
+};
+
+/* Filter structures for execution */
+struct f_line;
+/* The single instruction item */
+struct f_line_item {
+ enum f_instruction_code fi_code; /* What to do */
+ enum f_instruction_flags flags; /* Flags, instruction-specific */
+ uint lineno; /* Where */
+ union {
+ struct {
+ const struct f_val *vp;
+ const struct symbol *sym;
+ };
+ const struct f_line *lines[2];
+ enum filter_return fret;
+ struct f_static_attr sa;
+ struct f_dynamic_attr da;
+ enum ec_subtype ecs;
+ const char *s;
+ const struct f_tree *tree;
+ const struct rtable_config *rtc;
+ uint count;
+ }; /* Additional instruction data */
+};
+
+/* Line of instructions to be unconditionally executed one after another */
+struct f_line {
+ uint len; /* Line length */
+ struct f_line_item items[0]; /* The items themselves */
+};
+
+/* The filter encapsulating structure to be pointed-to from outside */
struct filter {
char *name;
- struct f_inst *root;
+ struct f_line *root;
+};
+
+/* Convert the f_inst infix tree to the f_line structures */
+struct f_line *f_postfixify_concat(struct f_inst *root, ...);
+static inline struct f_line *f_postfixify(struct f_inst *root)
+{ return f_postfixify_concat(root, NULL); }
+
+#define F_VAL_STACK_MAX 4096
+
+/* Value stack for execution */
+struct f_val_stack {
+ uint cnt; /* Current stack size; 0 for empty */
+ struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */
+};
+
+#define F_EXEC_STACK_MAX 4096
+
+/* Exception bits */
+enum f_exception {
+ FE_RETURN = 0x1,
+};
+
+/* Instruction stack for execution */
+struct f_exec_stack {
+ struct {
+ const struct f_line *line; /* The line that is being executed */
+ uint pos; /* Instruction index in the line */
+ uint ventry; /* Value stack depth on entry */
+ enum f_exception emask; /* Exception mask */
+ } item[F_EXEC_STACK_MAX];
+ uint cnt; /* Current stack size; 0 for empty */
+
};
struct f_inst *f_new_inst(enum f_instruction_code fi_code);
struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
-static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
+static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
+{ return (struct f_dynamic_attr) { .type = type, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
struct f_tree *f_new_tree(void);
-struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
+struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
struct f_tree *build_tree(struct f_tree *);
-struct f_tree *find_tree(struct f_tree *t, struct f_val val);
-int same_tree(struct f_tree *t1, struct f_tree *t2);
-void tree_format(struct f_tree *t, buffer *buf);
+const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
+int same_tree(const struct f_tree *t1, const struct f_tree *t2);
+void tree_format(const struct f_tree *t, buffer *buf);
struct f_trie *f_new_trie(linpool *lp, uint node_size);
void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
-int trie_match_net(struct f_trie *t, const net_addr *n);
-int trie_same(struct f_trie *t1, struct f_trie *t2);
-void trie_format(struct f_trie *t, buffer *buf);
+int trie_match_net(const struct f_trie *t, const net_addr *n);
+int trie_same(const struct f_trie *t1, const struct f_trie *t2);
+void trie_format(const struct f_trie *t, buffer *buf);
struct ea_list;
struct rte;
-enum filter_return {
- F_NOP = 0,
- F_NONL,
- F_RETURN,
- F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */
- F_REJECT,
- F_ERROR,
- F_QUITBIRD,
-};
-
-enum filter_return f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
-enum filter_return f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
-enum filter_return f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres);
-uint f_eval_int(struct f_inst *expr);
+enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
+enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
+enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
+uint f_eval_int(const struct f_line *expr);
char *filter_name(struct filter *filter);
int filter_same(struct filter *new, struct filter *old);
-int i_same(struct f_inst *f1, struct f_inst *f2);
+int f_same(const struct f_line *f1, const struct f_line *f2);
+
+int val_compare(const struct f_val *v1, const struct f_val *v2);
-int val_compare(struct f_val v1, struct f_val v2);
-int val_same(struct f_val v1, struct f_val v2);
+void val_format(const struct f_val *v, buffer *buf);
-void val_format(struct f_val v, buffer *buf);
+extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
#define FILTER_ACCEPT NULL
#define FILTER_REJECT ((void *) 1)
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
-/* Type numbers must be in 0..0xff range */
-#define T_MASK 0xff
-
-/* Internal types */
-/* Do not use type of zero, that way we'll see errors easier. */
-#define T_VOID 1
-
-/* User visible types, which fit in int */
-#define T_INT 0x10
-#define T_BOOL 0x11
-#define T_PAIR 0x12 /* Notice that pair is stored as integer: first << 16 | second */
-#define T_QUAD 0x13
-
-/* Put enumerational types in 0x30..0x3f range */
-#define T_ENUM_LO 0x30
-#define T_ENUM_HI 0x3f
-
-#define T_ENUM_RTS 0x30
-#define T_ENUM_BGP_ORIGIN 0x31
-#define T_ENUM_SCOPE 0x32
-#define T_ENUM_RTC 0x33
-#define T_ENUM_RTD 0x34
-#define T_ENUM_ROA 0x35
-#define T_ENUM_NETTYPE 0x36
-#define T_ENUM_RA_PREFERENCE 0x37
-
-/* new enums go here */
-#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
-
-#define T_ENUM T_ENUM_LO ... T_ENUM_HI
-
-/* Bigger ones */
-#define T_IP 0x20
-#define T_NET 0x21
-#define T_STRING 0x22
-#define T_PATH_MASK 0x23 /* mask for BGP path */
-#define T_PATH 0x24 /* BGP path */
-#define T_CLIST 0x25 /* Community list */
-#define T_EC 0x26 /* Extended community value, u64 */
-#define T_ECLIST 0x27 /* Extended community list */
-#define T_LC 0x28 /* Large community value, lcomm */
-#define T_LCLIST 0x29 /* Large community list */
-#define T_RD 0x2a /* Route distinguisher for VPN addresses */
-
-#define T_SET 0x80
-#define T_PREFIX_SET 0x81
-
-
-#define SA_FROM 1
-#define SA_GW 2
-#define SA_NET 3
-#define SA_PROTO 4
-#define SA_SOURCE 5
-#define SA_SCOPE 6
-#define SA_DEST 7
-#define SA_IFNAME 8
-#define SA_IFINDEX 9
-
struct f_tree {
struct f_tree *left, *right;
@@ -291,12 +382,12 @@ struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type);
/* Bird Tests */
struct f_bt_test_suite {
node n; /* Node in config->tests */
- struct f_inst *fn; /* Root of function */
+ struct f_line *fn; /* Root of function */
const char *fn_name; /* Name of test */
const char *dsc; /* Description */
};
/* Hook for call bt_assert() function in configuration */
-extern void (*bt_assert_hook)(int result, struct f_inst *assert);
+extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
#endif
diff --git a/filter/filter_test.c b/filter/filter_test.c
index 32555d82..e19b0a75 100644
--- a/filter/filter_test.c
+++ b/filter/filter_test.c
@@ -40,8 +40,7 @@ parse_config_file(const void *filename_void)
static int
run_function(const void *parsed_fn_def)
{
- /* XXX: const -> non-const */
- struct f_inst *f = (struct f_inst *) parsed_fn_def;
+ const struct f_line *f = (const struct f_line *) parsed_fn_def;
linpool *tmp = lp_new_default(&root_pool);
struct f_val res;
@@ -52,7 +51,7 @@ run_function(const void *parsed_fn_def)
}
static void
-bt_assert_filter(int result, struct f_inst *assert)
+bt_assert_filter(int result, const struct f_line_item *assert)
{
int bt_suit_case_result = 1;
if (!result)
@@ -62,7 +61,7 @@ bt_assert_filter(int result, struct f_inst *assert)
bt_suit_case_result = 0;
}
- bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a[1].p);
+ bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, assert->s);
}
int
diff --git a/filter/interpret.m4 b/filter/interpret.m4
index d1c83389..829b48f6 100644
--- a/filter/interpret.m4
+++ b/filter/interpret.m4
@@ -10,7 +10,60 @@ m4_divert(-1)m4_dnl
# Common aliases
m4_define(DNL, `m4_dnl')
-m4_define(INST, `break; case $1:')
+m4_define(INST, `break; case $1:
+m4_ifelse(eval($2 > 0), `if (vstk.cnt < $2) runtime("Stack underflow");', `')
+vstk.cnt -= $2;
+')
+m4_define(ARG, `if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)')
+
+m4_define(RESULT_OK, `vstk.cnt++')
+m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
+m4_define(RESULT_VAL, `do { res = $1; RESULT_OK; } while (0)')
+
+m4_define(LINEX, `do {
+ estk.item[estk.cnt].pos = 0;
+ estk.item[estk.cnt].line = $1;
+ estk.item[estk.cnt].ventry = vstk.cnt;
+ estk.item[estk.cnt].emask = 0;
+ estk.cnt++;
+} while (0)')
+
+m4_define(LINE, `do {
+ if (what->lines[$2]) {
+ estk.item[estk.cnt].pos = 0;
+ estk.item[estk.cnt].line = what->lines[$2];
+ estk.item[estk.cnt].ventry = vstk.cnt;
+ estk.item[estk.cnt].emask = 0;
+ estk.cnt++;
+ }
+} while (0)')
+
+m4_define(LINEP, LINE($1, $2))
+
+m4_define(ARG_ANY, `')
+
+m4_define(SYMBOL, `const struct symbol *sym = what->sym')
+
+m4_define(VALI, `res = *what->vp')
+m4_define(VALP, `res = *what->vp')
+m4_define(FRET, `enum filter_return fret = what->fret')
+m4_define(ECS, `enum ec_subtype ecs = what->ecs')
+m4_define(RTC, `struct rtable *table = what->rtc->table')
+m4_define(STATIC_ATTR, `struct f_static_attr sa = what->sa')
+m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da')
+m4_define(POSTFIXIFY, `')
+m4_define(LINE_SIZE, `')
+m4_define(SAME, `')
+m4_define(COUNT, `')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_divert(1)
m4_changequote([[,]])
-m4_divert(0)
+
diff --git a/filter/line-size.m4 b/filter/line-size.m4
new file mode 100644
index 00000000..0c005fa1
--- /dev/null
+++ b/filter/line-size.m4
@@ -0,0 +1,30 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Line size counting
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1: cnt += 1;
+m4_divert(-1)')
+m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/postfixify.m4 b/filter/postfixify.m4
new file mode 100644
index 00000000..8c96ba64
--- /dev/null
+++ b/filter/postfixify.m4
@@ -0,0 +1,55 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Converting instructions trees to instruction lines
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what->fi_code;
+dest->items[pos].lineno = what->lineno;')
+
+m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER
+break; case $1:
+m4_divert(-1)'))
+m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_divert(-1)')
+m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_divert(-1)')
+m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p;
+m4_divert(-1)')
+m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p;
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val);
+m4_divert(-1)')
+m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def;
+m4_divert(-1)')
+m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i;
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc;
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa;
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da;
+m4_divert(-1)')
+m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->a[$1-1].i;
+m4_divert(-1)')
+m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+POSTFIXIFY_TRAILER
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/same.m4 b/filter/same.m4
new file mode 100644
index 00000000..73f2d1c3
--- /dev/null
+++ b/filter/same.m4
@@ -0,0 +1,56 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Filter Comparator Generator
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1:
+m4_divert(-1)')
+
+m4_define(ARG, `')
+m4_define(ARG_ANY, `')
+
+m4_define(LINE, `m4_divert(1)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0;
+m4_divert(-1)')
+m4_define(LINEP, LINE)
+
+m4_define(SYMBOL, `m4_divert(1){
+ const struct symbol *s1 = f1->sym, *s2 = f2->sym;
+ if (strcmp(s1->name, s2->name)) return 0;
+ if (s1->class != s2->class) return 0;
+}
+m4_divert(-1)')
+
+m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0;
+m4_divert(-1)')
+m4_define(VALP, `')
+
+m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0;
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)if (f1->ecs != f2->ecs) return 0;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0;
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)if (f1->sa.sa_code != f2->sa.sa_code) return 0;
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)if (f1->da.ea_code != f2->da.ea_code) return 0;
+m4_divert(-1)')
+
+m4_define(SAME, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff);
+')
+
+m4_divert(1)
+m4_changequote([[,]])
+
diff --git a/filter/tree.c b/filter/tree.c
index f8379fa8..80e1d395 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -23,15 +23,15 @@
* Both set matching and |switch() { }| construction is implemented using this function,
* thus both are as fast as they can be.
*/
-struct f_tree *
-find_tree(struct f_tree *t, struct f_val val)
+const struct f_tree *
+find_tree(const struct f_tree *t, const struct f_val *val)
{
if (!t)
return NULL;
- if ((val_compare(t->from, val) != 1) &&
- (val_compare(t->to, val) != -1))
+ if ((val_compare(&(t->from), val) != 1) &&
+ (val_compare(&(t->to), val) != -1))
return t;
- if (val_compare(t->from, val) == -1)
+ if (val_compare(&(t->from), val) == -1)
return find_tree(t->right, val);
else
return find_tree(t->left, val);
@@ -56,7 +56,7 @@ build_tree_rec(struct f_tree **buf, int l, int h)
static int
tree_compare(const void *p1, const void *p2)
{
- return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
+ return val_compare(&((* (struct f_tree **) p1)->from), &((* (struct f_tree **) p2)->from));
}
/**
@@ -119,39 +119,39 @@ f_new_tree(void)
* Compares two trees and returns 1 if they are same
*/
int
-same_tree(struct f_tree *t1, struct f_tree *t2)
+same_tree(const struct f_tree *t1, const struct f_tree *t2)
{
if ((!!t1) != (!!t2))
return 0;
if (!t1)
return 1;
- if (val_compare(t1->from, t2->from))
+ if (val_compare(&(t1->from), &(t2->from)))
return 0;
- if (val_compare(t1->to, t2->to))
+ if (val_compare(&(t1->to), &(t2->to)))
return 0;
if (!same_tree(t1->left, t2->left))
return 0;
if (!same_tree(t1->right, t2->right))
return 0;
- if (!i_same(t1->data, t2->data))
+ if (!f_same(t1->data, t2->data))
return 0;
return 1;
}
static void
-tree_node_format(struct f_tree *t, buffer *buf)
+tree_node_format(const struct f_tree *t, buffer *buf)
{
if (t == NULL)
return;
tree_node_format(t->left, buf);
- val_format(t->from, buf);
- if (val_compare(t->from, t->to) != 0)
+ val_format(&(t->from), buf);
+ if (val_compare(&(t->from), &(t->to)) != 0)
{
buffer_puts(buf, "..");
- val_format(t->to, buf);
+ val_format(&(t->to), buf);
}
buffer_puts(buf, ", ");
@@ -159,7 +159,7 @@ tree_node_format(struct f_tree *t, buffer *buf)
}
void
-tree_format(struct f_tree *t, buffer *buf)
+tree_format(const struct f_tree *t, buffer *buf)
{
buffer_puts(buf, "[");
diff --git a/filter/tree_test.c b/filter/tree_test.c
index 5b22a9fe..f3e8ce49 100644
--- a/filter/tree_test.c
+++ b/filter/tree_test.c
@@ -226,8 +226,8 @@ t_find(void)
};
for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++)
{
- struct f_tree *found_tree = find_tree(tree, looking_up_value);
- bt_assert((val_compare(looking_up_value, found_tree->from) == 0) && (val_compare(looking_up_value, found_tree->to) == 0));
+ const struct f_tree *found_tree = find_tree(tree, &looking_up_value);
+ bt_assert((val_compare(&looking_up_value, &(found_tree->from)) == 0) && (val_compare(&looking_up_value, &(found_tree->to)) == 0));
}
}
@@ -278,11 +278,11 @@ t_find_ranges(void)
for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count)
{
- struct f_tree *found_tree = find_tree(tree, needle);
+ const struct f_tree *found_tree = find_tree(tree, &needle);
bt_debug("searching: %u \n", *i);
bt_assert(
- (val_compare(needle, found_tree->from) == 0) || (val_compare(needle, found_tree->to) == 0) ||
- ((val_compare(needle, found_tree->from) == 1) && (val_compare(needle, found_tree->to) == -1))
+ (val_compare(&needle, &(found_tree->from)) == 0) || (val_compare(&needle, &(found_tree->to)) == 0) ||
+ ((val_compare(&needle, &(found_tree->from)) == 1) && (val_compare(&needle, &(found_tree->to)) == -1))
);
}
}
diff --git a/filter/trie.c b/filter/trie.c
index adcfcdf3..a279e38c 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -220,7 +220,7 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
}
static int
-trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
+trie_match_prefix(const struct f_trie *t, ip_addr px, uint plen)
{
ip_addr pmask = ipa_mkmask(plen);
ip_addr paddr = ipa_and(px, pmask);
@@ -229,7 +229,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
return t->zero;
int plentest = plen - 1;
- struct f_trie_node *n = t->root;
+ const struct f_trie_node *n = t->root;
while(n)
{
@@ -264,7 +264,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
* is such prefix pattern in the trie.
*/
int
-trie_match_net(struct f_trie *t, const net_addr *n)
+trie_match_net(const struct f_trie *t, const net_addr *n)
{
uint add = 0;
@@ -279,7 +279,7 @@ trie_match_net(struct f_trie *t, const net_addr *n)
}
static int
-trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
+trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2)
{
if ((t1 == NULL) && (t2 == NULL))
return 1;
@@ -303,13 +303,13 @@ trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
* Compares two tries and returns 1 if they are same
*/
int
-trie_same(struct f_trie *t1, struct f_trie *t2)
+trie_same(const struct f_trie *t1, const struct f_trie *t2)
{
return (t1->zero == t2->zero) && trie_node_same(t1->root, t2->root);
}
static void
-trie_node_format(struct f_trie_node *t, buffer *buf)
+trie_node_format(const struct f_trie_node *t, buffer *buf)
{
if (t == NULL)
return;
@@ -329,7 +329,7 @@ trie_node_format(struct f_trie_node *t, buffer *buf)
* Prints the trie to the supplied buffer.
*/
void
-trie_format(struct f_trie *t, buffer *buf)
+trie_format(const struct f_trie *t, buffer *buf)
{
buffer_puts(buf, "[");