summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/conf.h2
-rw-r--r--conf/confbase.Y4
-rw-r--r--filter/Makefile10
-rw-r--r--filter/config.Y343
-rw-r--r--filter/dump.m44
-rw-r--r--filter/f-inst.c101
-rw-r--r--filter/f-inst.h124
-rw-r--r--filter/f-util.c98
-rw-r--r--filter/filter.c30
-rw-r--r--filter/filter.h222
-rw-r--r--filter/interpret.m411
-rw-r--r--filter/line-size.m414
-rw-r--r--filter/new.m484
-rw-r--r--filter/postfixify.m439
-rw-r--r--filter/same.m44
-rw-r--r--filter/struct.m467
-rw-r--r--nest/attrs.h2
-rw-r--r--proto/static/config.Y12
18 files changed, 744 insertions, 427 deletions
diff --git a/conf/conf.h b/conf/conf.h
index 427569fd..6138ccec 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -107,7 +107,7 @@ struct symbol {
struct sym_scope *scope;
int class;
int aux;
- void *aux2;
+ uint aux2;
void *def;
char name[1];
};
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 492ecd08..13f6aade 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -49,6 +49,10 @@ CF_DECLS
struct rtable_config *r;
struct channel_config *cc;
struct f_inst *x;
+ struct f_inst *xp[2];
+ struct { struct f_inst *inst; uint count; } xc;
+ enum filter_return fret;
+ enum ec_subtype ecs;
struct f_dynamic_attr fda;
struct f_static_attr fsa;
struct filter *f;
diff --git a/filter/Makefile b/filter/Makefile
index c74ba2f3..15f2c3d0 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -1,4 +1,4 @@
-src := filter.c f-util.c tree.c trie.c
+src := filter.c f-util.c tree.c trie.c f-inst-new.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
@@ -17,10 +17,16 @@ $(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp
$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+$(o)f-inst-struct.h: $(s)struct.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-new.c: $(s)new.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
+$(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 $(o)f-inst-struct.h
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 a79b1582..607f534e 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -16,6 +16,8 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
+#define f_generate_complex(fi_code, da, arg) \
+ f_new_inst(FI_EA_SET, da, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg))
/*
* Sets and their items are during parsing handled as lists, linked
@@ -158,30 +160,29 @@ 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_CONSTANT);
+ struct f_val empty;
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
- e->val = f_const_empty_path;
+ empty = f_const_empty_path;
break;
case EAF_TYPE_INT_SET:
- e->val = f_const_empty_clist;
+ empty = f_const_empty_clist;
break;
case EAF_TYPE_EC_SET:
- e->val = f_const_empty_eclist;
+ empty = f_const_empty_eclist;
break;
case EAF_TYPE_LC_SET:
- e->val = f_const_empty_lclist;
+ empty = f_const_empty_lclist;
break;
default:
cf_error("Can't empty that attribute");
}
- struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
- s->a[0].p = e;
- return s;
+ return f_new_inst(FI_EA_SET, dyn, f_new_inst(FI_CONSTANT, empty));
}
+#if 0
static inline struct f_inst *
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
@@ -332,6 +333,8 @@ f_generate_path_mask(struct f_inst *t)
return pmc;
}
+#endif
+
/*
* Remove all new lines and doubled whitespaces
* and convert all tabulators to spaces
@@ -380,21 +383,10 @@ assert_copy_expr(const char *start, size_t len)
static struct f_inst *
assert_done(struct f_inst *expr, const char *start, const char *end)
{
- struct f_inst *i;
- i = f_new_inst(FI_ASSERT);
- i->a[0].p = expr;
-
- if (end >= start)
- {
- i->a[1].p = assert_copy_expr(start, end - start + 1);
- }
- else
- {
- /* this is a break of lexer buffer */
- i->a[1].p = "???";
- }
-
- return i;
+ return f_new_inst(FI_ASSERT, expr,
+ (end >= start) ?
+ assert_copy_expr(start, end - start + 1)
+ : "???");
}
CF_DECLS
@@ -420,17 +412,20 @@ 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 bgp_path bgp_path_tail
+%type <xc> function_params declsn
+%type <xp> cmds_int function_body
+%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail one_decl decls
%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter filter_body where_filter
-%type <i> type break_command ec_kind
+%type <i> type
+%type <ecs> ec_kind
+%type <fret> break_command
%type <i32> cnum
%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
%type <trie> fprefix_set
%type <v> set_atom switch_atom fipa
%type <px> fprefix
-%type <s> decls declsn one_decl function_params
%type <t> get_cf_position
CF_GRAMMAR
@@ -515,8 +510,7 @@ one_decl:
val->type = T_VOID;
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
DBG( "New variable %s type %x\n", $2->name, $1 );
- $2->aux2 = NULL;
- $$=$2;
+ $$ = f_new_inst(FI_SET, NULL, $2);
}
;
@@ -524,24 +518,29 @@ one_decl:
decls: /* EMPTY */ { $$ = NULL; }
| one_decl ';' decls {
$$ = $1;
- $$->aux2 = $3;
+ f_inst_next($$, $3);
}
;
-/* Declarations that have no ';' at the end. */
-declsn: one_decl { $$ = $1; }
+/* Declarations that have no ';' at the end. Beware; these are reversed. */
+declsn: one_decl { $$.inst = $1; $$.count = 1; }
| one_decl ';' declsn {
- $$ = $1;
- $$->aux2 = $3;
+ $$ = $3;
+ $$.count++;
+ f_inst_next($$.inst, $1);
}
;
filter_body:
function_body {
- struct filter *f = cfg_alloc(sizeof(struct filter));
- f->name = NULL;
- f->root = f_postfixify($1);
- $$ = f;
+ $$ = cfg_alloc(sizeof(struct filter));
+ $$->name = NULL;
+ if ($1[0]) {
+ const struct f_inst *inst[2] = { $1[0], $1[1] };
+ $$->root = f_postfixify_concat(inst, 2);
+ }
+ else
+ $$->root = f_postfixify($1[1]);
}
;
@@ -556,42 +555,19 @@ filter:
where_filter:
WHERE term {
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
- struct filter *f = cfg_alloc(sizeof(struct filter));
- 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 = f_postfixify(&i);
- $$ = f;
+ $$ = f_new_where($2);
}
;
function_params:
- '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
- | '(' ')' { $$=NULL; }
+ '(' declsn ')' { $$ = $2; }
+ | '(' ')' { $$.inst = NULL; $$.count = 0; }
;
function_body:
decls '{' cmds '}' {
- if ($1) {
- /* Prepend instruction to clear local variables */
- $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
- $$->a[0].p = $1;
- $$->next = $3;
- } else
- $$ = $3;
+ $$[0] = $1 ? f_clear_local_vars($1) : NULL;
+ $$[1] = $3;
}
;
@@ -601,10 +577,26 @@ function_def:
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
cf_push_scope($2);
} function_params function_body {
- 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;
+ const struct f_inst *catlist[4];
+ uint count = 0;
+
+ /* Argument setters */
+ if ($4.inst)
+ catlist[count++] = $4.inst;
+
+ /* Local var clearers */
+ if ($5[0])
+ catlist[count++] = $5[0];
+
+ /* Return void if no return is needed */
+ catlist[count++] = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
+
+ /* Function body itself */
+ if ($5[1])
+ catlist[count++] = $5[1];
+
+ $2->def = f_postfixify_concat(catlist, count);
+ $2->aux2 = $4.count;
DBG("Hmm, we've got one function here - %s\n", $2->name);
cf_pop_scope();
}
@@ -612,15 +604,12 @@ function_def:
/* Programs */
-/* Hack: $$ of cmds_int is the last node.
- $$->next of cmds_int is temporary used for the first node */
-
cmds: /* EMPTY */ { $$ = NULL; }
- | cmds_int { $$ = $1->next; $1->next = NULL; }
+ | cmds_int { $$ = $1[0]; }
;
-cmds_int: cmd { $$ = $1; $1->next = $1; }
- | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
+cmds_int: cmd { $$[0] = $$[1] = $1; }
+ | cmds_int cmd { $$[1] = $2; f_inst_next($1[1], $2); $$[0] = $1[0]; }
;
block:
@@ -784,37 +773,36 @@ bgp_path:
;
bgp_path_tail:
- 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; }
+ NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); f_inst_next($$, $2); }
+ | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); f_inst_next($$, $4); }
+ | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); f_inst_next($$, $2); }
+ | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); f_inst_next($$, $2); }
+ | bgp_path_expr bgp_path_tail { $$ = $1; f_inst_next($$, $2); }
| { $$ = NULL; }
;
constant:
- NUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_INT, .val.i = $1, }; }
- | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 1, }; }
- | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 0, }; }
- | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_STRING, .val.s = $1, }; }
- | fipa { $$ = f_new_inst(FI_CONSTANT); $$->val = $1; }
- | VPN_RD { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_RD, .val.ec = $1, }; }
- | net_ { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_NET, .val.net = $1, }; }
+ NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
+ | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
+ | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
+ | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
+ | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
+ | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
+ | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
| '[' set_items ']' {
DBG( "We've got a set here..." );
- $$ = f_new_inst(FI_CONSTANT);
- $$->val = (struct f_val) { .type = T_SET, .val.t = build_tree($2), };
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
DBG( "ook\n" );
}
- | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }; }
- | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }; }
+ | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
+ | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
;
constructor:
- '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
- | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
- | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
- | bgp_path { $$ = f_generate_path_mask($1); }
+ '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
+ | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
+ | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
+ | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); }
;
@@ -823,23 +811,7 @@ rtadot: /* EMPTY, we are not permitted RTA. prefix */
function_call:
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;
- }
+ $$ = f_new_inst(FI_CALL, $1, $3);
}
;
@@ -847,15 +819,13 @@ symbol:
SYM {
switch ($1->class & 0xffff) {
case SYM_CONSTANT_RANGE:
- $$ = f_new_inst(FI_CONSTANT_INDIRECT);
- $$->a[0].p = $1;
+ $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def);
break;
case SYM_VARIABLE_RANGE:
- $$ = f_new_inst(FI_VARIABLE);
- $$->a[0].p = $1;
+ $$ = f_new_inst(FI_VARIABLE, $1);
break;
case SYM_ATTRIBUTE:
- $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
+ $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
break;
default:
cf_error("%s: variable expected.", $1->name);
@@ -876,22 +846,22 @@ static_attr:
term:
'(' term ')' { $$ = $2; }
- | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; }
- | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; }
- | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; }
- | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; }
- | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; }
+ | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
+ | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
+ | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
+ | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
+ | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
+ | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
+ | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
+ | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
+ | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
+ | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
+ | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
+ | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
+ | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
+ | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
+ | '!' term { $$ = f_new_inst(FI_NOT, $2); }
+ | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
| symbol { $$ = $1; }
| constant { $$ = $1; }
@@ -899,22 +869,22 @@ term:
| PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
- | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
+ | rtadot static_attr { $$ = f_new_inst(FI_RTA_GET, $2); }
- | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
+ | rtadot dynamic_attr { $$ = f_new_inst(FI_EA_GET, $2); }
- | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; }
- | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; }
- | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; }
- | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; }
- | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; }
- | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; }
- | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; }
- | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; }
- | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; }
- | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; }
- | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; }
- | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; }
+ | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
+ | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
+ | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
+ | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
+ | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
+ | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
+ | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
+ | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
+ | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
+ | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
+ | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
+ | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
/* Communities */
/* This causes one shift/reduce conflict
@@ -924,19 +894,19 @@ term:
| rtadot dynamic_attr '.' RESET{ }
*/
- | '+' 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); $$->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; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
+ | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
- | 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; }
+ | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
- | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
+ | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
/* | term '.' LEN { $$->code = P('P','l'); } */
@@ -953,30 +923,25 @@ break_command:
;
print_one:
- term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; }
+ term { $$ = f_new_inst(FI_PRINT, $1); }
;
print_list: /* EMPTY */ { $$ = NULL; }
| print_one { $$ = $1; }
| print_one ',' print_list {
if ($1) {
- $1->next = $3;
+ f_inst_next($1, $3);
$$ = $1;
} else $$ = $3;
}
;
var_listn: term {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = NULL;
- $$->a[1].p = $1;
- $$->next = NULL;
+ $$ = $1;
}
| term ',' var_listn {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = NULL;
- $$->a[1].p = $1;
- $$->next = $3;
+ $$ = $1;
+ f_inst_next($$, $3);
}
;
@@ -986,58 +951,42 @@ var_list: /* EMPTY */ { $$ = NULL; }
cmd:
IF term THEN block {
- $$ = f_new_inst(FI_CONDITION);
- $$->a[0].p = $2;
- $$->a[1].p = $4;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
}
| IF term THEN block ELSE block {
- $$ = f_new_inst(FI_CONDITION);
- $$->a[0].p = $2;
- $$->a[1].p = $4;
- $$->a[2].p = $6;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
}
| SYM '=' term ';' {
DBG( "Ook, we'll set value\n" );
if ($1->class == SYM_ATTRIBUTE) {
- $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def));
- $$->a[0].p = $3;
+ $$ = f_new_inst(FI_EA_SET, *((struct f_dynamic_attr *) $1->def), $3);
} else if (($1->class & ~T_MASK) == SYM_VARIABLE) {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = $1;
- $$->a[1].p = $3;
+ $$ = f_new_inst(FI_SET, $3, $1);
} else
cf_error( "Symbol `%s' is read-only.", $1->name );
}
| RETURN term ';' {
DBG( "Ook, we'll return the value\n" );
- $$ = f_new_inst(FI_RETURN);
- $$->a[0].p = $2;
+ $$ = f_new_inst(FI_RETURN, $2);
}
| rtadot dynamic_attr '=' term ';' {
- $$ = f_new_inst_da(FI_EA_SET, $2);
- $$->a[0].p = $4;
+ $$ = f_new_inst(FI_EA_SET, $2, $4);
}
| rtadot static_attr '=' term ';' {
- $$ = f_new_inst_sa(FI_RTA_SET, $2);
- if ($$->sa.readonly)
+ if ($2.readonly)
cf_error( "This static attribute is read-only.");
- $$->a[0].p = $4;
+ $$ = f_new_inst(FI_RTA_SET, $2, $4);
}
| PREFERENCE '=' term ';' {
- $$ = f_new_inst(FI_PREF_SET);
- $$->a[0].p = $3;
+ $$ = f_new_inst(FI_PREF_SET, $3);
}
| UNSET '(' rtadot dynamic_attr ')' ';' {
- $$ = f_new_inst_da(FI_EA_SET, $4);
- $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
- $$->a[0].p = NULL;
+ $$ = f_new_inst(FI_EA_UNSET, $4);
}
- | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
- | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; }
+ | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
+ | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
| CASE term '{' switch_body '}' {
- $$ = f_new_inst(FI_SWITCH);
- $$->a[0].p = $2;
- $$->a[1].p = build_tree( $4 );
+ $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
}
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
diff --git a/filter/dump.m4 b/filter/dump.m4
index 913a7652..cb8e5c5f 100644
--- a/filter/dump.m4
+++ b/filter/dump.m4
@@ -17,9 +17,9 @@ 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_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(&item->val));
m4_divert(-1)')
-m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
+m4_define(VAR, `m4_divert(1)debug("%svar %s: value %s\n", INDENT, item->sym->name, 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)')
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 02c88409..ae2b5289 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -108,6 +108,17 @@
INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
ARG_ANY(1);
COUNT(2);
+
+ NEW([[]], [[
+ uint len = 0;
+ uint dyn = 0;
+ for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
+ if (tt->fi_code != FI_CONSTANT)
+ dyn++;
+
+ WHAT().count = len;
+ ]]);
+
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);
@@ -239,13 +250,11 @@
RESULT_OK;
}
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; ]]);
+ VAR;
RESULT_OK;
}
INST(FI_CONSTANT_INDIRECT, 0, 1) {
- VALP(1);
- SAME([[if (!val_same(f1->vp, f2->vp)) return 0; ]]);
+ VALP;
RESULT_OK;
}
INST(FI_PRINT, 1, 0) {
@@ -261,15 +270,16 @@
}
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;
- }
+ {
+ uint opos = pos;
]]);
- LINE_SIZE([[
- if (what->a[0].p) {
- cnt += inst_line_size(what->a[0].p);
- }
+
+ ARG_ANY(1);
+
+ POSTFIXIFY([[
+ if (opos < pos)
+ dest->items[pos].flags |= FIF_PRINTED;
+ }
]]);
FRET(2);
@@ -544,11 +554,6 @@
runtime( "Setting lclist attribute to non-lclist value" );
l->attrs[0].u.ptr = v1.val.ad;
break;
- case EAF_TYPE_UNDEF:
- if (v1.type != T_VOID)
- runtime( "Setting void attribute to non-void value" );
- l->attrs[0].u.data = 0;
- break;
default: bug("Unknown type in e,S");
}
@@ -558,6 +563,28 @@
}
}
+ INST(FI_EA_UNSET, 0, 0) {
+ DYNAMIC_ATTR;
+ ACCESS_RTE;
+ ACCESS_EATTRS;
+
+ {
+ struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
+
+ l->next = NULL;
+ l->flags = EALF_SORTED;
+ l->count = 1;
+ l->attrs[0].id = da.ea_code;
+ l->attrs[0].flags = 0;
+ l->attrs[0].type = EAF_TYPE_UNDEF | EAF_TEMP | EAF_ORIGINATED | EAF_FRESH;
+ l->attrs[0].u.data = 0;
+
+ f_rta_cow(fs);
+ l->next = *fs->eattrs;
+ *fs->eattrs = l;
+ }
+ }
+
INST(FI_PREF_GET, 0, 1) {
ACCESS_RTE;
RESULT(T_INT, i, (*fs->rte)->pref);
@@ -660,6 +687,7 @@
if (!estk.cnt)
if (vstk.val[retpos].type == T_BOOL)
if (vstk.val[retpos].val.i)
+
return F_ACCEPT;
else
return F_REJECT;
@@ -674,28 +702,43 @@
}
INST(FI_CALL, 0, 1) {
- /* First push the code */
- LINEP(2,0);
+ /* Do not use the symbol on execution */
+ if (0) {
+ UNUSED SYMBOL;
+ }
+
+ /* Postfixify extracts the function body from the symbol */
+ POSTFIXIFY([[
+ dest->items[pos].lines[0] = what->sym->def;
+ ]]);
+
+ /* First push the body on stack */
+ LINEX(what->lines[0]);
curline.emask |= FE_RETURN;
/* Then push the arguments */
LINE(1,1);
+
+ NEW([[]], [[
+ if (sym->class != SYM_FUNCTION)
+ cf_error("You can't call something which is not a function. Really.");
+
+ uint count = 0;
+ for (const struct f_inst *inst = f1; inst; inst = inst->next)
+ count++;
+
+ if (count != sym->aux2)
+ cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count);
+ ]]);
}
INST(FI_DROP_RESULT, 1, 0) {
ARG_ANY(1);
}
- 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, 1, 0) {
ARG_ANY(1);
- POSTFIXIFY([[
- dest->items[pos].tree = what->a[1].p;
- ]]);
+ TREE;
const struct f_tree *t = find_tree(what->tree, &v1);
if (!t) {
v1.type = T_VOID;
@@ -940,8 +983,6 @@
INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
ARG(1, T_BOOL);
- POSTFIXIFY([[
- dest->items[pos].s = what->a[1].p;
- ]]);
+ STRING;
CALL(bt_assert_hook, res.val.i, what);
}
diff --git a/filter/f-inst.h b/filter/f-inst.h
new file mode 100644
index 00000000..5c3d1d58
--- /dev/null
+++ b/filter/f-inst.h
@@ -0,0 +1,124 @@
+/*
+ * BIRD Internet Routing Daemon -- Filter instructions
+ *
+ * (c) 2018--2019 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/* Filter instruction words */
+#define FI__TWOCHAR(a,b) ((a<<8) | b)
+#define FI__LIST \
+ F(FI_NOP, 0, '0') \
+ F(FI_ADD, 0, '+') \
+ F(FI_SUBTRACT, 0, '-') \
+ F(FI_MULTIPLY, 0, '*') \
+ F(FI_DIVIDE, 0, '/') \
+ F(FI_AND, 0, '&') \
+ F(FI_OR, 0, '|') \
+ F(FI_PAIR_CONSTRUCT, 'm', 'p') \
+ F(FI_EC_CONSTRUCT, 'm', 'c') \
+ F(FI_LC_CONSTRUCT, 'm', 'l') \
+ F(FI_PATHMASK_CONSTRUCT, 'm', 'P') \
+ F(FI_NEQ, '!', '=') \
+ F(FI_EQ, '=', '=') \
+ F(FI_LT, 0, '<') \
+ F(FI_LTE, '<', '=') \
+ F(FI_NOT, 0, '!') \
+ F(FI_MATCH, 0, '~') \
+ F(FI_NOT_MATCH, '!', '~') \
+ F(FI_DEFINED, 'd', 'e') \
+ F(FI_TYPE, 0, 'T') \
+ F(FI_IS_V4, 'I', 'i') \
+ F(FI_SET, 0, 's') \
+ F(FI_CONSTANT, 0, 'c') \
+ F(FI_VARIABLE, 0, 'V') \
+ F(FI_CONSTANT_INDIRECT, 0, 'C') \
+ F(FI_PRINT, 0, 'p') \
+ F(FI_CONDITION, 0, '?') \
+ F(FI_PRINT_AND_DIE, 'p', ',') \
+ F(FI_RTA_GET, 0, 'a') \
+ F(FI_RTA_SET, 'a', 'S') \
+ F(FI_EA_GET, 'e', 'a') \
+ F(FI_EA_SET, 'e', 'S') \
+ F(FI_PREF_GET, 0, 'P') \
+ F(FI_PREF_SET, 'P', 'S') \
+ F(FI_LENGTH, 0, 'L') \
+ F(FI_ROA_MAXLEN, 'R', 'M') \
+ F(FI_ROA_ASN, 'R', 'A') \
+ F(FI_SADR_SRC, 'n', 's') \
+ F(FI_IP, 'c', 'p') \
+ F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \
+ F(FI_AS_PATH_FIRST, 'a', 'f') \
+ F(FI_AS_PATH_LAST, 'a', 'l') \
+ 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_PATH_PREPEND, 'A', 'p') \
+ 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,
+FI__LIST
+#undef F
+ FI__MAX,
+} PACKED;
+
+/* Convert the instruction back to the enum name */
+const char *f_instruction_name(enum f_instruction_code fi);
+
+
+
+/* Instruction structure for config */
+struct f_inst {
+ const struct f_inst *next; /* Next instruction to be executed */
+ union { /* Instruction content */
+ struct { /* Instruction code for dispatching purposes */
+ enum f_instruction_code fi_code;
+ };
+
+ struct {
+ enum f_instruction_code fi_code_a;
+ const struct f_inst *p[3]; /* Three arguments at most */
+ };
+
+ struct {
+
+
+
+ struct {
+ enum f_instruction_code
+
+
+
+
+ enum f_iknst
+ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
+ union {
+
+ 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;
+};
+
diff --git a/filter/f-util.c b/filter/f-util.c
index 4f11a6d9..e94331b6 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -10,57 +10,15 @@
#include "nest/bird.h"
#include "conf/conf.h"
#include "filter/filter.h"
+#include "filter/f-inst-struct.h"
#include "lib/idm.h"
#include "nest/protocol.h"
#include "nest/route.h"
#define P(a,b) ((a<<8) | b)
-struct f_inst *
-f_new_inst(enum f_instruction_code fi_code)
-{
- struct f_inst * ret;
- ret = cfg_allocz(sizeof(struct f_inst));
- ret->fi_code = fi_code;
- ret->lineno = ifs->lino;
- return ret;
-}
-
-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->da = da;
- return ret;
-}
-
-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->sa = sa;
- return ret;
-}
-
-/*
- * Generate set_dynamic( operation( get_dynamic(), 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 *set_dyn = f_new_inst_da(FI_EA_SET, da),
- *oper = f_new_inst(fi_code),
- *get_dyn = f_new_inst_da(FI_EA_GET, da);
-
- oper->a[0].p = get_dyn;
- oper->a[1].p = argument;
-
- set_dyn->a[0].p = oper;
- return set_dyn;
-}
-
static const char * const f_instruction_name_str[] = {
-#define F(c,a,b) \
+#define F(c,...) \
[c] = #c,
FI__LIST
#undef F
@@ -88,6 +46,58 @@ filter_name(struct filter *filter)
return filter->name;
}
+void f_inst_next(struct f_inst *first, const struct f_inst *append)
+{
+ first->next = append;
+}
+
+struct filter *f_new_where(const struct f_inst *where)
+{
+ struct f_inst acc = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .lineno = ifs->lino,
+ .i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, },
+ };
+
+ struct f_inst rej = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .lineno = ifs->lino,
+ .i_FI_PRINT_AND_DIE = { .fret = F_REJECT, },
+ };
+
+ struct f_inst i = {
+ .fi_code = FI_CONDITION,
+ .lineno = ifs->lino,
+ .i_FI_CONDITION = {
+ .f1 = where,
+ .f2 = &acc,
+ .f3 = &rej,
+ },
+ };
+
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ f->name = NULL;
+ f->root = f_postfixify(&i);
+ return f;
+}
+
+struct f_inst *f_clear_local_vars(struct f_inst *decls)
+{
+ /* Prepend instructions to clear local variables */
+ struct f_inst *head = NULL;
+
+ for (const struct f_inst *si = decls; si; si = si->next) {
+ struct f_inst *cur = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
+ if (head)
+ f_inst_next(cur, head);
+ else
+ f_inst_next(cur, si);
+ head = cur; /* The first FI_CONSTANT put there */
+ }
+
+ return head;
+}
+
#define CA_KEY(n) n->name, n->fda.type
#define CA_NEXT(n) n->next
#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb))
diff --git a/filter/filter.c b/filter/filter.c
index 858d5fc5..a69d1b3d 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -47,6 +47,7 @@
#include "nest/attrs.h"
#include "conf/conf.h"
#include "filter/filter.h"
+#include "filter/f-inst-struct.h"
#define CMP_ERROR 999
@@ -614,11 +615,11 @@ 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)
+inst_line_size(const struct f_inst *what_)
{
uint cnt = 0;
- for ( ; what; what = what->next) {
- switch (what->fi_code) {
+ for ( ; what_; what_ = what_->next) {
+ switch (what_->fi_code) {
#include "filter/f-inst-line-size.c"
}
}
@@ -671,10 +672,10 @@ f_dump_line(const struct f_line *dest, int indent)
#endif
static uint
-postfixify(struct f_line *dest, const struct f_inst *what, uint pos)
+postfixify(struct f_line *dest, const struct f_inst *what_, uint pos)
{
- for ( ; what; what = what->next) {
- switch (what->fi_code) {
+ for ( ; what_; what_ = what_->next) {
+ switch (what_->fi_code) {
#include "filter/f-inst-postfixify.c"
}
pos++;
@@ -683,23 +684,16 @@ postfixify(struct f_line *dest, const struct f_inst *what, uint pos)
}
struct f_line *
-f_postfixify_concat(struct f_inst *first, ...)
+f_postfixify_concat(const struct f_inst * const inst[], uint count)
{
- 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);
+ for (uint i=0; i<count; i++)
+ len += inst_line_size(inst[i]);
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);
+ for (uint i=0; i<count; i++)
+ out->len = postfixify(out, inst[i], out->len);
f_dump_line(out, 0);
return out;
diff --git a/filter/filter.h b/filter/filter.h
index 87bd2c36..39f16e93 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -2,6 +2,7 @@
* BIRD Internet Routing Daemon -- Filters
*
* (c) 1999 Pavel Machek <pavel@ucw.cz>
+ * (c) 2018--2019 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -11,6 +12,7 @@
#include "lib/resource.h"
#include "lib/ip.h"
+#include "lib/macro.h"
#include "nest/route.h"
#include "nest/attrs.h"
@@ -115,71 +117,80 @@ struct f_static_attr {
int readonly:1; /* Don't allow writing */
};
-/* Filter instruction words */
-#define FI__TWOCHAR(a,b) ((a<<8) | b)
+/* 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 instruction declarations */
#define FI__LIST \
- F(FI_NOP, 0, '0') \
- F(FI_ADD, 0, '+') \
- F(FI_SUBTRACT, 0, '-') \
- F(FI_MULTIPLY, 0, '*') \
- F(FI_DIVIDE, 0, '/') \
- F(FI_AND, 0, '&') \
- F(FI_OR, 0, '|') \
- F(FI_PAIR_CONSTRUCT, 'm', 'p') \
- F(FI_EC_CONSTRUCT, 'm', 'c') \
- F(FI_LC_CONSTRUCT, 'm', 'l') \
- F(FI_PATHMASK_CONSTRUCT, 'm', 'P') \
- F(FI_NEQ, '!', '=') \
- F(FI_EQ, '=', '=') \
- F(FI_LT, 0, '<') \
- F(FI_LTE, '<', '=') \
- F(FI_NOT, 0, '!') \
- F(FI_MATCH, 0, '~') \
- F(FI_NOT_MATCH, '!', '~') \
- F(FI_DEFINED, 'd', 'e') \
- F(FI_TYPE, 0, 'T') \
- F(FI_IS_V4, 'I', 'i') \
- F(FI_SET, 0, 's') \
- F(FI_CONSTANT, 0, 'c') \
- F(FI_VARIABLE, 0, 'V') \
- F(FI_CONSTANT_INDIRECT, 0, 'C') \
- F(FI_PRINT, 0, 'p') \
- F(FI_CONDITION, 0, '?') \
- F(FI_PRINT_AND_DIE, 'p', ',') \
- F(FI_RTA_GET, 0, 'a') \
- F(FI_RTA_SET, 'a', 'S') \
- F(FI_EA_GET, 'e', 'a') \
- F(FI_EA_SET, 'e', 'S') \
- F(FI_PREF_GET, 0, 'P') \
- F(FI_PREF_SET, 'P', 'S') \
- F(FI_LENGTH, 0, 'L') \
- F(FI_ROA_MAXLEN, 'R', 'M') \
- F(FI_ROA_ASN, 'R', 'A') \
- F(FI_SADR_SRC, 'n', 's') \
- F(FI_IP, 'c', 'p') \
- F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \
- F(FI_AS_PATH_FIRST, 'a', 'f') \
- F(FI_AS_PATH_LAST, 'a', 'l') \
- 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_PATH_PREPEND, 'A', 'p') \
- 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')
+ F(FI_NOP) \
+ F(FI_ADD, ARG, ARG) \
+ F(FI_SUBTRACT, ARG, ARG) \
+ F(FI_MULTIPLY, ARG, ARG) \
+ F(FI_DIVIDE, ARG, ARG) \
+ F(FI_AND, ARG, LINE) \
+ F(FI_OR, ARG, LINE) \
+ F(FI_PAIR_CONSTRUCT, ARG, ARG) \
+ F(FI_EC_CONSTRUCT, ARG, ARG, ECS) \
+ F(FI_LC_CONSTRUCT, ARG, ARG, ARG) \
+ F(FI_PATHMASK_CONSTRUCT, ARG, COUNT) \
+ F(FI_NEQ, ARG, ARG) \
+ F(FI_EQ, ARG, ARG) \
+ F(FI_LT, ARG, ARG) \
+ F(FI_LTE, ARG, ARG) \
+ F(FI_NOT, ARG) \
+ F(FI_MATCH, ARG, ARG) \
+ F(FI_NOT_MATCH, ARG, ARG) \
+ F(FI_DEFINED, ARG) \
+ F(FI_TYPE, ARG) \
+ F(FI_IS_V4, ARG) \
+ F(FI_SET, ARG, SYMBOL) \
+ F(FI_CONSTANT, VALI) \
+ F(FI_VARIABLE, SYMBOL) \
+ F(FI_CONSTANT_INDIRECT, VALP) \
+ F(FI_PRINT, ARG) \
+ F(FI_CONDITION, ARG, LINE, LINE) \
+ F(FI_PRINT_AND_DIE, ARG, FRET) \
+ F(FI_RTA_GET, SA) \
+ F(FI_RTA_SET, SA, ARG) \
+ F(FI_EA_GET, EA) \
+ F(FI_EA_SET, EA, ARG) \
+ F(FI_EA_UNSET, EA) \
+ F(FI_PREF_GET) \
+ F(FI_PREF_SET, ARG) \
+ F(FI_LENGTH, ARG) \
+ F(FI_ROA_MAXLEN, ARG) \
+ F(FI_ROA_ASN, ARG) \
+ F(FI_SADR_SRC, ARG) \
+ F(FI_IP, ARG) \
+ F(FI_ROUTE_DISTINGUISHER, ARG) \
+ F(FI_AS_PATH_FIRST, ARG) \
+ F(FI_AS_PATH_LAST, ARG) \
+ F(FI_AS_PATH_LAST_NAG, ARG) \
+ F(FI_RETURN, ARG) \
+ F(FI_CALL, SYMBOL, LINE) \
+ F(FI_DROP_RESULT, ARG) \
+ F(FI_SWITCH, ARG, TREE) \
+ F(FI_IP_MASK, ARG, ARG) \
+ F(FI_PATH_PREPEND, ARG, ARG) \
+ F(FI_CLIST_ADD, ARG, ARG) \
+ F(FI_CLIST_DEL, ARG, ARG) \
+ F(FI_CLIST_FILTER, ARG, ARG) \
+ F(FI_ROA_CHECK_IMPLICIT, RTC) \
+ F(FI_ROA_CHECK_EXPLICIT, ARG, ARG, RTC) \
+ F(FI_FORMAT, ARG) \
+ F(FI_ASSERT, ARG, STRING)
/* The enum itself */
enum f_instruction_code {
-#define F(c,a,b) \
- c,
+#define F(c, ...) c,
FI__LIST
#undef F
FI__MAX,
@@ -188,47 +199,50 @@ FI__LIST
/* Convert the instruction back to the enum name */
const char *f_instruction_name(enum f_instruction_code fi);
+struct f_inst;
+void f_inst_next(struct f_inst *first, const struct f_inst *append);
+struct f_inst *f_clear_local_vars(struct f_inst *decls);
+
+#define FIA(x) , FIA_##x
+#define FIA_ARG const struct f_inst *
+#define FIA_LINE const struct f_inst *
+#define FIA_COUNT uint
+#define FIA_SYMBOL const struct symbol *
+#define FIA_VALI struct f_val
+#define FIA_VALP const struct f_val *
+#define FIA_FRET enum filter_return
+#define FIA_ECS enum ec_subtype
+#define FIA_SA struct f_static_attr
+#define FIA_EA struct f_dynamic_attr
+#define FIA_RTC const struct rtable_config *
+#define FIA_TREE const struct f_tree *
+#define FIA_STRING const char *
+#define F(c, ...) \
+ struct f_inst *f_new_inst_##c(enum f_instruction_code MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))()(MACRO_FOREACH(FIA, __VA_ARGS__)));
+FI__LIST
+#undef F
+#undef FIA_ARG
+#undef FIA_LINE
+#undef FIA_LINEP
+#undef FIA_COUNT
+#undef FIA_SYMBOL
+#undef FIA_VALI
+#undef FIA_VALP
+#undef FIA_FRET
+#undef FIA_ECS
+#undef FIA_SA
+#undef FIA_EA
+#undef FIA_RTC
+#undef FIA_STRING
+#undef FIA
+
+#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__)
+
+/* Flags for instructions */
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 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;
-};
-
-/* 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;
@@ -242,6 +256,7 @@ struct f_line_item {
const struct f_val *vp;
const struct symbol *sym;
};
+ struct f_val val;
const struct f_line *lines[2];
enum filter_return fret;
struct f_static_attr sa;
@@ -267,9 +282,9 @@ struct filter {
};
/* 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); }
+struct f_line *f_postfixify_concat(const struct f_inst * const inst[], uint count);
+static inline struct f_line *f_postfixify(const struct f_inst *root)
+{ return f_postfixify_concat(&root, 1); }
#define F_VAL_STACK_MAX 4096
@@ -295,12 +310,9 @@ struct f_exec_stack {
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);
+struct filter *f_new_where(const struct f_inst *);
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)
diff --git a/filter/interpret.m4 b/filter/interpret.m4
index 829b48f6..f449d580 100644
--- a/filter/interpret.m4
+++ b/filter/interpret.m4
@@ -45,17 +45,22 @@ 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(VALI, `res = what->val')
+m4_define(VALP, `res = what->val')
+m4_define(VAR, `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(TREE, `')
+m4_define(STRING, `')
+m4_define(COUNT, `')
m4_define(POSTFIXIFY, `')
m4_define(LINE_SIZE, `')
m4_define(SAME, `')
-m4_define(COUNT, `')
+m4_define(STRUCT, `')
+m4_define(NEW, `')
m4_m4wrap(`
m4_divert(0)DNL
diff --git a/filter/line-size.m4 b/filter/line-size.m4
index 0c005fa1..2c6b500b 100644
--- a/filter/line-size.m4
+++ b/filter/line-size.m4
@@ -10,13 +10,16 @@ m4_divert(-1)m4_dnl
# Common aliases
m4_define(DNL, `m4_dnl')
-m4_define(INST, `m4_divert(1)break; case $1: cnt += 1;
+m4_define(INST, `m4_divert(1)
+#undef what
+break; case $1: cnt += 1;
+#define what ((const struct f_inst_$1 *) &(what_->i_$1))
m4_divert(-1)')
-m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->f$1);
m4_divert(-1)')
-m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->f$1);
m4_divert(-1)')
-m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->f$1);
m4_divert(-1)')
m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)')
@@ -24,7 +27,8 @@ 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);
+#undef what
+break; default: bug( "Unknown instruction %d (%c)", what_->fi_code, what_->fi_code & 0xff);
')
m4_changequote([[,]])
diff --git a/filter/new.m4 b/filter/new.m4
new file mode 100644
index 00000000..ebb367d0
--- /dev/null
+++ b/filter/new.m4
@@ -0,0 +1,84 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Construction of per-instruction structures
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+#
+# Diversions:
+# 1 for prepared output
+# 2 for function arguments
+# 3 for function body
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(FNSTOP, `m4_divert(-1)')
+m4_define(FNOUT, `m4_divert(1)')
+m4_define(FNARG, `m4_divert(2)')
+m4_define(FNBODY, `m4_divert(3)')
+
+m4_define(INST, `m4_define([[INST_NAME]], [[$1]])FNOUT()DNL
+m4_undivert(2)DNL
+m4_undivert(3)DNL
+ return what;
+}
+
+struct f_inst *f_new_inst_$1(enum f_instruction_code fi_code
+FNBODY()) {
+ struct f_inst *what = cfg_allocz(sizeof(struct f_inst));
+ what->fi_code = fi_code;
+ what->lineno = ifs->lino;
+FNSTOP()')
+
+m4_define(WHAT, `what->i_[[]]INST_NAME()')
+
+m4_define(FNMETAARG, `FNARG(), $1 $2
+FNBODY() WHAT().$2 = $2;
+FNSTOP()')
+m4_define(ARG, `FNMETAARG(const struct f_inst *, f$1)')
+m4_define(ARG_ANY, `FNMETAARG(const struct f_inst *, f$1)')
+m4_define(LINE, `FNMETAARG(const struct f_inst *, f$1)')
+m4_define(SYMBOL, `FNMETAARG(const struct symbol *, sym)')
+m4_define(VALI, `FNMETAARG(struct f_val, vali)')
+m4_define(VALP, `FNMETAARG(const struct f_val *, valp)')
+m4_define(VAR, `FNARG(), const struct symbol * sym
+FNBODY() WHAT().valp = (WHAT().sym = sym)->def;
+FNSTOP()')
+m4_define(FRET, `FNMETAARG(enum filter_return, fret)')
+m4_define(ECS, `FNMETAARG(enum ec_subtype, ecs)')
+m4_define(RTC, `FNMETAARG(const struct rtable_config *, rtc)')
+m4_define(STATIC_ATTR, `FNMETAARG(struct f_static_attr, sa)')
+m4_define(DYNAMIC_ATTR, `FNMETAARG(struct f_dynamic_attr, da)')
+m4_define(COUNT, `FNMETAARG(uint, count)')
+m4_define(TREE, `FNMETAARG(const struct f_tree *, tree)')
+m4_define(STRING, `FNMETAARG(const char *, s)')
+m4_define(NEW, `FNARG()$1
+FNBODY()$2
+FNSTOP()')
+
+m4_m4wrap(`
+FNOUT()
+m4_undivert(2)
+m4_undivert(3)
+
+m4_divert(0)
+#include "nest/bird.h"
+#include "conf/conf.h"
+#include "filter/filter.h"
+#include "filter/f-inst-struct.h"
+
+struct f_inst *f_new_inst_FI_NOP(enum f_instruction_code fi_code) {
+ struct f_inst *what = cfg_allocz(sizeof(struct f_inst));
+ what->fi_code = fi_code;
+ what->lineno = ifs->lino;
+
+m4_undivert(1)
+
+ return what;
+}
+')
+
+m4_changequote([[,]])
diff --git a/filter/postfixify.m4 b/filter/postfixify.m4
index 8c96ba64..36cadfba 100644
--- a/filter/postfixify.m4
+++ b/filter/postfixify.m4
@@ -10,37 +10,45 @@ m4_divert(-1)m4_dnl
# 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(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:
+#undef what
+break; case $1:
+#define what ((const struct f_inst_$1 *) &(what_->i_$1))
m4_divert(-1)'))
-m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->f$1, pos);
m4_divert(-1)')
-m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->f$1, pos);
m4_divert(-1)')
-m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p);
+m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->f$1);
m4_divert(-1)')
-m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p;
+m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->fl$1;
m4_divert(-1)')
-m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p;
+m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->sym;
m4_divert(-1)')
-m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val);
+m4_define(VALI, `m4_divert(1)dest->items[pos].val = what->vali;
m4_divert(-1)')
-m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def;
+m4_define(VALP, `m4_divert(1)dest->items[pos].val = *(what->valp);
m4_divert(-1)')
-m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i;
+m4_define(VAR, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def;
m4_divert(-1)')
-m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux;
+m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->fret;
m4_divert(-1)')
-m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc;
+m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->ecs;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->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_define(COUNT, `m4_divert(1)dest->items[pos].count = what->count;
+m4_divert(-1)')
+m4_define(TREE, `m4_divert(1)dest->items[pos].tree = what->tree;
+m4_divert(-1)')
+m4_define(STRING, `m4_divert(1)dest->items[pos].s = what->s;
m4_divert(-1)')
m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)')
@@ -49,7 +57,8 @@ 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);
+#undef what
+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
index 73f2d1c3..10979449 100644
--- a/filter/same.m4
+++ b/filter/same.m4
@@ -29,7 +29,9 @@ 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(VALP, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0;
+m4_divert(-1)')
+m4_define(VAR, `SYMBOL()VALP()')
m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0;
m4_divert(-1)')
diff --git a/filter/struct.m4 b/filter/struct.m4
new file mode 100644
index 00000000..66205bfd
--- /dev/null
+++ b/filter/struct.m4
@@ -0,0 +1,67 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Definition of per-instruction structures
+#
+# (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(2)struct f_inst_$1 i_$1;
+m4_divert(1)};
+struct f_inst_$1 {
+m4_divert(-1)'))
+m4_define(ARG, `m4_divert(1)const struct f_inst *f$1;
+m4_divert(-1)')
+m4_define(ARG_ANY, `m4_divert(1)const struct f_inst *f$1;
+m4_divert(-1)')
+m4_define(LINE, `m4_divert(1)const struct f_inst *f$1;
+m4_divert(-1)')
+m4_define(LINEP, `m4_divert(1)const struct f_line *fl$1;
+m4_divert(-1)')
+m4_define(SYMBOL, `m4_divert(1)const struct symbol *sym;
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)struct f_val vali;
+m4_divert(-1)')
+m4_define(VALP, `m4_divert(1)const struct f_val *valp;
+m4_divert(-1)')
+m4_define(VAR, `VALP()SYMBOL()')
+m4_define(FRET, `m4_divert(1)enum filter_return fret;
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)enum ec_subtype ecs;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)const struct rtable_config *rtc;
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)struct f_static_attr sa;
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)struct f_dynamic_attr da;
+m4_divert(-1)')
+m4_define(COUNT, `m4_divert(1)uint count;
+m4_divert(-1)')
+m4_define(TREE, `m4_divert(1)const struct f_tree *tree;
+m4_divert(-1)')
+m4_define(STRING, `m4_divert(1)const char *s;
+m4_divert(-1)')
+m4_define(STRUCT, `m4_divert(1)$1
+m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+struct f_inst_FI_NOP {
+m4_undivert(1)
+};
+
+struct f_inst {
+ const struct f_inst *next; /* Next instruction */
+ enum f_instruction_code fi_code; /* Instruction code */
+ int lineno; /* Line number */
+ union {
+ m4_undivert(2)
+ };
+};
+')
+
+m4_changequote([[,]])
diff --git a/nest/attrs.h b/nest/attrs.h
index d9d97136..37227d9b 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -123,7 +123,7 @@ enum ec_subtype {
EC_RT = 0x0002,
EC_RO = 0x0003,
EC_GENERIC = 0xFFFF,
-} PACKED;
+};
/* Transitive bit (for first u32 half of EC) */
#define EC_TBIT 0x40000000
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 56caef24..527046ee 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -14,7 +14,7 @@ CF_DEFINES
#define STATIC_CFG ((struct static_config *) this_proto)
static struct static_route *this_srt, *this_snh;
-static struct f_inst *this_srt_cmds, **this_srt_last_cmd;
+static struct f_inst *this_srt_cmds, *this_srt_last_cmd;
static struct static_route *
static_nexthop_new(void)
@@ -111,7 +111,7 @@ stat_route0: ROUTE net_any {
add_tail(&STATIC_CFG->routes, &this_srt->n);
this_srt->net = $2;
this_srt_cmds = NULL;
- this_srt_last_cmd = &this_srt_cmds;
+ this_srt_last_cmd = NULL;
this_srt->mp_next = NULL;
this_snh = NULL;
}
@@ -137,7 +137,13 @@ stat_route:
;
stat_route_item:
- cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
+ cmd {
+ if (this_srt_last_cmd)
+ f_inst_next(this_srt_last_cmd, $1);
+ else
+ this_srt_cmds = $1;
+ this_srt_last_cmd = $1;
+ }
;
stat_route_opts: