0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-18 19:35:20 +00:00

Conf: Symbol hashes for all scopes

This is a backport cherry-pick of commits
  165156beeb
  cce974e8ea

from the v3.0 branch as we need symbol hashes directly inside their
scopes for more general usage than before.

The redefinable keywords must be specified in any .Y file as follows:

  toksym: THE_KEYWORD ;
This commit is contained in:
Maria Matejka 2022-05-02 20:29:03 +02:00 committed by Igor Putovny
parent 4938c122dc
commit 51e8996fff
10 changed files with 87 additions and 89 deletions

View File

@ -73,22 +73,22 @@ static uint cf_hash(const byte *c);
#define KW_FN(k) cf_hash(k)
#define KW_ORDER 8 /* Fixed */
#define SYM_KEY(n) n->name, n->scope
#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) ^ ptr_hash(s)
#define SYM_ORDER 6 /* Initial */
#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
#define SYM_PARAMS /8, *1, 2, 2, 6, 20
#define SYM_PARAMS /8, *1, 2, 2, 4, 20
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
HASH(struct keyword) kw_hash;
struct sym_scope *conf_this_scope;
struct sym_scope *global_root_scope;
linpool *cfg_mem;
@ -591,12 +591,13 @@ cf_new_symbol(const byte *c)
*s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
strcpy(s->name, c);
if (!new_config->sym_hash.data)
HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
if (!conf_this_scope->hash.data)
HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER);
HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
HASH_INSERT2(conf_this_scope->hash, SYM, new_config->pool, s);
add_tail(&(new_config->symbols), &(s->n));
if (conf_this_scope == new_config->root_scope)
add_tail(&(new_config->symbols), &(s->n));
return s;
}
@ -606,32 +607,27 @@ cf_symbol_from_keyword(const struct keyword *kw)
{ return cf_new_symbol(kw->name); }
/**
* cf_find_local_symbol - find a symbol by name
* @cfg: specificed config
* @scope: specified symbol scope
* cf_find_symbol_scope - find a symbol by name
* @scope: config scope
* @c: symbol name
*
* This functions searches the symbol table in the config @cfg for a symbol of
* given name. First it examines the scope @scope, then the parent scope
* This functions searches the symbol table in the scope @scope for a symbol of
* given name. First it examines the current scope, then the underlying one
* and so on until it either finds the symbol and returns a pointer to its
* &symbol structure or reaches the end of the scope chain and returns %NULL to
* signify no match.
*/
struct symbol *
cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c)
cf_find_symbol_scope(const struct sym_scope *scope, const byte *c)
{
struct symbol *s;
if (cfg->sym_hash.data)
for (; scope; scope = scope->next)
if (s = HASH_FIND(cfg->sym_hash, SYM, c, scope))
return s;
/* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */
if (cfg->fallback &&
cfg->fallback->sym_hash.data &&
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, cfg->fallback->root_scope)))
return s;
/* Find the symbol here or anywhere below */
while (scope)
if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c)))
return s;
else
scope = scope->next;
return NULL;
}
@ -648,7 +644,7 @@ cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, co
struct symbol *
cf_get_symbol(const byte *c)
{
return cf_find_local_symbol(new_config, conf_this_scope, c) ?: cf_new_symbol(c);
return cf_find_symbol_scope(conf_this_scope, c) ?: cf_new_symbol(c);
}
/**
@ -667,7 +663,7 @@ cf_localize_symbol(struct symbol *sym)
/* If the scope is the current, it is already defined in this scope. */
if (cf_symbol_is_local(sym))
cf_error("Symbol '%s' already defined", sym->name);
cf_error("Symbol already defined");
/* Not allocated here yet, doing it now. */
return cf_new_symbol(sym->name);
@ -696,23 +692,15 @@ static enum yytokentype
cf_lex_symbol(const char *data)
{
/* Have we defined such a symbol? */
struct symbol *sym = cf_find_local_symbol(new_config, conf_this_scope, data);
struct symbol *sym = cf_get_symbol(data);
cf_lval.s = sym;
if (sym && (sym->class != SYM_VOID))
{
cf_lval.s = sym;
return CF_SYM_KNOWN;
}
/* Is it a keyword? */
/* Is it a keyword? Prefer the keyword. */
struct keyword *k = HASH_FIND(kw_hash, KW, data);
if (k)
{
if (k->value > 0)
{
cf_lval.kw = k;
return k->value;
}
else
{
cf_lval.i = -k->value;
@ -720,19 +708,23 @@ cf_lex_symbol(const char *data)
}
}
/* OK, undefined symbol */
cf_lval.s = cf_new_symbol(data);
return CF_SYM_UNDEFINED;
/* 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);
HASH_INIT(kw_hash, &root_pool, KW_ORDER);
struct keyword *k;
for (k=keyword_list; k->name; k++)
HASH_INSERT(kw_hash, KW, k);
global_root_scope = mb_allocz(&root_pool, sizeof(*global_root_scope));
}
/**
@ -768,6 +760,11 @@ cf_lex_init(int is_cli, struct config *c)
c->root_scope = cfg_allocz(sizeof(struct sym_scope));
conf_this_scope = c->root_scope;
conf_this_scope->active = 1;
if (is_cli)
conf_this_scope->next = config->root_scope;
else
conf_this_scope->next = global_root_scope;
}
/**

View File

@ -170,7 +170,6 @@ int
cli_parse(struct config *c)
{
int done = 0;
c->fallback = config;
new_config = c;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
@ -181,7 +180,6 @@ cli_parse(struct config *c)
done = 1;
cleanup:
c->fallback = NULL;
new_config = NULL;
cfg_mem = NULL;
return done;
@ -551,7 +549,6 @@ order_shutdown(int gr)
init_list(&c->tables);
init_list(&c->symbols);
memset(c->def_tables, 0, sizeof(c->def_tables));
HASH_INIT(c->sym_hash, c->pool, 4);
c->shutdown = 1;
c->gr_down = gr;

View File

@ -16,7 +16,6 @@
#include "lib/timer.h"
/* Configuration structure */
struct config {
pool *pool; /* Pool the configuration is stored in */
linpool *mem; /* Linear pool containing configuration data */
@ -53,8 +52,7 @@ struct config {
char *err_file_name; /* File name containing error */
char *file_name; /* Name of main configuration file */
int file_fd; /* File descriptor of main configuration file */
HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */
struct config *fallback; /* Link to regular config for CLI parsing */
struct sym_scope *root_scope; /* Scope for root symbols */
int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */
@ -133,12 +131,17 @@ struct symbol {
struct sym_scope {
struct sym_scope *next; /* Next on scope stack */
struct symbol *name; /* Name of this scope */
HASH(struct symbol) hash; /* Local symbol hash */
uint slots; /* Variable slots */
byte active; /* Currently entered */
byte block; /* No independent stack frame */
byte soft_scopes; /* Number of soft scopes above */
};
extern struct sym_scope *global_root_scope;
struct bytestring {
size_t length;
byte data[];
@ -187,12 +190,14 @@ int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);
struct symbol *cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c);
static inline struct symbol *cf_find_symbol(const struct config *cfg, const byte *c)
{ return cf_find_local_symbol(cfg, cfg->root_scope, c); }
struct symbol *cf_find_symbol_scope(const struct sym_scope *scope, const byte *c);
static inline struct symbol *cf_find_symbol_cfg(const struct config *cfg, const byte *c)
{ return cf_find_symbol_scope(cfg->root_scope, c); }
struct keyword;
struct symbol *cf_symbol_from_keyword(const struct keyword *kw);
#define cf_find_symbol(where, what) _Generic(*(where), \
struct config: cf_find_symbol_cfg, \
struct sym_scope: cf_find_symbol_scope \
)((where), (what))
struct symbol *cf_get_symbol(const byte *c);
struct symbol *cf_default_name(char *template, int *counter);

View File

@ -120,8 +120,7 @@ CF_DECLS
%type <mls> label_stack_start label_stack
%type <t> text opttext
%type <s> symbol
%type <kw> kw_sym
%type <s> symbol symbol_known toksym
%nonassoc PREFIX_DUMMY
%left AND OR
@ -166,7 +165,7 @@ definition:
expr:
NUM
| '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
| CF_SYM_KNOWN {
| symbol_known {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
$$ = SYM_VAL($1).i; }
;
@ -177,7 +176,8 @@ expr_us:
| expr US { $$ = $1 US_; }
;
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | kw_sym { $$ = cf_symbol_from_keyword($1); } ;
symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | toksym ;
symbol_known: CF_SYM_KNOWN | toksym ;
/* Switches */

View File

@ -26,8 +26,7 @@ m4_define(CF_DEFINES, `m4_divert(-1)')
m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, NULL },
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, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
)DNL')
m4_define(CF_KEYWORDS, `CF_iterate([[CF_keywd]], [[$@]])DNL')
# CLI commands generate keywords as well
m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))

View File

@ -29,9 +29,9 @@ m4_define(CF_END, `m4_divert(-1)')
m4_define(CF_itera, `m4_ifelse($#, 1, [[CF_iter($1)]], [[CF_iter($1)[[]]CF_itera(m4_shift($@))]])')
m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)')
# Keywords act as %token<kw>
# Keywords act as %token<s>
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])')
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token<kw>[[]]CF_toks
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token<s>[[]]CF_toks
)DNL')
# CLI commands

View File

@ -316,8 +316,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
LEN, MAXLEN,
DATA, DATA1, DATA2,
DEFINED,
ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
ADD, DELETE, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED,
MIN, MAX,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
@ -371,7 +371,7 @@ custom_attr: ATTRIBUTE type symbol ';' {
conf: bt_test_suite ;
bt_test_suite:
BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
BT_TEST_SUITE '(' symbol_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;
@ -384,7 +384,7 @@ bt_test_suite:
conf: bt_test_same ;
bt_test_same:
BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
BT_TEST_SAME '(' symbol_known ',' symbol_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));
@ -465,7 +465,7 @@ function_vars:
filter_body: function_body ;
filter:
CF_SYM_KNOWN {
symbol_known {
cf_assert_symbol($1, SYM_FILTER);
$$ = $1->filter;
}
@ -578,7 +578,7 @@ set_atom:
if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
| CF_SYM_KNOWN {
| symbol_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;
@ -749,7 +749,7 @@ var_list: /* EMPTY */ { $$ = NULL; }
| var_list ',' term { $$ = $3; $$->next = $1; }
function_call:
CF_SYM_KNOWN '(' var_list ')'
symbol_known '(' var_list ')'
{
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
@ -768,7 +768,7 @@ function_call:
}
;
symbol_value: CF_SYM_KNOWN
symbol_value: symbol_known
{
switch ($1->class) {
case SYM_CONSTANT_RANGE:
@ -929,7 +929,7 @@ cmd:
$$ = f_new_inst(FI_FOR_INIT, $6, $3);
$$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
}
| CF_SYM_KNOWN '=' term ';' {
| symbol_known '=' term ';' {
switch ($1->class) {
case SYM_VARIABLE_RANGE:
$$ = f_new_inst(FI_VAR_SET, $3, $1);

View File

@ -51,17 +51,18 @@ cmd_show_symbols(struct sym_show_data *sd)
cli_msg(1010, "%-8s\t%s", sd->sym->name, cf_symbol_class_name(sd->sym));
else
{
HASH_WALK(config->sym_hash, next, sym)
{
if (!sym->scope->active)
continue;
for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next)
HASH_WALK(scope->hash, next, sym)
{
if (!sym->scope->active)
continue;
if (sd->type && (sym->class != sd->type))
continue;
if (sd->type && (sym->class != sd->type))
continue;
cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
}
HASH_WALK_END;
cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
}
HASH_WALK_END;
cli_msg(0, "");
}

View File

@ -118,11 +118,11 @@ CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
CF_KEYWORDS(PASSWORD, KEY, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
CF_KEYWORDS(CHECK, LINK)
CF_KEYWORDS(SORTED, TRIE, MIN, MAX, SETTLE, TIME, GC, THRESHOLD, PERIOD)
@ -154,7 +154,7 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
CF_GRAMMAR
kw_sym: MIN MAX ;
toksym: MIN MAX ;
/* Setting of router ID */
@ -642,7 +642,7 @@ r_args:
$$ = cfg_allocz(sizeof(struct rt_show_data));
init_list(&($$->tables));
$$->filter = FILTER_ACCEPT;
$$->running_on_config = new_config->fallback;
$$->running_on_config = config;
}
| r_args net_any {
$$ = $1;
@ -663,7 +663,7 @@ r_args:
$$->addr = $3;
$$->addr_mode = RSD_ADDR_IN;
}
| r_args TABLE CF_SYM_KNOWN {
| r_args TABLE symbol_known {
cf_assert_symbol($3, SYM_TABLE);
$$ = $1;
rt_show_add_table($$, $3->table->table);
@ -708,7 +708,7 @@ r_args:
$$ = $1;
$$->filtered = 1;
}
| r_args export_mode CF_SYM_KNOWN {
| r_args export_mode symbol_known {
cf_assert_symbol($3, SYM_PROTO);
struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
@ -725,7 +725,7 @@ r_args:
$$->export_channel = $3;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL CF_SYM_KNOWN {
| r_args PROTOCOL symbol_known {
cf_assert_symbol($3, SYM_PROTO);
struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;

View File

@ -45,8 +45,7 @@ CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
CF_GRAMMAR
/* Workaround for collisions between keywords and symbols */
kw_sym: ROLE | PEER | PROVIDER | CUSTOMER | RS_SERVER | RS_CLIENT ;
toksym: ROLE | PEER | PROVIDER | CUSTOMER | RS_SERVER | RS_CLIENT ;
proto: bgp_proto '}' ;