Filter: Improve handling of stack frames in filter bytecode

When f_line is done, we have to pop the stack frame. The old code just
removed nominal number of args/vars. Change it to use stored ventry value
modified by number of returned values. This allows to allocate variables
on a stack frame during execution of f_lines instead of just at start.

But we need to know the number of returned values for a f_line. It is 1
for term, 0 for cmd. Store that to f_line during linearization.
This commit is contained in:
Ondrej Zajicek (work) 2022-03-09 02:32:29 +01:00 committed by Ondrej Zajicek
parent f31f4e6eef
commit a2527ee53d
9 changed files with 26 additions and 24 deletions

View file

@ -153,14 +153,14 @@ conf: definition ;
definition: definition:
DEFINE symbol '=' term ';' { DEFINE symbol '=' term ';' {
struct f_val *val = cfg_allocz(sizeof(struct f_val)); struct f_val *val = cfg_allocz(sizeof(struct f_val));
if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); if (f_eval(f_linearize($4, 1), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
} }
; ;
expr: expr:
NUM NUM
| '(' term ')' { $$ = f_eval_int(f_linearize($2)); } | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
| CF_SYM_KNOWN { | CF_SYM_KNOWN {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected"); if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
$$ = SYM_VAL($1).i; } $$ = SYM_VAL($1).i; }

View file

@ -329,7 +329,7 @@ filter_def:
conf: filter_eval ; conf: filter_eval ;
filter_eval: filter_eval:
EVAL term { f_eval_int(f_linearize($2)); } EVAL term { f_eval_int(f_linearize($2, 1)); }
; ;
conf: custom_attr ; conf: custom_attr ;
@ -453,7 +453,7 @@ where_filter:
function_body: function_body:
function_vars '{' cmds '}' { function_vars '{' cmds '}' {
$$ = f_linearize($3); $$ = f_linearize($3, 0);
$$->vars = $1; $$->vars = $1;
} }
; ;
@ -537,7 +537,7 @@ set_atom:
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' { | '(' term ')' {
if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
} }
| CF_SYM_KNOWN { | CF_SYM_KNOWN {
@ -549,13 +549,13 @@ set_atom:
switch_atom: switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; } NUM { $$.type = T_INT; $$.val.i = $1; }
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); } | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2, 1)); }
| fipa { $$ = $1; } | fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
; ;
cnum: cnum:
term { $$ = f_eval_int(f_linearize($1)); } term { $$ = f_eval_int(f_linearize($1, 1)); }
pair_item: pair_item:
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
@ -642,7 +642,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body switch_items ':' cmds { | switch_body switch_items ':' cmds {
/* Fill data fields */ /* Fill data fields */
struct f_tree *t; struct f_tree *t;
struct f_line *line = f_linearize($4); struct f_line *line = f_linearize($4, 0);
for (t = $2; t; t = t->left) for (t = $2; t; t = t->left)
t->data = line; t->data = line;
$$ = f_merge_items($1, $2); $$ = f_merge_items($1, $2);
@ -651,7 +651,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
struct f_tree *t = f_new_tree(); struct f_tree *t = f_new_tree();
t->from.type = t->to.type = T_VOID; t->from.type = t->to.type = T_VOID;
t->right = t; t->right = t;
t->data = f_linearize($3); t->data = f_linearize($3, 0);
$$ = f_merge_items($1, t); $$ = f_merge_items($1, t);
} }
; ;

View file

@ -216,7 +216,7 @@ whati->f$1 = f$1;
FID_DUMP_BODY()m4_dnl FID_DUMP_BODY()m4_dnl
f_dump_line(item->fl$1, indent + 1); f_dump_line(item->fl$1, indent + 1);
FID_LINEARIZE_BODY()m4_dnl FID_LINEARIZE_BODY()m4_dnl
item->fl$1 = f_linearize(whati->f$1); item->fl$1 = f_linearize(whati->f$1, $2);
FID_SAME_BODY()m4_dnl FID_SAME_BODY()m4_dnl
if (!f_same(f1->fl$1, f2->fl$1)) return 0; if (!f_same(f1->fl$1, f2->fl$1)) return 0;
FID_ITERATE_BODY()m4_dnl FID_ITERATE_BODY()m4_dnl
@ -568,7 +568,7 @@ FID_WR_PUT(8)
} }
struct f_line * struct f_line *
f_linearize_concat(const struct f_inst * const inst[], uint count) f_linearize_concat(const struct f_inst * const inst[], uint count, uint results)
{ {
uint len = 0; uint len = 0;
for (uint i=0; i<count; i++) for (uint i=0; i<count; i++)
@ -580,6 +580,8 @@ f_linearize_concat(const struct f_inst * const inst[], uint count)
for (uint i=0; i<count; i++) for (uint i=0; i<count; i++)
out->len = linearize(out, inst[i], out->len); out->len = linearize(out, inst[i], out->len);
out->results = results;
#ifdef LOCAL_DEBUG #ifdef LOCAL_DEBUG
f_dump_line(out, 0); f_dump_line(out, 0);
#endif #endif

View file

@ -64,7 +64,7 @@
* m4_dnl ARG_ANY(num); argument with no type check accessible by v1, v2, v3 * m4_dnl ARG_ANY(num); argument with no type check accessible by v1, v2, v3
* m4_dnl ARG_TYPE(num, type); just declare the type of argument * m4_dnl ARG_TYPE(num, type); just declare the type of argument
* m4_dnl VARARG; variable-length argument list; accessible by vv(i) and whati->varcount * m4_dnl VARARG; variable-length argument list; accessible by vv(i) and whati->varcount
* m4_dnl LINE(num, unused); this argument has to be converted to its own f_line * m4_dnl LINE(num, out); this argument has to be converted to its own f_line
* m4_dnl SYMBOL; symbol handed from config * m4_dnl SYMBOL; symbol handed from config
* m4_dnl STATIC_ATTR; static attribute definition * m4_dnl STATIC_ATTR; static attribute definition
* m4_dnl DYNAMIC_ATTR; dynamic attribute definition * m4_dnl DYNAMIC_ATTR; dynamic attribute definition
@ -298,7 +298,7 @@
RESULT_TYPE(T_BOOL); RESULT_TYPE(T_BOOL);
if (v1.val.i) if (v1.val.i)
LINE(2,0); LINE(2,1);
else else
RESULT_VAL(v1); RESULT_VAL(v1);
} }
@ -308,7 +308,7 @@
RESULT_TYPE(T_BOOL); RESULT_TYPE(T_BOOL);
if (!v1.val.i) if (!v1.val.i)
LINE(2,0); LINE(2,1);
else else
RESULT_VAL(v1); RESULT_VAL(v1);
} }
@ -536,7 +536,7 @@
if (v1.val.i) if (v1.val.i)
LINE(2,0); LINE(2,0);
else else
LINE(3,1); LINE(3,0);
} }
INST(FI_PRINT, 0, 0) { INST(FI_PRINT, 0, 0) {

View file

@ -46,14 +46,15 @@ struct f_line {
uint len; /* Line length */ uint len; /* Line length */
u8 args; /* Function: Args required */ u8 args; /* Function: Args required */
u8 vars; u8 vars;
u8 results; /* Results left on stack: cmd -> 0, term -> 1 */
struct f_arg *arg_list; struct f_arg *arg_list;
struct f_line_item items[0]; /* The items themselves */ struct f_line_item items[0]; /* The items themselves */
}; };
/* Convert the f_inst infix tree to the f_line structures */ /* Convert the f_inst infix tree to the f_line structures */
struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count); struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count, uint results);
static inline struct f_line *f_linearize(const struct f_inst *root) static inline struct f_line *f_linearize(const struct f_inst *root, uint results)
{ return f_linearize_concat(&root, 1); } { return f_linearize_concat(&root, 1, results); }
void f_dump_line(const struct f_line *, uint indent); void f_dump_line(const struct f_line *, uint indent);

View file

@ -37,7 +37,7 @@ struct filter *f_new_where(struct f_inst *where)
f_new_inst(FI_DIE, F_REJECT)); f_new_inst(FI_DIE, F_REJECT));
struct filter *f = cfg_allocz(sizeof(struct filter)); struct filter *f = cfg_allocz(sizeof(struct filter));
f->root = f_linearize(cond); f->root = f_linearize(cond, 0);
return f; return f;
} }

View file

@ -215,8 +215,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
} }
/* End of current line. Drop local variables before exiting. */ /* End of current line. Drop local variables before exiting. */
fstk->vcnt -= curline.line->vars; fstk->vcnt = curline.ventry + curline.line->results;
fstk->vcnt -= curline.line->args;
fstk->ecnt--; fstk->ecnt--;
} }

View file

@ -165,7 +165,7 @@ rtrid:
idval: idval:
NUM { $$ = $1; } NUM { $$ = $1; }
| '(' term ')' { $$ = f_eval_int(f_linearize($2)); } | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
| IP4 { $$ = ip4_to_u32($1); } | IP4 { $$ = ip4_to_u32($1); }
| CF_SYM_KNOWN { | CF_SYM_KNOWN {
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
@ -860,7 +860,7 @@ CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])
{ filters_dump_all(); cli_msg(0, ""); } ; { filters_dump_all(); cli_msg(0, ""); } ;
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]]) CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
{ cmd_eval(f_linearize($2)); } ; { cmd_eval(f_linearize($2, 1)); } ;
CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]]) CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) { CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) {

View file

@ -40,7 +40,7 @@ static_route_finish(void)
if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest) if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
cf_error("Unexpected or missing nexthop/type"); cf_error("Unexpected or missing nexthop/type");
this_srt->cmds = f_linearize(this_srt_cmds); this_srt->cmds = f_linearize(this_srt_cmds, 0);
} }
CF_DECLS CF_DECLS