0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Merge commit '58efa944' into thread-next

Conflicts:
	conf/cf-lex.l
	conf/conf.h
	conf/confbase.Y
	conf/gen_keywords.m4
	conf/gen_parser.m4
	filter/config.Y
	nest/config.Y
	proto/bgp/config.Y
	proto/static/config.Y

Keywords and attributes are split to separate namespaces, to avoid
collisions between regular keyword use and attribute overlay.
This commit is contained in:
Maria Matejka 2023-10-25 14:41:11 +02:00
commit da52d66177
8 changed files with 121 additions and 98 deletions

View File

@ -54,7 +54,6 @@
struct keyword {
byte *name;
int value;
struct keyword *next;
};
#include "conf/keywords.h"
@ -67,16 +66,10 @@ struct keyword {
static uint cf_hash(const byte *c);
#define KW_KEY(n) n->name
#define KW_NEXT(n) n->next
#define KW_EQ(a,b) !strcmp(a,b)
#define KW_FN(k) cf_hash(k)
#define KW_ORDER 8 /* Fixed */
#define SYM_KEY(n) n->name, n->scope->active
#define SYM_KEY(n) n->name
#define SYM_NEXT(n) n->next
#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
#define SYM_FN(k,s) cf_hash(k)
#define SYM_EQ(a,b) !strcmp(a,b)
#define SYM_FN(k) cf_hash(k)
#define SYM_ORDER 4 /* Initial */
#define SYM_REHASH sym_rehash
@ -85,14 +78,20 @@ static uint cf_hash(const byte *c);
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
HASH(struct keyword) kw_hash;
HASH(struct ea_class) ea_name_hash;
/* Global symbol scopes */
static pool *global_root_scope_pool;
static struct sym_scope
global_root_scope = {
.active = 1,
},
global_filter_scope = {
.active = 0,
.next = &global_root_scope,
};
/* Local symbol scope: TODO this isn't thread-safe */
struct sym_scope *conf_this_scope;
static struct sym_scope global_root_scope__init = { .active = 1, };
struct sym_scope *global_root_scope = &global_root_scope__init;
linpool *cfg_mem;
int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
@ -581,7 +580,7 @@ cf_new_symbol(const byte *c)
s = cfg_allocz(sizeof(struct symbol) + l + 1);
*s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
strcpy(s->name, c);
memcpy(s->name, c, l+1);
if (!conf_this_scope->hash.data)
HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER);
@ -595,20 +594,20 @@ cf_new_symbol(const byte *c)
}
static struct symbol *
cf_root_symbol(const byte *c)
cf_root_symbol(const byte *c, struct sym_scope *ss)
{
uint l = strlen(c);
if (l > SYM_MAX_LEN)
bug("Root symbol %s too long", c);
struct symbol *s = mb_alloc(&root_pool, sizeof(struct symbol) + l + 1);
*s = (struct symbol) { .scope = global_root_scope, .class = SYM_VOID, };
*s = (struct symbol) { .scope = ss, .class = SYM_VOID, };
memcpy(s->name, c, l+1);
if (!global_root_scope->hash.data)
HASH_INIT(global_root_scope->hash, &root_pool, SYM_ORDER);
if (!ss->hash.data)
HASH_INIT(ss->hash, &root_pool, SYM_ORDER);
HASH_INSERT2(global_root_scope->hash, SYM, &root_pool, s);
HASH_INSERT2(ss->hash, SYM, &root_pool, s);
return s;
}
@ -631,7 +630,7 @@ cf_find_symbol_scope(const struct sym_scope *scope, const byte *c)
/* Find the symbol here or anywhere below */
while (scope)
if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c, 1)))
if (scope->active && scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c)))
return s;
else
scope = scope->next;
@ -702,50 +701,34 @@ cf_lex_symbol(const char *data)
struct symbol *sym = cf_get_symbol(data);
cf_lval.s = sym;
/* Is it a keyword? Prefer the keyword. */
struct keyword *k = HASH_FIND(kw_hash, KW, data);
if (k)
switch (sym->class)
{
if (k->value > 0)
return k->value;
else
{
cf_lval.i = -k->value;
return ENUM;
}
case SYM_KEYWORD:
if (sym->keyword->value > 0)
return sym->keyword->value;
else
{
cf_lval.i = -sym->keyword->value;
return ENUM;
}
case SYM_VOID:
return CF_SYM_UNDEFINED;
default:
return CF_SYM_KNOWN;
}
/* OK, only a symbol. */
if (sym->class == SYM_VOID)
return CF_SYM_UNDEFINED;
else
return CF_SYM_KNOWN;
}
static void
cf_lex_init_kh(void)
{
HASH_INIT(kw_hash, config_pool, KW_ORDER);
struct keyword *k;
for (k=keyword_list; k->name; k++)
HASH_INSERT(kw_hash, KW, k);
}
void
ea_lex_register(struct ea_class *def)
{
struct symbol *sym = cf_root_symbol(def->name);
sym->class = SYM_ATTRIBUTE;
sym->attribute = def;
def->sym = sym;
def->sym = cf_define_symbol(cf_root_symbol(def->name, &global_filter_scope), SYM_ATTRIBUTE, attribute, def);
}
void
ea_lex_unregister(struct ea_class *def)
{
struct symbol *sym = def->sym;
HASH_REMOVE2(global_root_scope->hash, SYM, &root_pool, sym);
HASH_REMOVE2(global_filter_scope.hash, SYM, &root_pool, sym);
mb_free(sym);
def->sym = NULL;
}
@ -753,7 +736,11 @@ ea_lex_unregister(struct ea_class *def)
struct ea_class *
ea_class_find_by_name(const char *name)
{
struct symbol *sym = cf_find_symbol(global_root_scope, name);
if (!global_filter_scope.hash.data)
return NULL;
struct symbol *sym = HASH_FIND(global_filter_scope.hash, SYM, name);
if (!sym || (sym->class != SYM_ATTRIBUTE))
return NULL;
else
@ -771,8 +758,13 @@ ea_class_find_by_name(const char *name)
void
cf_lex_init(int is_cli, struct config *c)
{
if (!kw_hash.data)
cf_lex_init_kh();
if (!global_root_scope_pool)
{
global_root_scope_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Keywords pool");
for (const struct keyword *k = keyword_list; k->name; k++)
cf_define_symbol(cf_root_symbol(k->name, &global_root_scope), SYM_KEYWORD, keyword, k);
}
ifs_head = ifs = push_ifs(NULL);
if (!is_cli)
@ -797,7 +789,7 @@ cf_lex_init(int is_cli, struct config *c)
if (is_cli)
conf_this_scope->next = config->root_scope;
else
conf_this_scope->next = global_root_scope;
conf_this_scope->next = &global_filter_scope;
}
/**
@ -886,6 +878,27 @@ cf_swap_soft_scope(void)
}
}
/**
* cf_enter_filters - enable filter / route attributes namespace
*/
void
cf_enter_filters(void)
{
ASSERT_DIE(!global_filter_scope.active);
global_filter_scope.active = 1;
}
/**
* cf_exit_filters - disable filter / route attributes namespace
*/
void
cf_exit_filters(void)
{
ASSERT_DIE(global_filter_scope.active);
global_filter_scope.active = 0;
}
/**
* cf_symbol_class_name - get name of a symbol class
* @sym: symbol
@ -912,6 +925,8 @@ cf_symbol_class_name(struct symbol *sym)
return "routing table";
case SYM_ATTRIBUTE:
return "custom attribute";
case SYM_KEYWORD:
return "symbol";
case SYM_CONSTANT_RANGE:
return "constant";
case SYM_VARIABLE_RANGE:

View File

@ -127,6 +127,7 @@ struct symbol {
struct ea_class *attribute; /* For SYM_ATTRIBUTE */
struct f_val *val; /* For SYM_CONSTANT */
uint offset; /* For SYM_VARIABLE */
const struct keyword *keyword; /* For SYM_KEYWORD */
};
char name[0];
@ -144,7 +145,8 @@ struct sym_scope {
byte soft_scopes; /* Number of soft scopes above */
};
extern struct sym_scope *global_root_scope;
void cf_enter_filters(void);
void cf_exit_filters(void);
struct bytestring {
size_t length;
@ -161,6 +163,7 @@ struct bytestring {
#define SYM_FILTER 4
#define SYM_TABLE 5
#define SYM_ATTRIBUTE 6
#define SYM_KEYWORD 7
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */
#define SYM_VARIABLE_RANGE SYM_VARIABLE ... (SYM_VARIABLE | 0xff)

View File

@ -121,7 +121,7 @@ CF_DECLS
%type <t> text opttext
%type <bs> bytestring
%type <s> symbol symbol_known toksym
%type <s> symbol
%type <v> bytestring_text text_or_ipa
%type <x> bytestring_expr
@ -169,7 +169,7 @@ definition:
expr:
NUM
| '(' term ')' { $$ = cf_eval_int($2); }
| symbol_known {
| CF_SYM_KNOWN {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
$$ = SYM_VAL($1).i; }
;
@ -180,9 +180,7 @@ expr_us:
| expr US { $$ = $1 US_; }
;
toksym: FROM | PREFERENCE ;
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | toksym ;
symbol_known: CF_SYM_KNOWN | toksym ;
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ;
/* Switches */

View File

@ -23,7 +23,7 @@ m4_define(CF_DECLS, `m4_divert(-1)')
m4_define(CF_DEFINES, `m4_divert(-1)')
# Keywords are translated to C initializers
m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, NULL },
m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1 },
m4_divert(-1)')
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])')
m4_define(CF_KEYWORDS, `CF_iterate([[CF_keywd]], [[$@]])DNL')
@ -34,16 +34,16 @@ m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
# Enums are translated to C initializers: use CF_ENUM(typename, prefix, values)
# For different prefix: CF_ENUM_PX(typename, external prefix, C prefix, values)
m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1), NULL },
m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1) },
m4_divert(-1)')
m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL')
m4_define(CF_ENUM_PX, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$3)CF_iterate([[CF_enum]], [[m4_shift(m4_shift(m4_shift($@)))]])DNL')
# After all configuration templates end, we generate the
# After all configuration templates end, we generate the keyword list
m4_m4wrap(`
m4_divert(0)
static struct keyword keyword_list[] = {
m4_undivert(1){ NULL, -1, NULL } };
static const struct keyword keyword_list[] = {
m4_undivert(1){ NULL, -1 } };
')
# As we are processing C source, we must access all M4 primitives via

View File

@ -364,13 +364,17 @@ conf: FILTER STACKS expr expr ';' {
conf: filter_def ;
filter_def:
FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
filter_body {
FILTER symbol {
$2 = cf_define_symbol($2, SYM_FILTER, filter, NULL);
cf_enter_filters();
cf_push_scope( $2 );
} filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .sym = $2, .root = $4 };
$2->filter = f;
cf_pop_scope();
cf_exit_filters();
}
;
@ -393,7 +397,7 @@ custom_attr: ATTRIBUTE type symbol ';' {
conf: bt_test_suite ;
bt_test_suite:
BT_TEST_SUITE '(' symbol_known ',' text ')' {
BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
cf_assert_symbol($3, SYM_FUNCTION);
struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
t->fn = $3->function;
@ -406,7 +410,7 @@ bt_test_suite:
conf: bt_test_same ;
bt_test_same:
BT_TEST_SAME '(' symbol_known ',' symbol_known ',' NUM ')' {
BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
cf_assert_symbol($3, SYM_FUNCTION);
cf_assert_symbol($5, SYM_FUNCTION);
struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
@ -488,23 +492,30 @@ function_vars:
filter_body: function_body ;
filter:
symbol_known {
CF_SYM_KNOWN {
cf_assert_symbol($1, SYM_FILTER);
$$ = $1->filter;
}
| { cf_push_scope(NULL); } filter_body {
| {
cf_enter_filters();
cf_push_scope(NULL);
} filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .root = $2 };
$$ = f;
cf_pop_scope();
cf_exit_filters();
}
;
where_filter:
WHERE term {
WHERE {
cf_enter_filters();
} term {
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
$$ = f_new_where($2);
$$ = f_new_where($3);
cf_exit_filters();
}
;
@ -520,6 +531,7 @@ function_def:
FUNCTION symbol {
DBG( "Beginning of function %s\n", $2->name );
$2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
cf_enter_filters();
cf_push_scope($2);
} function_args {
/* Make dummy f_line for storing function prototype */
@ -540,6 +552,7 @@ function_def:
$6->arg_list = $2->function->arg_list;
$2->function = $6;
cf_pop_scope();
cf_exit_filters();
}
;
@ -601,7 +614,7 @@ set_atom:
$$ = cf_eval_tmp($2, T_VOID);
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
| symbol_known {
| CF_SYM_KNOWN {
cf_assert_symbol($1, SYM_CONSTANT);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
$$ = *$1->val;
@ -773,7 +786,7 @@ var_list: /* EMPTY */ { $$ = NULL; }
| var_list ',' term { $$ = $3; $$->next = $1; }
function_call:
symbol_known '(' var_list ')'
CF_SYM_KNOWN '(' var_list ')'
{
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
@ -792,7 +805,7 @@ function_call:
}
;
symbol_value: symbol_known
symbol_value: CF_SYM_KNOWN
{
switch ($1->class) {
case SYM_CONSTANT_RANGE:
@ -951,7 +964,7 @@ cmd:
$$ = f_new_inst(FI_FOR_INIT, $6, $3);
$$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
}
| symbol_known '=' term ';' {
| CF_SYM_KNOWN '=' term ';' {
switch ($1->class) {
case SYM_VARIABLE_RANGE:
$$ = f_new_inst(FI_VAR_SET, $3, $1);
@ -974,7 +987,7 @@ cmd:
cf_error( "This static attribute is read-only.");
$$ = f_new_inst(FI_RTA_SET, $3, $1);
}
| UNSET '(' symbol_known ')' ';' {
| UNSET '(' CF_SYM_KNOWN ')' ';' {
if ($3->class != SYM_ATTRIBUTE)
cf_error("Can't unset %s", $3->name);
if ($3->attribute->readonly)
@ -1004,11 +1017,11 @@ cmd:
$$ = f_new_inst(FI_SWITCH, $2, $4);
}
| symbol_known '.' EMPTY ';' { $$ = f_generate_empty($1); }
| symbol_known '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); }
| symbol_known '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); }
| symbol_known '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); }
| symbol_known '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); }
| CF_SYM_KNOWN '.' EMPTY ';' { $$ = f_generate_empty($1); }
| CF_SYM_KNOWN '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); }
| CF_SYM_KNOWN '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); }
| CF_SYM_KNOWN '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); }
| CF_SYM_KNOWN '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
| BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
;
@ -1019,7 +1032,7 @@ get_cf_position:
};
lvalue:
symbol_known {
CF_SYM_KNOWN {
switch ($1->class) {
case SYM_VARIABLE_RANGE:
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };

View File

@ -154,8 +154,6 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
CF_GRAMMAR
toksym: MIN | MAX ;
/* Setting of router ID */
conf: rtrid ;
@ -694,7 +692,7 @@ r_args:
$$->addr = $3;
$$->addr_mode = TE_ADDR_IN;
}
| r_args TABLE symbol_known {
| r_args TABLE CF_SYM_KNOWN {
cf_assert_symbol($3, SYM_TABLE);
if (!$3->table) cf_error("Table %s not configured", $3->name);
$$ = $1;
@ -741,7 +739,7 @@ r_args:
$$ = $1;
$$->filtered = 1;
}
| r_args export_mode symbol_known {
| r_args export_mode CF_SYM_KNOWN {
cf_assert_symbol($3, SYM_PROTO);
struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
@ -758,7 +756,7 @@ r_args:
$$->export_channel = $3;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL symbol_known {
| r_args PROTOCOL CF_SYM_KNOWN {
cf_assert_symbol($3, SYM_PROTO);
struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
@ -870,7 +868,7 @@ sym_args:
| sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
| sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
| sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
| sym_args symbol { $$ = $1; $$->sym = $2; }
| sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; }
;

View File

@ -44,10 +44,6 @@ CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
CF_GRAMMAR
/* Workaround for collisions between keywords and symbols */
toksym: ROLE | PEER | PROVIDER | CUSTOMER | RS_SERVER | RS_CLIENT ;
toksym: BGP_MED | BGP_LOCAL_PREF | SOURCE ;
proto: bgp_proto '}' ;
bgp_proto_start: proto_start BGP {

View File

@ -153,7 +153,7 @@ stat_route_opts:
stat_route_opt_list:
/* empty */
| '{' stat_route_opts '}'
| '{' { cf_enter_filters(); } stat_route_opts '}' { cf_exit_filters(); }
;