1
0
mirror of https://gitlab.labs.nic.cz/labs/bird.git synced 2024-05-11 16:54:54 +00:00

Merge commit 'fc9d471b' into thread-next

Conflicts:
	conf/cf-lex.l
	conf/conf.h
	filter/config.Y
	filter/data.c
	filter/data.h
This commit is contained in:
Maria Matejka
2023-10-28 23:42:21 +02:00
17 changed files with 899 additions and 329 deletions

View File

@@ -19,25 +19,60 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
static struct symbol *this_function;
static struct f_method_scope {
struct f_inst *object;
struct sym_scope *main;
struct sym_scope scope;
} f_method_scope_stack[32];
static int f_method_scope_pos = -1;
#define FM (f_method_scope_stack[f_method_scope_pos])
static inline void f_push_method_scope(struct f_inst *object)
static inline void f_method_call_start(struct f_inst *object)
{
if (object->type == T_VOID)
cf_error("Can't infer type to properly call a method, please assign the value to a variable");
if (++f_method_scope_pos >= (int) ARRAY_SIZE(f_method_scope_stack))
cf_error("Too many nested method calls");
struct sym_scope *scope = f_type_method_scope(object->type);
if (!scope)
cf_error("No methods defined for type %s", f_type_name(object->type));
FM = (struct f_method_scope) {
.object = object,
.main = new_config->current_scope,
.scope = {
.next = NULL,
.hash = scope->hash,
.active = 1,
.block = 1,
.readonly = 1,
},
};
new_config->current_scope = &FM.scope;
}
static inline void f_pop_method_scope(void)
static inline void f_method_call_args(void)
{
ASSERT_DIE(FM.scope.active);
FM.scope.active = 0;
new_config->current_scope = FM.main;
}
static inline void f_method_call_end(void)
{
ASSERT_DIE(f_method_scope_pos >= 0);
if (FM.scope.active) {
ASSERT_DIE(&FM.scope == new_config->current_scope);
new_config->current_scope = FM.main;
FM.scope.active = 0;
}
f_method_scope_pos--;
}
@@ -209,20 +244,6 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
return t;
}
static inline struct f_inst *
f_generate_empty(const struct symbol *sym)
{
if (sym->class != SYM_ATTRIBUTE)
cf_error("Can't empty %s: not an attribute", sym->name);
const struct ea_class *def = sym->attribute;
const struct f_val empty = f_get_empty(def->type);
if (empty.type == T_VOID)
cf_error("Can't empty attribute %s", def->name);
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), def);
}
static inline struct f_inst *
f_implicit_roa_check(struct rtable_config *tab)
{
@@ -349,35 +370,35 @@ CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR,
INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC,
SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE,
FOR, IN, DO,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
ROA_CHECK, ASN, SRC, DST,
IS_V4, IS_V6,
LEN, MAXLEN,
DATA, DATA1, DATA2,
FROM, GW, NET, PROTO, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
ROA_CHECK,
DEFINED,
ADD, DELETE, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED,
MIN, MAX,
PREPEND,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
FROM_HEX,
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 ELSE
%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 method_cmd method_term
%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 <fsa> static_attr
%type <f> filter where_filter
%type <fl> filter_body function_body
%type <flv> lvalue
%type <i> type function_vars
%type <i> type maybe_type function_vars
%type <fa> function_argsn function_args
%type <ecs> ec_kind
%type <fret> break_command
@@ -403,6 +424,7 @@ filter_def:
$2 = cf_define_symbol(new_config, $2, SYM_FILTER, filter, NULL);
cf_enter_filters();
cf_push_scope( new_config, $2 );
this_function = NULL;
} filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .sym = $2, .root = $4 };
@@ -534,6 +556,7 @@ filter:
| {
cf_enter_filters();
cf_push_scope(new_config, NULL);
this_function = NULL;
} filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .root = $2 };
@@ -562,30 +585,39 @@ function_body:
;
conf: function_def ;
maybe_type:
/* EMPTY */ { $$ = T_VOID; }
| type { $$ = $1; }
;
function_def:
FUNCTION symbol {
DBG( "Beginning of function %s\n", $2->name );
$2 = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL);
FUNCTION maybe_type symbol {
DBG( "Beginning of function %s\n", $3->name );
this_function = cf_define_symbol(new_config, $3, SYM_FUNCTION, function, NULL);
/* if ($2 == T_VOID) cf_warn("Support for functions without explicit return type will be removed soon" ); */
cf_enter_filters();
cf_push_scope(new_config, $2);
cf_push_scope(new_config, this_function);
} function_args {
/* Make dummy f_line for storing function prototype */
struct f_line *dummy = cfg_allocz(sizeof(struct f_line));
$2->function = dummy;
this_function->function = dummy;
dummy->return_type = $2;
/* Revert the args */
while ($4) {
struct f_arg *tmp = $4;
$4 = $4->next;
while ($5) {
struct f_arg *tmp = $5;
$5 = $5->next;
tmp->next = dummy->arg_list;
dummy->arg_list = tmp;
dummy->args++;
}
} function_body {
$6->args = $2->function->args;
$6->arg_list = $2->function->arg_list;
$2->function = $6;
$7->args = this_function->function->args;
$7->arg_list = this_function->function->arg_list;
$7->return_type = this_function->function->return_type;
$3->function = $7;
cf_pop_scope(new_config);
cf_exit_filters();
}
@@ -869,33 +901,18 @@ static_attr:
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
;
method_term:
IS_V4 { $$ = f_new_inst(FI_IS_V4, FM.object); }
| TYPE { $$ = f_new_inst(FI_TYPE, FM.object); }
| IP { $$ = f_new_inst(FI_IP, FM.object); }
| RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, FM.object); }
| LEN { $$ = f_new_inst(FI_LENGTH, FM.object); }
| MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, FM.object); }
| ASN { $$ = f_new_inst(FI_ASN, FM.object); }
| SRC { $$ = f_new_inst(FI_NET_SRC, FM.object); }
| DST { $$ = f_new_inst(FI_NET_DST, FM.object); }
| MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, FM.object, $3); }
| FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, FM.object); }
| LAST { $$ = f_new_inst(FI_AS_PATH_LAST, FM.object); }
| LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, FM.object); }
| DATA { $$ = f_new_inst(FI_PAIR_DATA, FM.object); }
| DATA1 { $$ = f_new_inst(FI_LC_DATA1, FM.object); }
| DATA2 { $$ = f_new_inst(FI_LC_DATA2, FM.object); }
| MIN { $$ = f_new_inst(FI_MIN, FM.object); }
| MAX { $$ = f_new_inst(FI_MAX, FM.object); }
;
method_cmd:
EMPTY { $$ = f_new_inst(FI_CONSTANT, f_get_empty(FM.object->i_FI_EA_GET.da->type)); }
| PREPEND '(' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, FM.object, $3 ); }
| ADD '(' term ')' { $$ = f_new_inst(FI_CLIST_ADD, FM.object, $3 ); }
| DELETE '(' term ')' { $$ = f_new_inst(FI_CLIST_DEL, FM.object, $3 ); }
| FILTER '(' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, FM.object, $3 ); }
term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { $$ = $4; };
method_name_cont:
CF_SYM_METHOD_BARE {
$$ = $1->method->new_inst(FM.object, NULL);
f_method_call_end();
}
| CF_SYM_METHOD_ARGS {
f_method_call_args();
} '(' var_list ')' {
$$ = $1->method->new_inst(FM.object, $4);
f_method_call_end();
}
;
term:
@@ -925,21 +942,42 @@ term:
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
| term '.' {
f_push_method_scope($1);
} method_term {
f_pop_method_scope();
$$ = $4;
}
| term_dot_method
| '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_PATH)); }
| '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_ECLIST)); }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_LCLIST)); }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
| ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
| ADD '(' term ',' term ')' {
switch ($3->type) {
case T_CLIST: $$ = f_new_inst(FI_CLIST_ADD, $3, $5); break;
case T_ECLIST: $$ = f_new_inst(FI_ECLIST_ADD, $3, $5); break;
case T_LCLIST: $$ = f_new_inst(FI_LCLIST_ADD, $3, $5); break;
default: cf_error("Can't add to type %s", f_type_name($3->type));
}
cf_warn("add(x,y) function is deprecated, please use x.add(y)");
}
| DELETE '(' term ',' term ')' {
switch ($3->type) {
case T_PATH: $$ = f_new_inst(FI_PATH_DEL, $3, $5); break;
case T_CLIST: $$ = f_new_inst(FI_CLIST_DEL, $3, $5); break;
case T_ECLIST: $$ = f_new_inst(FI_ECLIST_DEL, $3, $5); break;
case T_LCLIST: $$ = f_new_inst(FI_LCLIST_DEL, $3, $5); break;
default: cf_error("Can't delete from type %s", f_type_name($3->type));
}
cf_warn("delete(x,y) function is deprecated, please use x.delete(y)");
}
| FILTER '(' term ',' term ')' {
switch ($3->type) {
case T_PATH: $$ = f_new_inst(FI_PATH_FILTER, $3, $5); break;
case T_CLIST: $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); break;
case T_ECLIST: $$ = f_new_inst(FI_ECLIST_FILTER, $3, $5); break;
case T_LCLIST: $$ = f_new_inst(FI_LCLIST_FILTER, $3, $5); break;
default: cf_error("Can't filter type %s", f_type_name($3->type));
}
cf_warn("filter(x,y) function is deprecated, please use x.filter(y)");
}
| ROA_CHECK '(' rtable ')' { $$ = f_implicit_roa_check($3); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK, $5, $7, $3); }
@@ -1024,6 +1062,18 @@ cmd:
}
| RETURN term ';' {
DBG( "Ook, we'll return the value\n" );
if (!this_function)
cf_error("Can't return from a non-function, use accept or reject instead.");
if (this_function->function->return_type == T_VOID)
{
if ($2->type != T_VOID)
cf_warn("Inferring function %s return type from its return value: %s", this_function->name, f_type_name($2->type));
((struct f_line *) this_function->function)->return_type = $2->type;
}
else if (this_function->function->return_type != $2->type)
cf_error("Can't return type %s from function %s, expected %s",
f_type_name($2->type), this_function->name, f_type_name(this_function->function->return_type));
$$ = f_new_inst(FI_RETURN, $2);
}
| static_attr '=' term ';' {
@@ -1062,9 +1112,8 @@ cmd:
}
| lvalue '.' {
f_push_method_scope(f_lval_getter(&$1));
} method_cmd ';' {
f_pop_method_scope();
f_method_call_start(f_lval_getter(&$1));
} method_name_cont ';' {
$$ = f_lval_setter(&$1, $4);
}
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }