From 064b59d1c7ee697d192bc90920aa81b973676cfd Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 9 Apr 2020 22:07:23 +0200 Subject: [PATCH] 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. --- conf/cf-lex.l | 20 ++++++---------- conf/conf.h | 12 +++++++--- conf/confbase.Y | 24 +++++++++++++++---- conf/gen_keywords.m4 | 2 +- conf/gen_parser.m4 | 13 ++++------- filter/config.Y | 55 ++++++++++++++++++++++++-------------------- nest/config.Y | 6 ++--- nest/route.h | 6 ++--- nest/rt-table.c | 14 ++++++----- sysdep/unix/main.c | 4 ++-- 10 files changed, 88 insertions(+), 68 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 1d6cae2cd..4cececd4f 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -51,12 +51,6 @@ #include "lib/string.h" #include "lib/hash.h" -struct keyword { - byte *name; - int value; - struct keyword *next; -}; - #include "conf/keywords.h" /* 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(). */ 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 (!sym->class) + if (sym && !sym->class) return sym; /* 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"); /* Not allocated here yet, doing it now. */ - return cf_new_symbol(sym->name); + return cf_new_symbol(c); } struct symbol * @@ -665,13 +661,11 @@ cf_lex_symbol(const char *data) struct keyword *k = HASH_FIND(kw_hash, KW, data); if (k) { + cf_lval.kw = *k; if (k->value > 0) return k->value; else - { - cf_lval.i = -k->value; return ENUM; - } } /* OK, undefined symbol */ diff --git a/conf/conf.h b/conf/conf.h index 34c6818dc..7a10d2cb8 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -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_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 @@ -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 * scope, it's the same @sym as passed to the function. */ -#define cf_define_symbol(osym_, type_, var_, def_) ({ \ - struct symbol *sym_ = cf_localize_symbol(osym_); \ +#define cf_define_symbol(name_, type_, var_, def_) ({ \ + struct symbol *sym_ = cf_localize_symbol(name_); \ sym_->class = type_; \ sym_->var_ = def_; \ sym_; }) @@ -208,6 +208,12 @@ void cf_push_scope(struct symbol *); void cf_pop_scope(void); char *cf_symbol_class_name(struct symbol *sym); +struct keyword { + byte *name; + int value; + struct keyword *next; +}; + /* Parser */ extern char *cf_text; diff --git a/conf/confbase.Y b/conf/confbase.Y index 8b22f2367..fbb49ed3b 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -22,6 +22,9 @@ CF_HDR #include "nest/cli.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? */ CF_DEFINES @@ -90,12 +93,14 @@ CF_DECLS struct channel_limit cl; struct timeformat *tf; mpls_label_stack *mls; + struct keyword kw; } %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT %token GEQ LEQ NEQ AND OR %token PO PC -%token NUM ENUM +%token ENUM +%token NUM %token IP4 %token IP6 %token VPN_RD @@ -110,8 +115,9 @@ CF_DECLS %type net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ %type label_stack_start label_stack -%type text opttext +%type text opttext token_def %type symbol +%type token keyword %nonassoc PREFIX_DUMMY %left AND OR @@ -146,7 +152,7 @@ conf: ';' ; conf: definition ; definition: - DEFINE symbol '=' term ';' { + DEFINE token_def '=' term ';' { 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"); cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); @@ -194,7 +200,7 @@ ipa: ipa_scope: /* empty */ { $$ = NULL; } - | '%' symbol { $$ = if_get_by_name($2->name); } + | '%' token { $$ = if_get_by_name($2.name); } ; @@ -379,6 +385,16 @@ opttext: | /* 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 diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 0c1dc545b..1f9962f60 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -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 m4_m4wrap(` m4_divert(0) -static struct keyword keyword_list[] = { +struct keyword keyword_list[] = { m4_undivert(1){ NULL, -1, NULL } }; ') diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4 index 5b378a93e..2905811b4 100644 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@ -25,14 +25,11 @@ m4_define(CF_GRAMMAR, `CF_ZONE(3, Grammar)') m4_define(CF_CODE, `CF_ZONE(4, C Code)') m4_define(CF_END, `m4_divert(-1)') -# Simple iterator -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 untyped %token -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') +# Keywords act as a %token + added to a keyword: rule +m4_define(CF_KEYWORDS, `m4_ifelse($#,1,,[[CF_KEYWORDS(m4_shift($@))]])DNL +m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_divert(2)%token $1 +m4_divert(3)keyword: $1 ; +m4_divert(2)]])') # CLI commands m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL diff --git a/filter/config.Y b/filter/config.Y index 995f6cd4d..160f36ed8 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -467,13 +467,16 @@ CF_GRAMMAR conf: filter_def ; filter_def: - FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } - filter_body { - struct filter *f = cfg_alloc(sizeof(struct filter)); - *f = (struct filter) { .sym = $2, .root = $4 }; - $2->filter = f; - + FILTER token_def { + cf_push_scope( cf_define_symbol($2, SYM_FILTER, filter, NULL) ); + } filter_body { 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 ; -custom_attr: ATTRIBUTE type symbol ';' { - cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda); +custom_attr: ATTRIBUTE type token_def ';' { + cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3, $2)->fda); }; conf: bt_test_suite ; @@ -555,24 +558,24 @@ type: function_argsn: /* EMPTY */ - | function_argsn type symbol ';' { - if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed"); - cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); + | function_argsn type token_def ';' { + if (conf_this_scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed"); + cf_define_symbol($3, SYM_VARIABLE | $2, offset, conf_this_scope->slots++); } ; function_args: '(' ')' { $$ = 0; } - | '(' function_argsn type symbol ')' { - cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++); - $$ = $4->scope->slots; + | '(' function_argsn type token_def ')' { + cf_define_symbol($4, SYM_VARIABLE | $3, offset, conf_this_scope->slots++); + $$ = conf_this_scope->slots; } ; function_vars: /* EMPTY */ { $$ = 0; } - | function_vars type symbol ';' { - cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++); + | function_vars type token_def ';' { + cf_define_symbol($3, SYM_VARIABLE | $2, offset, conf_this_scope->slots++); $$ = $1 + 1; } ; @@ -607,14 +610,16 @@ function_body: conf: function_def ; function_def: - FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name ); - $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); - cf_push_scope($2); + FUNCTION token_def { DBG( "Beginning of function %s\n", $2 ); + cf_push_scope(cf_define_symbol($2, SYM_FUNCTION, function, NULL)); } 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(); + + 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; } | fipa { $$ = $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 ')' { 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"); @@ -692,7 +697,7 @@ switch_atom: NUM { $$.type = T_INT; $$.val.i = $1; } | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); } | 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: @@ -833,7 +838,7 @@ constant: DBG( "ook\n" ); } | '[' 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: diff --git a/nest/config.Y b/nest/config.Y index bd1157c64..25643a21e 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -158,7 +158,7 @@ table_sorted: | SORTED { $$ = 1; } ; -table: net_type TABLE symbol table_sorted { +table: net_type TABLE token_def table_sorted { struct rtable_config *cf; cf = rt_new_table($3, $1); cf->sorted = $4; @@ -183,7 +183,7 @@ proto_name: this_proto->name = s->name; } | 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; } | FROM CF_SYM_KNOWN { @@ -199,7 +199,7 @@ proto_name: | symbol FROM CF_SYM_KNOWN { 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; proto_copy_config(this_proto, $3->proto); diff --git a/nest/route.h b/nest/route.h index 5421ece52..9fd552aaf 100644 --- a/nest/route.h +++ b/nest/route.h @@ -140,7 +140,7 @@ void fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src) struct rtable_config { node n; - char *name; + const char *name; struct rtable *table; struct proto_config *krt_attached; /* Kernel syncer attached to this table */ uint addr_type; /* Type of address data stored in table (NET_*) */ @@ -152,7 +152,7 @@ struct rtable_config { typedef struct rtable { node n; /* Node in list of all tables */ struct fib fib; - char *name; /* Name of this table */ + const char *name; /* Name of this table */ list channels; /* List of attached channels (struct channel) */ uint addr_type; /* Type of address data stored in table (NET_*) */ 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_prune_sync(rtable *t, int all); 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 */ diff --git a/nest/rt-table.c b/nest/rt-table.c index a46eeb77a..a5373af29 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1940,8 +1940,8 @@ rt_preconfig(struct config *c) { init_list(&c->tables); - rt_new_table(cf_get_symbol("master4"), NET_IP4); - rt_new_table(cf_get_symbol("master6"), NET_IP6); + rt_new_table("master4", NET_IP4); + rt_new_table("master6", NET_IP6); } @@ -2181,8 +2181,10 @@ rt_next_hop_update(rtable *tab) 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 */ if ((s->class == SYM_TABLE) && (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)); - cf_define_symbol(s, SYM_TABLE, table, c); - c->name = s->name; + cf_define_symbol(name, SYM_TABLE, table, c); + c->name = name; c->addr_type = addr_type; c->gc_max_ops = 1000; c->gc_min_time = 5; @@ -2248,7 +2250,7 @@ rt_unlock_table(rtable *r) } 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); return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL; diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 1d258f4c7..6fcf90fad 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -95,7 +95,7 @@ drop_gid(gid_t gid) #ifdef PATH_IPROUTE_DIR 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)); *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)) 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 -- 2.47.2