mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 08:38:42 +00:00
Filter: refactoring of instruction constructors
This commit is contained in:
parent
4c553c5a5b
commit
9b46748d5b
@ -107,7 +107,7 @@ struct symbol {
|
||||
struct sym_scope *scope;
|
||||
int class;
|
||||
int aux;
|
||||
void *aux2;
|
||||
uint aux2;
|
||||
void *def;
|
||||
char name[1];
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
343
filter/config.Y
343
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); }
|
||||
|
@ -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)')
|
||||
|
101
filter/f-inst.c
101
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);
|
||||
}
|
||||
|
124
filter/f-inst.h
Normal file
124
filter/f-inst.h
Normal file
@ -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;
|
||||
};
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
232
filter/filter.h
232
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,109 +117,6 @@ struct f_static_attr {
|
||||
int readonly:1; /* Don't allow writing */
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
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,
|
||||
@ -229,6 +128,121 @@ enum filter_return {
|
||||
F_QUITBIRD,
|
||||
};
|
||||
|
||||
/* Filter instruction declarations */
|
||||
#define FI__LIST \
|
||||
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, ...) 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);
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
/* 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)
|
||||
|
@ -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
|
||||
|
@ -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([[,]])
|
||||
|
84
filter/new.m4
Normal file
84
filter/new.m4
Normal file
@ -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([[,]])
|
@ -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([[,]])
|
||||
|
@ -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)')
|
||||
|
67
filter/struct.m4
Normal file
67
filter/struct.m4
Normal file
@ -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([[,]])
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user