]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Config: Allow keyword redefinition
authorMaria Matejka <mq@jmq.cz>
Thu, 9 Apr 2020 20:07:23 +0000 (22:07 +0200)
committerMaria Matejka <mq@jmq.cz>
Thu, 9 Apr 2020 20:19:06 +0000 (22:19 +0200)
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
conf/conf.h
conf/confbase.Y
conf/gen_keywords.m4
conf/gen_parser.m4
filter/config.Y
nest/config.Y
nest/route.h
nest/rt-table.c
sysdep/unix/main.c

index 1d6cae2cd52212a5e89e561c5cfd4da984d13323..4cececd4fc037d20bfe8ed71fc6ca443aefe96e3 100644 (file)
 #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 */
index 34c6818dcf1bc153521c27d105184ff95d9f8afd..7a10d2cb81b4cc687f6cecf54dac9b08a1b26782 100644 (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_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;
index 8b22f23673dc8a9d44ecce117d51575dafe92622..fbb49ed3be391b5c6d8e35713d2a5bda90130d47 100644 (file)
@@ -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 <i> NUM ENUM
+%token <kw> ENUM
+%token <i> NUM
 %token <ip4> IP4
 %token <ip6> IP6
 %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 <mls> label_stack_start label_stack
 
-%type <t> text opttext
+%type <t> text opttext token_def
 %type <s> symbol
+%type <kw> 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
 
index 0c1dc545b52835a46cfb4e6ee160e7101f18bffe..1f9962f606e346ef32cdfff9da0a9afcf0a17d5a 100644 (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 
 m4_m4wrap(`
 m4_divert(0)
-static struct keyword keyword_list[] = {
+struct keyword keyword_list[] = {
 m4_undivert(1){ NULL, -1, NULL } };
 ')
 
index 5b378a93e97dcbe9d2004e4bb6113dab1b8f6d94..2905811b440bbde461b5bc32b380b6d3b971438f 100644 (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_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 <kw> + 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 <kw> $1
+m4_divert(3)keyword: $1 ;
+m4_divert(2)]])')
 
 # CLI commands
 m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL
index 995f6cd4dc45bfc8dba121183b92ed7aa3b81c34..160f36ed8bf1e19d2dd3ed1026047ac3c2fa07a4 100644 (file)
@@ -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:
index bd1157c640c83dd94fe94e8157c430d15191aebd..25643a21ec38cfbb1761e1d227c768b62449b925 100644 (file)
@@ -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);
index 5421ece5217705be8288a3a136c99eefa407094a..9fd552aaf74f24e108b62a9857c425ee7770d598 100644 (file)
@@ -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 */
index a46eeb77a3eb3f9e3719b91bc7ac7a6bd9ff2096..a5373af29a3de7dd80a4ba2f44008583d2b84a39 100644 (file)
@@ -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;
index 1d258f4c7a81e6d549b9bd752e21997d8b0f490e..6fcf90fad718b41d7788aba949e2ed40e4408988 100644 (file)
@@ -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