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 $@ -$(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++; } - struct f_inst *rv = f_new_inst(FI_CONSTANT); - rv->val = (struct f_val) { - .type = T_PATH_MASK, - .val.path_mask = t, - }; + if (dyn) { + struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT); + pmc->a[0].p = t; + pmc->a[1].i = len; + return pmc; + } - return rv; + struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item)); + + 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 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 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 dynamic_attr %type static_attr %type filter filter_body where_filter @@ -420,7 +431,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type set_atom switch_atom fipa %type fprefix %type decls declsn one_decl function_params -%type bgp_path bgp_path_tail %type 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 +# +# 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); - if (res.val.i) - ARG_T(2,0,T_BOOL); - } - INST(FI_OR) { - ARG_T(1,0,T_BOOL); - if (!res.val.i) - ARG_T(2,0,T_BOOL); - } - INST(FI_PAIR_CONSTRUCT) { + INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - u1 = v1.val.i; - u2 = v2.val.i; + 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) + LINE(2,0); + else + RESULT_OK; + } + INST(FI_OR, 1, 1) { + ARG(1,T_BOOL); + if (!res.val.i) + LINE(2,0); + else + RESULT_OK; + } + INST(FI_PAIR_CONSTRUCT, 2, 1) { + ARG(1,T_INT); + ARG(2,T_INT); + 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; + + 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("Argument 1 of instruction FI_EC_CONSTRUCT must be integer or IPv4 address, got 0x%02x"); + + 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)); + } + + if (check && (val > 0xFFFF)) + runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF); } - INST(FI_EC_CONSTRUCT) { - { - ARG_ANY(1); - ARG(2, T_INT); + 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 }]]); + } - int check, ipv4_used; - u32 key, val; + 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); - if (v1.type == T_INT) { - ipv4_used = 0; key = v1.val.i; + 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; icount; 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" ); } - 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; - - 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 (check && (val > 0xFFFF)) - runtime("Can't operate with value out of bounds in EC constructor"); - - } } - INST(FI_LC_CONSTRUCT) { - { - ARG(1, T_INT); - ARG(2, T_INT); - ARG(3, T_INT); + vstk.cnt -= what->count; + pm->len = what->count; - res.type = T_LC; - res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i }; - - } - } - - 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); - } - - 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" ); + { + 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; + 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 */ - ARG(1, T_PATH); - res.type = T_INT; - res.val.i = as_path_get_last_nonaggregated(v1.val.ad); + 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)); } - INST(FI_RETURN) { - ARG_ANY_T(1,0); - return F_RETURN; + + 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_CALL) { - ARG_ANY_T(1,0); - fret = interpret(fs, what->a[1].p); - if (fret > F_RETURN) - return fret; + + 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_CLEAR_LOCAL_VARS) { /* Clear local variables */ - for (sym = what->a[0].p; sym != NULL; sym = sym->aux2) + + INST(FI_DROP_RESULT, 1, 0) { + ARG_ANY(1); + } + + INST(FI_CLEAR_LOCAL_VARS, 0, 0) { /* Clear local variables */ + SYMBOL(1); + for ( ; sym != NULL; sym = sym->aux2) ((struct f_val *) sym->def)->type = T_VOID; } - INST(FI_SWITCH) { + 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); - - res.type = T_PATH; - res.val.ad = as_path_prepend(fs->pool, v1.val.ad, v2.val.i); + RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]); } - INST(FI_CLIST_ADD_DEL) { /* (Extended) Community list add or delete */ + 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"); + } + + 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_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; - - 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; - - case 'f': - if (!arg_set) - runtime("Can't filter lc"); - res.val.ad = lclist_filter(fs->pool, v1.val.ad, v2, 1); - break; - - default: - bug("unknown Ca operation"); - } + runtime("Can't delete non-lc"); + else + RESULT(T_LCLIST, ad, [[ lc_set_del(fs->pool, v1.val.ad, v2.val.lc) ]]); } - else - runtime("Can't add/delete to non-[e|l]clist"); + else + runtime("Can't delete in non-[e|l]clist"); } - INST(FI_ROA_CHECK) { /* ROA Check */ - if (what->arg1) + INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */ + ARG_ANY(1); + ARG_ANY(2); + if (v1.type == T_PATH) { - ARG(1, T_NET); - ARG(2, T_INT); + u32 key = 0; - as = v2.val.i; + 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 if (v1.type == T_CLIST) + { + /* Community (or cluster) list */ + struct f_val dummy; + + 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) + { + /* 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"); + } + + 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; ilen; 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; ilen; 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; + 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; } - else - { - if ((m1->val != m2->val) || (m1->val2 != m2->val2)) - return 0; - } - - 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; ilen; 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] - for ( ; what; what = what->next) { - res = (struct f_val) { .type = T_VOID }; - switch (what->fi_code) { + while (estk.cnt > 0) { + while (curline.pos < curline.line->len) { + const struct f_line_item *what = &(curline.line->items[curline.pos++]); + + + 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--; + } + + 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; } - return F_NOP; } -#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; ilen; 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,58 +185,40 @@ 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 - -struct filter { - char *name; - struct f_inst *root; -}; - -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_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_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); - -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); - -struct ea_list; -struct rte; - +/* Possible return values of filter execution */ enum filter_return { F_NOP = 0, F_NONL, @@ -176,83 +229,121 @@ enum filter_return { 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); +/* 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_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(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(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 *); +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(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_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(struct f_val v1, struct f_val v2); -int val_same(struct f_val v1, struct f_val v2); +int val_compare(const struct f_val *v1, const struct f_val *v2); -void val_format(struct f_val v, buffer *buf); +void val_format(const 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 +# +# 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 +# +# 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 +# +# 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; ilen; 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; /* 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); +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, 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); +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, , [[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 [, ...] }) [], [[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 +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, [], [[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