mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-09-07 22:15:19 +00:00
Filter refactoring: dropped the recursion from the interpreter
This is a major change of how the filters are interpreted. If everything works how it should, it should not affect you unless you are hacking the filters themselves. Anyway, this change should make a huge improvement in the filter performance as previous benchmarks showed that our major problem lies in the recursion itself. There are also some changes in nest and protocols, related mostly to spreading const declarations throughout the whole BIRD and also to refactored dynamic attribute definitions. The need of these came up during the whole work and it is too difficult to split out these not-so-related changes.
This commit is contained in:
parent
967b88d938
commit
4c553c5a5b
@ -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; }
|
||||
|
@ -3982,7 +3982,7 @@ definitions, prefix definitions and DNS definitions:
|
||||
RAdv protocol could be configured to change its behavior based on
|
||||
availability of routes. When this option is used, the protocol waits in
|
||||
suppressed state until a <it/trigger route/ (for the specified network)
|
||||
is exported to the protocol, the protocol also returnsd to suppressed
|
||||
is exported to the protocol, the protocol also returns to suppressed
|
||||
state if the <it/trigger route/ disappears. Note that route export
|
||||
depends on specified export filter, as usual. This option could be used,
|
||||
e.g., for handling failover in multihoming scenarios.
|
||||
|
@ -5,10 +5,22 @@ $(cf-local)
|
||||
|
||||
M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS))
|
||||
|
||||
$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c
|
||||
$(o)f-inst-line-size.c: $(s)line-size.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
|
||||
|
||||
$(o)filter.o: $(o)f-inst-interpret.c
|
||||
$(o)f-inst-postfixify.c: $(s)postfixify.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
|
||||
|
||||
$(o)f-inst-interpret.c: $(s)interpret.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
|
||||
|
||||
$(o)f-inst-same.c: $(s)same.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
|
||||
|
||||
$(o)f-inst-dump.c: $(s)dump.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -P $^ >$@
|
||||
|
||||
$(o)filter.o: $(o)f-inst-interpret.c $(o)f-inst-line-size.c $(o)f-inst-postfixify.c $(o)f-inst-same.c $(o)f-inst-dump.c
|
||||
|
||||
tests_src := tree_test.c filter_test.c trie_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
|
185
filter/config.Y
185
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 <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
|
||||
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail
|
||||
%type <fda> dynamic_attr
|
||||
%type <fsa> static_attr
|
||||
%type <f> filter filter_body where_filter
|
||||
@ -420,7 +431,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
%type <v> set_atom switch_atom fipa
|
||||
%type <px> fprefix
|
||||
%type <s> decls declsn one_decl function_params
|
||||
%type <h> bgp_path bgp_path_tail
|
||||
%type <t> get_cf_position
|
||||
|
||||
CF_GRAMMAR
|
||||
@ -438,7 +448,7 @@ filter_def:
|
||||
|
||||
conf: filter_eval ;
|
||||
filter_eval:
|
||||
EVAL term { f_eval_int($2); }
|
||||
EVAL term { f_eval_int(f_postfixify($2)); }
|
||||
;
|
||||
|
||||
conf: custom_attr ;
|
||||
@ -530,7 +540,7 @@ filter_body:
|
||||
function_body {
|
||||
struct filter *f = cfg_alloc(sizeof(struct filter));
|
||||
f->name = NULL;
|
||||
f->root = $1;
|
||||
f->root = f_postfixify($1);
|
||||
$$ = f;
|
||||
}
|
||||
;
|
||||
@ -547,21 +557,25 @@ where_filter:
|
||||
WHERE term {
|
||||
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
|
||||
struct filter *f = cfg_alloc(sizeof(struct filter));
|
||||
struct f_inst *i, *acc, *rej;
|
||||
acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
|
||||
acc->a[0].p = NULL;
|
||||
acc->a[1].i = F_ACCEPT;
|
||||
rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
|
||||
rej->a[0].p = NULL;
|
||||
rej->a[1].i = F_REJECT;
|
||||
i = f_new_inst(FI_CONDITION); /* IF */
|
||||
i->a[0].p = $2;
|
||||
i->a[1].p = acc;
|
||||
i->a[2].p = rej;
|
||||
struct f_inst acc = {
|
||||
.fi_code = FI_PRINT_AND_DIE,
|
||||
.a = { { .p = NULL }, { .i = F_ACCEPT } },
|
||||
.lineno = ifs->lino,
|
||||
};
|
||||
struct f_inst rej = {
|
||||
.fi_code = FI_PRINT_AND_DIE,
|
||||
.a = { { .p = NULL }, { .i = F_REJECT } },
|
||||
.lineno = ifs->lino,
|
||||
};
|
||||
struct f_inst i = {
|
||||
.fi_code = FI_CONDITION,
|
||||
.a = { { .p = $2 }, { .p = &acc }, { .p = &rej } },
|
||||
.lineno = ifs->lino,
|
||||
};
|
||||
f->name = NULL;
|
||||
f->root = i;
|
||||
f->root = f_postfixify(&i);
|
||||
$$ = f;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
function_params:
|
||||
@ -587,7 +601,9 @@ function_def:
|
||||
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
|
||||
cf_push_scope($2);
|
||||
} function_params function_body {
|
||||
$2->def = $5;
|
||||
struct f_inst *vc = f_new_inst(FI_CONSTANT);
|
||||
vc->val = (struct f_val) { .type = T_VOID };
|
||||
$2->def = f_postfixify_concat($5, vc, NULL);
|
||||
$2->aux2 = $4;
|
||||
DBG("Hmm, we've got one function here - %s\n", $2->name);
|
||||
cf_pop_scope();
|
||||
@ -639,7 +655,7 @@ set_atom:
|
||||
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
|
||||
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
|
||||
| '(' term ')' {
|
||||
if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
|
||||
if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
|
||||
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
|
||||
}
|
||||
| SYM {
|
||||
@ -651,13 +667,13 @@ set_atom:
|
||||
|
||||
switch_atom:
|
||||
NUM { $$.type = T_INT; $$.val.i = $1; }
|
||||
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
|
||||
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); }
|
||||
| fipa { $$ = $1; }
|
||||
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
|
||||
;
|
||||
|
||||
cnum:
|
||||
term { $$ = f_eval_int($1); }
|
||||
term { $$ = f_eval_int(f_postfixify($1)); }
|
||||
|
||||
pair_item:
|
||||
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
|
||||
@ -744,15 +760,16 @@ switch_body: /* EMPTY */ { $$ = NULL; }
|
||||
| switch_body switch_items ':' cmds {
|
||||
/* Fill data fields */
|
||||
struct f_tree *t;
|
||||
struct f_line *line = f_postfixify($4);
|
||||
for (t = $2; t; t = t->left)
|
||||
t->data = $4;
|
||||
t->data = line;
|
||||
$$ = f_merge_items($1, $2);
|
||||
}
|
||||
| switch_body ELSECOL cmds {
|
||||
struct f_tree *t = f_new_tree();
|
||||
t->from.type = t->to.type = T_VOID;
|
||||
t->right = t;
|
||||
t->data = $3;
|
||||
t->data = f_postfixify($3);
|
||||
$$ = f_merge_items($1, t);
|
||||
}
|
||||
;
|
||||
@ -767,11 +784,11 @@ bgp_path:
|
||||
;
|
||||
|
||||
bgp_path_tail:
|
||||
NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
|
||||
| NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
|
||||
| '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
|
||||
| '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
|
||||
| bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
|
||||
NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; }
|
||||
| NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; }
|
||||
| '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; }
|
||||
| '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; }
|
||||
| bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
|
||||
| { $$ = NULL; }
|
||||
;
|
||||
|
||||
@ -831,12 +848,11 @@ symbol:
|
||||
switch ($1->class & 0xffff) {
|
||||
case SYM_CONSTANT_RANGE:
|
||||
$$ = f_new_inst(FI_CONSTANT_INDIRECT);
|
||||
goto cv_common;
|
||||
$$->a[0].p = $1;
|
||||
break;
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = f_new_inst(FI_VARIABLE);
|
||||
cv_common:
|
||||
$$->a[0].p = $1->def;
|
||||
$$->a[1].p = $1->name;
|
||||
$$->a[0].p = $1;
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
|
||||
@ -847,15 +863,15 @@ symbol:
|
||||
}
|
||||
|
||||
static_attr:
|
||||
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
|
||||
| GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
|
||||
| NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
|
||||
| PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
|
||||
| SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
|
||||
| SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
|
||||
| DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
|
||||
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); }
|
||||
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
|
||||
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
|
||||
| GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
|
||||
| NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
|
||||
| PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
|
||||
| SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
|
||||
| SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
|
||||
| DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
|
||||
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
|
||||
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
|
||||
;
|
||||
|
||||
term:
|
||||
@ -908,42 +924,23 @@ term:
|
||||
| rtadot dynamic_attr '.' RESET{ }
|
||||
*/
|
||||
|
||||
| '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
|
||||
| '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
|
||||
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
|
||||
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
|
||||
| '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; }
|
||||
| '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; }
|
||||
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; }
|
||||
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; }
|
||||
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; }
|
||||
| ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; }
|
||||
| DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; }
|
||||
| FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; }
|
||||
| ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; }
|
||||
| DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; }
|
||||
| FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; }
|
||||
|
||||
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
|
||||
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
|
||||
| ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; }
|
||||
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; }
|
||||
|
||||
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
|
||||
|
||||
/* | term '.' LEN { $$->code = P('P','l'); } */
|
||||
|
||||
/* function_call is inlined here */
|
||||
| SYM '(' var_list ')' {
|
||||
struct symbol *sym;
|
||||
struct f_inst *inst = $3;
|
||||
if ($1->class != SYM_FUNCTION)
|
||||
cf_error("You can't call something which is not a function. Really.");
|
||||
DBG("You are calling function %s\n", $1->name);
|
||||
$$ = f_new_inst(FI_CALL);
|
||||
$$->a[0].p = inst;
|
||||
$$->a[1].p = $1->def;
|
||||
sym = $1->aux2;
|
||||
while (sym || inst) {
|
||||
if (!sym || !inst)
|
||||
cf_error("Wrong number of arguments for function %s.", $1->name);
|
||||
DBG( "You should pass parameter called %s\n", sym->name);
|
||||
inst->a[0].p = sym;
|
||||
sym = sym->aux2;
|
||||
inst = inst->next;
|
||||
}
|
||||
}
|
||||
| function_call
|
||||
;
|
||||
|
||||
break_command:
|
||||
@ -1022,7 +1019,7 @@ cmd:
|
||||
}
|
||||
| rtadot static_attr '=' term ';' {
|
||||
$$ = f_new_inst_sa(FI_RTA_SET, $2);
|
||||
if (!$$->a[0].i)
|
||||
if ($$->sa.readonly)
|
||||
cf_error( "This static attribute is read-only.");
|
||||
$$->a[0].p = $4;
|
||||
}
|
||||
@ -1036,7 +1033,7 @@ cmd:
|
||||
$$->a[0].p = NULL;
|
||||
}
|
||||
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
|
||||
| function_call ';' { $$ = $1; }
|
||||
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; }
|
||||
| CASE term '{' switch_body '}' {
|
||||
$$ = f_new_inst(FI_SWITCH);
|
||||
$$->a[0].p = $2;
|
||||
@ -1044,10 +1041,10 @@ cmd:
|
||||
}
|
||||
|
||||
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
|
||||
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
|
||||
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
|
||||
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
|
||||
;
|
||||
|
||||
|
43
filter/dump.m4
Normal file
43
filter/dump.m4
Normal file
@ -0,0 +1,43 @@
|
||||
m4_divert(-1)m4_dnl
|
||||
#
|
||||
# BIRD -- Dumping instruction lines
|
||||
#
|
||||
# (c) 2018 Maria Matejka <mq@jmq.cz>
|
||||
#
|
||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||
#
|
||||
|
||||
# Common aliases
|
||||
m4_define(DNL, `m4_dnl')
|
||||
|
||||
m4_define(INST, `m4_divert(1)break; case $1:
|
||||
m4_divert(-1)'))
|
||||
m4_define(LINE, `m4_divert(1)f_dump_line(item->lines[$2], indent + 1);
|
||||
m4_divert(-1)')
|
||||
m4_define(LINEP, `LINE($@)')
|
||||
m4_define(SYMBOL, `m4_divert(1)debug("%ssymbol %s\n", INDENT, item->sym->name);
|
||||
m4_divert(-1)')
|
||||
m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
|
||||
m4_divert(-1)')
|
||||
m4_define(VALI, `m4_divert(1)debug("%svalue %s\n", INDENT, val_dump(item->vp));
|
||||
m4_divert(-1)')
|
||||
m4_define(FRET, `m4_divert(1)debug("%sfilter return value %d\n", INDENT, item->fret);
|
||||
m4_divert(-1)')
|
||||
m4_define(ECS, `m4_divert(1)debug("%sec subtype %d\n", INDENT, item->ecs);
|
||||
m4_divert(-1)')
|
||||
m4_define(RTC, `m4_divert(1)debug("%sroute table %s\n", INDENT, item->rtc->name);
|
||||
m4_divert(-1)')
|
||||
m4_define(STATIC_ATTR, `m4_divert(1)debug("%sstatic attribute %u/%u/%u\n", INDENT, item->sa.f_type, item->sa.sa_code, item->sa.readonly);
|
||||
m4_divert(-1)')
|
||||
m4_define(DYNAMIC_ATTR, `m4_divert(1)debug("%sdynamic attribute %u/%u/%u/%u\n", INDENT, item->da.type, item->da.bit, item->da.f_type, item->da.ea_code);
|
||||
m4_divert(-1)')
|
||||
m4_define(DUMP, `m4_divert(1)$1m4_divert(-1)')
|
||||
|
||||
m4_m4wrap(`
|
||||
m4_divert(0)DNL
|
||||
case FI_NOP: bug("This shall not happen");
|
||||
m4_undivert(1)
|
||||
break; default: bug( "Unknown instruction %d (%c)", item->fi_code, item->fi_code & 0xff);
|
||||
')
|
||||
|
||||
m4_changequote([[,]])
|
1007
filter/f-inst.c
1007
filter/f-inst.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
544
filter/filter.c
544
filter/filter.c
@ -50,15 +50,6 @@
|
||||
|
||||
#define CMP_ERROR 999
|
||||
|
||||
#define FILTER_STACK_DEPTH 16384
|
||||
|
||||
/* Filter interpreter stack. Make this thread local after going parallel. */
|
||||
struct filter_stack {
|
||||
struct f_val val;
|
||||
};
|
||||
|
||||
static struct filter_stack filter_stack[FILTER_STACK_DEPTH];
|
||||
|
||||
/* Internal filter state, to be allocated on stack when executing filters */
|
||||
struct filter_state {
|
||||
struct rte **rte;
|
||||
@ -66,14 +57,10 @@ struct filter_state {
|
||||
struct ea_list **eattrs;
|
||||
struct linpool *pool;
|
||||
struct buffer buf;
|
||||
struct filter_stack *stack;
|
||||
int stack_ptr;
|
||||
int flags;
|
||||
};
|
||||
|
||||
void (*bt_assert_hook)(int result, struct f_inst *assert);
|
||||
|
||||
static struct adata undef_adata; /* adata of length 0 used for undefined */
|
||||
void (*bt_assert_hook)(int result, const struct f_line_item *assert);
|
||||
|
||||
/* Special undef value for paths and clists */
|
||||
static inline int
|
||||
@ -81,9 +68,23 @@ undef_value(struct f_val v)
|
||||
{
|
||||
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
|
||||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
|
||||
(v.val.ad == &undef_adata);
|
||||
(v.val.ad == &null_adata);
|
||||
}
|
||||
|
||||
const struct f_val f_const_empty_path = {
|
||||
.type = T_PATH,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_clist = {
|
||||
.type = T_CLIST,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_eclist = {
|
||||
.type = T_ECLIST,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_lclist = {
|
||||
.type = T_LCLIST,
|
||||
.val.ad = &null_adata,
|
||||
};
|
||||
|
||||
static struct adata *
|
||||
adata_empty(struct linpool *pool, int l)
|
||||
{
|
||||
@ -93,16 +94,16 @@ adata_empty(struct linpool *pool, int l)
|
||||
}
|
||||
|
||||
static void
|
||||
pm_format(struct f_path_mask *p, buffer *buf)
|
||||
pm_format(const struct f_path_mask *p, buffer *buf)
|
||||
{
|
||||
buffer_puts(buf, "[= ");
|
||||
|
||||
while (p)
|
||||
for (uint i=0; i<p->len; i++)
|
||||
{
|
||||
switch(p->kind)
|
||||
switch(p->item[i].kind)
|
||||
{
|
||||
case PM_ASN:
|
||||
buffer_print(buf, "%u ", p->val);
|
||||
buffer_print(buf, "%u ", p->item[i].asn);
|
||||
break;
|
||||
|
||||
case PM_QUESTION:
|
||||
@ -114,21 +115,20 @@ pm_format(struct f_path_mask *p, buffer *buf)
|
||||
break;
|
||||
|
||||
case PM_ASN_RANGE:
|
||||
buffer_print(buf, "%u..%u ", p->val, p->val2);
|
||||
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
|
||||
break;
|
||||
|
||||
case PM_ASN_EXPR:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
buffer_puts(buf, "=]");
|
||||
}
|
||||
|
||||
static inline int val_is_ip4(const struct f_val v)
|
||||
{ return (v.type == T_IP) && ipa_is_ip4(v.val.ip); }
|
||||
static inline int val_is_ip4(const struct f_val *v)
|
||||
{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
|
||||
|
||||
static inline int
|
||||
lcomm_cmp(lcomm v1, lcomm v2)
|
||||
@ -152,25 +152,25 @@ lcomm_cmp(lcomm v1, lcomm v2)
|
||||
* that it can be used for building balanced trees.
|
||||
*/
|
||||
int
|
||||
val_compare(struct f_val v1, struct f_val v2)
|
||||
val_compare(const struct f_val *v1, const struct f_val *v2)
|
||||
{
|
||||
if (v1.type != v2.type) {
|
||||
if (v1.type == T_VOID) /* Hack for else */
|
||||
if (v1->type != v2->type) {
|
||||
if (v1->type == T_VOID) /* Hack for else */
|
||||
return -1;
|
||||
if (v2.type == T_VOID)
|
||||
if (v2->type == T_VOID)
|
||||
return 1;
|
||||
|
||||
/* IP->Quad implicit conversion */
|
||||
if ((v1.type == T_QUAD) && val_is_ip4(v2))
|
||||
return uint_cmp(v1.val.i, ipa_to_u32(v2.val.ip));
|
||||
if (val_is_ip4(v1) && (v2.type == T_QUAD))
|
||||
return uint_cmp(ipa_to_u32(v1.val.ip), v2.val.i);
|
||||
if ((v1->type == T_QUAD) && val_is_ip4(v2))
|
||||
return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
|
||||
if (val_is_ip4(v1) && (v2->type == T_QUAD))
|
||||
return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
|
||||
|
||||
debug( "Types do not match in val_compare\n" );
|
||||
return CMP_ERROR;
|
||||
}
|
||||
|
||||
switch (v1.type) {
|
||||
switch (v1->type) {
|
||||
case T_VOID:
|
||||
return 0;
|
||||
case T_ENUM:
|
||||
@ -178,47 +178,52 @@ val_compare(struct f_val v1, struct f_val v2)
|
||||
case T_BOOL:
|
||||
case T_PAIR:
|
||||
case T_QUAD:
|
||||
return uint_cmp(v1.val.i, v2.val.i);
|
||||
return uint_cmp(v1->val.i, v2->val.i);
|
||||
case T_EC:
|
||||
case T_RD:
|
||||
return u64_cmp(v1.val.ec, v2.val.ec);
|
||||
return u64_cmp(v1->val.ec, v2->val.ec);
|
||||
case T_LC:
|
||||
return lcomm_cmp(v1.val.lc, v2.val.lc);
|
||||
return lcomm_cmp(v1->val.lc, v2->val.lc);
|
||||
case T_IP:
|
||||
return ipa_compare(v1.val.ip, v2.val.ip);
|
||||
return ipa_compare(v1->val.ip, v2->val.ip);
|
||||
case T_NET:
|
||||
return net_compare(v1.val.net, v2.val.net);
|
||||
return net_compare(v1->val.net, v2->val.net);
|
||||
case T_STRING:
|
||||
return strcmp(v1.val.s, v2.val.s);
|
||||
return strcmp(v1->val.s, v2->val.s);
|
||||
default:
|
||||
return CMP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
|
||||
pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
|
||||
{
|
||||
while (m1 && m2)
|
||||
if (m1->len != m2->len)
|
||||
|
||||
for (uint i=0; i<m1->len; i++)
|
||||
{
|
||||
if (m1->kind != m2->kind)
|
||||
if (m1->item[i].kind != m2->item[i].kind)
|
||||
return 0;
|
||||
|
||||
if (m1->kind == PM_ASN_EXPR)
|
||||
{
|
||||
if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
|
||||
return 0;
|
||||
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; i<dest->len; i++)
|
||||
f_dump_line_item(&dest->items[i], indent+1);
|
||||
debug("%sFilter line %p dump done\n", INDENT, dest);
|
||||
#undef INDENT
|
||||
}
|
||||
#else
|
||||
#define f_dump_line(...)
|
||||
#endif
|
||||
|
||||
static uint
|
||||
postfixify(struct f_line *dest, const struct f_inst *what, uint pos)
|
||||
{
|
||||
for ( ; what; what = what->next) {
|
||||
switch (what->fi_code) {
|
||||
#include "filter/f-inst-postfixify.c"
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
struct f_line *
|
||||
f_postfixify_concat(struct f_inst *first, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_list argd;
|
||||
va_start(args, first);
|
||||
va_copy(argd, args);
|
||||
|
||||
uint len = 0;
|
||||
for (struct f_inst *what = first; what; what = va_arg(args, struct f_inst *))
|
||||
len += inst_line_size(what);
|
||||
|
||||
va_end(args);
|
||||
|
||||
struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len);
|
||||
|
||||
for (struct f_inst *what = first; what; what = va_arg(argd, struct f_inst *))
|
||||
out->len = postfixify(out, what, out->len);
|
||||
|
||||
f_dump_line(out, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* interpret
|
||||
* @fs: filter state
|
||||
@ -624,26 +721,28 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||
* TWOARGS macro to get both of them evaluated.
|
||||
*/
|
||||
static enum filter_return
|
||||
interpret(struct filter_state *fs, struct f_inst *what)
|
||||
interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct f_val *vp;
|
||||
unsigned u1, u2;
|
||||
enum filter_return fret;
|
||||
int i;
|
||||
u32 as;
|
||||
struct f_val_stack vstk;
|
||||
vstk.cnt = 0;
|
||||
|
||||
#define res fs->stack[fs->stack_ptr].val
|
||||
#define v0 res
|
||||
#define v1 fs->stack[fs->stack_ptr + 1].val
|
||||
#define v2 fs->stack[fs->stack_ptr + 2].val
|
||||
#define v3 fs->stack[fs->stack_ptr + 3].val
|
||||
struct f_exec_stack estk;
|
||||
estk.cnt = 1;
|
||||
estk.item[0].line = line;
|
||||
estk.item[0].pos = 0;
|
||||
|
||||
res = (struct f_val) { .type = T_VOID };
|
||||
#define curline estk.item[estk.cnt-1]
|
||||
|
||||
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; i<fl1->len; i++) {
|
||||
#define f1 (&(fl1->items[i]))
|
||||
#define f2 (&(fl2->items[i]))
|
||||
if (f1->fi_code != f2->fi_code)
|
||||
return 0;
|
||||
if (f1->flags != f2->flags)
|
||||
return 0;
|
||||
|
||||
switch(f1->fi_code) {
|
||||
switch(f1->fi_code) {
|
||||
#include "filter/f-inst-same.c"
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
case FI_ADD: /* fall through */
|
||||
case FI_SUBTRACT:
|
||||
case FI_MULTIPLY:
|
||||
@ -842,9 +927,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
case FI_ASSERT: ONEARG; break;
|
||||
default:
|
||||
bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
|
||||
}
|
||||
return i_same(f1->next, f2->next);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* f_run - run a filter for a route
|
||||
@ -871,7 +954,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
* modified in place, old cached rta is possibly freed.
|
||||
*/
|
||||
enum filter_return
|
||||
f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
|
||||
f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
|
||||
{
|
||||
if (filter == FILTER_ACCEPT)
|
||||
return F_ACCEPT;
|
||||
@ -886,12 +969,11 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
|
||||
.rte = rte,
|
||||
.pool = tmp_pool,
|
||||
.flags = flags,
|
||||
.stack = filter_stack,
|
||||
};
|
||||
|
||||
LOG_BUFFER_INIT(fs.buf);
|
||||
|
||||
enum filter_return fret = interpret(&fs, filter->root);
|
||||
enum filter_return fret = interpret(&fs, filter->root, NULL);
|
||||
|
||||
if (fs.old_rta) {
|
||||
/*
|
||||
@ -925,54 +1007,52 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
|
||||
/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
|
||||
|
||||
enum filter_return
|
||||
f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
|
||||
f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
|
||||
{
|
||||
|
||||
struct filter_state fs = {
|
||||
.rte = rte,
|
||||
.pool = tmp_pool,
|
||||
.stack = filter_stack,
|
||||
};
|
||||
|
||||
LOG_BUFFER_INIT(fs.buf);
|
||||
|
||||
/* Note that in this function we assume that rte->attrs is private / uncached */
|
||||
return interpret(&fs, expr);
|
||||
return interpret(&fs, expr, NULL);
|
||||
}
|
||||
|
||||
enum filter_return
|
||||
f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres)
|
||||
f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
|
||||
{
|
||||
struct filter_state fs = {
|
||||
.pool = tmp_pool,
|
||||
.stack = filter_stack,
|
||||
};
|
||||
|
||||
LOG_BUFFER_INIT(fs.buf);
|
||||
|
||||
enum filter_return fret = interpret(&fs, expr);
|
||||
*pres = filter_stack[0].val;
|
||||
enum filter_return fret = interpret(&fs, expr, pres);
|
||||
return fret;
|
||||
}
|
||||
|
||||
uint
|
||||
f_eval_int(struct f_inst *expr)
|
||||
f_eval_int(const struct f_line *expr)
|
||||
{
|
||||
/* Called independently in parse-time to eval expressions */
|
||||
struct filter_state fs = {
|
||||
.pool = cfg_mem,
|
||||
.stack = filter_stack,
|
||||
};
|
||||
|
||||
struct f_val val;
|
||||
|
||||
LOG_BUFFER_INIT(fs.buf);
|
||||
|
||||
if (interpret(&fs, expr) > F_RETURN)
|
||||
if (interpret(&fs, expr, &val) > F_RETURN)
|
||||
cf_error("Runtime error while evaluating expression");
|
||||
|
||||
if (filter_stack[0].val.type != T_INT)
|
||||
if (val.type != T_INT)
|
||||
cf_error("Integer expression expected");
|
||||
|
||||
return filter_stack[0].val.val.i;
|
||||
return val.val.i;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -993,5 +1073,5 @@ filter_same(struct filter *new, struct filter *old)
|
||||
if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
|
||||
new == FILTER_ACCEPT || new == FILTER_REJECT)
|
||||
return 0;
|
||||
return i_same(new->root, old->root);
|
||||
return f_same(new->root, old->root);
|
||||
}
|
||||
|
349
filter/filter.h
349
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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
30
filter/line-size.m4
Normal file
30
filter/line-size.m4
Normal file
@ -0,0 +1,30 @@
|
||||
m4_divert(-1)m4_dnl
|
||||
#
|
||||
# BIRD -- Line size counting
|
||||
#
|
||||
# (c) 2018 Maria Matejka <mq@jmq.cz>
|
||||
#
|
||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||
#
|
||||
|
||||
# Common aliases
|
||||
m4_define(DNL, `m4_dnl')
|
||||
|
||||
m4_define(INST, `m4_divert(1)break; case $1: cnt += 1;
|
||||
m4_divert(-1)')
|
||||
m4_define(ARG, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
|
||||
m4_divert(-1)')
|
||||
m4_define(ARG_T, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
|
||||
m4_divert(-1)')
|
||||
m4_define(ARG_ANY, `m4_divert(1)cnt += inst_line_size(what->a[$1-1].p);
|
||||
m4_divert(-1)')
|
||||
m4_define(LINE_SIZE, `m4_divert(1)$1m4_divert(-1)')
|
||||
|
||||
m4_m4wrap(`
|
||||
m4_divert(0)DNL
|
||||
case FI_NOP: bug("This shall not happen");
|
||||
m4_undivert(1)
|
||||
break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
|
||||
')
|
||||
|
||||
m4_changequote([[,]])
|
55
filter/postfixify.m4
Normal file
55
filter/postfixify.m4
Normal file
@ -0,0 +1,55 @@
|
||||
m4_divert(-1)m4_dnl
|
||||
#
|
||||
# BIRD -- Converting instructions trees to instruction lines
|
||||
#
|
||||
# (c) 2018 Maria Matejka <mq@jmq.cz>
|
||||
#
|
||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||
#
|
||||
|
||||
# Common aliases
|
||||
m4_define(DNL, `m4_dnl')
|
||||
|
||||
m4_define(POSTFIXIFY_TRAILER, `dest->items[pos].fi_code = what->fi_code;
|
||||
dest->items[pos].lineno = what->lineno;')
|
||||
|
||||
m4_define(INST, `m4_divert(1)POSTFIXIFY_TRAILER
|
||||
break; case $1:
|
||||
m4_divert(-1)'))
|
||||
m4_define(ARG, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
|
||||
m4_divert(-1)')
|
||||
m4_define(ARG_ANY, `m4_divert(1)pos = postfixify(dest, what->a[$1-1].p, pos);
|
||||
m4_divert(-1)')
|
||||
m4_define(LINE, `m4_divert(1)dest->items[pos].lines[$2] = f_postfixify(what->a[$1-1].p);
|
||||
m4_divert(-1)')
|
||||
m4_define(LINEP, `m4_divert(1)dest->items[pos].lines[$2] = what->a[$1-1].p;
|
||||
m4_divert(-1)')
|
||||
m4_define(SYMBOL, `m4_divert(1)dest->items[pos].sym = what->a[$1-1].p;
|
||||
m4_divert(-1)')
|
||||
m4_define(VALI, `m4_divert(1)dest->items[pos].vp = &(what->val);
|
||||
m4_divert(-1)')
|
||||
m4_define(VALP, `m4_divert(1)dest->items[pos].vp = (dest->items[pos].sym = what->a[$1-1].p)->def;
|
||||
m4_divert(-1)')
|
||||
m4_define(FRET, `m4_divert(1)dest->items[pos].fret = what->a[$1-1].i;
|
||||
m4_divert(-1)')
|
||||
m4_define(ECS, `m4_divert(1)dest->items[pos].ecs = what->aux;
|
||||
m4_divert(-1)')
|
||||
m4_define(RTC, `m4_divert(1)dest->items[pos].rtc = what->a[$1-1].rtc;
|
||||
m4_divert(-1)')
|
||||
m4_define(STATIC_ATTR, `m4_divert(1)dest->items[pos].sa = what->sa;
|
||||
m4_divert(-1)')
|
||||
m4_define(DYNAMIC_ATTR, `m4_divert(1)dest->items[pos].da = what->da;
|
||||
m4_divert(-1)')
|
||||
m4_define(COUNT, `m4_divert(1)dest->items[pos].count = what->a[$1-1].i;
|
||||
m4_divert(-1)')
|
||||
m4_define(POSTFIXIFY, `m4_divert(1)$1m4_divert(-1)')
|
||||
|
||||
m4_m4wrap(`
|
||||
m4_divert(0)DNL
|
||||
case FI_NOP: bug("This shall not happen");
|
||||
m4_undivert(1)
|
||||
POSTFIXIFY_TRAILER
|
||||
break; default: bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
|
||||
')
|
||||
|
||||
m4_changequote([[,]])
|
56
filter/same.m4
Normal file
56
filter/same.m4
Normal file
@ -0,0 +1,56 @@
|
||||
m4_divert(-1)m4_dnl
|
||||
#
|
||||
# BIRD -- Filter Comparator Generator
|
||||
#
|
||||
# (c) 2018 Maria Matejka <mq@jmq.cz>
|
||||
#
|
||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||
#
|
||||
|
||||
# Common aliases
|
||||
m4_define(DNL, `m4_dnl')
|
||||
|
||||
m4_define(INST, `m4_divert(1)break; case $1:
|
||||
m4_divert(-1)')
|
||||
|
||||
m4_define(ARG, `')
|
||||
m4_define(ARG_ANY, `')
|
||||
|
||||
m4_define(LINE, `m4_divert(1)if (!f_same(f1->lines[$2], f2->lines[$2])) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(LINEP, LINE)
|
||||
|
||||
m4_define(SYMBOL, `m4_divert(1){
|
||||
const struct symbol *s1 = f1->sym, *s2 = f2->sym;
|
||||
if (strcmp(s1->name, s2->name)) return 0;
|
||||
if (s1->class != s2->class) return 0;
|
||||
}
|
||||
m4_divert(-1)')
|
||||
|
||||
m4_define(VALI, `m4_divert(1)if (!val_same(f1->vp, f2->vp)) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(VALP, `')
|
||||
|
||||
m4_define(FRET, `m4_divert(1)if (f1->fret != f2->fret) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(ECS, `m4_divert(1)if (f1->ecs != f2->ecs) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(RTC, `m4_divert(1)if (strcmp(f1->rtc->name, f2->rtc->name)) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(STATIC_ATTR, `m4_divert(1)if (f1->sa.sa_code != f2->sa.sa_code) return 0;
|
||||
m4_divert(-1)')
|
||||
m4_define(DYNAMIC_ATTR, `m4_divert(1)if (f1->da.ea_code != f2->da.ea_code) return 0;
|
||||
m4_divert(-1)')
|
||||
|
||||
m4_define(SAME, `m4_divert(1)$1m4_divert(-1)')
|
||||
|
||||
m4_m4wrap(`
|
||||
m4_divert(0)DNL
|
||||
case FI_NOP: bug("This shall not happen");
|
||||
m4_undivert(1)
|
||||
break; default: bug( "Unknown instruction %d (%c)", f1->fi_code, f1->fi_code & 0xff);
|
||||
')
|
||||
|
||||
m4_divert(1)
|
||||
m4_changequote([[,]])
|
||||
|
@ -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, "[");
|
||||
|
||||
|
@ -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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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, "[");
|
||||
|
||||
|
4
lib/ip.h
4
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);
|
||||
|
@ -77,10 +77,10 @@ bad:
|
||||
}
|
||||
|
||||
int
|
||||
as_path_16to32(byte *dst, byte *src, uint len)
|
||||
as_path_16to32(byte *dst, const byte *src, uint len)
|
||||
{
|
||||
byte *dst0 = dst;
|
||||
byte *end = src + len;
|
||||
const byte *end = src + len;
|
||||
uint i, n;
|
||||
|
||||
while (src < end)
|
||||
@ -101,10 +101,10 @@ as_path_16to32(byte *dst, byte *src, uint len)
|
||||
}
|
||||
|
||||
int
|
||||
as_path_32to16(byte *dst, byte *src, uint len)
|
||||
as_path_32to16(byte *dst, const byte *src, uint len)
|
||||
{
|
||||
byte *dst0 = dst;
|
||||
byte *end = src + len;
|
||||
const byte *end = src + len;
|
||||
uint i, n;
|
||||
|
||||
while (src < end)
|
||||
@ -273,11 +273,11 @@ as_path_to_old(struct linpool *pool, const struct adata *path)
|
||||
* AS_CONFED_* segments have zero length and must be added if they are on edge.
|
||||
* In contrast to other as_path_* functions, @path is modified in place.
|
||||
*/
|
||||
void
|
||||
as_path_cut(struct adata *path, uint num)
|
||||
struct adata *
|
||||
as_path_cut(struct linpool *pool, const struct adata *path, uint num)
|
||||
{
|
||||
byte *pos = path->data;
|
||||
byte *end = pos + path->length;
|
||||
const byte *pos = path->data;
|
||||
const byte *end = pos + path->length;
|
||||
|
||||
while (pos < end)
|
||||
{
|
||||
@ -297,28 +297,39 @@ as_path_cut(struct adata *path, uint num)
|
||||
/* Cannot add whole segment, so try partial one and finish */
|
||||
if (num < n)
|
||||
{
|
||||
const byte *nend = pos;
|
||||
if (num)
|
||||
nend += 2 + BS * num;
|
||||
|
||||
struct adata *res = lp_alloc_adata(pool, path->length);
|
||||
res->length = nend - (const byte *) path->data;
|
||||
memcpy(res->data, path->data, res->length);
|
||||
|
||||
if (num)
|
||||
{
|
||||
pos[1] = num;
|
||||
pos += 2 + BS * num;
|
||||
byte *dpos = ((byte *) res->data) + (pos - (const byte *) path->data);
|
||||
dpos[1] = num;
|
||||
}
|
||||
|
||||
break;
|
||||
return res;
|
||||
}
|
||||
|
||||
num -= n;
|
||||
pos += 2 + BS * l;
|
||||
}
|
||||
|
||||
path->length = pos - path->data;
|
||||
struct adata *res = lp_alloc_adata(pool, path->length);
|
||||
res->length = path->length;
|
||||
memcpy(res->data, path->data, res->length);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge (concatenate) paths @p1 and @p2 and return the result.
|
||||
* In contrast to other as_path_* functions, @p1 and @p2 may be reused.
|
||||
*/
|
||||
struct adata *
|
||||
as_path_merge(struct linpool *pool, struct adata *p1, struct adata *p2)
|
||||
const struct adata *
|
||||
as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2)
|
||||
{
|
||||
if (p1->length == 0)
|
||||
return p2;
|
||||
@ -561,7 +572,7 @@ as_path_contains(const struct adata *path, u32 as, int min)
|
||||
}
|
||||
|
||||
int
|
||||
as_path_match_set(const struct adata *path, struct f_tree *set)
|
||||
as_path_match_set(const struct adata *path, const struct f_tree *set)
|
||||
{
|
||||
const u8 *p = path->data;
|
||||
const u8 *q = p+path->length;
|
||||
@ -574,7 +585,7 @@ as_path_match_set(const struct adata *path, struct f_tree *set)
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
struct f_val v = {T_INT, .val.i = get_as(p)};
|
||||
if (find_tree(set, v))
|
||||
if (find_tree(set, &v))
|
||||
return 1;
|
||||
p += BS;
|
||||
}
|
||||
@ -583,8 +594,8 @@ as_path_match_set(const struct adata *path, struct f_tree *set)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct adata *
|
||||
as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos)
|
||||
const struct adata *
|
||||
as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tree *set, u32 key, int pos)
|
||||
{
|
||||
if (!path)
|
||||
return NULL;
|
||||
@ -612,7 +623,10 @@ as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32
|
||||
int match;
|
||||
|
||||
if (set)
|
||||
match = !!find_tree(set, (struct f_val){T_INT, .val.i = as});
|
||||
{
|
||||
struct f_val v = {T_INT, .val.i = as};
|
||||
match = !!find_tree(set, &v);
|
||||
}
|
||||
else
|
||||
match = (as == key);
|
||||
|
||||
@ -771,7 +785,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
|
||||
* is marked.
|
||||
*/
|
||||
int
|
||||
as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||
as_path_match(const struct adata *path, const struct f_path_mask *mask)
|
||||
{
|
||||
struct pm_pos pos[2048 + 1];
|
||||
int plen = parse_path(path, pos);
|
||||
@ -788,12 +802,12 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||
l = h = 0;
|
||||
pos[0].mark = 1;
|
||||
|
||||
while (mask)
|
||||
for (uint m=0; m < mask->len; m++)
|
||||
{
|
||||
/* We remove this mark to not step after pos[plen] */
|
||||
pos[plen].mark = 0;
|
||||
|
||||
switch (mask->kind)
|
||||
switch (mask->item[m].kind)
|
||||
{
|
||||
case PM_ASTERISK:
|
||||
for (i = l; i <= plen; i++)
|
||||
@ -802,13 +816,13 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||
break;
|
||||
|
||||
case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
|
||||
val2 = val = mask->val;
|
||||
val2 = val = mask->item[m].asn;
|
||||
goto step;
|
||||
case PM_ASN_EXPR:
|
||||
bug("Expressions should be evaluated on AS path mask construction.");
|
||||
case PM_ASN_RANGE:
|
||||
val = mask->val;
|
||||
val2 = mask->val2;
|
||||
val = mask->item[m].from;
|
||||
val2 = mask->item[m].to;
|
||||
goto step;
|
||||
case PM_QUESTION:
|
||||
step:
|
||||
@ -817,7 +831,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||
if (pos[i].mark)
|
||||
{
|
||||
pos[i].mark = 0;
|
||||
if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2))
|
||||
if ((mask->item[m].kind == PM_QUESTION) || pm_match(pos + i, val, val2))
|
||||
pm_mark(pos, i, plen, &nl, &nh);
|
||||
}
|
||||
|
||||
@ -828,8 +842,6 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
|
||||
l = nl;
|
||||
break;
|
||||
}
|
||||
|
||||
mask = mask->next;
|
||||
}
|
||||
|
||||
return pos[plen].mark;
|
||||
|
@ -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;
|
||||
|
||||
|
60
nest/a-set.c
60
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);
|
||||
|
@ -15,10 +15,10 @@
|
||||
#include "lib/resource.h"
|
||||
|
||||
#define SET_SIZE 10
|
||||
static struct adata *set_sequence; /* <0; SET_SIZE) */
|
||||
static struct adata *set_sequence_same; /* <0; SET_SIZE) */
|
||||
static struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
|
||||
static struct adata *set_random;
|
||||
static const struct adata *set_sequence; /* <0; SET_SIZE) */
|
||||
static const struct adata *set_sequence_same; /* <0; SET_SIZE) */
|
||||
static const struct adata *set_sequence_higher; /* <SET_SIZE; 2*SET_SIZE) */
|
||||
static const struct adata *set_random;
|
||||
|
||||
#define BUFFER_SIZE 1000
|
||||
static byte buf[BUFFER_SIZE] = {};
|
||||
@ -34,14 +34,14 @@ enum set_type
|
||||
};
|
||||
|
||||
static void
|
||||
generate_set_sequence(enum set_type type)
|
||||
generate_set_sequence(enum set_type type, int len)
|
||||
{
|
||||
struct adata empty_as_path = {};
|
||||
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
|
||||
lp = lp_new_default(&root_pool);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (type == SET_TYPE_INT)
|
||||
{
|
||||
@ -72,7 +72,7 @@ t_set_int_contains(void)
|
||||
int i;
|
||||
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
|
||||
|
||||
bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
@ -93,9 +93,9 @@ static int
|
||||
t_set_int_union(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
|
||||
|
||||
struct adata *set_union;
|
||||
const struct adata *set_union;
|
||||
set_union = int_set_union(lp, set_sequence, set_sequence_same);
|
||||
bt_assert(int_set_get_size(set_union) == SET_SIZE);
|
||||
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
|
||||
@ -112,9 +112,8 @@ static int
|
||||
t_set_int_format(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
generate_set_sequence(SET_TYPE_INT, SET_SIZE_FOR_FORMAT_OUTPUT);
|
||||
|
||||
set_sequence->length = 4 * SET_SIZE_FOR_FORMAT_OUTPUT; /* dirty */
|
||||
bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0);
|
||||
bt_assert(strcmp(buf, "0.0.0.0 0.0.0.1 0.0.0.2 0.0.0.3 0.0.0.4 0.0.0.5 0.0.0.6 0.0.0.7 0.0.0.8 0.0.0.9") == 0);
|
||||
|
||||
@ -134,9 +133,9 @@ static int
|
||||
t_set_int_delete(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_INT);
|
||||
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
|
||||
|
||||
struct adata *deleting_sequence = set_sequence;
|
||||
const struct adata *deleting_sequence = set_sequence;
|
||||
u32 i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
{
|
||||
@ -162,7 +161,7 @@ t_set_ec_contains(void)
|
||||
u32 i;
|
||||
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
|
||||
|
||||
bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
|
||||
|
||||
@ -183,9 +182,9 @@ static int
|
||||
t_set_ec_union(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
|
||||
|
||||
struct adata *set_union;
|
||||
const struct adata *set_union;
|
||||
set_union = ec_set_union(lp, set_sequence, set_sequence_same);
|
||||
bt_assert(ec_set_get_size(set_union) == SET_SIZE);
|
||||
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
|
||||
@ -203,7 +202,7 @@ t_set_ec_format(void)
|
||||
{
|
||||
resource_init();
|
||||
|
||||
struct adata empty_as_path = {};
|
||||
const struct adata empty_as_path = {};
|
||||
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
|
||||
lp = lp_new_default(&root_pool);
|
||||
|
||||
@ -224,9 +223,9 @@ static int
|
||||
t_set_ec_delete(void)
|
||||
{
|
||||
resource_init();
|
||||
generate_set_sequence(SET_TYPE_EC);
|
||||
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
|
||||
|
||||
struct adata *deleting_sequence = set_sequence;
|
||||
const struct adata *deleting_sequence = set_sequence;
|
||||
u32 i;
|
||||
for (i = 0; i < SET_SIZE; i++)
|
||||
{
|
||||
|
109
nest/attrs.h
109
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 */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -112,7 +112,7 @@ rtrid:
|
||||
|
||||
idval:
|
||||
NUM { $$ = $1; }
|
||||
| '(' term ')' { $$ = f_eval_int($2); }
|
||||
| '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
|
||||
| IP4 { $$ = ip4_to_u32($1); }
|
||||
| SYM {
|
||||
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
|
||||
@ -732,7 +732,7 @@ CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
|
||||
{ protos_dump_all(); cli_msg(0, ""); } ;
|
||||
|
||||
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
|
||||
{ cmd_eval($2); } ;
|
||||
{ cmd_eval(f_postfixify($2)); } ;
|
||||
|
||||
CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
|
||||
CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) {
|
||||
@ -790,7 +790,7 @@ proto_patt2:
|
||||
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
||||
;
|
||||
|
||||
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ;
|
||||
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_GEN_IGP_METRIC); } ;
|
||||
|
||||
|
||||
CF_CODE
|
||||
|
@ -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)); }
|
||||
|
||||
|
||||
|
@ -58,6 +58,8 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
const adata null_adata; /* adata of length 0 */
|
||||
|
||||
const char * const rta_src_names[RTS_MAX] = {
|
||||
[RTS_DUMMY] = "",
|
||||
[RTS_STATIC] = "static",
|
||||
@ -763,7 +765,7 @@ ea_free(ea_list *o)
|
||||
{
|
||||
eattr *a = &o->attrs[i];
|
||||
if (!(a->type & EAF_EMBEDDED))
|
||||
mb_free(a->u.ptr);
|
||||
mb_free((void *) a->u.ptr);
|
||||
}
|
||||
mb_free(o);
|
||||
}
|
||||
@ -808,7 +810,7 @@ ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names,
|
||||
}
|
||||
|
||||
static inline void
|
||||
opaque_format(struct adata *ad, byte *buf, uint size)
|
||||
opaque_format(const struct adata *ad, byte *buf, uint size)
|
||||
{
|
||||
byte *bound = buf + size - 10;
|
||||
uint i;
|
||||
@ -831,7 +833,7 @@ opaque_format(struct adata *ad, byte *buf, uint size)
|
||||
}
|
||||
|
||||
static inline void
|
||||
ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end)
|
||||
ea_show_int_set(struct cli *c, const struct adata *ad, int way, byte *pos, byte *buf, byte *end)
|
||||
{
|
||||
int i = int_set_format(ad, way, 0, pos, end - pos);
|
||||
cli_printf(c, -1012, "\t%s", buf);
|
||||
@ -843,7 +845,7 @@ ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf,
|
||||
}
|
||||
|
||||
static inline void
|
||||
ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
|
||||
ea_show_ec_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
|
||||
{
|
||||
int i = ec_set_format(ad, 0, pos, end - pos);
|
||||
cli_printf(c, -1012, "\t%s", buf);
|
||||
@ -855,7 +857,7 @@ ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
|
||||
}
|
||||
|
||||
static inline void
|
||||
ea_show_lc_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
|
||||
ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
|
||||
{
|
||||
int i = lc_set_format(ad, 0, pos, end - pos);
|
||||
cli_printf(c, -1012, "\t%s", buf);
|
||||
@ -882,7 +884,7 @@ ea_show(struct cli *c, eattr *e)
|
||||
{
|
||||
struct protocol *p;
|
||||
int status = GA_UNKNOWN;
|
||||
struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
|
||||
const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
|
||||
byte buf[CLI_MSG_SIZE];
|
||||
byte *pos = buf, *end = buf + sizeof(buf);
|
||||
|
||||
@ -1023,7 +1025,7 @@ ea_hash(ea_list *e)
|
||||
h ^= a->u.data;
|
||||
else
|
||||
{
|
||||
struct adata *d = a->u.ptr;
|
||||
const struct adata *d = a->u.ptr;
|
||||
h ^= mem_hash(d->data, d->length);
|
||||
}
|
||||
h *= mul;
|
||||
|
@ -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]]);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)); } ;
|
||||
|
||||
|
||||
|
||||
|
@ -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++)
|
||||
|
@ -498,10 +498,10 @@ ospf_iface:
|
||||
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
|
||||
;
|
||||
|
||||
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ;
|
||||
dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ;
|
||||
dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ;
|
||||
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
||||
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC1); } ;
|
||||
dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC2); } ;
|
||||
dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_TAG); } ;
|
||||
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
||||
|
||||
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
|
||||
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]])
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]]);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user