mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Conf: Symbol hashes for all scopes
This is a backport cherry-pick of commits165156beeb
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:
parent
a19a60bd6c
commit
df338396cd
@ -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,11 +591,12 @@ 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);
|
||||
|
||||
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)))
|
||||
/* 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);
|
||||
|
||||
if (sym && (sym->class != SYM_VOID))
|
||||
{
|
||||
struct symbol *sym = cf_get_symbol(data);
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
|
21
conf/conf.h
21
conf/conf.h
@ -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);
|
||||
|
@ -117,8 +117,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
|
||||
@ -163,7 +162,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; }
|
||||
;
|
||||
@ -174,7 +173,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 */
|
||||
|
||||
|
@ -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, [[ ]], [[,]]))
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -51,7 +51,8 @@ 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)
|
||||
for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next)
|
||||
HASH_WALK(scope->hash, next, sym)
|
||||
{
|
||||
if (!sym->scope->active)
|
||||
continue;
|
||||
|
@ -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;
|
||||
|
@ -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 '}' ;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user