mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 20:58:44 +00:00
Merge commit 'fdd39c81' into thread-next
This commit is contained in:
commit
ef02744998
@ -385,15 +385,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
|||||||
FROM_HEX,
|
FROM_HEX,
|
||||||
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
|
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
|
||||||
|
|
||||||
CF_METHODS(IS_V4, TYPE, IP, RD, LEN, MAXLEN, ASN, SRC, DST, MASK,
|
|
||||||
FIRST, LAST, LAST_NONAGGREGATED, DATA, DATA1, DATA2, MIN, MAX,
|
|
||||||
EMPTY, PREPEND, ADD, DELETE, FILTER)
|
|
||||||
|
|
||||||
%nonassoc THEN
|
%nonassoc THEN
|
||||||
%nonassoc ELSE
|
%nonassoc ELSE
|
||||||
|
|
||||||
%type <xp> cmds_int cmd_prep
|
%type <xp> cmds_int cmd_prep
|
||||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
||||||
%type <fsa> static_attr
|
%type <fsa> static_attr
|
||||||
%type <f> filter where_filter
|
%type <f> filter where_filter
|
||||||
%type <fl> filter_body function_body
|
%type <fl> filter_body function_body
|
||||||
@ -998,16 +994,6 @@ break_command:
|
|||||||
| ERROR { $$ = F_ERROR; }
|
| ERROR { $$ = F_ERROR; }
|
||||||
;
|
;
|
||||||
|
|
||||||
print_list: /* EMPTY */ { $$ = NULL; }
|
|
||||||
| term { $$ = $1; }
|
|
||||||
| term ',' print_list {
|
|
||||||
ASSERT($1);
|
|
||||||
ASSERT($1->next == NULL);
|
|
||||||
$1->next = $3;
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
var:
|
var:
|
||||||
type symbol '=' term ';' {
|
type symbol '=' term ';' {
|
||||||
struct symbol *sym = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope));
|
struct symbol *sym = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope));
|
||||||
@ -1043,8 +1029,7 @@ cmd:
|
|||||||
{ new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
|
{ new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
|
||||||
DO cmd {
|
DO cmd {
|
||||||
cf_pop_block_scope(new_config);
|
cf_pop_block_scope(new_config);
|
||||||
$$ = f_new_inst(FI_FOR_INIT, $6, $3);
|
$$ = f_for_cycle($3, $6, $9);
|
||||||
$$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
|
|
||||||
}
|
}
|
||||||
| CF_SYM_KNOWN '=' term ';' {
|
| CF_SYM_KNOWN '=' term ';' {
|
||||||
switch ($1->class) {
|
switch ($1->class) {
|
||||||
@ -1088,23 +1073,14 @@ cmd:
|
|||||||
cf_error("Attribute %s is read-only", $3->attribute->name);
|
cf_error("Attribute %s is read-only", $3->attribute->name);
|
||||||
$$ = f_new_inst(FI_EA_UNSET, $3->attribute);
|
$$ = f_new_inst(FI_EA_UNSET, $3->attribute);
|
||||||
}
|
}
|
||||||
| break_command print_list ';' {
|
| break_command var_list ';' {
|
||||||
struct f_inst *breaker = f_new_inst(FI_DIE, $1);
|
$$ = f_print($2, !!$2, $1);
|
||||||
if ($2) {
|
|
||||||
struct f_inst *printer = f_new_inst(FI_PRINT, $2);
|
|
||||||
struct f_inst *flusher = f_new_inst(FI_FLUSH);
|
|
||||||
printer->next = flusher;
|
|
||||||
flusher->next = breaker;
|
|
||||||
$$ = printer;
|
|
||||||
} else
|
|
||||||
$$ = breaker;
|
|
||||||
}
|
}
|
||||||
| PRINT print_list ';' {
|
| PRINT var_list ';' {
|
||||||
$$ = f_new_inst(FI_PRINT, $2);
|
$$ = f_print($2, 1, F_NOP);
|
||||||
$$->next = f_new_inst(FI_FLUSH);
|
|
||||||
}
|
}
|
||||||
| PRINTN print_list ';' {
|
| PRINTN var_list ';' {
|
||||||
$$ = f_new_inst(FI_PRINT, $2);
|
$$ = f_print($2, 0, F_NOP);
|
||||||
}
|
}
|
||||||
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
||||||
| CASE term '{' switch_body '}' {
|
| CASE term '{' switch_body '}' {
|
||||||
|
@ -130,7 +130,7 @@ m4_ifelse($1,1,,[[FID_NEW_METHOD()m4_dnl
|
|||||||
struct f_inst *arg$1 = args;
|
struct f_inst *arg$1 = args;
|
||||||
if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */
|
if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */
|
||||||
args = args->next;
|
args = args->next;
|
||||||
FID_METHOD_CALL() , arg$1]])
|
FID_METHOD_CALL() , arg$1]])
|
||||||
FID_LINEARIZE_BODY()m4_dnl
|
FID_LINEARIZE_BODY()m4_dnl
|
||||||
pos = linearize(dest, whati->f$1, pos);
|
pos = linearize(dest, whati->f$1, pos);
|
||||||
FID_INTERPRET_BODY()')
|
FID_INTERPRET_BODY()')
|
||||||
@ -231,6 +231,12 @@ FID_NEW_ARGS()m4_dnl
|
|||||||
, struct f_inst * f$1
|
, struct f_inst * f$1
|
||||||
FID_NEW_BODY()m4_dnl
|
FID_NEW_BODY()m4_dnl
|
||||||
whati->f$1 = f$1;
|
whati->f$1 = f$1;
|
||||||
|
m4_define([[INST_METHOD_NUM_ARGS]],m4_eval($1-1))m4_dnl
|
||||||
|
FID_NEW_METHOD()m4_dnl
|
||||||
|
struct f_inst *arg$1 = args;
|
||||||
|
if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */
|
||||||
|
args = NULL; /* The rest is the line itself */
|
||||||
|
FID_METHOD_CALL() , arg$1
|
||||||
FID_DUMP_BODY()m4_dnl
|
FID_DUMP_BODY()m4_dnl
|
||||||
f_dump_line(item->fl$1, indent + 1);
|
f_dump_line(item->fl$1, indent + 1);
|
||||||
FID_LINEARIZE_BODY()m4_dnl
|
FID_LINEARIZE_BODY()m4_dnl
|
||||||
@ -287,6 +293,21 @@ m4_define([[INST_IS_METHOD]])
|
|||||||
m4_define([[INST_METHOD_NAME]],$1)
|
m4_define([[INST_METHOD_NAME]],$1)
|
||||||
FID_INTERPRET_BODY()')
|
FID_INTERPRET_BODY()')
|
||||||
|
|
||||||
|
# Short method constructor
|
||||||
|
# $1 = type
|
||||||
|
# $2 = name
|
||||||
|
# $3 = method inputs
|
||||||
|
# method outputs are always 1
|
||||||
|
# $4 = code
|
||||||
|
m4_define(METHOD, `m4_dnl
|
||||||
|
INST([[FI_METHOD__]]$1[[__]]$2, m4_eval($3 + 1), 1) {
|
||||||
|
ARG(1, $1);
|
||||||
|
$4
|
||||||
|
METHOD_CONSTRUCTOR("$2");
|
||||||
|
}')
|
||||||
|
|
||||||
|
m4_define(METHOD_R, `METHOD($1, $2, $3, [[ RESULT($4, $5, $6) ]])')
|
||||||
|
|
||||||
# 2) Code wrapping
|
# 2) Code wrapping
|
||||||
# The code produced in 1xx temporary diversions is a raw code without
|
# The code produced in 1xx temporary diversions is a raw code without
|
||||||
# any auxiliary commands and syntactical structures around. When the
|
# any auxiliary commands and syntactical structures around. When the
|
||||||
@ -399,7 +420,7 @@ m4_undivert(112)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FID_METHOD_SCOPE_INIT()m4_dnl
|
FID_METHOD_SCOPE_INIT()m4_dnl
|
||||||
[INST_METHOD_OBJECT_TYPE] = {},
|
[INST_METHOD_OBJECT_TYPE] = { .active = 1, },
|
||||||
FID_METHOD_REGISTER()m4_dnl
|
FID_METHOD_REGISTER()m4_dnl
|
||||||
sym = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]);
|
sym = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]);
|
||||||
sym->class = SYM_METHOD;
|
sym->class = SYM_METHOD;
|
||||||
|
275
filter/f-inst.c
275
filter/f-inst.c
@ -100,6 +100,11 @@
|
|||||||
*
|
*
|
||||||
* Other code is just copied into the interpreter part.
|
* Other code is just copied into the interpreter part.
|
||||||
*
|
*
|
||||||
|
* It's also possible to declare type methods in a short way:
|
||||||
|
*
|
||||||
|
* m4_dnl METHOD(type, method name, argument count, code)
|
||||||
|
* m4_dnl METHOD_R(type, method name, argument count, result type, union-field, value)
|
||||||
|
*
|
||||||
* The filter language uses a simple type system, where values have types
|
* The filter language uses a simple type system, where values have types
|
||||||
* (constants T_*) and also terms (instructions) are statically typed. Our
|
* (constants T_*) and also terms (instructions) are statically typed. Our
|
||||||
* static typing is partial (some terms do not declare types of arguments
|
* static typing is partial (some terms do not declare types of arguments
|
||||||
@ -498,17 +503,8 @@
|
|||||||
RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
|
RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_NET_TYPE, 1, 1) {
|
METHOD_R(T_NET, type, 0, T_ENUM_NETTYPE, i, v1.val.net->type);
|
||||||
ARG(1, T_NET);
|
METHOD_R(T_IP, is_v4, 0, T_BOOL, i, ipa_is_ip4(v1.val.ip));
|
||||||
METHOD_CONSTRUCTOR("type");
|
|
||||||
RESULT(T_ENUM_NETTYPE, i, v1.val.net->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_IS_V4, 1, 1) {
|
|
||||||
ARG(1, T_IP);
|
|
||||||
METHOD_CONSTRUCTOR("is_v4");
|
|
||||||
RESULT(T_BOOL, i, ipa_is_ip4(v1.val.ip));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add initialized variable */
|
/* Add initialized variable */
|
||||||
INST(FI_VAR_INIT, 1, 0) {
|
INST(FI_VAR_INIT, 1, 0) {
|
||||||
@ -564,116 +560,68 @@
|
|||||||
RESULT_VAL(val);
|
RESULT_VAL(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_PATH_EMPTY, 1, 1) {
|
METHOD_R(T_PATH, empty, 0, T_PATH, ad, &null_adata);
|
||||||
|
METHOD_R(T_CLIST, empty, 0, T_CLIST, ad, &null_adata);
|
||||||
|
METHOD_R(T_ECLIST, empty, 0, T_ECLIST, ad, &null_adata);
|
||||||
|
METHOD_R(T_LCLIST, empty, 0, T_LCLIST, ad, &null_adata);
|
||||||
|
|
||||||
|
/* Common loop begin instruction, always created by f_for_cycle() */
|
||||||
|
INST(FI_FOR_LOOP_START, 0, 3) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
|
SYMBOL;
|
||||||
|
|
||||||
|
/* Repeat the instruction which called us */
|
||||||
|
ASSERT_DIE(fstk->ecnt > 1);
|
||||||
|
prevline.pos--;
|
||||||
|
|
||||||
|
/* There should be exactly three items on the value stack to be taken care of */
|
||||||
|
fstk->vcnt += 3;
|
||||||
|
|
||||||
|
/* And these should also stay there after we finish for the caller instruction */
|
||||||
|
curline.ventry += 3;
|
||||||
|
|
||||||
|
/* Assert the iterator variable positioning */
|
||||||
|
ASSERT_DIE(curline.vbase + sym->offset == fstk->vcnt - 1);
|
||||||
|
|
||||||
|
/* The result type declaration makes no sense here but is needed */
|
||||||
|
RESULT_TYPE(T_VOID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Type-specific for_next iterators */
|
||||||
|
INST(FI_PATH_FOR_NEXT, 3, 0) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
ARG(1, T_PATH);
|
ARG(1, T_PATH);
|
||||||
METHOD_CONSTRUCTOR("empty");
|
if (as_path_walk(v1.val.ad, &v2.val.i, &v3.val.i))
|
||||||
RESULT(T_PATH, ad, &null_adata);
|
LINE(2,0);
|
||||||
|
|
||||||
|
METHOD_CONSTRUCTOR("!for_next");
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_CLIST_EMPTY, 1, 1) {
|
INST(FI_CLIST_FOR_NEXT, 3, 0) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
ARG(1, T_CLIST);
|
ARG(1, T_CLIST);
|
||||||
METHOD_CONSTRUCTOR("empty");
|
if (int_set_walk(v1.val.ad, &v2.val.i, &v3.val.i))
|
||||||
RESULT(T_CLIST, ad, &null_adata);
|
LINE(2,0);
|
||||||
|
|
||||||
|
METHOD_CONSTRUCTOR("!for_next");
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_ECLIST_EMPTY, 1, 1) {
|
INST(FI_ECLIST_FOR_NEXT, 3, 0) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
ARG(1, T_ECLIST);
|
ARG(1, T_ECLIST);
|
||||||
METHOD_CONSTRUCTOR("empty");
|
if (ec_set_walk(v1.val.ad, &v2.val.i, &v3.val.ec))
|
||||||
RESULT(T_ECLIST, ad, &null_adata);
|
LINE(2,0);
|
||||||
|
|
||||||
|
METHOD_CONSTRUCTOR("!for_next");
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_LCLIST_EMPTY, 1, 1) {
|
INST(FI_LCLIST_FOR_NEXT, 3, 0) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
ARG(1, T_LCLIST);
|
ARG(1, T_LCLIST);
|
||||||
METHOD_CONSTRUCTOR("empty");
|
if (lc_set_walk(v1.val.ad, &v2.val.i, &v3.val.lc))
|
||||||
RESULT(T_LCLIST, ad, &null_adata);
|
LINE(2,0);
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_FOR_INIT, 1, 0) {
|
METHOD_CONSTRUCTOR("!for_next");
|
||||||
NEVER_CONSTANT;
|
|
||||||
ARG_ANY(1);
|
|
||||||
SYMBOL;
|
|
||||||
|
|
||||||
FID_NEW_BODY()
|
|
||||||
ASSERT((sym->class & ~0xff) == SYM_VARIABLE);
|
|
||||||
|
|
||||||
/* Static type check */
|
|
||||||
if (f1->type)
|
|
||||||
{
|
|
||||||
enum btype t_var = (sym->class & 0xff);
|
|
||||||
enum btype t_arg = f_type_element_type(f1->type);
|
|
||||||
if (!t_arg)
|
|
||||||
cf_error("Value of expression in FOR must be iterable, got %s",
|
|
||||||
f_type_name(f1->type));
|
|
||||||
if (t_var != t_arg)
|
|
||||||
cf_error("Loop variable '%s' in FOR must be %s, is %s",
|
|
||||||
sym->name, f_type_name(t_arg), f_type_name(t_var));
|
|
||||||
}
|
|
||||||
|
|
||||||
FID_INTERPRET_BODY()
|
|
||||||
|
|
||||||
/* Dynamic type check */
|
|
||||||
if ((sym->class & 0xff) != f_type_element_type(v1.type))
|
|
||||||
runtime("Mismatched argument and variable type");
|
|
||||||
|
|
||||||
/* Setup the index */
|
|
||||||
v2 = (struct f_val) { .type = T_INT, .val.i = 0 };
|
|
||||||
|
|
||||||
/* Keep v1 and v2 on the stack */
|
|
||||||
fstk->vcnt += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_FOR_NEXT, 2, 0) {
|
|
||||||
NEVER_CONSTANT;
|
|
||||||
SYMBOL;
|
|
||||||
|
|
||||||
/* Type checks are done in FI_FOR_INIT */
|
|
||||||
|
|
||||||
/* Loop variable */
|
|
||||||
struct f_val *var = &fstk->vstk[curline.vbase + sym->offset];
|
|
||||||
int step = 0;
|
|
||||||
|
|
||||||
switch(v1.type)
|
|
||||||
{
|
|
||||||
case T_PATH:
|
|
||||||
var->type = T_INT;
|
|
||||||
step = as_path_walk(v1.val.ad, &v2.val.i, &var->val.i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_CLIST:
|
|
||||||
var->type = T_PAIR;
|
|
||||||
step = int_set_walk(v1.val.ad, &v2.val.i, &var->val.i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_ECLIST:
|
|
||||||
var->type = T_EC;
|
|
||||||
step = ec_set_walk(v1.val.ad, &v2.val.i, &var->val.ec);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_LCLIST:
|
|
||||||
var->type = T_LC;
|
|
||||||
step = lc_set_walk(v1.val.ad, &v2.val.i, &var->val.lc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
runtime( "Clist or lclist expected" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step)
|
|
||||||
{
|
|
||||||
/* Keep v1 and v2 on the stack */
|
|
||||||
fstk->vcnt += 2;
|
|
||||||
|
|
||||||
/* Repeat this instruction */
|
|
||||||
curline.pos--;
|
|
||||||
|
|
||||||
/* Execute the loop body */
|
|
||||||
LINE(1, 0);
|
|
||||||
|
|
||||||
/* Space for loop variable, may be unused */
|
|
||||||
fstk->vcnt += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
var->type = T_VOID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_CONDITION, 1, 0) {
|
INST(FI_CONDITION, 1, 0) {
|
||||||
@ -684,17 +632,16 @@
|
|||||||
LINE(3,0);
|
LINE(3,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_PRINT, 0, 0) {
|
INST(FI_PRINT, 1, 0) {
|
||||||
NEVER_CONSTANT;
|
NEVER_CONSTANT;
|
||||||
VARARG;
|
ARG_ANY(1);
|
||||||
|
|
||||||
if (whati->varcount && !(fs->flags & FF_SILENT))
|
if (!(fs->flags & FF_SILENT))
|
||||||
{
|
{
|
||||||
if (!fs->buf.class)
|
if (!fs->buf.class)
|
||||||
log_prepare(&fs->buf, *L_INFO);
|
log_prepare(&fs->buf, *L_INFO);
|
||||||
|
|
||||||
for (uint i=0; i<whati->varcount; i++)
|
val_format(&v1, &fs->buf.buf);
|
||||||
val_format(&(vv(i)), &fs->buf.buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,35 +919,12 @@
|
|||||||
RESULT_VAL(v1);
|
RESULT_VAL(v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_NET_LENGTH, 1, 1) { /* Get length of */
|
/* Get length of */
|
||||||
ARG(1, T_NET);
|
METHOD_R(T_NET, len, 0, T_INT, i, net_pxlen(v1.val.net));
|
||||||
METHOD_CONSTRUCTOR("len");
|
METHOD_R(T_PATH, len, 0, T_INT, i, as_path_getlen(v1.val.ad));
|
||||||
RESULT(T_INT, i, net_pxlen(v1.val.net));
|
METHOD_R(T_CLIST, len, 0, T_INT, i, int_set_get_size(v1.val.ad));
|
||||||
}
|
METHOD_R(T_ECLIST, len, 0, T_INT, i, ec_set_get_size(v1.val.ad));
|
||||||
|
METHOD_R(T_LCLIST, len, 0, T_INT, i, lc_set_get_size(v1.val.ad));
|
||||||
INST(FI_PATH_LENGTH, 1, 1) { /* Get length of */
|
|
||||||
ARG(1, T_PATH);
|
|
||||||
METHOD_CONSTRUCTOR("len");
|
|
||||||
RESULT(T_INT, i, as_path_getlen(v1.val.ad));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_CLIST_LENGTH, 1, 1) { /* Get length of */
|
|
||||||
ARG(1, T_CLIST);
|
|
||||||
METHOD_CONSTRUCTOR("len");
|
|
||||||
RESULT(T_INT, i, int_set_get_size(v1.val.ad));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_ECLIST_LENGTH, 1, 1) { /* Get length of */
|
|
||||||
ARG(1, T_ECLIST);
|
|
||||||
METHOD_CONSTRUCTOR("len");
|
|
||||||
RESULT(T_INT, i, ec_set_get_size(v1.val.ad));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_LCLIST_LENGTH, 1, 1) { /* Get length of */
|
|
||||||
ARG(1, T_LCLIST);
|
|
||||||
METHOD_CONSTRUCTOR("len");
|
|
||||||
RESULT(T_INT, i, lc_set_get_size(v1.val.ad));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
|
INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
|
||||||
ARG(1, T_NET);
|
ARG(1, T_NET);
|
||||||
@ -1074,45 +998,32 @@
|
|||||||
RESULT(T_NET, net, dst);
|
RESULT(T_NET, net, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
|
/* Get ROA max prefix length */
|
||||||
ARG(1, T_NET);
|
METHOD(T_NET, maxlen, 0, [[
|
||||||
METHOD_CONSTRUCTOR("maxlen")
|
|
||||||
if (!net_is_roa(v1.val.net))
|
if (!net_is_roa(v1.val.net))
|
||||||
runtime( "ROA expected" );
|
runtime( "ROA expected" );
|
||||||
|
|
||||||
RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
|
RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
|
||||||
((net_addr_roa4 *) v1.val.net)->max_pxlen :
|
((net_addr_roa4 *) v1.val.net)->max_pxlen :
|
||||||
((net_addr_roa6 *) v1.val.net)->max_pxlen);
|
((net_addr_roa6 *) v1.val.net)->max_pxlen);
|
||||||
}
|
]]);
|
||||||
|
|
||||||
INST(FI_NET_ASN, 1, 1) { /* Get ROA ASN or community ASN part */
|
/* Get ROA ASN or community ASN part */
|
||||||
ARG(1, T_NET);
|
METHOD_R(T_PAIR, asn, 0, T_INT, i, v1.val.i >> 16);
|
||||||
METHOD_CONSTRUCTOR("asn");
|
METHOD_R(T_LC, asn, 0, T_INT, i, v1.val.lc.asn);
|
||||||
|
|
||||||
|
METHOD(T_NET, asn, 0, [[
|
||||||
if (!net_is_roa(v1.val.net))
|
if (!net_is_roa(v1.val.net))
|
||||||
runtime( "ROA expected" );
|
runtime( "ROA expected" );
|
||||||
|
|
||||||
RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
|
RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
|
||||||
((net_addr_roa4 *) v1.val.net)->asn :
|
((net_addr_roa4 *) v1.val.net)->asn :
|
||||||
((net_addr_roa6 *) v1.val.net)->asn);
|
((net_addr_roa6 *) v1.val.net)->asn);
|
||||||
}
|
]]);
|
||||||
|
|
||||||
INST(FI_PAIR_ASN, 1, 1) { /* Get ROA ASN or community ASN part */
|
|
||||||
ARG(1, T_PAIR);
|
|
||||||
METHOD_CONSTRUCTOR("asn");
|
|
||||||
RESULT(T_INT, i, v1.val.i >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_LC_ASN, 1, 1) { /* Get ROA ASN or community ASN part */
|
/* Convert prefix to IP */
|
||||||
ARG(1, T_LC);
|
METHOD_R(T_NET, ip, 0, T_IP, ip, net_prefix(v1.val.net));
|
||||||
METHOD_CONSTRUCTOR("asn");
|
|
||||||
RESULT(T_INT, i, v1.val.lc.asn);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_NET_IP, 1, 1) { /* Convert prefix to ... */
|
|
||||||
ARG(1, T_NET);
|
|
||||||
METHOD_CONSTRUCTOR("ip");
|
|
||||||
RESULT(T_IP, ip, net_prefix(v1.val.net));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
|
INST(FI_ROUTE_DISTINGUISHER, 1, 1) {
|
||||||
ARG(1, T_NET);
|
ARG(1, T_NET);
|
||||||
@ -1138,29 +1049,17 @@
|
|||||||
RESULT(T_INT, i, as);
|
RESULT(T_INT, i, as);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_AS_PATH_LAST_NAG, 1, 1) { /* Get last ASN from non-aggregated part of AS PATH */
|
/* Get last ASN from non-aggregated part of AS PATH */
|
||||||
ARG(1, T_PATH);
|
METHOD_R(T_PATH, last_nonaggregated, 0, T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
|
||||||
METHOD_CONSTRUCTOR("last_nonaggregated");
|
|
||||||
RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_PAIR_DATA, 1, 1) { /* Get data part from the standard community */
|
/* Get data part from the standard community */
|
||||||
ARG(1, T_PAIR);
|
METHOD_R(T_PAIR, data, 0, T_INT, i, v1.val.i & 0xFFFF);
|
||||||
METHOD_CONSTRUCTOR("data");
|
|
||||||
RESULT(T_INT, i, v1.val.i & 0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_LC_DATA1, 1, 1) { /* Get data1 part from the large community */
|
/* Get data1 part from the large community */
|
||||||
ARG(1, T_LC);
|
METHOD_R(T_LC, data1, 0, T_INT, i, v1.val.lc.ldp1);
|
||||||
METHOD_CONSTRUCTOR("data1");
|
|
||||||
RESULT(T_INT, i, v1.val.lc.ldp1);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_LC_DATA2, 1, 1) { /* Get data2 part from the large community */
|
/* Get data2 part from the large community */
|
||||||
ARG(1, T_LC);
|
METHOD_R(T_LC, data2, 0, T_INT, i, v1.val.lc.ldp2);
|
||||||
METHOD_CONSTRUCTOR("data2");
|
|
||||||
RESULT(T_INT, i, v1.val.lc.ldp2);
|
|
||||||
}
|
|
||||||
|
|
||||||
INST(FI_CLIST_MIN, 1, 1) { /* Get minimum element from list */
|
INST(FI_CLIST_MIN, 1, 1) { /* Get minimum element from list */
|
||||||
ARG(1, T_CLIST);
|
ARG(1, T_CLIST);
|
||||||
|
@ -96,6 +96,9 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
|
|||||||
|
|
||||||
|
|
||||||
struct filter *f_new_where(struct f_inst *);
|
struct filter *f_new_where(struct f_inst *);
|
||||||
|
struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block);
|
||||||
|
struct f_inst *f_print(struct f_inst *vars, int flush, enum filter_return fret);
|
||||||
|
|
||||||
static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
|
static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
|
||||||
{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
|
{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
|
||||||
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
|
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
|
||||||
|
@ -40,3 +40,61 @@ struct filter *f_new_where(struct f_inst *where)
|
|||||||
f->root = f_linearize(cond, 0);
|
f->root = f_linearize(cond, 0);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct f_inst *
|
||||||
|
f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
|
||||||
|
{
|
||||||
|
ASSERT((var->class & ~0xff) == SYM_VARIABLE);
|
||||||
|
ASSERT(term->next == NULL);
|
||||||
|
|
||||||
|
/* Static type check */
|
||||||
|
if (term->type == T_VOID)
|
||||||
|
cf_error("Couldn't infer the type of FOR expression, please assign it to a variable.");
|
||||||
|
|
||||||
|
enum btype el_type = f_type_element_type(term->type);
|
||||||
|
struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL;
|
||||||
|
struct symbol *ms = scope ? cf_find_symbol_scope(scope, "!for_next") : NULL;
|
||||||
|
|
||||||
|
if (!ms)
|
||||||
|
cf_error("Type %s is not iterable, can't be used in FOR", f_type_name(term->type));
|
||||||
|
|
||||||
|
if (var->class != (SYM_VARIABLE | el_type))
|
||||||
|
cf_error("Loop variable '%s' in FOR must be of type %s, got %s",
|
||||||
|
var->name, f_type_name(el_type), f_type_name(var->class & 0xff));
|
||||||
|
|
||||||
|
/* Push the iterator auxiliary value onto stack */
|
||||||
|
struct f_inst *iter = term->next = f_new_inst(FI_CONSTANT, (struct f_val) {});
|
||||||
|
|
||||||
|
/* Initialize the iterator variable */
|
||||||
|
iter->next = f_new_inst(FI_CONSTANT, (struct f_val) { .type = el_type });
|
||||||
|
|
||||||
|
/* Prepend the loop block with loop beginning instruction */
|
||||||
|
struct f_inst *loop_start = f_new_inst(FI_FOR_LOOP_START, var);
|
||||||
|
loop_start->next = block;
|
||||||
|
|
||||||
|
return ms->method->new_inst(term, loop_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct f_inst *
|
||||||
|
f_print(struct f_inst *vars, int flush, enum filter_return fret)
|
||||||
|
{
|
||||||
|
#define AX(...) do { struct f_inst *_tmp = f_new_inst(__VA_ARGS__); _tmp->next = output; output = _tmp; } while (0)
|
||||||
|
struct f_inst *output = NULL;
|
||||||
|
if (fret != F_NOP)
|
||||||
|
AX(FI_DIE, fret);
|
||||||
|
|
||||||
|
if (flush)
|
||||||
|
AX(FI_FLUSH);
|
||||||
|
|
||||||
|
while (vars)
|
||||||
|
{
|
||||||
|
struct f_inst *tmp = vars;
|
||||||
|
vars = vars->next;
|
||||||
|
tmp->next = NULL;
|
||||||
|
|
||||||
|
AX(FI_PRINT, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
#undef AX
|
||||||
|
}
|
||||||
|
@ -128,6 +128,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define curline fstk->estk[fstk->ecnt-1]
|
#define curline fstk->estk[fstk->ecnt-1]
|
||||||
|
#define prevline fstk->estk[fstk->ecnt-2]
|
||||||
|
|
||||||
#ifdef LOCAL_DEBUG
|
#ifdef LOCAL_DEBUG
|
||||||
debug("Interpreting line.");
|
debug("Interpreting line.");
|
||||||
|
Loading…
Reference in New Issue
Block a user