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:
201
filter/config.Y
201
filter/config.Y
@@ -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); }
|
||||
|
||||
Reference in New Issue
Block a user