]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Conf: Symbol hashes for all scopes
authorMaria Matejka <mq@ucw.cz>
Mon, 2 May 2022 18:29:03 +0000 (20:29 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 12 Sep 2023 13:20:50 +0000 (15:20 +0200)
This is a backport cherry-pick of commits
  165156beeb2926472bbceca3c103aacc3f81a8cc
  cce974e8ea992d0e6d2f649eca7880b436d91d71

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

conf/cf-lex.l
conf/conf.c
conf/conf.h
conf/confbase.Y
conf/gen_keywords.m4
conf/gen_parser.m4
filter/config.Y
nest/cmds.c
nest/config.Y

index e789e8641586382f567a91300857a5b67840a6ba..8637de4015bcf394ffd39ba49b423268829d08b9 100644 (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;
 
@@ -580,12 +580,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;
 }
@@ -595,32 +596,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;
 }
@@ -637,7 +633,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);
 }
 
 /**
@@ -685,23 +681,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))
-  {
-    cf_lval.s = sym;
-    return CF_SYM_KNOWN;
-  }
+  struct symbol *sym = cf_get_symbol(data);
+  cf_lval.s = sym;
 
-  /* 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;
@@ -709,19 +697,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));
 }
 
 /**
@@ -757,6 +749,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;
 }
 
 /**
index 7ef729b336ea17b2dc47f8045a24288bdc59c42d..b9239d9bedff7686e5f711822f5d30fae25dfee1 100644 (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;
 
index d40f955eb903904c8f6a8923044a337a3a18a0b5..fe8ee5bf2f31aa8863256cec4b4397fe55665cb2 100644 (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);
index a43a8cca5d5f282f2e4635238938f7f2e1bc815b..0c2807dc5f5db3fc7185af07eb96b071615080f0 100644 (file)
@@ -118,7 +118,7 @@ CF_DECLS
 
 %type <t> text opttext
 %type <bs> bytestring
-%type <s> symbol
+%type <s> symbol symbol_known
 
 %type <v> bytestring_text text_or_ipa
 %type <x> bytestring_expr
@@ -166,7 +166,7 @@ definition:
 expr:
    NUM
  | '(' term ')' { $$ = cf_eval_int($2); }
- | CF_SYM_KNOWN {
+ | symbol_known {
      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
      $$ = SYM_VAL($1).i; }
  ;
@@ -177,7 +177,8 @@ expr_us:
  | expr US { $$ = $1 US_; }
  ;
 
-symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD { $$ = cf_symbol_from_keyword($1); } ;
+symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | KEYWORD ;
+symbol_known: CF_SYM_KNOWN | KEYWORD ;
 
 /* Switches */
 
index 3206c18631ebb6ebba47aaa2964d0bd7fbe13429..4ab6d50dbac13451ea71ff24609bae81ba01d8fd 100644 (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')
 m4_define(CF_KEYWORDS_EXCLUSIVE, `CF_KEYWORDS($@)')
 
 # CLI commands generate keywords as well
index a26af8510b1c01e29e6197d833e8530abb447113..caf22307064bb5dea08ef40f18802e43c9b15f80 100644 (file)
@@ -31,13 +31,13 @@ m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)')
 
 m4_define(CF_append, `m4_define([[$1]], m4_ifdef([[$1]], m4_defn([[$1]])[[$3]])[[$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)CF_append([[CF_kw_rule]],$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')
 
 m4_define(CF_keywd2, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])')
-m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token<kw>[[]]CF_toks
+m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token<s>[[]]CF_toks
 )DNL')
 
 # CLI commands
@@ -61,7 +61,7 @@ m4_undivert(1)DNL
 
 m4_undivert(2)DNL
 
-%type <kw> KEYWORD
+%type <s> KEYWORD
 
 %%
 KEYWORD: CF_kw_rule;
index 9141f964dbdb0258ca52474552e302eba7ebb1ef..fcdbb4a9df700735cd690b971f55002dd5d9763a 100644 (file)
@@ -317,8 +317,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,
@@ -373,7 +373,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;
@@ -386,7 +386,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));
@@ -468,7 +468,7 @@ function_vars:
 filter_body: function_body ;
 
 filter:
-   CF_SYM_KNOWN {
+   symbol_known {
      cf_assert_symbol($1, SYM_FILTER);
      $$ = $1->filter;
    }
@@ -581,7 +581,7 @@ set_atom:
      $$ = cf_eval($2, T_VOID);
      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;
@@ -753,7 +753,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.");
@@ -772,7 +772,7 @@ function_call:
    }
  ;
 
-symbol_value: CF_SYM_KNOWN
+symbol_value: symbol_known
   {
     switch ($1->class) {
       case SYM_CONSTANT_RANGE:
@@ -938,7 +938,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);
index bcc8d6c29bc26391e8a8d12b3c84e8963edc6080..d49bbc53c32384454d7f38f8537142943adbe365 100644 (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;
-
-      if (sd->type && (sym->class != sd->type))
-       continue;
-
-      cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
-    }
-    HASH_WALK_END;
+    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;
+
+       cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
+      }
+      HASH_WALK_END;
 
     cli_msg(0, "");
   }
index c583dc7f907e3377016e198bdf2eecb546eb79af..8aaf0128fc90e290c0b76e20193751f4a292fad0 100644 (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)
@@ -645,7 +645,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;
@@ -666,7 +666,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);
@@ -711,7 +711,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;
@@ -728,7 +728,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;