summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/confbase.Y5
-rw-r--r--doc/bird.sgml2
-rw-r--r--filter/Makefile16
-rw-r--r--filter/config.Y185
-rw-r--r--filter/dump.m443
-rw-r--r--filter/f-inst.c983
-rw-r--r--filter/f-util.c29
-rw-r--r--filter/filter.c544
-rw-r--r--filter/filter.h325
-rw-r--r--filter/filter_test.c7
-rw-r--r--filter/interpret.m457
-rw-r--r--filter/line-size.m430
-rw-r--r--filter/postfixify.m455
-rw-r--r--filter/same.m456
-rw-r--r--filter/tree.c30
-rw-r--r--filter/tree_test.c10
-rw-r--r--filter/trie.c14
-rw-r--r--lib/ip.h4
-rw-r--r--nest/a-path.c68
-rw-r--r--nest/a-path_test.c18
-rw-r--r--nest/a-set.c60
-rw-r--r--nest/a-set_test.c37
-rw-r--r--nest/attrs.h111
-rw-r--r--nest/cmds.c5
-rw-r--r--nest/cmds.h4
-rw-r--r--nest/config.Y6
-rw-r--r--nest/route.h6
-rw-r--r--nest/rt-attr.c16
-rw-r--r--proto/babel/config.Y2
-rw-r--r--proto/bgp/attrs.c41
-rw-r--r--proto/bgp/bgp.h4
-rw-r--r--proto/bgp/config.Y24
-rw-r--r--proto/bgp/packets.c6
-rw-r--r--proto/ospf/config.Y8
-rw-r--r--proto/radv/config.Y4
-rw-r--r--proto/rip/config.Y4
-rw-r--r--proto/static/config.Y7
-rw-r--r--proto/static/static.c2
-rw-r--r--proto/static/static.h2
-rw-r--r--sysdep/linux/krt-sys.h21
-rw-r--r--sysdep/linux/netlink.Y58
-rw-r--r--sysdep/linux/netlink.c9
-rw-r--r--sysdep/unix/krt.Y4
43 files changed, 1676 insertions, 1246 deletions
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 3d573e10..492ecd08 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -55,7 +55,6 @@ CF_DECLS
struct f_tree *e;
struct f_trie *trie;
struct f_val v;
- struct f_path_mask *h;
struct password_item *p;
struct rt_show_data *ra;
struct sym_show_data *sd;
@@ -124,14 +123,14 @@ conf: definition ;
definition:
DEFINE SYM '=' term ';' {
struct f_val *val = cfg_alloc(sizeof(struct f_val));
- if (f_eval($4, cfg_mem, val) > F_RETURN) cf_error("Runtime error");
+ if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
cf_define_symbol($2, SYM_CONSTANT | val->type, val);
}
;
expr:
NUM
- | '(' term ')' { $$ = f_eval_int($2); }
+ | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
| SYM {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
$$ = SYM_VAL($1).i; }
diff --git a/doc/bird.sgml b/doc/bird.sgml
index e531da40..8594b930 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -3982,7 +3982,7 @@ definitions, prefix definitions and DNS definitions:
RAdv protocol could be configured to change its behavior based on
availability of routes. When this option is used, the protocol waits in
suppressed state until a <it/trigger route/ (for the specified network)
- is exported to the protocol, the protocol also returnsd to suppressed
+ is exported to the protocol, the protocol also returns to suppressed
state if the <it/trigger route/ disappears. Note that route export
depends on specified export filter, as usual. This option could be used,
e.g., for handling failover in multihoming scenarios.
diff --git a/filter/Makefile b/filter/Makefile
index 0979a34f..c74ba2f3 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -5,10 +5,22 @@ $(cf-local)
M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS))
-$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c
+$(o)f-inst-line-size.c: $(s)line-size.m4 $(s)f-inst.c $(objdir)/.dir-stamp
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
-$(o)filter.o: $(o)f-inst-interpret.c
+$(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp
+ $(M4) $(M4FLAGS_FILTERS) -P $^ >$@
+
+$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c
tests_src := tree_test.c filter_test.c trie_test.c
tests_targets := $(tests_targets) $(tests-target-files)
diff --git a/filter/config.Y b/filter/config.Y
index e1f3fec8..a79b1582 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -158,20 +158,20 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
static inline struct f_inst *
f_generate_empty(struct f_dynamic_attr dyn)
{
- struct f_inst *e = f_new_inst(FI_EMPTY);
+ struct f_inst *e = f_new_inst(FI_CONSTANT);
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
- e->aux = T_PATH;
+ e->val = f_const_empty_path;
break;
case EAF_TYPE_INT_SET:
- e->aux = T_CLIST;
+ e->val = f_const_empty_clist;
break;
case EAF_TYPE_EC_SET:
- e->aux = T_ECLIST;
+ e->val = f_const_empty_eclist;
break;
case EAF_TYPE_LC_SET:
- e->aux = T_LCLIST;
+ e->val = f_const_empty_lclist;
break;
default:
cf_error("Can't empty that attribute");
@@ -302,23 +302,34 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
}
static inline struct f_inst *
-f_generate_path_mask(struct f_path_mask *t)
+f_generate_path_mask(struct f_inst *t)
{
- for (struct f_path_mask *tt = t; tt; tt = tt->next) {
- if (tt->kind == PM_ASN_EXPR) {
- struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
- mrv->a[0].p = t;
- return mrv;
- }
+ uint len = 0;
+ uint dyn = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next) {
+ if (tt->fi_code != FI_CONSTANT)
+ dyn++;
+ len++;
+ }
+
+ if (dyn) {
+ struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
+ pmc->a[0].p = t;
+ pmc->a[1].i = len;
+ return pmc;
}
- struct f_inst *rv = f_new_inst(FI_CONSTANT);
- rv->val = (struct f_val) {
- .type = T_PATH_MASK,
- .val.path_mask = t,
- };
+ struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
- return rv;
+ uint i = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next)
+ pm->item[i++] = tt->val.val.pmi;
+
+ pm->len = i;
+ struct f_inst *pmc = f_new_inst(FI_CONSTANT);
+ pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
+
+ return pmc;
}
/*
@@ -409,7 +420,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN
%nonassoc ELSE
-%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
+%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail
%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter filter_body where_filter
@@ -420,7 +431,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom switch_atom fipa
%type <px> fprefix
%type <s> decls declsn one_decl function_params
-%type <h> bgp_path bgp_path_tail
%type <t> get_cf_position
CF_GRAMMAR
@@ -438,7 +448,7 @@ filter_def:
conf: filter_eval ;
filter_eval:
- EVAL term { f_eval_int($2); }
+ EVAL term { f_eval_int(f_postfixify($2)); }
;
conf: custom_attr ;
@@ -530,7 +540,7 @@ filter_body:
function_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
f->name = NULL;
- f->root = $1;
+ f->root = f_postfixify($1);
$$ = f;
}
;
@@ -547,21 +557,25 @@ where_filter:
WHERE term {
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
struct filter *f = cfg_alloc(sizeof(struct filter));
- struct f_inst *i, *acc, *rej;
- acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
- acc->a[0].p = NULL;
- acc->a[1].i = F_ACCEPT;
- rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
- rej->a[0].p = NULL;
- rej->a[1].i = F_REJECT;
- i = f_new_inst(FI_CONDITION); /* IF */
- i->a[0].p = $2;
- i->a[1].p = acc;
- i->a[2].p = rej;
+ struct f_inst acc = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .a = { { .p = NULL }, { .i = F_ACCEPT } },
+ .lineno = ifs->lino,
+ };
+ struct f_inst rej = {
+ .fi_code = FI_PRINT_AND_DIE,
+ .a = { { .p = NULL }, { .i = F_REJECT } },
+ .lineno = ifs->lino,
+ };
+ struct f_inst i = {
+ .fi_code = FI_CONDITION,
+ .a = { { .p = $2 }, { .p = &acc }, { .p = &rej } },
+ .lineno = ifs->lino,
+ };
f->name = NULL;
- f->root = i;
+ f->root = f_postfixify(&i);
$$ = f;
- }
+ }
;
function_params:
@@ -587,7 +601,9 @@ function_def:
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
cf_push_scope($2);
} function_params function_body {
- $2->def = $5;
+ struct f_inst *vc = f_new_inst(FI_CONSTANT);
+ vc->val = (struct f_val) { .type = T_VOID };
+ $2->def = f_postfixify_concat($5, vc, NULL);
$2->aux2 = $4;
DBG("Hmm, we've got one function here - %s\n", $2->name);
cf_pop_scope();
@@ -639,7 +655,7 @@ set_atom:
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
- if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
+ if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
| SYM {
@@ -651,13 +667,13 @@ set_atom:
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
cnum:
- term { $$ = f_eval_int($1); }
+ term { $$ = f_eval_int(f_postfixify($1)); }
pair_item:
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
@@ -744,15 +760,16 @@ switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body switch_items ':' cmds {
/* Fill data fields */
struct f_tree *t;
+ struct f_line *line = f_postfixify($4);
for (t = $2; t; t = t->left)
- t->data = $4;
+ t->data = line;
$$ = f_merge_items($1, $2);
}
| switch_body ELSECOL cmds {
struct f_tree *t = f_new_tree();
t->from.type = t->to.type = T_VOID;
t->right = t;
- t->data = $3;
+ t->data = f_postfixify($3);
$$ = f_merge_items($1, t);
}
;
@@ -767,11 +784,11 @@ bgp_path:
;
bgp_path_tail:
- NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
- | NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
- | '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
- | '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
- | bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
+ NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; }
+ | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; }
+ | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; }
+ | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; }
+ | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
@@ -831,12 +848,11 @@ symbol:
switch ($1->class & 0xffff) {
case SYM_CONSTANT_RANGE:
$$ = f_new_inst(FI_CONSTANT_INDIRECT);
- goto cv_common;
+ $$->a[0].p = $1;
+ break;
case SYM_VARIABLE_RANGE:
$$ = f_new_inst(FI_VARIABLE);
- cv_common:
- $$->a[0].p = $1->def;
- $$->a[1].p = $1->name;
+ $$->a[0].p = $1;
break;
case SYM_ATTRIBUTE:
$$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
@@ -847,15 +863,15 @@ symbol:
}
static_attr:
- FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
- | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
- | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
- | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
- | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
- | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
- | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
- | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); }
- | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
+ FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
+ | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
+ | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
+ | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
+ | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
+ | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
+ | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
+ | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
+ | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
;
term:
@@ -908,42 +924,23 @@ term:
| rtadot dynamic_attr '.' RESET{ }
*/
- | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
- | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
- | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; }
- | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; }
- | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; }
- | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; }
- | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
- | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+ | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; }
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
/* | term '.' LEN { $$->code = P('P','l'); } */
-/* function_call is inlined here */
- | SYM '(' var_list ')' {
- struct symbol *sym;
- struct f_inst *inst = $3;
- if ($1->class != SYM_FUNCTION)
- cf_error("You can't call something which is not a function. Really.");
- DBG("You are calling function %s\n", $1->name);
- $$ = f_new_inst(FI_CALL);
- $$->a[0].p = inst;
- $$->a[1].p = $1->def;
- sym = $1->aux2;
- while (sym || inst) {
- if (!sym || !inst)
- cf_error("Wrong number of arguments for function %s.", $1->name);
- DBG( "You should pass parameter called %s\n", sym->name);
- inst->a[0].p = sym;
- sym = sym->aux2;
- inst = inst->next;
- }
- }
+ | function_call
;
break_command:
@@ -1022,7 +1019,7 @@ cmd:
}
| rtadot static_attr '=' term ';' {
$$ = f_new_inst_sa(FI_RTA_SET, $2);
- if (!$$->a[0].i)
+ if ($$->sa.readonly)
cf_error( "This static attribute is read-only.");
$$->a[0].p = $4;
}
@@ -1036,7 +1033,7 @@ cmd:
$$->a[0].p = NULL;
}
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
- | function_call ';' { $$ = $1; }
+ | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; }
| CASE term '{' switch_body '}' {
$$ = f_new_inst(FI_SWITCH);
$$->a[0].p = $2;
@@ -1044,10 +1041,10 @@ cmd:
}
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
+ | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
+ | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
+ | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
+ | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
;
diff --git a/filter/dump.m4 b/filter/dump.m4
new file mode 100644
index 00000000..913a7652
--- /dev/null
+++ b/filter/dump.m4
@@ -0,0 +1,43 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Dumping instruction lines
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1:
+m4_divert(-1)'))
+m4_define(LINE, `m4_divert(1)f_dump_line(item->lines[$2], indent + 1);
+m4_divert(-1)')
+m4_define(LINEP, `LINE($@)')
+m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name);
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
+m4_divert(-1)')
+m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret);
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)debug("%sec subtype %d\n", INDENT, item->ecs);
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)debug("%sroute table %s\n", INDENT, item->rtc->name);
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly);
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code);
+m4_divert(-1)')
+m4_define(DUMP, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/f-inst.c b/filter/f-inst.c
index ef5d4f06..02c88409 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -10,269 +10,282 @@
*/
/* Binary operators */
- INST(FI_ADD) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i += v1.val.i;
- }
- INST(FI_SUBTRACT) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i -= v1.val.i;
- }
- INST(FI_MULTIPLY) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- res.val.i *= v1.val.i;
- }
- INST(FI_DIVIDE) {
- ARG_T(1,0,T_INT);
- ARG_T(2,1,T_INT);
- if (v1.val.i == 0) runtime( "Mother told me not to divide by 0" );
- res.val.i /= v1.val.i;
- }
- INST(FI_AND) {
- ARG_T(1,0,T_BOOL);
+ INST(FI_ADD, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i += v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_SUBTRACT, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i -= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_MULTIPLY, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ res.val.i *= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_DIVIDE, 2, 1) {
+ ARG(1,T_INT);
+ ARG(2,T_INT);
+ if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
+ res.val.i /= v2.val.i;
+ RESULT_OK;
+ }
+ INST(FI_AND, 1, 1) {
+ ARG(1,T_BOOL);
if (res.val.i)
- ARG_T(2,0,T_BOOL);
+ LINE(2,0);
+ else
+ RESULT_OK;
}
- INST(FI_OR) {
- ARG_T(1,0,T_BOOL);
+ INST(FI_OR, 1, 1) {
+ ARG(1,T_BOOL);
if (!res.val.i)
- ARG_T(2,0,T_BOOL);
+ LINE(2,0);
+ else
+ RESULT_OK;
}
- INST(FI_PAIR_CONSTRUCT) {
+ INST(FI_PAIR_CONSTRUCT, 2, 1) {
ARG(1,T_INT);
ARG(2,T_INT);
- u1 = v1.val.i;
- u2 = v2.val.i;
+ uint u1 = v1.val.i;
+ uint u2 = v2.val.i;
if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
runtime( "Can't operate with value out of bounds in pair constructor" );
- res.val.i = (u1 << 16) | u2;
- res.type = T_PAIR;
+ RESULT(T_PAIR, i, (u1 << 16) | u2);
}
+ INST(FI_EC_CONSTRUCT, 2, 1) {
+ ARG_ANY(1);
+ ARG(2, T_INT);
+ ECS;
- INST(FI_EC_CONSTRUCT) {
- {
- ARG_ANY(1);
- ARG(2, T_INT);
-
- int check, ipv4_used;
- u32 key, val;
-
- if (v1.type == T_INT) {
- ipv4_used = 0; key = v1.val.i;
- }
- else if (v1.type == T_QUAD) {
- ipv4_used = 1; key = v1.val.i;
- }
- /* IP->Quad implicit conversion */
- else if (val_is_ip4(v1)) {
- ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
- }
- else
- runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
-
- val = v2.val.i;
-
- /* XXXX */
- res.type = T_EC;
+ int check, ipv4_used;
+ u32 key, val;
- if (what->aux == EC_GENERIC) {
- check = 0; res.val.ec = ec_generic(key, val);
- }
- else if (ipv4_used) {
- check = 1; res.val.ec = ec_ip4(what->aux, key, val);
- }
- else if (key < 0x10000) {
- check = 0; res.val.ec = ec_as2(what->aux, key, val);
- }
- else {
- check = 1; res.val.ec = ec_as4(what->aux, key, val);
- }
+ if (v1.type == T_INT) {
+ ipv4_used = 0; key = v1.val.i;
+ }
+ else if (v1.type == T_QUAD) {
+ ipv4_used = 1; key = v1.val.i;
+ }
+ /* IP->Quad implicit conversion */
+ else if (val_is_ip4(&v1)) {
+ ipv4_used = 1; key = ipa_to_u32(v1.val.ip);
+ }
+ else
+ runtime("Argument 1 of instruction FI_EC_CONSTRUCT must be integer or IPv4 address, got 0x%02x");
- if (check && (val > 0xFFFF))
- runtime("Can't operate with value out of bounds in EC constructor");
+ val = v2.val.i;
+ if (ecs == EC_GENERIC) {
+ check = 0; RESULT(T_EC, ec, ec_generic(key, val));
+ }
+ else if (ipv4_used) {
+ check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
}
+ else if (key < 0x10000) {
+ check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
+ }
+ else {
+ check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
}
- INST(FI_LC_CONSTRUCT) {
- {
- ARG(1, T_INT);
- ARG(2, T_INT);
- ARG(3, T_INT);
+ if (check && (val > 0xFFFF))
+ runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
+ }
- res.type = T_LC;
- res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
+ INST(FI_LC_CONSTRUCT, 3, 1) {
+ ARG(1, T_INT);
+ ARG(2, T_INT);
+ ARG(3, T_INT);
+ RESULT(T_LC, lc, [[(lcomm) { v1.val.i, v2.val.i, v3.val.i }]]);
+ }
- }
+ INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
+ ARG_ANY(1);
+ COUNT(2);
+ if (vstk.cnt < what->count) /* TODO: make this check systematic */
+ runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count);
+
+ struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item));
+ for (uint i=0; i<what->count; i++) {
+//#define pv vstk.val[vstk.cnt-i-1]
+#define pv vstk.val[vstk.cnt - what->count + i]
+ switch (pv.type) {
+ case T_PATH_MASK_ITEM:
+ pm->item[i] = pv.val.pmi;
+ break;
+ case T_INT:
+ pm->item[i] = (struct f_path_mask_item) {
+ .asn = pv.val.i,
+ .kind = PM_ASN,
+ };
+ break;
+ default:
+ runtime( "Error resolving path mask template: value not an integer" );
+ }
}
- INST(FI_PATHMASK_CONSTRUCT) {
- {
- struct f_path_mask *tt = what->a[0].p, *vbegin, **vv = &vbegin;
-
- while (tt) {
- *vv = lp_alloc(fs->pool, sizeof(struct f_path_mask));
- if (tt->kind == PM_ASN_EXPR) {
- INTERPRET((struct f_inst *) tt->val, 0);
- (*vv)->kind = PM_ASN;
- if (res.type != T_INT) {
- runtime( "Error resolving path mask template: value not an integer" );
- return F_ERROR;
- }
-
- (*vv)->val = res.val.i;
- } else {
- **vv = *tt;
- }
- tt = tt->next;
- vv = &((*vv)->next);
- }
+ vstk.cnt -= what->count;
+ pm->len = what->count;
- res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin };
- }
- }
+ RESULT(T_PATH_MASK, path_mask, pm);
+ }
/* Relational operators */
- INST(FI_NEQ) {
+ INST(FI_NEQ, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = !val_same(v1, v2);
+ RESULT(T_BOOL, i, !val_same(&v1, &v2));
}
- INST(FI_EQ) {
+ INST(FI_EQ, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_same(v1, v2);
+ RESULT(T_BOOL, i, val_same(&v1, &v2));
}
- INST(FI_LT) {
+ INST(FI_LT, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- i = val_compare(v1, v2);
- if (i==CMP_ERROR)
+ int i = val_compare(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
- res.type = T_BOOL;
- res.val.i = (i == -1);
+ RESULT(T_BOOL, i, (i == -1));
}
- INST(FI_LTE) {
+ INST(FI_LTE, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- i = val_compare(v1, v2);
- if (i==CMP_ERROR)
+ int i = val_compare(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
- res.type = T_BOOL;
- res.val.i = (i != 1);
+ RESULT(T_BOOL, i, (i != 1));
}
- INST(FI_NOT) {
- ARG_T(1,0,T_BOOL);
- res.val.i = !res.val.i;
+ INST(FI_NOT, 1, 1) {
+ ARG(1,T_BOOL);
+ RESULT(T_BOOL, i, !v1.val.i);
}
- INST(FI_MATCH) {
+ INST(FI_MATCH, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_in_range(v1, v2);
- if (res.val.i == CMP_ERROR)
+ int i = val_in_range(&v1, &v2);
+ if (i == CMP_ERROR)
runtime( "~ applied on unknown type pair" );
- res.val.i = !!res.val.i;
+ RESULT(T_BOOL, i, !!i);
}
- INST(FI_NOT_MATCH) {
+ INST(FI_NOT_MATCH, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
- res.type = T_BOOL;
- res.val.i = val_in_range(v1, v2);
+ int i = val_in_range(&v1, &v2);
if (res.val.i == CMP_ERROR)
runtime( "!~ applied on unknown type pair" );
- res.val.i = !res.val.i;
+ RESULT(T_BOOL, i, !i);
}
- INST(FI_DEFINED) {
+ INST(FI_DEFINED, 1, 1) {
ARG_ANY(1);
- res.type = T_BOOL;
- res.val.i = (v1.type != T_VOID) && !undef_value(v1);
+ RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
}
- INST(FI_TYPE) {
+
+ INST(FI_TYPE, 1, 1) {
ARG_ANY(1); /* There may be more types supporting this operation */
switch (v1.type)
{
case T_NET:
- res.type = T_ENUM_NETTYPE;
- res.val.i = v1.val.net->type;
+ RESULT(T_ENUM_NETTYPE, i, v1.val.net->type);
break;
default:
runtime( "Can't determine type of this item" );
}
}
- INST(FI_IS_V4) {
+
+ INST(FI_IS_V4, 1, 1) {
ARG(1, T_IP);
- res.type = T_BOOL;
- res.val.i = ipa_is_ip4(v1.val.ip);
+ RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip));
}
- /* Set to indirect value, a[0] = variable, a[1] = value */
- INST(FI_SET) {
+ /* Set to indirect value prepared in v1 */
+ INST(FI_SET, 1, 0) {
ARG_ANY(2);
- sym = what->a[0].p;
- vp = sym->def;
- if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID))
+ SYMBOL(1);
+ if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
{
/* IP->Quad implicit conversion */
- if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(v2))
+ if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
{
- vp->type = T_QUAD;
- vp->val.i = ipa_to_u32(v2.val.ip);
+ *((struct f_val *) sym->def) = (struct f_val) {
+ .type = T_QUAD,
+ .val.i = ipa_to_u32(v1.val.ip),
+ };
break;
}
runtime( "Assigning to variable of incompatible type" );
}
- *vp = v2;
+ *((struct f_val *) sym->def) = v1;
}
/* some constants have value in a[1], some in *a[0].p, strange. */
- INST(FI_CONSTANT) { /* integer (or simple type) constant, string, set, or prefix_set */
- res = what->val;
+ INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */
+ VALI; // res = what->val;
+ RESULT_OK;
}
- INST(FI_VARIABLE) {
- res = * ((struct f_val *) what->a[0].p);
+ INST(FI_VARIABLE, 0, 1) {
+ VALP(1); // res = * ((struct f_val *) what->a[0].p);
+ SAME([[if (strcmp(f1->sym->name, f2->sym->name)) return 0; ]]);
+ RESULT_OK;
}
- INST(FI_CONSTANT_INDIRECT) {
- res = * ((struct f_val *) what->a[0].p);
+ INST(FI_CONSTANT_INDIRECT, 0, 1) {
+ VALP(1);
+ SAME([[if (!val_same(f1->vp, f2->vp)) return 0; ]]);
+ RESULT_OK;
}
- INST(FI_PRINT) {
+ INST(FI_PRINT, 1, 0) {
ARG_ANY(1);
- val_format(v1, &fs->buf);
+ val_format(&(v1), &fs->buf);
}
- INST(FI_CONDITION) {
- ARG_T(1, 0, T_BOOL);
+ INST(FI_CONDITION, 1, 0) {
+ ARG(1, T_BOOL);
if (res.val.i)
- ARG_ANY_T(2,0);
+ LINE(2,0);
else
- ARG_ANY_T(3,0);
+ LINE(3,1);
}
- INST(FI_PRINT_AND_DIE) {
- ARG_ANY(1);
- if ((what->a[1].i == F_NOP || (what->a[1].i != F_NONL && what->a[0].p)) &&
+ INST(FI_PRINT_AND_DIE, 0, 0) {
+ POSTFIXIFY([[
+ if (what->a[0].p) {
+ pos = postfixify(dest, what->a[0].p, pos);
+ dest->items[pos].flags |= FIF_PRINTED;
+ }
+ ]]);
+ LINE_SIZE([[
+ if (what->a[0].p) {
+ cnt += inst_line_size(what->a[0].p);
+ }
+ ]]);
+
+ FRET(2);
+
+ if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) &&
!(fs->flags & FF_SILENT))
log_commit(*L_INFO, &fs->buf);
- switch (what->a[1].i) {
+ switch (fret) {
case F_QUITBIRD:
die( "Filter asked me to die" );
case F_ACCEPT:
/* Should take care about turning ACCEPT into MODIFY */
case F_ERROR:
case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
- return what->a[1].i; /* We have to return now, no more processing. */
+ return fret; /* We have to return now, no more processing. */
case F_NONL:
case F_NOP:
break;
@@ -280,40 +293,43 @@
bug( "unknown return type: Can't happen");
}
}
- INST(FI_RTA_GET) { /* rta access */
+
+ INST(FI_RTA_GET, 0, 1) { /* rta access */
{
+ STATIC_ATTR;
ACCESS_RTE;
struct rta *rta = (*fs->rte)->attrs;
- res.type = what->aux;
- switch (what->a[1].i)
+ switch (sa.sa_code)
{
- case SA_FROM: res.val.ip = rta->from; break;
- case SA_GW: res.val.ip = rta->nh.gw; break;
- case SA_NET: res.val.net = (*fs->rte)->net->n.addr; break;
- case SA_PROTO: res.val.s = rta->src->proto->name; break;
- case SA_SOURCE: res.val.i = rta->source; break;
- case SA_SCOPE: res.val.i = rta->scope; break;
- case SA_DEST: res.val.i = rta->dest; break;
- case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break;
- case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break;
+ case SA_FROM: RESULT(sa.f_type, ip, rta->from); break;
+ case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break;
+ case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
+ case SA_PROTO: RESULT(sa.f_type, s, rta->src->proto->name); break;
+ case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break;
+ case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break;
+ case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
+ case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
+ case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
default:
- bug("Invalid static attribute access (%x)", res.type);
+ bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
}
}
- INST(FI_RTA_SET) {
+
+ INST(FI_RTA_SET, 1, 0) {
+ STATIC_ATTR;
ACCESS_RTE;
ARG_ANY(1);
- if (what->aux != v1.type)
+ if (sa.f_type != v1.type)
runtime( "Attempt to set static attribute to incompatible type" );
f_rta_cow(fs);
{
struct rta *rta = (*fs->rte)->attrs;
- switch (what->a[1].i)
+ switch (sa.sa_code)
{
case SA_FROM:
rta->from = v1.val.ip;
@@ -339,15 +355,17 @@
break;
case SA_DEST:
- i = v1.val.i;
- if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
- runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
-
- rta->dest = i;
- rta->nh.gw = IPA_NONE;
- rta->nh.iface = NULL;
- rta->nh.next = NULL;
- rta->hostentry = NULL;
+ {
+ int i = v1.val.i;
+ if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
+ runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
+
+ rta->dest = i;
+ rta->nh.gw = IPA_NONE;
+ rta->nh.iface = NULL;
+ rta->nh.next = NULL;
+ rta->hostentry = NULL;
+ }
break;
case SA_IFNAME:
@@ -365,124 +383,112 @@
break;
default:
- bug("Invalid static attribute access (%x)", res.type);
+ bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
}
}
- INST(FI_EA_GET) { /* Access to extended attributes */
+
+ INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */
+ DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
{
- u16 code = what->a[1].i;
- int f_type = what->aux >> 8;
- eattr *e = ea_find(*fs->eattrs, code);
+ eattr *e = ea_find(*fs->eattrs, da.ea_code);
if (!e) {
/* A special case: undefined as_path looks like empty as_path */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) {
- res.type = T_PATH;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_AS_PATH) {
+ RESULT(T_PATH, ad, &null_adata);
break;
}
/* The same special case for int_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
- res.type = T_CLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_INT_SET) {
+ RESULT(T_CLIST, ad, &null_adata);
break;
}
/* The same special case for ec_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
- res.type = T_ECLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_EC_SET) {
+ RESULT(T_ECLIST, ad, &null_adata);
break;
}
/* The same special case for lc_set */
- if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
- res.type = T_LCLIST;
- res.val.ad = &undef_adata;
+ if (da.type == EAF_TYPE_LC_SET) {
+ RESULT(T_LCLIST, ad, &null_adata);
break;
}
/* Undefined value */
res.type = T_VOID;
+ RESULT_OK;
break;
}
switch (e->type & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
- res.type = f_type;
- res.val.i = e->u.data;
+ RESULT(da.f_type, i, e->u.data);
break;
case EAF_TYPE_ROUTER_ID:
- res.type = T_QUAD;
- res.val.i = e->u.data;
+ RESULT(T_QUAD, i, e->u.data);
break;
case EAF_TYPE_OPAQUE:
- res.type = T_ENUM_EMPTY;
- res.val.i = 0;
+ RESULT(T_ENUM_EMPTY, i, 0);
break;
case EAF_TYPE_IP_ADDRESS:
- res.type = T_IP;
- struct adata * ad = e->u.ptr;
- res.val.ip = * (ip_addr *) ad->data;
+ RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
break;
case EAF_TYPE_AS_PATH:
- res.type = T_PATH;
- res.val.ad = e->u.ptr;
+ RESULT(T_PATH, ad, e->u.ptr);
break;
case EAF_TYPE_BITFIELD:
- res.type = T_BOOL;
- res.val.i = !!(e->u.data & BITFIELD_MASK(what));
+ RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
break;
case EAF_TYPE_INT_SET:
- res.type = T_CLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_CLIST, ad, e->u.ptr);
break;
case EAF_TYPE_EC_SET:
- res.type = T_ECLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_ECLIST, ad, e->u.ptr);
break;
case EAF_TYPE_LC_SET:
- res.type = T_LCLIST;
- res.val.ad = e->u.ptr;
+ RESULT(T_LCLIST, ad, e->u.ptr);
break;
case EAF_TYPE_UNDEF:
res.type = T_VOID;
+ RESULT_OK;
break;
default:
- bug("Unknown type in e,a");
+ bug("Unknown dynamic attribute type");
}
}
}
- INST(FI_EA_SET) {
+
+ INST(FI_EA_SET, 1, 0) {
+ DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
ARG_ANY(1);
{
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
- u16 code = what->a[1].i;
- int f_type = what->aux >> 8;
l->next = NULL;
l->flags = EALF_SORTED;
l->count = 1;
- l->attrs[0].id = code;
+ l->attrs[0].id = da.ea_code;
l->attrs[0].flags = 0;
- l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH;
+ l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
- switch (what->aux & EAF_TYPE_MASK) {
+ switch (da.type) {
case EAF_TYPE_INT:
- if (v1.type != f_type)
+ if (v1.type != da.f_type)
runtime( "Setting int attribute to non-int value" );
l->attrs[0].u.data = v1.val.i;
break;
case EAF_TYPE_ROUTER_ID:
/* IP->Quad implicit conversion */
- if (val_is_ip4(v1)) {
+ if (val_is_ip4(&v1)) {
l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
break;
}
@@ -514,13 +520,13 @@
runtime( "Setting bit in bitfield attribute to non-bool value" );
{
/* First, we have to find the old value */
- eattr *e = ea_find(*fs->eattrs, code);
+ eattr *e = ea_find(*fs->eattrs, da.ea_code);
u32 data = e ? e->u.data : 0;
if (v1.val.i)
- l->attrs[0].u.data = data | BITFIELD_MASK(what);
+ l->attrs[0].u.data = data | (1u << da.bit);
else
- l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
+ l->attrs[0].u.data = data & ~(1u << da.bit);
}
break;
case EAF_TYPE_INT_SET:
@@ -551,12 +557,13 @@
*fs->eattrs = l;
}
}
- INST(FI_PREF_GET) {
+
+ INST(FI_PREF_GET, 0, 1) {
ACCESS_RTE;
- res.type = T_INT;
- res.val.i = (*fs->rte)->pref;
+ RESULT(T_INT, i, (*fs->rte)->pref);
}
- INST(FI_PREF_SET) {
+
+ INST(FI_PREF_SET, 1, 0) {
ACCESS_RTE;
ARG(1,T_INT);
if (v1.val.i > 0xFFFF)
@@ -564,149 +571,221 @@
f_rte_cow(fs);
(*fs->rte)->pref = v1.val.i;
}
- INST(FI_LENGTH) { /* Get length of */
+
+ INST(FI_LENGTH, 1, 1) { /* Get length of */
ARG_ANY(1);
- res.type = T_INT;
switch(v1.type) {
- case T_NET: res.val.i = net_pxlen(v1.val.net); break;
- case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
- case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
- case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
- case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
+ case T_NET: RESULT(T_INT, i, net_pxlen(v1.val.net)); break;
+ case T_PATH: RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break;
+ case T_CLIST: RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break;
+ case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break;
+ case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break;
default: runtime( "Prefix, path, clist or eclist expected" );
}
}
- INST(FI_SADR_SRC) { /* Get SADR src prefix */
+
+ INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */
ARG(1, T_NET);
if (!net_is_sadr(v1.val.net))
runtime( "SADR expected" );
- {
- net_addr_ip6_sadr *net = (void *) v1.val.net;
- net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6));
- net_fill_ip6(src, net->src_prefix, net->src_pxlen);
+ net_addr_ip6_sadr *net = (void *) v1.val.net;
+ net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6));
+ net_fill_ip6(src, net->src_prefix, net->src_pxlen);
- res.type = T_NET;
- res.val.net = src;
- }
+ RESULT(T_NET, net, src);
}
- INST(FI_ROA_MAXLEN) { /* Get ROA max prefix length */
+
+ INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
runtime( "ROA expected" );
- res.type = T_INT;
- res.val.i = (v1.val.net->type == NET_ROA4) ?
+ RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
((net_addr_roa4 *) v1.val.net)->max_pxlen :
- ((net_addr_roa6 *) v1.val.net)->max_pxlen;
+ ((net_addr_roa6 *) v1.val.net)->max_pxlen);
}
- INST(FI_ROA_ASN) { /* Get ROA ASN */
+
+ INST(FI_ROA_ASN, 1, 1) { /* Get ROA ASN */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
runtime( "ROA expected" );
- res.type = T_INT;
- res.val.i = (v1.val.net->type == NET_ROA4) ?
+ RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
((net_addr_roa4 *) v1.val.net)->asn :
- ((net_addr_roa6 *) v1.val.net)->asn;
+ ((net_addr_roa6 *) v1.val.net)->asn);
}
- INST(FI_IP) { /* Convert prefix to ... */
+
+ INST(FI_IP, 1, 1) { /* Convert prefix to ... */
ARG(1, T_NET);
- res.type = T_IP;
- res.val.ip = net_prefix(v1.val.net);
+ RESULT(T_IP, ip, net_prefix(v1.val.net));
}
- INST(FI_ROUTE_DISTINGUISHER) {
+
+ INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
ARG(1, T_NET);
if (!net_is_vpn(v1.val.net))
runtime( "VPN address expected" );
- res.type = T_RD;
- res.val.ec = net_rd(v1.val.net);
+ RESULT(T_RD, ec, net_rd(v1.val.net));
}
- INST(FI_AS_PATH_FIRST) { /* Get first ASN from AS PATH */
- ARG(1, T_PATH);
- as = 0;
+ INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */
+ ARG(1, T_PATH);
+ int as = 0;
as_path_get_first(v1.val.ad, &as);
- res.type = T_INT;
- res.val.i = as;
+ RESULT(T_INT, i, as);
}
- INST(FI_AS_PATH_LAST) { /* Get last ASN from AS PATH */
- ARG(1, T_PATH);
- as = 0;
+ INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */
+ ARG(1, T_PATH);
+ int as = 0;
as_path_get_last(v1.val.ad, &as);
- res.type = T_INT;
- res.val.i = as;
+ RESULT(T_INT, i, as);
}
- INST(FI_AS_PATH_LAST_NAG) { /* Get last ASN from non-aggregated part of AS PATH */
+
+ INST(FI_AS_PATH_LAST_NAG, 1, 1) { /* Get last ASN from non-aggregated part of AS PATH */
ARG(1, T_PATH);
+ RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
+ }
- res.type = T_INT;
- res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
+ INST(FI_RETURN, 1, 1) {
+ /* Acquire the return value */
+ ARG_ANY(1);
+ uint retpos = vstk.cnt;
+
+ /* Drop every sub-block including ourselves */
+ while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN))
+ ;
+
+ /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
+ if (!estk.cnt)
+ if (vstk.val[retpos].type == T_BOOL)
+ if (vstk.val[retpos].val.i)
+ return F_ACCEPT;
+ else
+ return F_REJECT;
+ else
+ runtime("Can't return non-bool from non-function");
+
+ /* Set the value stack position */
+ vstk.cnt = estk.item[estk.cnt].ventry;
+
+ /* Copy the return value */
+ RESULT_VAL(vstk.val[retpos]);
}
- INST(FI_RETURN) {
- ARG_ANY_T(1,0);
- return F_RETURN;
+
+ INST(FI_CALL, 0, 1) {
+ /* First push the code */
+ LINEP(2,0);
+ curline.emask |= FE_RETURN;
+
+ /* Then push the arguments */
+ LINE(1,1);
}
- INST(FI_CALL) {
- ARG_ANY_T(1,0);
- fret = interpret(fs, what->a[1].p);
- if (fret > F_RETURN)
- return fret;
+
+ INST(FI_DROP_RESULT, 1, 0) {
+ ARG_ANY(1);
}
- INST(FI_CLEAR_LOCAL_VARS) { /* Clear local variables */
- for (sym = what->a[0].p; sym != NULL; sym = sym->aux2)
+
+ INST(FI_CLEAR_LOCAL_VARS, 0, 0) { /* Clear local variables */
+ SYMBOL(1);
+ for ( ; sym != NULL; sym = sym->aux2)
((struct f_val *) sym->def)->type = T_VOID;
}
- INST(FI_SWITCH) {
+ INST(FI_SWITCH, 1, 0) {
ARG_ANY(1);
- {
- struct f_tree *t = find_tree(what->a[1].p, v1);
+ POSTFIXIFY([[
+ dest->items[pos].tree = what->a[1].p;
+ ]]);
+ const struct f_tree *t = find_tree(what->tree, &v1);
+ if (!t) {
+ v1.type = T_VOID;
+ t = find_tree(what->tree, &v1);
if (!t) {
- v1.type = T_VOID;
- t = find_tree(what->a[1].p, v1);
- if (!t) {
- debug( "No else statement?\n");
- break;
- }
+ debug( "No else statement?\n");
+ break;
}
- /* It is actually possible to have t->data NULL */
-
- fret = interpret(fs, t->data);
- if (fret >= F_RETURN)
- return fret;
}
+ /* It is actually possible to have t->data NULL */
+
+ LINEX(t->data);
}
- INST(FI_IP_MASK) { /* IP.MASK(val) */
+
+ INST(FI_IP_MASK, 2, 1) { /* IP.MASK(val) */
ARG(1, T_IP);
ARG(2, T_INT);
-
- res.type = T_IP;
- res.val.ip = ipa_is_ip4(v1.val.ip) ?
+ RESULT(T_IP, ip, [[ ipa_is_ip4(v1.val.ip) ?
ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
- ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
+ ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]);
}
- INST(FI_EMPTY) { /* Create empty attribute */
- res.type = what->aux;
- res.val.ad = adata_empty(fs->pool, 0);
- }
- INST(FI_PATH_PREPEND) { /* Path prepend */
+ INST(FI_PATH_PREPEND, 2, 1) { /* Path prepend */
ARG(1, T_PATH);
ARG(2, T_INT);
+ RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]);
+ }
+
+ INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */
+ ARG_ANY(1);
+ ARG_ANY(2);
+ if (v1.type == T_PATH)
+ runtime("Can't add to path");
+
+ else if (v1.type == T_CLIST)
+ {
+ /* Community (or cluster) list */
+ struct f_val dummy;
+
+ if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
+ RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, v2.val.i) ]]);
+ /* IP->Quad implicit conversion */
+ else if (val_is_ip4(&v2))
+ RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
+ runtime("Can't add set");
+ else if (v2.type == T_CLIST)
+ RESULT(T_CLIST, ad, [[ int_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else
+ runtime("Can't add non-pair");
+ }
- res.type = T_PATH;
- res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i);
+ else if (v1.type == T_ECLIST)
+ {
+ /* v2.val is either EC or EC-set */
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
+ runtime("Can't add set");
+ else if (v2.type == T_ECLIST)
+ RESULT(T_ECLIST, ad, [[ ec_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else if (v2.type != T_EC)
+ runtime("Can't add non-ec");
+ else
+ RESULT(T_ECLIST, ad, [[ ec_set_add(fs->pool, v1.val.ad, v2.val.ec) ]]);
+ }
+
+ else if (v1.type == T_LCLIST)
+ {
+ /* v2.val is either LC or LC-set */
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
+ runtime("Can't add set");
+ else if (v2.type == T_LCLIST)
+ RESULT(T_LCLIST, ad, [[ lc_set_union(fs->pool, v1.val.ad, v2.val.ad) ]]);
+ else if (v2.type != T_LC)
+ runtime("Can't add non-lc");
+ else
+ RESULT(T_LCLIST, ad, [[ lc_set_add(fs->pool, v1.val.ad, v2.val.lc) ]]);
+
+ }
+
+ else
+ runtime("Can't add to non-[e|l]clist");
}
- INST(FI_CLIST_ADD_DEL) { /* (Extended) Community list add or delete */
+ INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
if (v1.type == T_PATH)
{
- struct f_tree *set = NULL;
+ const struct f_tree *set = NULL;
u32 key = 0;
- int pos;
if (v2.type == T_INT)
key = v2.val.i;
@@ -715,210 +794,154 @@
else
runtime("Can't delete non-integer (set)");
- switch (what->aux)
- {
- case 'a': runtime("Can't add to path");
- case 'd': pos = 0; break;
- case 'f': pos = 1; break;
- default: bug("unknown Ca operation");
- }
-
- if (pos && !set)
- runtime("Can't filter integer");
-
- res.type = T_PATH;
- res.val.ad = as_path_filter(fs->pool, v1.val.ad, set, key, pos);
+ RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, set, key, 0) ]]);
}
+
else if (v1.type == T_CLIST)
{
/* Community (or cluster) list */
struct f_val dummy;
- int arg_set = 0;
- uint n = 0;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- n = v2.val.i;
+ RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
- else if (val_is_ip4(v2))
- n = ipa_to_u32(v2.val.ip);
- else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
- arg_set = 1;
- else if (v2.type == T_CLIST)
- arg_set = 2;
+ else if (val_is_ip4(&v2))
+ RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
+ RESULT(T_CLIST, ad, [[ clist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else
- runtime("Can't add/delete non-pair");
-
- res.type = T_CLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = int_set_add(fs->pool, v1.val.ad, n);
- else
- res.val.ad = int_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
-
- case 'd':
- if (!arg_set)
- res.val.ad = int_set_del(fs->pool, v1.val.ad, n);
- else
- res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
-
- case 'f':
- if (!arg_set)
- runtime("Can't filter pair");
- res.val.ad = clist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
-
- default:
- bug("unknown Ca operation");
- }
+ runtime("Can't delete non-pair");
}
+
else if (v1.type == T_ECLIST)
{
- /* Extended community list */
- int arg_set = 0;
-
/* v2.val is either EC or EC-set */
- if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
- arg_set = 1;
- else if (v2.type == T_ECLIST)
- arg_set = 2;
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_EC)
- runtime("Can't add/delete non-ec");
-
- res.type = T_ECLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = ec_set_add(fs->pool, v1.val.ad, v2.val.ec);
- else
- res.val.ad = ec_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
-
- case 'd':
- if (!arg_set)
- res.val.ad = ec_set_del(fs->pool, v1.val.ad, v2.val.ec);
- else
- res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
-
- case 'f':
- if (!arg_set)
- runtime("Can't filter ec");
- res.val.ad = eclist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
-
- default:
- bug("unknown Ca operation");
- }
+ runtime("Can't delete non-ec");
+ else
+ RESULT(T_ECLIST, ad, [[ ec_set_del(fs->pool, v1.val.ad, v2.val.ec) ]]);
}
+
else if (v1.type == T_LCLIST)
{
- /* Large community list */
- int arg_set = 0;
-
/* v2.val is either LC or LC-set */
- if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
- arg_set = 1;
- else if (v2.type == T_LCLIST)
- arg_set = 2;
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fs->pool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_LC)
- runtime("Can't add/delete non-lc");
-
- res.type = T_LCLIST;
- switch (what->aux)
- {
- case 'a':
- if (arg_set == 1)
- runtime("Can't add set");
- else if (!arg_set)
- res.val.ad = lc_set_add(fs->pool, v1.val.ad, v2.val.lc);
- else
- res.val.ad = lc_set_union(fs->pool, v1.val.ad, v2.val.ad);
- break;
+ runtime("Can't delete non-lc");
+ else
+ RESULT(T_LCLIST, ad, [[ lc_set_del(fs->pool, v1.val.ad, v2.val.lc) ]]);
+ }
- case 'd':
- if (!arg_set)
- res.val.ad = lc_set_del(fs->pool, v1.val.ad, v2.val.lc);
- else
- res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 0);
- break;
+ else
+ runtime("Can't delete in non-[e|l]clist");
+ }
- case 'f':
- if (!arg_set)
- runtime("Can't filter lc");
- res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1);
- break;
+ INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */
+ ARG_ANY(1);
+ ARG_ANY(2);
+ if (v1.type == T_PATH)
+ {
+ u32 key = 0;
- default:
- bug("unknown Ca operation");
- }
+ if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
+ RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, v2.val.t, key, 1) ]]);
+ else
+ runtime("Can't filter integer");
}
- else
- runtime("Can't add/delete to non-[e|l]clist");
- }
+ else if (v1.type == T_CLIST)
+ {
+ /* Community (or cluster) list */
+ struct f_val dummy;
- INST(FI_ROA_CHECK) { /* ROA Check */
- if (what->arg1)
+ if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
+ RESULT(T_CLIST, ad, [[ clist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter pair");
+ }
+
+ else if (v1.type == T_ECLIST)
{
- ARG(1, T_NET);
- ARG(2, T_INT);
+ /* v2.val is either EC or EC-set */
+ if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
+ RESULT(T_ECLIST, ad, [[ eclist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter ec");
+ }
- as = v2.val.i;
+ else if (v1.type == T_LCLIST)
+ {
+ /* v2.val is either LC or LC-set */
+ if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
+ RESULT(T_LCLIST, ad, [[ lclist_filter(fs->pool, v1.val.ad, &v2, 1) ]]);
+ else
+ runtime("Can't filter lc");
}
+
else
- {
- ACCESS_RTE;
- ACCESS_EATTRS;
- v1.val.net = (*fs->rte)->net->n.addr;
+ runtime("Can't filter non-[e|l]clist");
+ }
- /* We ignore temporary attributes, probably not a problem here */
- /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
- eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
+ INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */
+ RTC(1);
+ ACCESS_RTE;
+ ACCESS_EATTRS;
+ const net_addr *net = (*fs->rte)->net->n.addr;
- if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
- runtime("Missing AS_PATH attribute");
+ /* We ignore temporary attributes, probably not a problem here */
+ /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
+ eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
- as_path_get_last(e->u.ptr, &as);
- }
+ if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
+ runtime("Missing AS_PATH attribute");
+
+ u32 as = 0;
+ as_path_get_last(e->u.ptr, &as);
- struct rtable *table = what->a[2].rtc->table;
if (!table)
runtime("Missing ROA table");
if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
runtime("Table type must be either ROA4 or ROA6");
- res.type = T_ENUM_ROA;
+ if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
+ RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
+ else
+ RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]);
+ }
+
+ INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */
+ ARG(1, T_NET);
+ ARG(2, T_INT);
+ RTC(3);
+
+ u32 as = v2.val.i;
+
+ if (!table)
+ runtime("Missing ROA table");
+
+ if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
+ runtime("Table type must be either ROA4 or ROA6");
if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
- res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */
+ RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */
else
- res.val.i = net_roa_check(table, v1.val.net, as);
+ RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, v1.val.net, as) ]]);
}
- INST(FI_FORMAT) { /* Format */
+ INST(FI_FORMAT, 1, 0) { /* Format */
ARG_ANY(1);
-
- res.type = T_STRING;
- res.val.s = val_format_str(fs, v1);
+ RESULT(T_STRING, s, val_format_str(fs, &v1));
}
- INST(FI_ASSERT) { /* Birdtest Assert */
+ INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
ARG(1, T_BOOL);
-
- res.type = v1.type;
- res.val = v1.val;
-
+ POSTFIXIFY([[
+ dest->items[pos].s = what->a[1].p;
+ ]]);
CALL(bt_assert_hook, res.val.i, what);
}
-
diff --git a/filter/f-util.c b/filter/f-util.c
index 11a5e97e..4f11a6d9 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -30,8 +30,7 @@ struct f_inst *
f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
{
struct f_inst *ret = f_new_inst(fi_code);
- ret->aux = (da.f_type << 8) | da.type;
- ret->a[1].i = da.ea_code;
+ ret->da = da;
return ret;
}
@@ -39,9 +38,7 @@ struct f_inst *
f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
{
struct f_inst *ret = f_new_inst(fi_code);
- ret->aux = sa.f_type;
- ret->a[1].i = sa.sa_code;
- ret->a[0].i = sa.readonly;
+ ret->sa = sa;
return ret;
}
@@ -49,13 +46,12 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
* Generate set_dynamic( operation( get_dynamic(), argument ) )
*/
struct f_inst *
-f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
+f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument)
{
struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
- *oper = f_new_inst(operation),
+ *oper = f_new_inst(fi_code),
*get_dyn = f_new_inst_da(FI_EA_GET, da);
- oper->aux = operation_aux;
oper->a[0].p = get_dyn;
oper->a[1].p = argument;
@@ -63,21 +59,6 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s
return set_dyn;
}
-struct f_inst *
-f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
-{
- struct f_inst *ret = f_new_inst(FI_ROA_CHECK);
- ret->arg1 = prefix;
- ret->arg2 = asn;
- /* prefix == NULL <-> asn == NULL */
-
- if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
- cf_error("%s is not a ROA table", table->name);
- ret->arg3 = table;
-
- return ret;
-}
-
static const char * const f_instruction_name_str[] = {
#define F(c,a,b) \
[c] = #c,
@@ -219,7 +200,7 @@ ca_lookup(pool *p, const char *name, int f_type)
}
cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1);
- cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id));
+ cas->fda = f_new_dynamic_attr(ea_type, 0, f_type, EA_CUSTOM(id));
cas->uc = 1;
strcpy(cas->name, name);
diff --git a/filter/filter.c b/filter/filter.c
index 308792b9..858d5fc5 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -50,15 +50,6 @@
#define CMP_ERROR 999
-#define FILTER_STACK_DEPTH 16384
-
-/* Filter interpreter stack. Make this thread local after going parallel. */
-struct filter_stack {
- struct f_val val;
-};
-
-static struct filter_stack filter_stack[FILTER_STACK_DEPTH];
-
/* Internal filter state, to be allocated on stack when executing filters */
struct filter_state {
struct rte **rte;
@@ -66,14 +57,10 @@ struct filter_state {
struct ea_list **eattrs;
struct linpool *pool;
struct buffer buf;
- struct filter_stack *stack;
- int stack_ptr;
int flags;
};
-void (*bt_assert_hook)(int result, struct f_inst *assert);
-
-static struct adata undef_adata; /* adata of length 0 used for undefined */
+void (*bt_assert_hook)(int result, const struct f_line_item *assert);
/* Special undef value for paths and clists */
static inline int
@@ -81,9 +68,23 @@ undef_value(struct f_val v)
{
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
- (v.val.ad == &undef_adata);
+ (v.val.ad == &null_adata);
}
+const struct f_val f_const_empty_path = {
+ .type = T_PATH,
+ .val.ad = &null_adata,
+}, f_const_empty_clist = {
+ .type = T_CLIST,
+ .val.ad = &null_adata,
+}, f_const_empty_eclist = {
+ .type = T_ECLIST,
+ .val.ad = &null_adata,
+}, f_const_empty_lclist = {
+ .type = T_LCLIST,
+ .val.ad = &null_adata,
+};
+
static struct adata *
adata_empty(struct linpool *pool, int l)
{
@@ -93,16 +94,16 @@ adata_empty(struct linpool *pool, int l)
}
static void
-pm_format(struct f_path_mask *p, buffer *buf)
+pm_format(const struct f_path_mask *p, buffer *buf)
{
buffer_puts(buf, "[= ");
- while (p)
+ for (uint i=0; i<p->len; i++)
{
- switch(p->kind)
+ switch(p->item[i].kind)
{
case PM_ASN:
- buffer_print(buf, "%u ", p->val);
+ buffer_print(buf, "%u ", p->item[i].asn);
break;
case PM_QUESTION:
@@ -114,21 +115,20 @@ pm_format(struct f_path_mask *p, buffer *buf)
break;
case PM_ASN_RANGE:
- buffer_print(buf, "%u..%u ", p->val, p->val2);
+ buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
break;
case PM_ASN_EXPR:
ASSERT(0);
}
- p = p->next;
}
buffer_puts(buf, "=]");
}
-static inline int val_is_ip4(const struct f_val v)
-{ return (v.type == T_IP) && ipa_is_ip4(v.val.ip); }
+static inline int val_is_ip4(const struct f_val *v)
+{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
static inline int
lcomm_cmp(lcomm v1, lcomm v2)
@@ -152,25 +152,25 @@ lcomm_cmp(lcomm v1, lcomm v2)
* that it can be used for building balanced trees.
*/
int
-val_compare(struct f_val v1, struct f_val v2)
+val_compare(const struct f_val *v1, const struct f_val *v2)
{
- if (v1.type != v2.type) {
- if (v1.type == T_VOID) /* Hack for else */
+ if (v1->type != v2->type) {
+ if (v1->type == T_VOID) /* Hack for else */
return -1;
- if (v2.type == T_VOID)
+ if (v2->type == T_VOID)
return 1;
/* IP->Quad implicit conversion */
- if ((v1.type == T_QUAD) && val_is_ip4(v2))
- return uint_cmp(v1.val.i, ipa_to_u32(v2.val.ip));
- if (val_is_ip4(v1) && (v2.type == T_QUAD))
- return uint_cmp(ipa_to_u32(v1.val.ip), v2.val.i);
+ if ((v1->type == T_QUAD) && val_is_ip4(v2))
+ return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
+ if (val_is_ip4(v1) && (v2->type == T_QUAD))
+ return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
debug( "Types do not match in val_compare\n" );
return CMP_ERROR;
}
- switch (v1.type) {
+ switch (v1->type) {
case T_VOID:
return 0;
case T_ENUM:
@@ -178,47 +178,52 @@ val_compare(struct f_val v1, struct f_val v2)
case T_BOOL:
case T_PAIR:
case T_QUAD:
- return uint_cmp(v1.val.i, v2.val.i);
+ return uint_cmp(v1->val.i, v2->val.i);
case T_EC:
case T_RD:
- return u64_cmp(v1.val.ec, v2.val.ec);
+ return u64_cmp(v1->val.ec, v2->val.ec);
case T_LC:
- return lcomm_cmp(v1.val.lc, v2.val.lc);
+ return lcomm_cmp(v1->val.lc, v2->val.lc);
case T_IP:
- return ipa_compare(v1.val.ip, v2.val.ip);
+ return ipa_compare(v1->val.ip, v2->val.ip);
case T_NET:
- return net_compare(v1.val.net, v2.val.net);
+ return net_compare(v1->val.net, v2->val.net);
case T_STRING:
- return strcmp(v1.val.s, v2.val.s);
+ return strcmp(v1->val.s, v2->val.s);
default:
return CMP_ERROR;
}
}
static int
-pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
+pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
{
- while (m1 && m2)
+ if (m1->len != m2->len)
+
+ for (uint i=0; i<m1->len; i++)
{
- if (m1->kind != m2->kind)
+ if (m1->item[i].kind != m2->item[i].kind)
return 0;
- if (m1->kind == PM_ASN_EXPR)
- {
- if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
- return 0;
- }
- else
- {
- if ((m1->val != m2->val) || (m1->val2 != m2->val2))
- return 0;
+ switch (m1->item[i].kind) {
+ case PM_ASN:
+ if (m1->item[i].asn != m2->item[i].asn)
+ return 0;
+ break;
+ case PM_ASN_EXPR:
+ if (!f_same(m1->item[i].expr, m2->item[i].expr))
+ return 0;
+ break;
+ case PM_ASN_RANGE:
+ if (m1->item[i].from != m2->item[i].from)
+ return 0;
+ if (m1->item[i].to != m2->item[i].to)
+ return 0;
+ break;
}
-
- m1 = m1->next;
- m2 = m2->next;
}
- return !m1 && !m2;
+ return 1;
}
/**
@@ -230,7 +235,7 @@ pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
* Comparison of values of different types is valid and returns 0.
*/
int
-val_same(struct f_val v1, struct f_val v2)
+val_same(const struct f_val *v1, const struct f_val *v2)
{
int rc;
@@ -238,28 +243,28 @@ val_same(struct f_val v1, struct f_val v2)
if (rc != CMP_ERROR)
return !rc;
- if (v1.type != v2.type)
+ if (v1->type != v2->type)
return 0;
- switch (v1.type) {
+ switch (v1->type) {
case T_PATH_MASK:
- return pm_same(v1.val.path_mask, v2.val.path_mask);
+ return pm_same(v1->val.path_mask, v2->val.path_mask);
case T_PATH:
case T_CLIST:
case T_ECLIST:
case T_LCLIST:
- return adata_same(v1.val.ad, v2.val.ad);
+ return adata_same(v1->val.ad, v2->val.ad);
case T_SET:
- return same_tree(v1.val.t, v2.val.t);
+ return same_tree(v1->val.t, v2->val.t);
case T_PREFIX_SET:
- return trie_same(v1.val.ti, v2.val.ti);
+ return trie_same(v1->val.ti, v2->val.ti);
default:
- bug("Invalid type in val_same(): %x", v1.type);
+ bug("Invalid type in val_same(): %x", v1->type);
}
}
static int
-clist_set_type(struct f_tree *set, struct f_val *v)
+clist_set_type(const struct f_tree *set, struct f_val *v)
{
switch (set->from.type)
{
@@ -272,7 +277,7 @@ clist_set_type(struct f_tree *set, struct f_val *v)
return 1;
case T_IP:
- if (val_is_ip4(set->from) && val_is_ip4(set->to))
+ if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
{
v->type = T_QUAD;
return 1;
@@ -285,15 +290,15 @@ clist_set_type(struct f_tree *set, struct f_val *v)
}
static inline int
-eclist_set_type(struct f_tree *set)
+eclist_set_type(const struct f_tree *set)
{ return set->from.type == T_EC; }
static inline int
-lclist_set_type(struct f_tree *set)
+lclist_set_type(const struct f_tree *set)
{ return set->from.type == T_LC; }
static int
-clist_match_set(struct adata *clist, struct f_tree *set)
+clist_match_set(const struct adata *clist, const struct f_tree *set)
{
if (!clist)
return 0;
@@ -307,14 +312,14 @@ clist_match_set(struct adata *clist, struct f_tree *set)
while (l < end) {
v.val.i = *l++;
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
return 0;
}
static int
-eclist_match_set(struct adata *list, struct f_tree *set)
+eclist_match_set(const struct adata *list, const struct f_tree *set)
{
if (!list)
return 0;
@@ -330,7 +335,7 @@ eclist_match_set(struct adata *list, struct f_tree *set)
v.type = T_EC;
for (i = 0; i < len; i += 2) {
v.val.ec = ec_get(l, i);
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
@@ -338,7 +343,7 @@ eclist_match_set(struct adata *list, struct f_tree *set)
}
static int
-lclist_match_set(struct adata *list, struct f_tree *set)
+lclist_match_set(const struct adata *list, const struct f_tree *set)
{
if (!list)
return 0;
@@ -354,23 +359,23 @@ lclist_match_set(struct adata *list, struct f_tree *set)
v.type = T_LC;
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
}
return 0;
}
-static struct adata *
-clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
if (tree)
- clist_set_type(set.val.t, &v);
+ clist_set_type(set->val.t, &v);
else
v.type = T_PAIR;
@@ -383,7 +388,7 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos
while (l < end) {
v.val.i = *l++;
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
+ if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
*k++ = v.val.i;
}
@@ -396,13 +401,13 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos
return res;
}
-static struct adata *
-eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
@@ -415,7 +420,7 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
for (i = 0; i < len; i += 2) {
v.val.ec = ec_get(l, i);
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
+ if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
*k++ = l[i];
*k++ = l[i+1];
}
@@ -430,13 +435,13 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
return res;
}
-static struct adata *
-lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
+static const struct adata *
+lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
{
if (!list)
return NULL;
- int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+ int tree = (set->type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
@@ -449,7 +454,7 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
- if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
+ if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
k = lc_copy(k, l+i);
}
@@ -470,57 +475,57 @@ lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
* Checks if @v1 is element (|~| operator) of @v2.
*/
static int
-val_in_range(struct f_val v1, struct f_val v2)
+val_in_range(const struct f_val *v1, const struct f_val *v2)
{
- if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
- return as_path_match(v1.val.ad, v2.val.path_mask);
+ if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
+ return as_path_match(v1->val.ad, v2->val.path_mask);
- if ((v1.type == T_INT) && (v2.type == T_PATH))
- return as_path_contains(v2.val.ad, v1.val.i, 1);
+ if ((v1->type == T_INT) && (v2->type == T_PATH))
+ return as_path_contains(v2->val.ad, v1->val.i, 1);
- if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
- return int_set_contains(v2.val.ad, v1.val.i);
+ if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
+ return int_set_contains(v2->val.ad, v1->val.i);
/* IP->Quad implicit conversion */
- if (val_is_ip4(v1) && (v2.type == T_CLIST))
- return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
+ if (val_is_ip4(v1) && (v2->type == T_CLIST))
+ return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
- if ((v1.type == T_EC) && (v2.type == T_ECLIST))
- return ec_set_contains(v2.val.ad, v1.val.ec);
+ if ((v1->type == T_EC) && (v2->type == T_ECLIST))
+ return ec_set_contains(v2->val.ad, v1->val.ec);
- if ((v1.type == T_LC) && (v2.type == T_LCLIST))
- return lc_set_contains(v2.val.ad, v1.val.lc);
+ if ((v1->type == T_LC) && (v2->type == T_LCLIST))
+ return lc_set_contains(v2->val.ad, v1->val.lc);
- if ((v1.type == T_STRING) && (v2.type == T_STRING))
- return patmatch(v2.val.s, v1.val.s);
+ if ((v1->type == T_STRING) && (v2->type == T_STRING))
+ return patmatch(v2->val.s, v1->val.s);
- if ((v1.type == T_IP) && (v2.type == T_NET))
- return ipa_in_netX(v1.val.ip, v2.val.net);
+ if ((v1->type == T_IP) && (v2->type == T_NET))
+ return ipa_in_netX(v1->val.ip, v2->val.net);
- if ((v1.type == T_NET) && (v2.type == T_NET))
- return net_in_netX(v1.val.net, v2.val.net);
+ if ((v1->type == T_NET) && (v2->type == T_NET))
+ return net_in_netX(v1->val.net, v2->val.net);
- if ((v1.type == T_NET) && (v2.type == T_PREFIX_SET))
- return trie_match_net(v2.val.ti, v1.val.net);
+ if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
+ return trie_match_net(v2->val.ti, v1->val.net);
- if (v2.type != T_SET)
+ if (v2->type != T_SET)
return CMP_ERROR;
/* With integrated Quad<->IP implicit conversion */
- if ((v1.type == v2.val.t->from.type) ||
- ((v1.type == T_QUAD) && val_is_ip4(v2.val.t->from) && val_is_ip4(v2.val.t->to)))
- return !!find_tree(v2.val.t, v1);
+ if ((v1->type == v2->val.t->from.type) ||
+ ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
+ return !!find_tree(v2->val.t, v1);
- if (v1.type == T_CLIST)
- return clist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_CLIST)
+ return clist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_ECLIST)
- return eclist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_ECLIST)
+ return eclist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_LCLIST)
- return lclist_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_LCLIST)
+ return lclist_match_set(v1->val.ad, v2->val.t);
- if (v1.type == T_PATH)
- return as_path_match_set(v1.val.ad, v2.val.t);
+ if (v1->type == T_PATH)
+ return as_path_match_set(v1->val.ad, v2->val.t);
return CMP_ERROR;
}
@@ -529,31 +534,31 @@ val_in_range(struct f_val v1, struct f_val v2)
* val_format - format filter value
*/
void
-val_format(struct f_val v, buffer *buf)
+val_format(const struct f_val *v, buffer *buf)
{
char buf2[1024];
- switch (v.type)
+ switch (v->type)
{
case T_VOID: buffer_puts(buf, "(void)"); return;
- case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
- case T_INT: buffer_print(buf, "%u", v.val.i); return;
- case T_STRING: buffer_print(buf, "%s", v.val.s); return;
- case T_IP: buffer_print(buf, "%I", v.val.ip); return;
- case T_NET: buffer_print(buf, "%N", v.val.net); return;
- case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
- case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
- case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
- case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
- case T_RD: rd_format(v.val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
- case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
- case T_SET: tree_format(v.val.t, buf); return;
- case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
- case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
- case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
- case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
- case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
- case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
- default: buffer_print(buf, "[unknown type %x]", v.type); return;
+ case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
+ case T_INT: buffer_print(buf, "%u", v->val.i); return;
+ case T_STRING: buffer_print(buf, "%s", v->val.s); return;
+ case T_IP: buffer_print(buf, "%I", v->val.ip); return;
+ case T_NET: buffer_print(buf, "%N", v->val.net); return;
+ case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
+ case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
+ case T_EC: ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
+ case T_LC: lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
+ case T_RD: rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
+ case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
+ case T_SET: tree_format(v->val.t, buf); return;
+ case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
+ case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
+ case T_CLIST: int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
+ case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
+ case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
+ case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
+ default: buffer_print(buf, "[unknown type %x]", v->type); return;
}
}
@@ -599,7 +604,7 @@ f_rta_cow(struct filter_state *fs)
}
static char *
-val_format_str(struct filter_state *fs, struct f_val v) {
+val_format_str(struct filter_state *fs, struct f_val *v) {
buffer b;
LOG_BUFFER_INIT(b);
val_format(v, &b);
@@ -608,6 +613,98 @@ val_format_str(struct filter_state *fs, struct f_val v) {
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
+static uint
+inst_line_size(const struct f_inst *what)
+{
+ uint cnt = 0;
+ for ( ; what; what = what->next) {
+ switch (what->fi_code) {
+#include "filter/f-inst-line-size.c"
+ }
+ }
+ return cnt;
+}
+
+#if DEBUGGING
+#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
+static const char f_dump_line_indent_str[] = " ";
+
+static char val_dump_buffer[1024];
+
+static const char *
+val_dump(const struct f_val *v) {
+ static buffer b = {
+ .start = val_dump_buffer,
+ .end = val_dump_buffer + 1024,
+ };
+ b.pos = b.start;
+ val_format(v, &b);
+ return val_dump_buffer;
+}
+
+static void f_dump_line(const struct f_line *dest, int indent);
+
+static void
+f_dump_line_item(const struct f_line_item *item, int indent)
+{
+ debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno);
+ switch (item->fi_code) {
+#include "filter/f-inst-dump.c"
+ }
+}
+
+static void
+f_dump_line(const struct f_line *dest, int indent)
+{
+ if (!dest) {
+ debug("%sNo filter line (NULL)\n", INDENT);
+ return;
+ }
+ debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
+ for (uint i=0; i<dest->len; i++)
+ f_dump_line_item(&dest->items[i], indent+1);
+ debug("%sFilter line %p dump done\n", INDENT, dest);
+#undef INDENT
+}
+#else
+#define f_dump_line(...)
+#endif
+
+static uint
+postfixify(struct f_line *dest, const struct f_inst *what, uint pos)
+{
+ for ( ; what; what = what->next) {
+ switch (what->fi_code) {
+#include "filter/f-inst-postfixify.c"
+ }
+ pos++;
+ }
+ return pos;
+}
+
+struct f_line *
+f_postfixify_concat(struct f_inst *first, ...)
+{
+ va_list args;
+ va_list argd;
+ va_start(args, first);
+ va_copy(argd, args);
+
+ uint len = 0;
+ for (struct f_inst *what = first; what; what = va_arg(args, struct f_inst *))
+ len += inst_line_size(what);
+
+ va_end(args);
+
+ struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len);
+
+ for (struct f_inst *what = first; what; what = va_arg(argd, struct f_inst *))
+ out->len = postfixify(out, what, out->len);
+
+ f_dump_line(out, 0);
+ return out;
+}
+
/**
* interpret
* @fs: filter state
@@ -624,26 +721,28 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
* TWOARGS macro to get both of them evaluated.
*/
static enum filter_return
-interpret(struct filter_state *fs, struct f_inst *what)
+interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
{
- struct symbol *sym;
- struct f_val *vp;
- unsigned u1, u2;
- enum filter_return fret;
- int i;
- u32 as;
+ struct f_val_stack vstk;
+ vstk.cnt = 0;
-#define res fs->stack[fs->stack_ptr].val
-#define v0 res
-#define v1 fs->stack[fs->stack_ptr + 1].val
-#define v2 fs->stack[fs->stack_ptr + 2].val
-#define v3 fs->stack[fs->stack_ptr + 3].val
+ struct f_exec_stack estk;
+ estk.cnt = 1;
+ estk.item[0].line = line;
+ estk.item[0].pos = 0;
- res = (struct f_val) { .type = T_VOID };
+#define curline estk.item[estk.cnt-1]
+
+ while (estk.cnt > 0) {
+ while (curline.pos < curline.line->len) {
+ const struct f_line_item *what = &(curline.line->items[curline.pos++]);
- for ( ; what; what = what->next) {
- res = (struct f_val) { .type = T_VOID };
- switch (what->fi_code) {
+
+ switch (what->fi_code) {
+#define res vstk.val[vstk.cnt]
+#define v1 vstk.val[vstk.cnt]
+#define v2 vstk.val[vstk.cnt + 1]
+#define v3 vstk.val[vstk.cnt + 2]
#define runtime(fmt, ...) do { \
if (!(fs->flags & FF_SILENT)) \
@@ -651,84 +750,70 @@ interpret(struct filter_state *fs, struct f_inst *what)
return F_ERROR; \
} while(0)
-#define ARG_ANY_T(n, tt) INTERPRET(what->a[n-1].p, tt)
-#define ARG_ANY(n) ARG_ANY_T(n, n)
-
-#define ARG_T(n,tt,t) do { \
- ARG_ANY_T(n,tt); \
- if (v##tt.type != t) \
- runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
- n, f_instruction_name(what->fi_code), t, v##tt.type); \
-} while (0)
-
-#define ARG(n,t) ARG_T(n,n,t)
-
-#define INTERPRET(what_, n) do { \
- fs->stack_ptr += n; \
- fret = interpret(fs, what_); \
- fs->stack_ptr -= n; \
- if (fret == F_RETURN) \
- bug("This shall not happen"); \
- if (fret > F_RETURN) \
- return fret; \
-} while (0)
-
#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
-
#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
-#define BITFIELD_MASK(what_) (1u << EA_BIT_GET(what_->a[1].i))
-
- case FI_NOP:
- bug("This shall not happen");
-
#include "filter/f-inst-interpret.c"
-
- break;
- default:
- bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
-
#undef res
+#undef v1
+#undef v2
+#undef v3
#undef runtime
-#undef ARG_ANY
-#undef ARG
-#undef INTERPRET
#undef ACCESS_RTE
#undef ACCESS_EATTRS
+ }
}
+ estk.cnt--;
}
- return F_NOP;
-}
+ switch (vstk.cnt) {
+ case 0:
+ if (val) {
+ log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack");
+ return F_ERROR;
+ }
+ return F_NOP;
+ case 1:
+ if (val) {
+ *val = vstk.val[0];
+ return F_NOP;
+ }
+ /* fallthrough */
+ default:
+ log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt);
+ return F_ERROR;
+ }
+}
-#define ARG(n) \
- if (!i_same(f1->a[n-1].p, f2->a[n-1].p)) \
- return 0;
-
-#define ONEARG ARG(1);
-#define TWOARGS ONEARG; ARG(2);
-#define THREEARGS TWOARGS; ARG(3);
-
-#define A2_SAME if (f1->a[1].i != f2->a[1].i) return 0;
/*
- * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
+ * f_same - function that does real comparing of instruction trees, you should call filter_same from outside
*/
int
-i_same(struct f_inst *f1, struct f_inst *f2)
+f_same(const struct f_line *fl1, const struct f_line *fl2)
{
- if ((!!f1) != (!!f2))
- return 0;
- if (!f1)
+ if ((!fl1) && (!fl2))
return 1;
- if (f1->aux != f2->aux)
+ if ((!fl1) || (!fl2))
return 0;
- if (f1->fi_code != f2->fi_code)
+ if (fl1->len != fl2->len)
return 0;
- if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
- return 1;
+ for (uint i=0; i<fl1->len; i++) {
+#define f1 (&(fl1->items[i]))
+#define f2 (&(fl2->items[i]))
+ if (f1->fi_code != f2->fi_code)
+ return 0;
+ if (f1->flags != f2->flags)
+ return 0;
- switch(f1->fi_code) {
+ switch(f1->fi_code) {
+#include "filter/f-inst-same.c"
+ }
+ }
+ return 1;
+}
+
+#if 0
case FI_ADD: /* fall through */
case FI_SUBTRACT:
case FI_MULTIPLY:
@@ -842,9 +927,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case FI_ASSERT: ONEARG; break;
default:
bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
- }
- return i_same(f1->next, f2->next);
-}
+#endif
/**
* f_run - run a filter for a route
@@ -871,7 +954,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
* modified in place, old cached rta is possibly freed.
*/
enum filter_return
-f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
+f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
{
if (filter == FILTER_ACCEPT)
return F_ACCEPT;
@@ -886,12 +969,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
.rte = rte,
.pool = tmp_pool,
.flags = flags,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
- enum filter_return fret = interpret(&fs, filter->root);
+ enum filter_return fret = interpret(&fs, filter->root, NULL);
if (fs.old_rta) {
/*
@@ -925,54 +1007,52 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
enum filter_return
-f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
+f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
{
struct filter_state fs = {
.rte = rte,
.pool = tmp_pool,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
/* Note that in this function we assume that rte->attrs is private / uncached */
- return interpret(&fs, expr);
+ return interpret(&fs, expr, NULL);
}
enum filter_return
-f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres)
+f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
{
struct filter_state fs = {
.pool = tmp_pool,
- .stack = filter_stack,
};
LOG_BUFFER_INIT(fs.buf);
- enum filter_return fret = interpret(&fs, expr);
- *pres = filter_stack[0].val;
+ enum filter_return fret = interpret(&fs, expr, pres);
return fret;
}
uint
-f_eval_int(struct f_inst *expr)
+f_eval_int(const struct f_line *expr)
{
/* Called independently in parse-time to eval expressions */
struct filter_state fs = {
.pool = cfg_mem,
- .stack = filter_stack,
};
+ struct f_val val;
+
LOG_BUFFER_INIT(fs.buf);
- if (interpret(&fs, expr) > F_RETURN)
+ if (interpret(&fs, expr, &val) > F_RETURN)
cf_error("Runtime error while evaluating expression");
- if (filter_stack[0].val.type != T_INT)
+ if (val.type != T_INT)
cf_error("Integer expression expected");
- return filter_stack[0].val.val.i;
+ return val.val.i;
}
/**
@@ -993,5 +1073,5 @@ filter_same(struct filter *new, struct filter *old)
if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
new == FILTER_ACCEPT || new == FILTER_REJECT)
return 0;
- return i_same(new->root, old->root);
+ return f_same(new->root, old->root);
}
diff --git a/filter/filter.h b/filter/filter.h
index 594c9511..87bd2c36 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -14,13 +14,65 @@
#include "nest/route.h"
#include "nest/attrs.h"
+/* IP prefix range structure */
struct f_prefix {
- net_addr net;
- u8 lo, hi;
+ net_addr net; /* The matching prefix must match this net */
+ u8 lo, hi; /* And its length must fit between lo and hi */
};
+/* Type numbers must be in 0..0xff range */
+#define T_MASK 0xff
+
+/* Internal types */
+enum f_type {
+/* Do not use type of zero, that way we'll see errors easier. */
+ T_VOID = 1,
+
+/* User visible types, which fit in int */
+ T_INT = 0x10,
+ T_BOOL = 0x11,
+ T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */
+ T_QUAD = 0x13,
+
+/* Put enumerational types in 0x30..0x3f range */
+ T_ENUM_LO = 0x30,
+ T_ENUM_HI = 0x3f,
+
+ T_ENUM_RTS = 0x30,
+ T_ENUM_BGP_ORIGIN = 0x31,
+ T_ENUM_SCOPE = 0x32,
+ T_ENUM_RTC = 0x33,
+ T_ENUM_RTD = 0x34,
+ T_ENUM_ROA = 0x35,
+ T_ENUM_NETTYPE = 0x36,
+ T_ENUM_RA_PREFERENCE = 0x37,
+
+/* new enums go here */
+ T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
+
+#define T_ENUM T_ENUM_LO ... T_ENUM_HI
+
+/* Bigger ones */
+ T_IP = 0x20,
+ T_NET = 0x21,
+ T_STRING = 0x22,
+ T_PATH_MASK = 0x23, /* mask for BGP path */
+ T_PATH = 0x24, /* BGP path */
+ T_CLIST = 0x25, /* Community list */
+ T_EC = 0x26, /* Extended community value, u64 */
+ T_ECLIST = 0x27, /* Extended community list */
+ T_LC = 0x28, /* Large community value, lcomm */
+ T_LCLIST = 0x29, /* Large community list */
+ T_RD = 0x2a, /* Route distinguisher for VPN addresses */
+ T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */
+
+ T_SET = 0x80,
+ T_PREFIX_SET = 0x81,
+} PACKED;
+
+/* Filter value; size of this affects filter memory consumption */
struct f_val {
- int type; /* T_* */
+ enum f_type type; /* T_* */
union {
uint i;
u64 ec;
@@ -28,27 +80,42 @@ struct f_val {
ip_addr ip;
const net_addr *net;
char *s;
- struct f_tree *t;
- struct f_trie *ti;
- struct adata *ad;
- struct f_path_mask *path_mask;
+ const struct f_tree *t;
+ const struct f_trie *ti;
+ const struct adata *ad;
+ const struct f_path_mask *path_mask;
+ struct f_path_mask_item pmi;
} val;
};
+/* Dynamic attribute definition (eattrs) */
struct f_dynamic_attr {
- int type;
- int f_type;
- int ea_code;
+ u8 type; /* EA type (EAF_*) */
+ u8 bit; /* For bitfield accessors */
+ enum f_type f_type; /* Filter type */
+ uint ea_code; /* EA code */
};
+enum f_sa_code {
+ SA_FROM = 1,
+ SA_GW,
+ SA_NET,
+ SA_PROTO,
+ SA_SOURCE,
+ SA_SCOPE,
+ SA_DEST,
+ SA_IFNAME,
+ SA_IFINDEX,
+} PACKED;
+
+/* Static attribute definition (members of struct rta) */
struct f_static_attr {
- int f_type;
- int sa_code;
- int readonly;
+ enum f_type f_type; /* Filter type */
+ enum f_sa_code sa_code; /* Static attribute id */
+ int readonly:1; /* Don't allow writing */
};
-/* Filter instruction types */
-
+/* Filter instruction words */
#define FI__TWOCHAR(a,b) ((a<<8) | b)
#define FI__LIST \
F(FI_NOP, 0, '0') \
@@ -96,16 +163,20 @@ struct f_static_attr {
F(FI_AS_PATH_LAST_NAG, 'a', 'L') \
F(FI_RETURN, 0, 'r') \
F(FI_CALL, 'c', 'a') \
+ F(FI_DROP_RESULT, 'd', 'r') \
F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \
F(FI_SWITCH, 'S', 'W') \
F(FI_IP_MASK, 'i', 'M') \
- F(FI_EMPTY, 0, 'E') \
F(FI_PATH_PREPEND, 'A', 'p') \
- F(FI_CLIST_ADD_DEL, 'C', 'a') \
- F(FI_ROA_CHECK, 'R', 'C') \
+ F(FI_CLIST_ADD, 'C', 'a') \
+ F(FI_CLIST_DEL, 'C', 'd') \
+ F(FI_CLIST_FILTER, 'C', 'f') \
+ F(FI_ROA_CHECK_IMPLICIT, 'R', 'i') \
+ F(FI_ROA_CHECK_EXPLICIT, 'R', 'e') \
F(FI_FORMAT, 0, 'F') \
F(FI_ASSERT, 'a', 's')
+/* The enum itself */
enum f_instruction_code {
#define F(c,a,b) \
c,
@@ -114,145 +185,165 @@ FI__LIST
FI__MAX,
} PACKED;
+/* Convert the instruction back to the enum name */
const char *f_instruction_name(enum f_instruction_code fi);
-struct f_inst { /* Instruction */
- struct f_inst *next; /* Structure is 16 bytes, anyway */
- enum f_instruction_code fi_code;
+enum f_instruction_flags {
+ FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */
+};
+
+union f_inst_attr {
+ uint i;
+ void *p;
+ struct rtable_config *rtc;
+};
+
+/* Instruction structure for config */
+struct f_inst {
+ struct f_inst *next; /* Next instruction to be executed */
+ enum f_instruction_code fi_code; /* The instruction itself */
u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union {
- union {
- uint i;
- void *p;
- struct rtable_config *rtc;
- } a[3]; /* The three arguments */
+ union f_inst_attr a[3]; /* The three arguments */
struct f_val val; /* The value if FI_CONSTANT */
+ struct {
+ union f_inst_attr sa_a[1];
+ struct f_static_attr sa; /* Static attribute def for FI_RTA_* */
+ };
+ struct {
+ union f_inst_attr da_a[1];
+ struct f_dynamic_attr da; /* Dynamic attribute def for FI_EA_* */
+ };
};
int lineno;
};
-#define arg1 a[0].p
-#define arg2 a[1].p
-#define arg3 a[2].p
+/* Possible return values of filter execution */
+enum filter_return {
+ F_NOP = 0,
+ F_NONL,
+ F_RETURN,
+ F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */
+ F_REJECT,
+ F_ERROR,
+ F_QUITBIRD,
+};
+
+/* Filter structures for execution */
+struct f_line;
+/* The single instruction item */
+struct f_line_item {
+ enum f_instruction_code fi_code; /* What to do */
+ enum f_instruction_flags flags; /* Flags, instruction-specific */
+ uint lineno; /* Where */
+ union {
+ struct {
+ const struct f_val *vp;
+ const struct symbol *sym;
+ };
+ const struct f_line *lines[2];
+ enum filter_return fret;
+ struct f_static_attr sa;
+ struct f_dynamic_attr da;
+ enum ec_subtype ecs;
+ const char *s;
+ const struct f_tree *tree;
+ const struct rtable_config *rtc;
+ uint count;
+ }; /* Additional instruction data */
+};
+
+/* Line of instructions to be unconditionally executed one after another */
+struct f_line {
+ uint len; /* Line length */
+ struct f_line_item items[0]; /* The items themselves */
+};
+
+/* The filter encapsulating structure to be pointed-to from outside */
struct filter {
char *name;
- struct f_inst *root;
+ struct f_line *root;
+};
+
+/* Convert the f_inst infix tree to the f_line structures */
+struct f_line *f_postfixify_concat(struct f_inst *root, ...);
+static inline struct f_line *f_postfixify(struct f_inst *root)
+{ return f_postfixify_concat(root, NULL); }
+
+#define F_VAL_STACK_MAX 4096
+
+/* Value stack for execution */
+struct f_val_stack {
+ uint cnt; /* Current stack size; 0 for empty */
+ struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */
+};
+
+#define F_EXEC_STACK_MAX 4096
+
+/* Exception bits */
+enum f_exception {
+ FE_RETURN = 0x1,
+};
+
+/* Instruction stack for execution */
+struct f_exec_stack {
+ struct {
+ const struct f_line *line; /* The line that is being executed */
+ uint pos; /* Instruction index in the line */
+ uint ventry; /* Value stack depth on entry */
+ enum f_exception emask; /* Exception mask */
+ } item[F_EXEC_STACK_MAX];
+ uint cnt; /* Current stack size; 0 for empty */
+
};
struct f_inst *f_new_inst(enum f_instruction_code fi_code);
struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
-static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
+static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
+{ return (struct f_dynamic_attr) { .type = type, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
struct f_tree *f_new_tree(void);
-struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
+struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
struct f_tree *build_tree(struct f_tree *);
-struct f_tree *find_tree(struct f_tree *t, struct f_val val);
-int same_tree(struct f_tree *t1, struct f_tree *t2);
-void tree_format(struct f_tree *t, buffer *buf);
+const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
+int same_tree(const struct f_tree *t1, const struct f_tree *t2);
+void tree_format(const struct f_tree *t, buffer *buf);
struct f_trie *f_new_trie(linpool *lp, uint node_size);
void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
-int trie_match_net(struct f_trie *t, const net_addr *n);
-int trie_same(struct f_trie *t1, struct f_trie *t2);
-void trie_format(struct f_trie *t, buffer *buf);
+int trie_match_net(const struct f_trie *t, const net_addr *n);
+int trie_same(const struct f_trie *t1, const struct f_trie *t2);
+void trie_format(const struct f_trie *t, buffer *buf);
struct ea_list;
struct rte;
-enum filter_return {
- F_NOP = 0,
- F_NONL,
- F_RETURN,
- F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */
- F_REJECT,
- F_ERROR,
- F_QUITBIRD,
-};
-
-enum filter_return f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
-enum filter_return f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
-enum filter_return f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres);
-uint f_eval_int(struct f_inst *expr);
+enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
+enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
+enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
+uint f_eval_int(const struct f_line *expr);
char *filter_name(struct filter *filter);
int filter_same(struct filter *new, struct filter *old);
-int i_same(struct f_inst *f1, struct f_inst *f2);
+int f_same(const struct f_line *f1, const struct f_line *f2);
+
+int val_compare(const struct f_val *v1, const struct f_val *v2);
-int val_compare(struct f_val v1, struct f_val v2);
-int val_same(struct f_val v1, struct f_val v2);
+void val_format(const struct f_val *v, buffer *buf);
-void val_format(struct f_val v, buffer *buf);
+extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
#define FILTER_ACCEPT NULL
#define FILTER_REJECT ((void *) 1)
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
-/* Type numbers must be in 0..0xff range */
-#define T_MASK 0xff
-
-/* Internal types */
-/* Do not use type of zero, that way we'll see errors easier. */
-#define T_VOID 1
-
-/* User visible types, which fit in int */
-#define T_INT 0x10
-#define T_BOOL 0x11
-#define T_PAIR 0x12 /* Notice that pair is stored as integer: first << 16 | second */
-#define T_QUAD 0x13
-
-/* Put enumerational types in 0x30..0x3f range */
-#define T_ENUM_LO 0x30
-#define T_ENUM_HI 0x3f
-
-#define T_ENUM_RTS 0x30
-#define T_ENUM_BGP_ORIGIN 0x31
-#define T_ENUM_SCOPE 0x32
-#define T_ENUM_RTC 0x33
-#define T_ENUM_RTD 0x34
-#define T_ENUM_ROA 0x35
-#define T_ENUM_NETTYPE 0x36
-#define T_ENUM_RA_PREFERENCE 0x37
-
-/* new enums go here */
-#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
-
-#define T_ENUM T_ENUM_LO ... T_ENUM_HI
-
-/* Bigger ones */
-#define T_IP 0x20
-#define T_NET 0x21
-#define T_STRING 0x22
-#define T_PATH_MASK 0x23 /* mask for BGP path */
-#define T_PATH 0x24 /* BGP path */
-#define T_CLIST 0x25 /* Community list */
-#define T_EC 0x26 /* Extended community value, u64 */
-#define T_ECLIST 0x27 /* Extended community list */
-#define T_LC 0x28 /* Large community value, lcomm */
-#define T_LCLIST 0x29 /* Large community list */
-#define T_RD 0x2a /* Route distinguisher for VPN addresses */
-
-#define T_SET 0x80
-#define T_PREFIX_SET 0x81
-
-
-#define SA_FROM 1
-#define SA_GW 2
-#define SA_NET 3
-#define SA_PROTO 4
-#define SA_SOURCE 5
-#define SA_SCOPE 6
-#define SA_DEST 7
-#define SA_IFNAME 8
-#define SA_IFINDEX 9
-
struct f_tree {
struct f_tree *left, *right;
@@ -291,12 +382,12 @@ struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type);
/* Bird Tests */
struct f_bt_test_suite {
node n; /* Node in config->tests */
- struct f_inst *fn; /* Root of function */
+ struct f_line *fn; /* Root of function */
const char *fn_name; /* Name of test */
const char *dsc; /* Description */
};
/* Hook for call bt_assert() function in configuration */
-extern void (*bt_assert_hook)(int result, struct f_inst *assert);
+extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
#endif
diff --git a/filter/filter_test.c b/filter/filter_test.c
index 32555d82..e19b0a75 100644
--- a/filter/filter_test.c
+++ b/filter/filter_test.c
@@ -40,8 +40,7 @@ parse_config_file(const void *filename_void)
static int
run_function(const void *parsed_fn_def)
{
- /* XXX: const -> non-const */
- struct f_inst *f = (struct f_inst *) parsed_fn_def;
+ const struct f_line *f = (const struct f_line *) parsed_fn_def;
linpool *tmp = lp_new_default(&root_pool);
struct f_val res;
@@ -52,7 +51,7 @@ run_function(const void *parsed_fn_def)
}
static void
-bt_assert_filter(int result, struct f_inst *assert)
+bt_assert_filter(int result, const struct f_line_item *assert)
{
int bt_suit_case_result = 1;
if (!result)
@@ -62,7 +61,7 @@ bt_assert_filter(int result, struct f_inst *assert)
bt_suit_case_result = 0;
}
- bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, (char *) assert->a[1].p);
+ bt_log_suite_case_result(bt_suit_case_result, "Assertion at line %d (%s)", assert->lineno, assert->s);
}
int
diff --git a/filter/interpret.m4 b/filter/interpret.m4
index d1c83389..829b48f6 100644
--- a/filter/interpret.m4
+++ b/filter/interpret.m4
@@ -10,7 +10,60 @@ m4_divert(-1)m4_dnl
# Common aliases
m4_define(DNL, `m4_dnl')
-m4_define(INST, `break; case $1:')
+m4_define(INST, `break; case $1:
+m4_ifelse(eval($2 > 0), `if (vstk.cnt < $2) runtime("Stack underflow");', `')
+vstk.cnt -= $2;
+')
+m4_define(ARG, `if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)')
+
+m4_define(RESULT_OK, `vstk.cnt++')
+m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
+m4_define(RESULT_VAL, `do { res = $1; RESULT_OK; } while (0)')
+
+m4_define(LINEX, `do {
+ estk.item[estk.cnt].pos = 0;
+ estk.item[estk.cnt].line = $1;
+ estk.item[estk.cnt].ventry = vstk.cnt;
+ estk.item[estk.cnt].emask = 0;
+ estk.cnt++;
+} while (0)')
+
+m4_define(LINE, `do {
+ if (what->lines[$2]) {
+ estk.item[estk.cnt].pos = 0;
+ estk.item[estk.cnt].line = what->lines[$2];
+ estk.item[estk.cnt].ventry = vstk.cnt;
+ estk.item[estk.cnt].emask = 0;
+ estk.cnt++;
+ }
+} while (0)')
+
+m4_define(LINEP, LINE($1, $2))
+
+m4_define(ARG_ANY, `')
+
+m4_define(SYMBOL, `const struct symbol *sym = what->sym')
+
+m4_define(VALI, `res = *what->vp')
+m4_define(VALP, `res = *what->vp')
+m4_define(FRET, `enum filter_return fret = what->fret')
+m4_define(ECS, `enum ec_subtype ecs = what->ecs')
+m4_define(RTC, `struct rtable *table = what->rtc->table')
+m4_define(STATIC_ATTR, `struct f_static_attr sa = what->sa')
+m4_define(DYNAMIC_ATTR, `struct f_dynamic_attr da = what->da')
+m4_define(POSTFIXIFY, `')
+m4_define(LINE_SIZE, `')
+m4_define(SAME, `')
+m4_define(COUNT, `')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_divert(1)
m4_changequote([[,]])
-m4_divert(0)
+
diff --git a/filter/line-size.m4 b/filter/line-size.m4
new file mode 100644
index 00000000..0c005fa1
--- /dev/null
+++ b/filter/line-size.m4
@@ -0,0 +1,30 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Line size counting
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1: cnt += 1;
+m4_divert(-1)')
+m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/postfixify.m4 b/filter/postfixify.m4
new file mode 100644
index 00000000..8c96ba64
--- /dev/null
+++ b/filter/postfixify.m4
@@ -0,0 +1,55 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Converting instructions trees to instruction lines
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what->fi_code;
+dest->items[pos].lineno = what->lineno;')
+
+m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER
+break; case $1:
+m4_divert(-1)'))
+m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_divert(-1)')
+m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
+m4_divert(-1)')
+m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p);
+m4_divert(-1)')
+m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p;
+m4_divert(-1)')
+m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p;
+m4_divert(-1)')
+m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val);
+m4_divert(-1)')
+m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def;
+m4_divert(-1)')
+m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i;
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc;
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa;
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da;
+m4_divert(-1)')
+m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->a[$1-1].i;
+m4_divert(-1)')
+m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+POSTFIXIFY_TRAILER
+break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
+')
+
+m4_changequote([[,]])
diff --git a/filter/same.m4 b/filter/same.m4
new file mode 100644
index 00000000..73f2d1c3
--- /dev/null
+++ b/filter/same.m4
@@ -0,0 +1,56 @@
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Filter Comparator Generator
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# Can be freely distributed and used under the terms of the GNU GPL.
+#
+
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+m4_define(INST, `m4_divert(1)break; case $1:
+m4_divert(-1)')
+
+m4_define(ARG, `')
+m4_define(ARG_ANY, `')
+
+m4_define(LINE, `m4_divert(1)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0;
+m4_divert(-1)')
+m4_define(LINEP, LINE)
+
+m4_define(SYMBOL, `m4_divert(1){
+ const struct symbol *s1 = f1->sym, *s2 = f2->sym;
+ if (strcmp(s1->name, s2->name)) return 0;
+ if (s1->class != s2->class) return 0;
+}
+m4_divert(-1)')
+
+m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0;
+m4_divert(-1)')
+m4_define(VALP, `')
+
+m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0;
+m4_divert(-1)')
+m4_define(ECS, `m4_divert(1)if (f1->ecs != f2->ecs) return 0;
+m4_divert(-1)')
+m4_define(RTC, `m4_divert(1)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0;
+m4_divert(-1)')
+m4_define(STATIC_ATTR, `m4_divert(1)if (f1->sa.sa_code != f2->sa.sa_code) return 0;
+m4_divert(-1)')
+m4_define(DYNAMIC_ATTR, `m4_divert(1)if (f1->da.ea_code != f2->da.ea_code) return 0;
+m4_divert(-1)')
+
+m4_define(SAME, `m4_divert(1)$1m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)DNL
+case FI_NOP: bug("This shall not happen");
+m4_undivert(1)
+break; default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff);
+')
+
+m4_divert(1)
+m4_changequote([[,]])
+
diff --git a/filter/tree.c b/filter/tree.c
index f8379fa8..80e1d395 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -23,15 +23,15 @@
* Both set matching and |switch() { }| construction is implemented using this function,
* thus both are as fast as they can be.
*/
-struct f_tree *
-find_tree(struct f_tree *t, struct f_val val)
+const struct f_tree *
+find_tree(const struct f_tree *t, const struct f_val *val)
{
if (!t)
return NULL;
- if ((val_compare(t->from, val) != 1) &&
- (val_compare(t->to, val) != -1))
+ if ((val_compare(&(t->from), val) != 1) &&
+ (val_compare(&(t->to), val) != -1))
return t;
- if (val_compare(t->from, val) == -1)
+ if (val_compare(&(t->from), val) == -1)
return find_tree(t->right, val);
else
return find_tree(t->left, val);
@@ -56,7 +56,7 @@ build_tree_rec(struct f_tree **buf, int l, int h)
static int
tree_compare(const void *p1, const void *p2)
{
- return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
+ return val_compare(&((* (struct f_tree **) p1)->from), &((* (struct f_tree **) p2)->from));
}
/**
@@ -119,39 +119,39 @@ f_new_tree(void)
* Compares two trees and returns 1 if they are same
*/
int
-same_tree(struct f_tree *t1, struct f_tree *t2)
+same_tree(const struct f_tree *t1, const struct f_tree *t2)
{
if ((!!t1) != (!!t2))
return 0;
if (!t1)
return 1;
- if (val_compare(t1->from, t2->from))
+ if (val_compare(&(t1->from), &(t2->from)))
return 0;
- if (val_compare(t1->to, t2->to))
+ if (val_compare(&(t1->to), &(t2->to)))
return 0;
if (!same_tree(t1->left, t2->left))
return 0;
if (!same_tree(t1->right, t2->right))
return 0;
- if (!i_same(t1->data, t2->data))
+ if (!f_same(t1->data, t2->data))
return 0;
return 1;
}
static void
-tree_node_format(struct f_tree *t, buffer *buf)
+tree_node_format(const struct f_tree *t, buffer *buf)
{
if (t == NULL)
return;
tree_node_format(t->left, buf);
- val_format(t->from, buf);
- if (val_compare(t->from, t->to) != 0)
+ val_format(&(t->from), buf);
+ if (val_compare(&(t->from), &(t->to)) != 0)
{
buffer_puts(buf, "..");
- val_format(t->to, buf);
+ val_format(&(t->to), buf);
}
buffer_puts(buf, ", ");
@@ -159,7 +159,7 @@ tree_node_format(struct f_tree *t, buffer *buf)
}
void
-tree_format(struct f_tree *t, buffer *buf)
+tree_format(const struct f_tree *t, buffer *buf)
{
buffer_puts(buf, "[");
diff --git a/filter/tree_test.c b/filter/tree_test.c
index 5b22a9fe..f3e8ce49 100644
--- a/filter/tree_test.c
+++ b/filter/tree_test.c
@@ -226,8 +226,8 @@ t_find(void)
};
for(looking_up_value.val.i = 0; looking_up_value.val.i < nodes_count; looking_up_value.val.i++)
{
- struct f_tree *found_tree = find_tree(tree, looking_up_value);
- bt_assert((val_compare(looking_up_value, found_tree->from) == 0) && (val_compare(looking_up_value, found_tree->to) == 0));
+ const struct f_tree *found_tree = find_tree(tree, &looking_up_value);
+ bt_assert((val_compare(&looking_up_value, &(found_tree->from)) == 0) && (val_compare(&looking_up_value, &(found_tree->to)) == 0));
}
}
@@ -278,11 +278,11 @@ t_find_ranges(void)
for(*i = 0; *i <= max_value; *i += (uint)bt_random()/nodes_count)
{
- struct f_tree *found_tree = find_tree(tree, needle);
+ const struct f_tree *found_tree = find_tree(tree, &needle);
bt_debug("searching: %u \n", *i);
bt_assert(
- (val_compare(needle, found_tree->from) == 0) || (val_compare(needle, found_tree->to) == 0) ||
- ((val_compare(needle, found_tree->from) == 1) && (val_compare(needle, found_tree->to) == -1))
+ (val_compare(&needle, &(found_tree->from)) == 0) || (val_compare(&needle, &(found_tree->to)) == 0) ||
+ ((val_compare(&needle, &(found_tree->from)) == 1) && (val_compare(&needle, &(found_tree->to)) == -1))
);
}
}
diff --git a/filter/trie.c b/filter/trie.c
index adcfcdf3..a279e38c 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -220,7 +220,7 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
}
static int
-trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
+trie_match_prefix(const struct f_trie *t, ip_addr px, uint plen)
{
ip_addr pmask = ipa_mkmask(plen);
ip_addr paddr = ipa_and(px, pmask);
@@ -229,7 +229,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
return t->zero;
int plentest = plen - 1;
- struct f_trie_node *n = t->root;
+ const struct f_trie_node *n = t->root;
while(n)
{
@@ -264,7 +264,7 @@ trie_match_prefix(struct f_trie *t, ip_addr px, uint plen)
* is such prefix pattern in the trie.
*/
int
-trie_match_net(struct f_trie *t, const net_addr *n)
+trie_match_net(const struct f_trie *t, const net_addr *n)
{
uint add = 0;
@@ -279,7 +279,7 @@ trie_match_net(struct f_trie *t, const net_addr *n)
}
static int
-trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
+trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2)
{
if ((t1 == NULL) && (t2 == NULL))
return 1;
@@ -303,13 +303,13 @@ trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
* Compares two tries and returns 1 if they are same
*/
int
-trie_same(struct f_trie *t1, struct f_trie *t2)
+trie_same(const struct f_trie *t1, const struct f_trie *t2)
{
return (t1->zero == t2->zero) && trie_node_same(t1->root, t2->root);
}
static void
-trie_node_format(struct f_trie_node *t, buffer *buf)
+trie_node_format(const struct f_trie_node *t, buffer *buf)
{
if (t == NULL)
return;
@@ -329,7 +329,7 @@ trie_node_format(struct f_trie_node *t, buffer *buf)
* Prints the trie to the supplied buffer.
*/
void
-trie_format(struct f_trie *t, buffer *buf)
+trie_format(const struct f_trie *t, buffer *buf)
{
buffer_puts(buf, "[");
diff --git a/lib/ip.h b/lib/ip.h
index b78a5e22..945f2893 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -354,12 +354,12 @@ mpls_put(char *buf, int len, u32 *stack)
* Unaligned data access (in network order)
*/
-static inline ip4_addr get_ip4(void *buf)
+static inline ip4_addr get_ip4(const void *buf)
{
return _MI4(get_u32(buf));
}
-static inline ip6_addr get_ip6(void *buf)
+static inline ip6_addr get_ip6(const void *buf)
{
ip6_addr a;
memcpy(&a, buf, 16);
diff --git a/nest/a-path.c b/nest/a-path.c
index 6f1c40bf..d3a1d636 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -77,10 +77,10 @@ bad:
}
int
-as_path_16to32(byte *dst, byte *src, uint len)
+as_path_16to32(byte *dst, const byte *src, uint len)
{
byte *dst0 = dst;
- byte *end = src + len;
+ const byte *end = src + len;
uint i, n;
while (src < end)
@@ -101,10 +101,10 @@ as_path_16to32(byte *dst, byte *src, uint len)
}
int
-as_path_32to16(byte *dst, byte *src, uint len)
+as_path_32to16(byte *dst, const byte *src, uint len)
{
byte *dst0 = dst;
- byte *end = src + len;
+ const byte *end = src + len;
uint i, n;
while (src < end)
@@ -273,11 +273,11 @@ as_path_to_old(struct linpool *pool, const struct adata *path)
* AS_CONFED_* segments have zero length and must be added if they are on edge.
* In contrast to other as_path_* functions, @path is modified in place.
*/
-void
-as_path_cut(struct adata *path, uint num)
+struct adata *
+as_path_cut(struct linpool *pool, const struct adata *path, uint num)
{
- byte *pos = path->data;
- byte *end = pos + path->length;
+ const byte *pos = path->data;
+ const byte *end = pos + path->length;
while (pos < end)
{
@@ -297,28 +297,39 @@ as_path_cut(struct adata *path, uint num)
/* Cannot add whole segment, so try partial one and finish */
if (num < n)
{
+ const byte *nend = pos;
+ if (num)
+ nend += 2 + BS * num;
+
+ struct adata *res = lp_alloc_adata(pool, path->length);
+ res->length = nend - (const byte *) path->data;
+ memcpy(res->data, path->data, res->length);
+
if (num)
{
- pos[1] = num;
- pos += 2 + BS * num;
+ byte *dpos = ((byte *) res->data) + (pos - (const byte *) path->data);
+ dpos[1] = num;
}
- break;
+ return res;
}
num -= n;
pos += 2 + BS * l;
}
- path->length = pos - path->data;
+ struct adata *res = lp_alloc_adata(pool, path->length);
+ res->length = path->length;
+ memcpy(res->data, path->data, res->length);
+ return res;
}
/*
* Merge (concatenate) paths @p1 and @p2 and return the result.
* In contrast to other as_path_* functions, @p1 and @p2 may be reused.
*/
-struct adata *
-as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2)
+const struct adata *
+as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2)
{
if (p1->length == 0)
return p2;
@@ -561,7 +572,7 @@ as_path_contains(const struct adata *path, u32 as, int min)
}
int
-as_path_match_set(const struct adata *path, struct f_tree *set)
+as_path_match_set(const struct adata *path, const struct f_tree *set)
{
const u8 *p = path->data;
const u8 *q = p+path->length;
@@ -574,7 +585,7 @@ as_path_match_set(const struct adata *path, struct f_tree *set)
for (i=0; i<n; i++)
{
struct f_val v = {T_INT, .val.i = get_as(p)};
- if (find_tree(set, v))
+ if (find_tree(set, &v))
return 1;
p += BS;
}
@@ -583,8 +594,8 @@ as_path_match_set(const struct adata *path, struct f_tree *set)
return 0;
}
-struct adata *
-as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos)
+const struct adata *
+as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tree *set, u32 key, int pos)
{
if (!path)
return NULL;
@@ -612,7 +623,10 @@ as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32
int match;
if (set)
- match = !!find_tree(set, (struct f_val){T_INT, .val.i = as});
+ {
+ struct f_val v = {T_INT, .val.i = as};
+ match = !!find_tree(set, &v);
+ }
else
match = (as == key);
@@ -771,7 +785,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
* is marked.
*/
int
-as_path_match(const struct adata *path, struct f_path_mask *mask)
+as_path_match(const struct adata *path, const struct f_path_mask *mask)
{
struct pm_pos pos[2048 + 1];
int plen = parse_path(path, pos);
@@ -788,12 +802,12 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
l = h = 0;
pos[0].mark = 1;
- while (mask)
+ for (uint m=0; m < mask->len; m++)
{
/* We remove this mark to not step after pos[plen] */
pos[plen].mark = 0;
- switch (mask->kind)
+ switch (mask->item[m].kind)
{
case PM_ASTERISK:
for (i = l; i <= plen; i++)
@@ -802,13 +816,13 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
break;
case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
- val2 = val = mask->val;
+ val2 = val = mask->item[m].asn;
goto step;
case PM_ASN_EXPR:
bug("Expressions should be evaluated on AS path mask construction.");
case PM_ASN_RANGE:
- val = mask->val;
- val2 = mask->val2;
+ val = mask->item[m].from;
+ val2 = mask->item[m].to;
goto step;
case PM_QUESTION:
step:
@@ -817,7 +831,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
if (pos[i].mark)
{
pos[i].mark = 0;
- if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2))
+ if ((mask->item[m].kind == PM_QUESTION) || pm_match(pos + i, val, val2))
pm_mark(pos, i, plen, &nl, &nh);
}
@@ -828,8 +842,6 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
l = nl;
break;
}
-
- mask = mask->next;
}
return pos[plen].mark;
diff --git a/nest/a-path_test.c b/nest/a-path_test.c
index a71b48ba..9ed0a786 100644
--- a/nest/a-path_test.c
+++ b/nest/a-path_test.c
@@ -34,26 +34,24 @@ t_as_path_match(void)
first_prepended = last_prepended = 0;
struct linpool *lp = lp_new_default(&root_pool);
- struct f_path_mask mask[AS_PATH_LENGTH] = {};
- int i;
- for (i = 0; i < AS_PATH_LENGTH; i++)
+ struct f_path_mask *mask = alloca(sizeof(struct f_path_mask) + AS_PATH_LENGTH * sizeof(struct f_path_mask_item));
+ mask->len = AS_PATH_LENGTH;
+ for (int i = AS_PATH_LENGTH - 1; i >= 0; i--)
{
u32 val = bt_random();
as_path = as_path_prepend(lp, as_path, val);
bt_debug("Prepending ASN: %10u \n", val);
if (i == 0)
- first_prepended = val;
- if (i == AS_PATH_LENGTH-1)
last_prepended = val;
+ if (i == AS_PATH_LENGTH-1)
+ first_prepended = val;
- mask[i].kind = PM_ASN;
- mask[i].val = val;
- if (i)
- mask[i].next = &mask[i-1];
+ mask->item[i].kind = PM_ASN;
+ mask->item[i].asn = val;
}
- bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path");
+ bt_assert_msg(as_path_match(as_path, mask), "Mask should match with AS path");
u32 asn;
diff --git a/nest/a-set.c b/nest/a-set.c
index 048e522d..10ddd139 100644
--- a/nest/a-set.c
+++ b/nest/a-set.c
@@ -34,7 +34,7 @@
* the buffer to indicate truncation.
*/
int
-int_set_format(struct adata *set, int way, int from, byte *buf, uint size)
+int_set_format(const struct adata *set, int way, int from, byte *buf, uint size)
{
u32 *z = (u32 *) set->data;
byte *end = buf + size - 24;
@@ -115,7 +115,7 @@ ec_format(byte *buf, u64 ec)
}
int
-ec_set_format(struct adata *set, int from, byte *buf, uint size)
+ec_set_format(const struct adata *set, int from, byte *buf, uint size)
{
u32 *z = int_set_get_data(set);
byte *end = buf + size - 64;
@@ -150,7 +150,7 @@ lc_format(byte *buf, lcomm lc)
}
int
-lc_set_format(struct adata *set, int from, byte *buf, uint bufsize)
+lc_set_format(const struct adata *set, int from, byte *buf, uint bufsize)
{
u32 *d = (u32 *) set->data;
byte *end = buf + bufsize - 64;
@@ -181,7 +181,7 @@ lc_set_format(struct adata *set, int from, byte *buf, uint bufsize)
}
int
-int_set_contains(struct adata *list, u32 val)
+int_set_contains(const struct adata *list, u32 val)
{
if (!list)
return 0;
@@ -198,7 +198,7 @@ int_set_contains(struct adata *list, u32 val)
}
int
-ec_set_contains(struct adata *list, u64 val)
+ec_set_contains(const struct adata *list, u64 val)
{
if (!list)
return 0;
@@ -217,7 +217,7 @@ ec_set_contains(struct adata *list, u64 val)
}
int
-lc_set_contains(struct adata *list, lcomm val)
+lc_set_contains(const struct adata *list, lcomm val)
{
if (!list)
return 0;
@@ -233,8 +233,8 @@ lc_set_contains(struct adata *list, lcomm val)
return 0;
}
-struct adata *
-int_set_prepend(struct linpool *pool, struct adata *list, u32 val)
+const struct adata *
+int_set_prepend(struct linpool *pool, const struct adata *list, u32 val)
{
struct adata *res;
int len;
@@ -254,8 +254,8 @@ int_set_prepend(struct linpool *pool, struct adata *list, u32 val)
return res;
}
-struct adata *
-int_set_add(struct linpool *pool, struct adata *list, u32 val)
+const struct adata *
+int_set_add(struct linpool *pool, const struct adata *list, u32 val)
{
struct adata *res;
int len;
@@ -275,8 +275,8 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val)
return res;
}
-struct adata *
-ec_set_add(struct linpool *pool, struct adata *list, u64 val)
+const struct adata *
+ec_set_add(struct linpool *pool, const struct adata *list, u64 val)
{
if (ec_set_contains(list, val))
return list;
@@ -295,8 +295,8 @@ ec_set_add(struct linpool *pool, struct adata *list, u64 val)
return res;
}
-struct adata *
-lc_set_add(struct linpool *pool, struct adata *list, lcomm val)
+const struct adata *
+lc_set_add(struct linpool *pool, const struct adata *list, lcomm val)
{
if (lc_set_contains(list, val))
return list;
@@ -313,8 +313,8 @@ lc_set_add(struct linpool *pool, struct adata *list, lcomm val)
return res;
}
-struct adata *
-int_set_del(struct linpool *pool, struct adata *list, u32 val)
+const struct adata *
+int_set_del(struct linpool *pool, const struct adata *list, u32 val)
{
if (!int_set_contains(list, val))
return list;
@@ -335,8 +335,8 @@ int_set_del(struct linpool *pool, struct adata *list, u32 val)
return res;
}
-struct adata *
-ec_set_del(struct linpool *pool, struct adata *list, u64 val)
+const struct adata *
+ec_set_del(struct linpool *pool, const struct adata *list, u64 val)
{
if (!ec_set_contains(list, val))
return list;
@@ -362,8 +362,8 @@ ec_set_del(struct linpool *pool, struct adata *list, u64 val)
return res;
}
-struct adata *
-lc_set_del(struct linpool *pool, struct adata *list, lcomm val)
+const struct adata *
+lc_set_del(struct linpool *pool, const struct adata *list, lcomm val)
{
if (!lc_set_contains(list, val))
return list;
@@ -384,8 +384,8 @@ lc_set_del(struct linpool *pool, struct adata *list, lcomm val)
return res;
}
-struct adata *
-int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
+const struct adata *
+int_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2)
{
if (!l1)
return l2;
@@ -414,8 +414,8 @@ int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
return res;
}
-struct adata *
-ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
+const struct adata *
+ec_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2)
{
if (!l1)
return l2;
@@ -447,8 +447,8 @@ ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
return res;
}
-struct adata *
-lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
+const struct adata *
+lc_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2)
{
if (!l1)
return l2;
@@ -479,7 +479,7 @@ lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2)
struct adata *
-ec_set_del_nontrans(struct linpool *pool, struct adata *set)
+ec_set_del_nontrans(struct linpool *pool, const struct adata *set)
{
adata *res = lp_alloc_adata(pool, set->length);
u32 *src = int_set_get_data(set);
@@ -510,7 +510,7 @@ int_set_cmp(const void *X, const void *Y)
}
struct adata *
-int_set_sort(struct linpool *pool, struct adata *src)
+int_set_sort(struct linpool *pool, const struct adata *src)
{
struct adata *dst = lp_alloc_adata(pool, src->length);
memcpy(dst->data, src->data, src->length);
@@ -528,7 +528,7 @@ ec_set_cmp(const void *X, const void *Y)
}
struct adata *
-ec_set_sort(struct linpool *pool, struct adata *src)
+ec_set_sort(struct linpool *pool, const struct adata *src)
{
struct adata *dst = lp_alloc_adata(pool, src->length);
memcpy(dst->data, src->data, src->length);
@@ -558,7 +558,7 @@ lc_set_cmp(const void *X, const void *Y)
}
struct adata *
-lc_set_sort(struct linpool *pool, struct adata *src)
+lc_set_sort(struct linpool *pool, const struct adata *src)
{
struct adata *dst = lp_alloc_adata(pool, src->length);
memcpy(dst->data, src->data, src->length);
diff --git a/nest/a-set_test.c b/nest/a-set_test.c
index a5081f9f..96b6a727 100644
--- a/nest/a-set_test.c
+++ b/nest/a-set_test.c
@@ -15,10 +15,10 @@
#include "lib/resource.h"
#define SET_SIZE 10
-static struct adata *set_sequence; /* <0; SET_SIZE) */
-static struct adata *set_sequence_same; /* <0; SET_SIZE) */
-static struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
-static struct adata *set_random;
+static const struct adata *set_sequence; /* <0; SET_SIZE) */
+static const struct adata *set_sequence_same; /* <0; SET_SIZE) */
+static const struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
+static const struct adata *set_random;
#define BUFFER_SIZE 1000
static byte buf[BUFFER_SIZE] = {};
@@ -34,14 +34,14 @@ enum set_type
};
static void
-generate_set_sequence(enum set_type type)
+generate_set_sequence(enum set_type type, int len)
{
struct adata empty_as_path = {};
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
lp = lp_new_default(&root_pool);
int i;
- for (i = 0; i < SET_SIZE; i++)
+ for (i = 0; i < len; i++)
{
if (type == SET_TYPE_INT)
{
@@ -72,7 +72,7 @@ t_set_int_contains(void)
int i;
resource_init();
- generate_set_sequence(SET_TYPE_INT);
+ generate_set_sequence(SET_TYPE_INT, SET_SIZE);
bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
@@ -93,9 +93,9 @@ static int
t_set_int_union(void)
{
resource_init();
- generate_set_sequence(SET_TYPE_INT);
+ generate_set_sequence(SET_TYPE_INT, SET_SIZE);
- struct adata *set_union;
+ const struct adata *set_union;
set_union = int_set_union(lp, set_sequence, set_sequence_same);
bt_assert(int_set_get_size(set_union) == SET_SIZE);
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
@@ -112,9 +112,8 @@ static int
t_set_int_format(void)
{
resource_init();
- generate_set_sequence(SET_TYPE_INT);
+ generate_set_sequence(SET_TYPE_INT, SET_SIZE_FOR_FORMAT_OUTPUT);
- set_sequence->length = 4 * SET_SIZE_FOR_FORMAT_OUTPUT; /* dirty */
bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0);
bt_assert(strcmp(buf, "0.0.0.0 0.0.0.1 0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
@@ -134,9 +133,9 @@ static int
t_set_int_delete(void)
{
resource_init();
- generate_set_sequence(SET_TYPE_INT);
+ generate_set_sequence(SET_TYPE_INT, SET_SIZE);
- struct adata *deleting_sequence = set_sequence;
+ const struct adata *deleting_sequence = set_sequence;
u32 i;
for (i = 0; i < SET_SIZE; i++)
{
@@ -162,7 +161,7 @@ t_set_ec_contains(void)
u32 i;
resource_init();
- generate_set_sequence(SET_TYPE_EC);
+ generate_set_sequence(SET_TYPE_EC, SET_SIZE);
bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
@@ -183,9 +182,9 @@ static int
t_set_ec_union(void)
{
resource_init();
- generate_set_sequence(SET_TYPE_EC);
+ generate_set_sequence(SET_TYPE_EC, SET_SIZE);
- struct adata *set_union;
+ const struct adata *set_union;
set_union = ec_set_union(lp, set_sequence, set_sequence_same);
bt_assert(ec_set_get_size(set_union) == SET_SIZE);
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
@@ -203,7 +202,7 @@ t_set_ec_format(void)
{
resource_init();
- struct adata empty_as_path = {};
+ const struct adata empty_as_path = {};
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
lp = lp_new_default(&root_pool);
@@ -224,9 +223,9 @@ static int
t_set_ec_delete(void)
{
resource_init();
- generate_set_sequence(SET_TYPE_EC);
+ generate_set_sequence(SET_TYPE_EC, SET_SIZE);
- struct adata *deleting_sequence = set_sequence;
+ const struct adata *deleting_sequence = set_sequence;
u32 i;
for (i = 0; i < SET_SIZE; i++)
{
diff --git a/nest/attrs.h b/nest/attrs.h
index 102f378a..d9d97136 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -31,15 +31,15 @@
struct f_tree;
int as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen);
-int as_path_16to32(byte *dst, byte *src, uint len);
-int as_path_32to16(byte *dst, byte *src, uint len);
+int as_path_16to32(byte *dst, const byte *src, uint len);
+int as_path_32to16(byte *dst, const byte *src, uint len);
int as_path_contains_as4(const struct adata *path);
int as_path_contains_confed(const struct adata *path);
struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op);
struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as);
struct adata *as_path_to_old(struct linpool *pool, const struct adata *path);
-void as_path_cut(struct adata *path, uint num);
-struct adata *as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2);
+struct adata *as_path_cut(struct linpool *pool, const struct adata *path, uint num);
+const struct adata *as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2);
void as_path_format(const struct adata *path, byte *buf, uint size);
int as_path_getlen(const struct adata *path);
int as_path_getlen_int(const struct adata *path, int bs);
@@ -48,8 +48,8 @@ int as_path_get_first_regular(const struct adata *path, u32 *last_as);
int as_path_get_last(const struct adata *path, u32 *last_as);
u32 as_path_get_last_nonaggregated(const struct adata *path);
int as_path_contains(const struct adata *path, u32 as, int min);
-int as_path_match_set(const struct adata *path, struct f_tree *set);
-struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);
+int as_path_match_set(const struct adata *path, const struct f_tree *set);
+const struct adata *as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tree *set, u32 key, int pos);
static inline struct adata *as_path_prepend(struct linpool *pool, const struct adata *path, u32 as)
{ return as_path_prepend2(pool, path, AS_PATH_SEQUENCE, as); }
@@ -61,20 +61,30 @@ static inline struct adata *as_path_prepend(struct linpool *pool, const struct a
#define PM_ASN_EXPR 3
#define PM_ASN_RANGE 4
-struct f_path_mask {
- struct f_path_mask *next;
+struct f_path_mask_item {
+ union {
+ u32 asn; /* PM_ASN */
+ struct f_line *expr; /* PM_ASN_EXPR */
+ struct { /* PM_ASN_RANGE */
+ u32 from;
+ u32 to;
+ };
+ };
int kind;
- uintptr_t val;
- uintptr_t val2;
};
-int as_path_match(const struct adata *path, struct f_path_mask *mask);
+struct f_path_mask {
+ uint len;
+ struct f_path_mask_item item[0];
+};
+
+int as_path_match(const struct adata *path, const struct f_path_mask *mask);
/* Counterparts to appropriate as_path_* functions */
static inline int
-aggregator_16to32(byte *dst, byte *src)
+aggregator_16to32(byte *dst, const byte *src)
{
put_u32(dst, get_u16(src));
memcpy(dst+4, src+2, 4);
@@ -82,7 +92,7 @@ aggregator_16to32(byte *dst, byte *src)
}
static inline int
-aggregator_32to16(byte *dst, byte *src)
+aggregator_32to16(byte *dst, const byte *src)
{
put_u16(dst, get_u32(src));
memcpy(dst+2, src+4, 4);
@@ -90,13 +100,13 @@ aggregator_32to16(byte *dst, byte *src)
}
static inline int
-aggregator_contains_as4(struct adata *a)
+aggregator_contains_as4(const struct adata *a)
{
return get_u32(a->data) > 0xFFFF;
}
static inline struct adata *
-aggregator_to_old(struct linpool *pool, struct adata *a)
+aggregator_to_old(struct linpool *pool, const struct adata *a)
{
struct adata *d = lp_alloc_adata(pool, 8);
put_u32(d->data, 0xFFFF);
@@ -109,26 +119,27 @@ aggregator_to_old(struct linpool *pool, struct adata *a)
/* Extended Community subtypes (kinds) */
-#define EC_RT 0x0002
-#define EC_RO 0x0003
-
-#define EC_GENERIC 0xFFFF
+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
#define ECOMM_LENGTH 8
-static inline int int_set_get_size(struct adata *list)
+static inline int int_set_get_size(const struct adata *list)
{ return list->length / 4; }
-static inline int ec_set_get_size(struct adata *list)
+static inline int ec_set_get_size(const struct adata *list)
{ return list->length / 8; }
-static inline int lc_set_get_size(struct adata *list)
+static inline int lc_set_get_size(const struct adata *list)
{ return list->length / 12; }
-static inline u32 *int_set_get_data(struct adata *list)
+static inline u32 *int_set_get_data(const struct adata *list)
{ return (u32 *) list->data; }
static inline u32 ec_hi(u64 ec) { return ec >> 32; }
@@ -137,16 +148,16 @@ static inline u64 ec_get(const u32 *l, int i)
{ return (((u64) l[i]) << 32) | l[i+1]; }
/* RFC 4360 3.1. Two-Octet AS Specific Extended Community */
-static inline u64 ec_as2(u64 kind, u64 key, u64 val)
-{ return ((kind | 0x0000) << 48) | (key << 32) | val; }
+static inline u64 ec_as2(enum ec_subtype kind, u64 key, u64 val)
+{ return (((u64) kind | 0x0000) << 48) | (key << 32) | val; }
/* RFC 5668 4-Octet AS Specific BGP Extended Community */
-static inline u64 ec_as4(u64 kind, u64 key, u64 val)
-{ return ((kind | 0x0200) << 48) | (key << 16) | val; }
+static inline u64 ec_as4(enum ec_subtype kind, u64 key, u64 val)
+{ return (((u64) kind | 0x0200) << 48) | (key << 16) | val; }
/* RFC 4360 3.2. IPv4 Address Specific Extended Community */
-static inline u64 ec_ip4(u64 kind, u64 key, u64 val)
-{ return ((kind | 0x0100) << 48) | (key << 16) | val; }
+static inline u64 ec_ip4(enum ec_subtype kind, u64 key, u64 val)
+{ return (((u64) kind | 0x0100) << 48) | (key << 16) | val; }
static inline u64 ec_generic(u64 key, u64 val)
{ return (key << 32) | val; }
@@ -173,29 +184,29 @@ static inline u32 *lc_copy(u32 *dst, const u32 *src)
{ memcpy(dst, src, LCOMM_LENGTH); return dst + 3; }
-int int_set_format(struct adata *set, int way, int from, byte *buf, uint size);
+int int_set_format(const struct adata *set, int way, int from, byte *buf, uint size);
int ec_format(byte *buf, u64 ec);
-int ec_set_format(struct adata *set, int from, byte *buf, uint size);
+int ec_set_format(const struct adata *set, int from, byte *buf, uint size);
int lc_format(byte *buf, lcomm lc);
-int lc_set_format(struct adata *set, int from, byte *buf, uint size);
-int int_set_contains(struct adata *list, u32 val);
-int ec_set_contains(struct adata *list, u64 val);
-int lc_set_contains(struct adata *list, lcomm val);
-struct adata *int_set_prepend(struct linpool *pool, struct adata *list, u32 val);
-struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
-struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val);
-struct adata *lc_set_add(struct linpool *pool, struct adata *list, lcomm val);
-struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
-struct adata *ec_set_del(struct linpool *pool, struct adata *list, u64 val);
-struct adata *lc_set_del(struct linpool *pool, struct adata *list, lcomm val);
-struct adata *int_set_union(struct linpool *pool, struct adata *l1, struct adata *l2);
-struct adata *ec_set_union(struct linpool *pool, struct adata *l1, struct adata *l2);
-struct adata *lc_set_union(struct linpool *pool, struct adata *l1, struct adata *l2);
-
-struct adata *ec_set_del_nontrans(struct linpool *pool, struct adata *set);
-struct adata *int_set_sort(struct linpool *pool, struct adata *src);
-struct adata *ec_set_sort(struct linpool *pool, struct adata *src);
-struct adata *lc_set_sort(struct linpool *pool, struct adata *src);
+int lc_set_format(const struct adata *set, int from, byte *buf, uint size);
+int int_set_contains(const struct adata *list, u32 val);
+int ec_set_contains(const struct adata *list, u64 val);
+int lc_set_contains(const struct adata *list, lcomm val);
+const struct adata *int_set_prepend(struct linpool *pool, const struct adata *list, u32 val);
+const struct adata *int_set_add(struct linpool *pool, const struct adata *list, u32 val);
+const struct adata *ec_set_add(struct linpool *pool, const struct adata *list, u64 val);
+const struct adata *lc_set_add(struct linpool *pool, const struct adata *list, lcomm val);
+const struct adata *int_set_del(struct linpool *pool, const struct adata *list, u32 val);
+const struct adata *ec_set_del(struct linpool *pool, const struct adata *list, u64 val);
+const struct adata *lc_set_del(struct linpool *pool, const struct adata *list, lcomm val);
+const struct adata *int_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2);
+const struct adata *ec_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2);
+const struct adata *lc_set_union(struct linpool *pool, const struct adata *l1, const struct adata *l2);
+
+struct adata *ec_set_del_nontrans(struct linpool *pool, const struct adata *set);
+struct adata *int_set_sort(struct linpool *pool, const struct adata *src);
+struct adata *ec_set_sort(struct linpool *pool, const struct adata *src);
+struct adata *lc_set_sort(struct linpool *pool, const struct adata *src);
void ec_set_sort_x(struct adata *set); /* Sort in place */
diff --git a/nest/cmds.c b/nest/cmds.c
index 0c89d20f..6daafcb3 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -95,8 +95,9 @@ cmd_show_memory(void)
}
void
-cmd_eval(struct f_inst *expr)
+cmd_eval(const struct f_line *expr)
{
+ /* TODO: Return directly the string from eval */
struct f_val v;
if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN)
{
@@ -106,6 +107,6 @@ cmd_eval(struct f_inst *expr)
buffer buf;
LOG_BUFFER_INIT(buf);
- val_format(v, &buf);
+ val_format(&v, &buf);
cli_msg(23, "%s", buf.start);
}
diff --git a/nest/cmds.h b/nest/cmds.h
index 4cf8fb1b..194a9d7f 100644
--- a/nest/cmds.h
+++ b/nest/cmds.h
@@ -16,4 +16,6 @@ struct f_inst;
void cmd_show_status(void);
void cmd_show_symbols(struct sym_show_data *sym);
void cmd_show_memory(void);
-void cmd_eval(struct f_inst *expr);
+
+struct f_line;
+void cmd_eval(const struct f_line *expr);
diff --git a/nest/config.Y b/nest/config.Y
index aef5ed46..51fb0bd7 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -112,7 +112,7 @@ rtrid:
idval:
NUM { $$ = $1; }
- | '(' term ')' { $$ = f_eval_int($2); }
+ | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
| IP4 { $$ = ip4_to_u32($1); }
| SYM {
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
@@ -732,7 +732,7 @@ CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
{ protos_dump_all(); cli_msg(0, ""); } ;
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
-{ cmd_eval($2); } ;
+{ cmd_eval(f_postfixify($2)); } ;
CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) {
@@ -790,7 +790,7 @@ proto_patt2:
| TEXT { $$.ptr = $1; $$.patt = 1; }
;
-dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ;
+dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_GEN_IGP_METRIC); } ;
CF_CODE
diff --git a/nest/route.h b/nest/route.h
index 74446f48..c7ed80ff 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -473,7 +473,7 @@ typedef struct eattr {
byte type; /* Attribute type and several flags (EAF_...) */
union {
u32 data;
- struct adata *ptr; /* Attribute data elsewhere */
+ const struct adata *ptr; /* Attribute data elsewhere */
} u;
} eattr;
@@ -517,6 +517,8 @@ typedef struct adata {
byte data[0];
} adata;
+extern const adata null_adata; /* adata of length 0 */
+
static inline struct adata *
lp_alloc_adata(struct linpool *pool, uint len)
{
@@ -525,7 +527,7 @@ lp_alloc_adata(struct linpool *pool, uint len)
return ad;
}
-static inline int adata_same(struct adata *a, struct adata *b)
+static inline int adata_same(const struct adata *a, const struct adata *b)
{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 3e4578b0..01e807fa 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -58,6 +58,8 @@
#include <stddef.h>
+const adata null_adata; /* adata of length 0 */
+
const char * const rta_src_names[RTS_MAX] = {
[RTS_DUMMY] = "",
[RTS_STATIC] = "static",
@@ -763,7 +765,7 @@ ea_free(ea_list *o)
{
eattr *a = &o->attrs[i];
if (!(a->type & EAF_EMBEDDED))
- mb_free(a->u.ptr);
+ mb_free((void *) a->u.ptr);
}
mb_free(o);
}
@@ -808,7 +810,7 @@ ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names,
}
static inline void
-opaque_format(struct adata *ad, byte *buf, uint size)
+opaque_format(const struct adata *ad, byte *buf, uint size)
{
byte *bound = buf + size - 10;
uint i;
@@ -831,7 +833,7 @@ opaque_format(struct adata *ad, byte *buf, uint size)
}
static inline void
-ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end)
+ea_show_int_set(struct cli *c, const struct adata *ad, int way, byte *pos, byte *buf, byte *end)
{
int i = int_set_format(ad, way, 0, pos, end - pos);
cli_printf(c, -1012, "\t%s", buf);
@@ -843,7 +845,7 @@ ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf,
}
static inline void
-ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
+ea_show_ec_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
{
int i = ec_set_format(ad, 0, pos, end - pos);
cli_printf(c, -1012, "\t%s", buf);
@@ -855,7 +857,7 @@ ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
}
static inline void
-ea_show_lc_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
+ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
{
int i = lc_set_format(ad, 0, pos, end - pos);
cli_printf(c, -1012, "\t%s", buf);
@@ -882,7 +884,7 @@ ea_show(struct cli *c, eattr *e)
{
struct protocol *p;
int status = GA_UNKNOWN;
- struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
+ const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
byte buf[CLI_MSG_SIZE];
byte *pos = buf, *end = buf + sizeof(buf);
@@ -1023,7 +1025,7 @@ ea_hash(ea_list *e)
h ^= a->u.data;
else
{
- struct adata *d = a->u.ptr;
+ const struct adata *d = a->u.ptr;
h ^= mem_hash(d->data, d->length);
}
h *= mul;
diff --git a/proto/babel/config.Y b/proto/babel/config.Y
index 3af79fd6..b93a423b 100644
--- a/proto/babel/config.Y
+++ b/proto/babel/config.Y
@@ -125,7 +125,7 @@ babel_iface_opt_list:
babel_iface:
babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish;
-dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BABEL_METRIC); } ;
+dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_BABEL_METRIC); } ;
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index cbb22038..7c6f2ee9 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -181,7 +181,7 @@ bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size
}
static int
-bgp_put_attr(byte *buf, uint size, uint code, uint flags, byte *data, uint len)
+bgp_put_attr(byte *buf, uint size, uint code, uint flags, const byte *data, uint len)
{
if (size < (4+len))
return -1;
@@ -234,15 +234,15 @@ bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
static int
bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
{
- byte *data = a->u.ptr->data;
+ const byte *data = a->u.ptr->data;
uint len = a->u.ptr->length;
if (!s->as4_session)
{
/* Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer */
- byte *src = data;
- data = alloca(len);
- len = as_path_32to16(data, src, len);
+ byte *dst = alloca(len);
+ len = as_path_32to16(dst, data, len);
+ data = dst;
}
return bgp_put_attr(buf, size, BA_AS_PATH, a->flags, data, len);
@@ -381,15 +381,14 @@ bgp_decode_atomic_aggr(struct bgp_parse_state *s, uint code UNUSED, uint flags,
static int
bgp_encode_aggregator(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
{
- byte *data = a->u.ptr->data;
+ const byte *data = a->u.ptr->data;
uint len = a->u.ptr->length;
if (!s->as4_session)
{
/* Prepare 16-bit AGGREGATOR (from 32-bit one) in a temporary buffer */
- byte *src = data;
- data = alloca(6);
- len = aggregator_32to16(data, src);
+ byte *dst = alloca(6);
+ len = aggregator_32to16(dst, data);
}
return bgp_put_attr(buf, size, BA_AGGREGATOR, a->flags, data, len);
@@ -415,7 +414,7 @@ bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, b
static void
bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED)
{
- byte *data = a->u.ptr->data;
+ const byte *data = a->u.ptr->data;
bsprintf(buf, "%I4 AS%u", get_ip4(data+4), get_u32(data+0));
}
@@ -545,12 +544,13 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla
static void
bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
{
- a->u.ptr = ec_set_del_nontrans(s->pool, a->u.ptr);
+ struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
- if (a->u.ptr->length == 0)
+ if (ad->length == 0)
UNSET(a);
- ec_set_sort_x(a->u.ptr);
+ ec_set_sort_x(ad);
+ a->u.ptr = ad;
}
static void
@@ -1232,7 +1232,7 @@ bgp_get_bucket(struct bgp_channel *c, ea_list *new)
if (!(a->type & EAF_EMBEDDED))
{
- struct adata *oa = a->u.ptr;
+ const struct adata *oa = a->u.ptr;
struct adata *na = (struct adata *) dest;
memcpy(na, oa, sizeof(struct adata) + oa->length);
a->u.ptr = na;
@@ -1404,7 +1404,7 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
if (p->cf->interpret_communities &&
(c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
{
- struct adata *d = c->u.ptr;
+ const struct adata *d = c->u.ptr;
/* Do not export anywhere */
if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
@@ -1426,9 +1426,6 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
return 0;
}
-
-static adata null_adata; /* adata of length 0 */
-
static ea_list *
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
{
@@ -1437,7 +1434,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
ea_list *attrs = attrs0;
eattr *a;
- adata *ad;
+ const adata *ad;
/* ORIGIN attribute - mandatory, attach if missing */
if (! bgp_find_attr(attrs0, BA_ORIGIN))
@@ -1962,7 +1959,7 @@ struct rte *
bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
{
eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
- struct adata *ad = a ? a->u.ptr : NULL;
+ const struct adata *ad = a ? a->u.ptr : NULL;
uint flags = a ? a->flags : BAF_PARTIAL;
if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
@@ -2021,8 +2018,8 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
return;
/* Merge AS_PATH and AS4_PATH */
- as_path_cut(p2->u.ptr, p2_len - p4_len);
- p2->u.ptr = as_path_merge(pool, p2->u.ptr, p4->u.ptr);
+ struct adata *apc = as_path_cut(pool, p2->u.ptr, p2_len - p4_len);
+ p2->u.ptr = as_path_merge(pool, apc, p4->u.ptr);
}
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index cfc88d8e..b604c7aa 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -376,7 +376,7 @@ struct bgp_write_state {
int mpls;
eattr *mp_next_hop;
- adata *mpls_labels;
+ const adata *mpls_labels;
};
struct bgp_parse_state {
@@ -507,7 +507,7 @@ bgp_set_attr_u32(ea_list **to, struct linpool *pool, uint code, uint flags, u32
{ bgp_set_attr(to, pool, code, flags, (uintptr_t) val); }
static inline void
-bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, struct adata *val)
+bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, const struct adata *val)
{ bgp_set_attr(to, pool, code, flags, (uintptr_t) val); }
static inline void
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index ac8d024a..f9e5efaf 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -272,29 +272,29 @@ bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;
dynamic_attr: BGP_ORIGIN
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ;
dynamic_attr: BGP_PATH
- { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, 0, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ;
dynamic_attr: BGP_NEXT_HOP
- { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ;
dynamic_attr: BGP_MED
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ;
dynamic_attr: BGP_LOCAL_PREF
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ;
dynamic_attr: BGP_ATOMIC_AGGR
- { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, 0, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
dynamic_attr: BGP_AGGREGATOR
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
dynamic_attr: BGP_COMMUNITY
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
dynamic_attr: BGP_ORIGINATOR_ID
- { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ;
dynamic_attr: BGP_CLUSTER_LIST
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ;
dynamic_attr: BGP_EXT_COMMUNITY
- { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, 0, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ;
dynamic_attr: BGP_LARGE_COMMUNITY
- { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, 0, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 26716573..2b5cc440 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1210,10 +1210,10 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
}
static void
-bgp_encode_mpls_labels(struct bgp_write_state *s UNUSED, adata *mpls, byte **pos, uint *size, byte *pxlen)
+bgp_encode_mpls_labels(struct bgp_write_state *s UNUSED, const adata *mpls, byte **pos, uint *size, byte *pxlen)
{
- u32 dummy = 0;
- u32 *labels = mpls ? (u32 *) mpls->data : &dummy;
+ const u32 dummy = 0;
+ const u32 *labels = mpls ? (const u32 *) mpls->data : &dummy;
uint lnum = mpls ? (mpls->length / 4) : 1;
for (uint i = 0; i < lnum; i++)
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 36fbd5f1..9669b708 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -498,10 +498,10 @@ ospf_iface:
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
-dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ;
-dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ;
-dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ;
-dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ;
+dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC1); } ;
+dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC2); } ;
+dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_TAG); } ;
+dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]])
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 53715f77..b8eeb439 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -332,8 +332,8 @@ radv_sensitive:
| SENSITIVE bool { $$ = $2; }
;
-dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ;
-dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ;
+dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ;
+dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RA_LIFETIME); } ;
CF_CODE
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 172299d0..265912b2 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -186,8 +186,8 @@ rip_iface:
rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish;
-dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ;
-dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ;
+dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_METRIC); } ;
+dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_TAG); } ;
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
diff --git a/proto/static/config.Y b/proto/static/config.Y
index d7a02961..56caef24 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_last_cmd;
+static struct f_inst *this_srt_cmds, **this_srt_last_cmd;
static struct static_route *
static_nexthop_new(void)
@@ -39,6 +39,8 @@ static_route_finish(void)
{
if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
cf_error("Unexpected or missing nexthop/type");
+
+ this_srt->cmds = f_postfixify(this_srt_cmds);
}
CF_DECLS
@@ -108,7 +110,8 @@ stat_route0: ROUTE net_any {
this_srt = cfg_allocz(sizeof(struct static_route));
add_tail(&STATIC_CFG->routes, &this_srt->n);
this_srt->net = $2;
- this_srt_last_cmd = &(this_srt->cmds);
+ this_srt_cmds = NULL;
+ this_srt_last_cmd = &this_srt_cmds;
this_srt->mp_next = NULL;
this_snh = NULL;
}
diff --git a/proto/static/static.c b/proto/static/static.c
index 75a74ad0..2fa687eb 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -308,7 +308,7 @@ static inline int
static_same_rte(struct static_route *or, struct static_route *nr)
{
/* Note that i_same() requires arguments in (new, old) order */
- return static_same_dest(or, nr) && i_same(nr->cmds, or->cmds);
+ return static_same_dest(or, nr) && f_same(nr->cmds, or->cmds);
}
static void
diff --git a/proto/static/static.h b/proto/static/static.h
index a3c30b87..f736996c 100644
--- a/proto/static/static.h
+++ b/proto/static/static.h
@@ -39,7 +39,7 @@ struct static_route {
struct static_route *chain; /* Next for the same neighbor */
struct static_route *mp_head; /* First nexthop of this route */
struct static_route *mp_next; /* Nexthops for multipath routes */
- struct f_inst *cmds; /* List of commands for setting attributes */
+ struct f_line *cmds; /* List of commands for setting attributes */
byte dest; /* Destination type (RTD_*) */
byte state; /* State of route announcement (SRS_*) */
byte active; /* Next hop is active (nbr/iface/BFD available) */
diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h
index 2b8cdaa7..a8af4c95 100644
--- a/sysdep/linux/krt-sys.h
+++ b/sysdep/linux/krt-sys.h
@@ -65,27 +65,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e)
#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f)
-/* Bits of EA_KRT_LOCK, also based on RTAX_* constants */
-#define EA_KRT_LOCK_MTU EA_KRT_LOCK | EA_BIT(0x2)
-#define EA_KRT_LOCK_WINDOW EA_KRT_LOCK | EA_BIT(0x3)
-#define EA_KRT_LOCK_RTT EA_KRT_LOCK | EA_BIT(0x4)
-#define EA_KRT_LOCK_RTTVAR EA_KRT_LOCK | EA_BIT(0x5)
-#define EA_KRT_LOCK_SSTHRESH EA_KRT_LOCK | EA_BIT(0x6)
-#define EA_KRT_LOCK_CWND EA_KRT_LOCK | EA_BIT(0x7)
-#define EA_KRT_LOCK_ADVMSS EA_KRT_LOCK | EA_BIT(0x8)
-#define EA_KRT_LOCK_REORDERING EA_KRT_LOCK | EA_BIT(0x9)
-#define EA_KRT_LOCK_HOPLIMIT EA_KRT_LOCK | EA_BIT(0xa)
-// define EA_KRT_LOCK_INITCWND EA_KRT_LOCK | EA_BIT(0xb)
-// define EA_KRT_LOCK_FEATURES EA_KRT_LOCK | EA_BIT(0xc)
-#define EA_KRT_LOCK_RTO_MIN EA_KRT_LOCK | EA_BIT(0xd)
-// define EA_KRT_LOCK_INITRWND EA_KRT_LOCK | EA_BIT(0xe)
-
-/* Bits of EA_KRT_FEATURES, based on RTAX_FEATURE_* constants */
-#define EA_KRT_FEATURE_ECN EA_KRT_FEATURES | EA_BIT(0x0)
-// define EA_KRT_FEATURE_SACK EA_KRT_FEATURES | EA_BIT(0x1)
-// define EA_KRT_FEATURE_TSTAMP EA_KRT_FEATURES | EA_BIT(0x2)
-#define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3)
-
struct krt_params {
u32 table_id; /* Kernel table ID we sync with */
diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y
index 1030e5d4..8f0a91c1 100644
--- a/sysdep/linux/netlink.Y
+++ b/sysdep/linux/netlink.Y
@@ -26,37 +26,39 @@ kern_sys_item:
| METRIC expr { THIS_KRT->sys.metric = $2; }
;
-dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ;
-dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ;
-dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ;
+dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_KRT_PREFSRC); } ;
+dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REALM); } ;
+dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SCOPE); } ;
-dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ;
-dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ;
-dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ;
-dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ;
-dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ;
-dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ;
-dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ;
-dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ;
-dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ;
-dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ;
-dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ;
-dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ;
-dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ;
+dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_MTU); } ;
+dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_WINDOW); } ;
+dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTT); } ;
+dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTTVAR); } ;
+dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SSTRESH); } ;
+dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_CWND); } ;
+dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_ADVMSS); } ;
+dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REORDERING); } ;
+dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_HOPLIMIT); } ;
+dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITCWND); } ;
+dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTO_MIN); } ;
+dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITRWND); } ;
+dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_QUICKACK); } ;
-dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_MTU); } ;
-dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_WINDOW); } ;
-dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTT); } ;
-dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTTVAR); } ;
-dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_SSTHRESH); } ;
-dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_CWND); } ;
-dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_ADVMSS); } ;
-dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_REORDERING); } ;
-dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_HOPLIMIT); } ;
-dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTO_MIN); } ;
+/* Bits of EA_KRT_LOCK, based on RTAX_* constants */
-dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ECN); } ;
-dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ALLFRAG); } ;
+dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 2, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 4, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 5, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 6, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 7, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 8, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 9, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 10, T_BOOL, EA_KRT_LOCK); } ;
+dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 13, T_BOOL, EA_KRT_LOCK); } ;
+
+dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 0, T_BOOL, EA_KRT_FEATURES); } ;
+dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_FEATURES); } ;
CF_CODE
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index d773743d..e21f4039 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -1719,9 +1719,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ea->attrs[0].id = EA_KRT_PREFSRC;
ea->attrs[0].flags = 0;
ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
- ea->attrs[0].u.ptr = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps));
- ea->attrs[0].u.ptr->length = sizeof(ps);
- memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
+
+ struct adata *ad = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps));
+ ad->length = sizeof(ps);
+ memcpy(ad->data, &ps, sizeof(ps));
+
+ ea->attrs[0].u.ptr = ad;
}
if (a[RTA_FLOW])
diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y
index 95b54d65..e3f6271c 100644
--- a/sysdep/unix/krt.Y
+++ b/sysdep/unix/krt.Y
@@ -122,8 +122,8 @@ kif_iface:
kif_iface_start iface_patt_list_nopx kif_iface_opt_list;
-dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SOURCE); } ;
-dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_METRIC); } ;
+dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SOURCE); } ;
+dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_METRIC); } ;
CF_CODE