0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 07:31:54 +00:00

Config: Allow keyword redefinition

When you redefine a keyword, a warning is issued. It is recommended to
abstain from redefining keywords as it may yield lots of strange parse
errors in config.

It is not possible to use a keyword as a protocol or template name due
to collisions in config language.
This commit is contained in:
Maria Matejka 2020-04-09 22:07:23 +02:00
parent fd9f0c0640
commit 064b59d1c7
10 changed files with 88 additions and 68 deletions

View File

@ -51,12 +51,6 @@
#include "lib/string.h" #include "lib/string.h"
#include "lib/hash.h" #include "lib/hash.h"
struct keyword {
byte *name;
int value;
struct keyword *next;
};
#include "conf/keywords.h" #include "conf/keywords.h"
/* Could be defined by Bison in cf-parse.tab.h, inteferes with SYM hash */ /* Could be defined by Bison in cf-parse.tab.h, inteferes with SYM hash */
@ -618,18 +612,20 @@ cf_get_symbol(const byte *c)
* for purposes of cf_define_symbol(). * for purposes of cf_define_symbol().
*/ */
struct symbol * struct symbol *
cf_localize_symbol(struct symbol *sym) cf_localize_symbol(const byte *c)
{ {
struct symbol *sym = cf_find_symbol(new_config, c);
/* If the symbol type is void, it has been recently allocated just in this scope. */ /* If the symbol type is void, it has been recently allocated just in this scope. */
if (!sym->class) if (sym && !sym->class)
return sym; return sym;
/* If the scope is the current, it is already defined in this scope. */ /* If the scope is the current, it is already defined in this scope. */
if (sym->scope == conf_this_scope) if (sym && (sym->scope == conf_this_scope))
cf_error("Symbol already defined"); cf_error("Symbol already defined");
/* Not allocated here yet, doing it now. */ /* Not allocated here yet, doing it now. */
return cf_new_symbol(sym->name); return cf_new_symbol(c);
} }
struct symbol * struct symbol *
@ -665,14 +661,12 @@ cf_lex_symbol(const char *data)
struct keyword *k = HASH_FIND(kw_hash, KW, data); struct keyword *k = HASH_FIND(kw_hash, KW, data);
if (k) if (k)
{ {
cf_lval.kw = *k;
if (k->value > 0) if (k->value > 0)
return k->value; return k->value;
else else
{
cf_lval.i = -k->value;
return ENUM; return ENUM;
} }
}
/* OK, undefined symbol */ /* OK, undefined symbol */
cf_lval.s = sym; cf_lval.s = sym;

View File

@ -181,7 +181,7 @@ struct symbol *cf_find_symbol(const struct config *cfg, const byte *c);
struct symbol *cf_get_symbol(const byte *c); struct symbol *cf_get_symbol(const byte *c);
struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_default_name(char *template, int *counter);
struct symbol *cf_localize_symbol(struct symbol *sym); struct symbol *cf_localize_symbol(const byte *c);
/** /**
* cf_define_symbol - define meaning of a symbol * cf_define_symbol - define meaning of a symbol
@ -198,8 +198,8 @@ struct symbol *cf_localize_symbol(struct symbol *sym);
* Result: Pointer to the newly defined symbol. If we are in the top-level * Result: Pointer to the newly defined symbol. If we are in the top-level
* scope, it's the same @sym as passed to the function. * scope, it's the same @sym as passed to the function.
*/ */
#define cf_define_symbol(osym_, type_, var_, def_) ({ \ #define cf_define_symbol(name_, type_, var_, def_) ({ \
struct symbol *sym_ = cf_localize_symbol(osym_); \ struct symbol *sym_ = cf_localize_symbol(name_); \
sym_->class = type_; \ sym_->class = type_; \
sym_->var_ = def_; \ sym_->var_ = def_; \
sym_; }) sym_; })
@ -208,6 +208,12 @@ void cf_push_scope(struct symbol *);
void cf_pop_scope(void); void cf_pop_scope(void);
char *cf_symbol_class_name(struct symbol *sym); char *cf_symbol_class_name(struct symbol *sym);
struct keyword {
byte *name;
int value;
struct keyword *next;
};
/* Parser */ /* Parser */
extern char *cf_text; extern char *cf_text;

View File

@ -22,6 +22,9 @@ CF_HDR
#include "nest/cli.h" #include "nest/cli.h"
#include "filter/filter.h" #include "filter/filter.h"
extern struct keyword keyword_list[];
extern struct sym_scope *conf_this_scope;
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */ /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
CF_DEFINES CF_DEFINES
@ -90,12 +93,14 @@ CF_DECLS
struct channel_limit cl; struct channel_limit cl;
struct timeformat *tf; struct timeformat *tf;
mpls_label_stack *mls; mpls_label_stack *mls;
struct keyword kw;
} }
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
%token GEQ LEQ NEQ AND OR %token GEQ LEQ NEQ AND OR
%token PO PC %token PO PC
%token <i> NUM ENUM %token <kw> ENUM
%token <i> NUM
%token <ip4> IP4 %token <ip4> IP4
%token <ip6> IP6 %token <ip6> IP6
%token <i64> VPN_RD %token <i64> VPN_RD
@ -110,8 +115,9 @@ CF_DECLS
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
%type <mls> label_stack_start label_stack %type <mls> label_stack_start label_stack
%type <t> text opttext %type <t> text opttext token_def
%type <s> symbol %type <s> symbol
%type <kw> token keyword
%nonassoc PREFIX_DUMMY %nonassoc PREFIX_DUMMY
%left AND OR %left AND OR
@ -146,7 +152,7 @@ conf: ';' ;
conf: definition ; conf: definition ;
definition: definition:
DEFINE symbol '=' term ';' { DEFINE token_def '=' term ';' {
struct f_val *val = cfg_alloc(sizeof(struct f_val)); struct f_val *val = cfg_alloc(sizeof(struct f_val));
if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
@ -194,7 +200,7 @@ ipa:
ipa_scope: ipa_scope:
/* empty */ { $$ = NULL; } /* empty */ { $$ = NULL; }
| '%' symbol { $$ = if_get_by_name($2->name); } | '%' token { $$ = if_get_by_name($2.name); }
; ;
@ -379,6 +385,16 @@ opttext:
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;
token:
symbol { $$ = (struct keyword) { .name = $1->name, }; }
| keyword { $$ = $1; }
| ENUM { $$ = $1; }
;
token_def:
symbol { $$ = $1->name; }
| keyword { log(L_WARN "Redefining a keyword: \"%s\"", $1.name); $$ = $1.name; }
| ENUM { log(L_WARN "Redefining a keyword: \"%s\"", $1.name); $$ = $1.name; }
CF_CODE CF_CODE

View File

@ -43,7 +43,7 @@ m4_define(CF_ENUM_PX, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_
# After all configuration templates end, we generate the # After all configuration templates end, we generate the
m4_m4wrap(` m4_m4wrap(`
m4_divert(0) m4_divert(0)
static struct keyword keyword_list[] = { struct keyword keyword_list[] = {
m4_undivert(1){ NULL, -1, NULL } }; m4_undivert(1){ NULL, -1, NULL } };
') ')

View File

@ -25,14 +25,11 @@ m4_define(CF_GRAMMAR, `CF_ZONE(3, Grammar)')
m4_define(CF_CODE, `CF_ZONE(4, C Code)') m4_define(CF_CODE, `CF_ZONE(4, C Code)')
m4_define(CF_END, `m4_divert(-1)') m4_define(CF_END, `m4_divert(-1)')
# Simple iterator # Keywords act as a %token <kw> + added to a keyword: rule
m4_define(CF_itera, `m4_ifelse($#, 1, [[CF_iter($1)]], [[CF_iter($1)[[]]CF_itera(m4_shift($@))]])') m4_define(CF_KEYWORDS, `m4_ifelse($#,1,,[[CF_KEYWORDS(m4_shift($@))]])DNL
m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)') m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_divert(2)%token <kw> $1
m4_divert(3)keyword: $1 ;
# Keywords act as untyped %token m4_divert(2)]])')
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[[]]CF_toks
)DNL')
# CLI commands # CLI commands
m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL

View File

@ -467,13 +467,16 @@ CF_GRAMMAR
conf: filter_def ; conf: filter_def ;
filter_def: filter_def:
FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } FILTER token_def {
filter_body { cf_push_scope( cf_define_symbol($2, SYM_FILTER, filter, NULL) );
struct filter *f = cfg_alloc(sizeof(struct filter)); } filter_body {
*f = (struct filter) { .sym = $2, .root = $4 };
$2->filter = f;
cf_pop_scope(); cf_pop_scope();
struct symbol *sym = cf_get_symbol($2);
ASSERT(sym->class == SYM_FILTER);
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .sym = sym, .root = $4 };
sym->filter = f;
} }
; ;
@ -483,8 +486,8 @@ filter_eval:
; ;
conf: custom_attr ; conf: custom_attr ;
custom_attr: ATTRIBUTE type symbol ';' { custom_attr: ATTRIBUTE type token_def ';' {
cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda); cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3, $2)->fda);
}; };
conf: bt_test_suite ; conf: bt_test_suite ;
@ -555,24 +558,24 @@ type:
function_argsn: function_argsn:
/* EMPTY */ /* EMPTY */
| function_argsn type symbol ';' { | function_argsn type token_def ';' {
if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed"); if (conf_this_scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); cf_define_symbol($3, SYM_VARIABLE | $2, offset, conf_this_scope->slots++);
} }
; ;
function_args: function_args:
'(' ')' { $$ = 0; } '(' ')' { $$ = 0; }
| '(' function_argsn type symbol ')' { | '(' function_argsn type token_def ')' {
cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++); cf_define_symbol($4, SYM_VARIABLE | $3, offset, conf_this_scope->slots++);
$$ = $4->scope->slots; $$ = conf_this_scope->slots;
} }
; ;
function_vars: function_vars:
/* EMPTY */ { $$ = 0; } /* EMPTY */ { $$ = 0; }
| function_vars type symbol ';' { | function_vars type token_def ';' {
cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); cf_define_symbol($3, SYM_VARIABLE | $2, offset, conf_this_scope->slots++);
$$ = $1 + 1; $$ = $1 + 1;
} }
; ;
@ -607,14 +610,16 @@ function_body:
conf: function_def ; conf: function_def ;
function_def: function_def:
FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name ); FUNCTION token_def { DBG( "Beginning of function %s\n", $2 );
$2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope(cf_define_symbol($2, SYM_FUNCTION, function, NULL));
cf_push_scope($2);
} function_args function_body { } function_args function_body {
DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars);
$5->args = $4;
$2->function = $5;
cf_pop_scope(); cf_pop_scope();
struct symbol *sym = cf_get_symbol($2);
ASSERT(sym->class == SYM_FUNCTION);
DBG("Definition of function %s with %u args and %u local vars.\n", $2, $4, $5->vars);
$5->args = $4;
sym->function = $5;
} }
; ;
@ -676,7 +681,7 @@ set_atom:
NUM { $$.type = T_INT; $$.val.i = $1; } NUM { $$.type = T_INT; $$.val.i = $1; }
| fipa { $$ = $1; } | fipa { $$ = $1; }
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a(-$1.value); $$.val.i = pair_b(-$1.value); }
| '(' term ')' { | '(' term ')' {
if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
@ -692,7 +697,7 @@ switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; } NUM { $$.type = T_INT; $$.val.i = $1; }
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); } | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
| fipa { $$ = $1; } | fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a(-$1.value); $$.val.i = pair_b(-$1.value); }
; ;
cnum: cnum:
@ -833,7 +838,7 @@ constant:
DBG( "ook\n" ); DBG( "ook\n" );
} }
| '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); } | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
| ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = (-$1.value) >> 16, .val.i = (-$1.value) & 0xffff, }); }
; ;
constructor: constructor:

View File

@ -158,7 +158,7 @@ table_sorted:
| SORTED { $$ = 1; } | SORTED { $$ = 1; }
; ;
table: net_type TABLE symbol table_sorted { table: net_type TABLE token_def table_sorted {
struct rtable_config *cf; struct rtable_config *cf;
cf = rt_new_table($3, $1); cf = rt_new_table($3, $1);
cf->sorted = $4; cf->sorted = $4;
@ -183,7 +183,7 @@ proto_name:
this_proto->name = s->name; this_proto->name = s->name;
} }
| symbol { | symbol {
cf_define_symbol($1, this_proto->class, proto, this_proto); cf_define_symbol($1->name, this_proto->class, proto, this_proto);
this_proto->name = $1->name; this_proto->name = $1->name;
} }
| FROM CF_SYM_KNOWN { | FROM CF_SYM_KNOWN {
@ -199,7 +199,7 @@ proto_name:
| symbol FROM CF_SYM_KNOWN { | symbol FROM CF_SYM_KNOWN {
if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
cf_define_symbol($1, this_proto->class, proto, this_proto); cf_define_symbol($1->name, this_proto->class, proto, this_proto);
this_proto->name = $1->name; this_proto->name = $1->name;
proto_copy_config(this_proto, $3->proto); proto_copy_config(this_proto, $3->proto);

View File

@ -140,7 +140,7 @@ void fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src)
struct rtable_config { struct rtable_config {
node n; node n;
char *name; const char *name;
struct rtable *table; struct rtable *table;
struct proto_config *krt_attached; /* Kernel syncer attached to this table */ struct proto_config *krt_attached; /* Kernel syncer attached to this table */
uint addr_type; /* Type of address data stored in table (NET_*) */ uint addr_type; /* Type of address data stored in table (NET_*) */
@ -152,7 +152,7 @@ struct rtable_config {
typedef struct rtable { typedef struct rtable {
node n; /* Node in list of all tables */ node n; /* Node in list of all tables */
struct fib fib; struct fib fib;
char *name; /* Name of this table */ const char *name; /* Name of this table */
list channels; /* List of attached channels (struct channel) */ list channels; /* List of attached channels (struct channel) */
uint addr_type; /* Type of address data stored in table (NET_*) */ uint addr_type; /* Type of address data stored in table (NET_*) */
int pipe_busy; /* Pipe loop detection */ int pipe_busy; /* Pipe loop detection */
@ -329,7 +329,7 @@ int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c); void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all); void rt_prune_sync(rtable *t, int all);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed); int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); struct rtable_config *rt_new_table(const char *name, uint addr_type);
/* Default limit for ECMP next hops, defined in sysdep code */ /* Default limit for ECMP next hops, defined in sysdep code */

View File

@ -1940,8 +1940,8 @@ rt_preconfig(struct config *c)
{ {
init_list(&c->tables); init_list(&c->tables);
rt_new_table(cf_get_symbol("master4"), NET_IP4); rt_new_table("master4", NET_IP4);
rt_new_table(cf_get_symbol("master6"), NET_IP6); rt_new_table("master6", NET_IP6);
} }
@ -2181,8 +2181,10 @@ rt_next_hop_update(rtable *tab)
struct rtable_config * struct rtable_config *
rt_new_table(struct symbol *s, uint addr_type) rt_new_table(const char *name, uint addr_type)
{ {
struct symbol *s = cf_get_symbol(name);
/* Hack that allows to 'redefine' the master table */ /* Hack that allows to 'redefine' the master table */
if ((s->class == SYM_TABLE) && if ((s->class == SYM_TABLE) &&
(s->table == new_config->def_tables[addr_type]) && (s->table == new_config->def_tables[addr_type]) &&
@ -2191,8 +2193,8 @@ rt_new_table(struct symbol *s, uint addr_type)
struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config)); struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
cf_define_symbol(s, SYM_TABLE, table, c); cf_define_symbol(name, SYM_TABLE, table, c);
c->name = s->name; c->name = name;
c->addr_type = addr_type; c->addr_type = addr_type;
c->gc_max_ops = 1000; c->gc_max_ops = 1000;
c->gc_min_time = 5; c->gc_min_time = 5;
@ -2248,7 +2250,7 @@ rt_unlock_table(rtable *r)
} }
static struct rtable_config * static struct rtable_config *
rt_find_table_config(struct config *cf, char *name) rt_find_table_config(struct config *cf, const char *name)
{ {
struct symbol *sym = cf_find_symbol(cf, name); struct symbol *sym = cf_find_symbol(cf, name);
return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL; return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL;

View File

@ -95,7 +95,7 @@ drop_gid(gid_t gid)
#ifdef PATH_IPROUTE_DIR #ifdef PATH_IPROUTE_DIR
static inline void static inline void
add_num_const(char *name, int val, const char *file, const uint line) add_num_const(const char *name, int val, const char *file, const uint line)
{ {
struct f_val *v = cfg_alloc(sizeof(struct f_val)); struct f_val *v = cfg_alloc(sizeof(struct f_val));
*v = (struct f_val) { .type = T_INT, .val.i = val }; *v = (struct f_val) { .type = T_INT, .val.i = val };
@ -103,7 +103,7 @@ add_num_const(char *name, int val, const char *file, const uint line)
if (sym->class && (sym->scope == conf_this_scope)) if (sym->class && (sym->scope == conf_this_scope))
cf_error("Error reading value for %s from %s:%d: already defined", name, file, line); cf_error("Error reading value for %s from %s:%d: already defined", name, file, line);
cf_define_symbol(sym, SYM_CONSTANT | T_INT, val, v); cf_define_symbol(name, SYM_CONSTANT | T_INT, val, v);
} }
/* the code of read_iproute_table() is based on /* the code of read_iproute_table() is based on