Hi all,

Some weird idea. I'm not sure it needs to be in the mainstream version, but
somebody might find it helpful.

For example I may want to refactor the naming scheme for protocols/tables
in my bird config. But when I apply the new config with the new names, such
renamed protocols will be recreated or restarted, which may be undesired.
So if I could rename protocols/tables in advance and then load the new
config, I can hope than no changes would be found and the there would be no
interruptions.

The attached patch solves the problem, by introducing such changes:

To rename some symbol one can use cli command:
rename <old_symbol> "<new_name>"
The new name is in the form of the string, because symbol form requires
symbol to be created. I tried to use CF_SYM_UNDEFINED for the second
parameter. It works somehow, but leaves duplicate symbols in the table. If
there is some way to clean them after it, it could be more visually
pleasing option.

The other problem is that a symbol has the fixed buffer for the name bound
by its length. And one would not be able to rename it to a new name that is
longer. But to overcome that, I add a field to a symbol to remember the
length of the allocated buffer and allow the buffer to be bigger. This can
be controlled by config option:
symbols min <len>
Which sets minum length that will fit the buffer. But as symbols are
allocated while reading the config, you need to place this configuration
option to the top of your config, i.e. before all the symbols you want to
rename.

So you can load the old config with the old names and this option added, it
will allocate bigger buffers for the symbols. Then you can rename your
symbols to the new ones. And finally load the new config with the new names.

Of course you need the bird version with this patch applied in advace to do
the trick. :)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index ceedee8a..92d81989 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -584,11 +584,13 @@ cf_new_symbol(const byte *c)
   uint l = strlen(c);
   if (l > SYM_MAX_LEN)
     cf_error("Symbol too long");
+  if (l < new_config->symbols_min)
+    l = new_config->symbols_min;
 
   cf_swap_soft_scope();
 
   s = cfg_allocz(sizeof(struct symbol) + l + 1);
-  *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
+  *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, .len = l, };
   strcpy(s->name, c);
 
   if (!new_config->sym_hash.data)
@@ -667,6 +669,23 @@ cf_localize_symbol(struct symbol *sym)
   return cf_new_symbol(sym->name);
 }
 
+int
+cf_rename_symbol(struct symbol *sym, const char *name)
+{
+  if (sym->len < strlen(name))
+    return 1;
+
+  if (cf_find_symbol(config, name))
+    return 1;
+
+  strcpy(sym->name, name);
+
+  HASH_REMOVE2(config->sym_hash, SYM, config->pool, sym);
+  HASH_INSERT2(config->sym_hash, SYM, config->pool, sym);
+
+  return 0;
+}
+
 struct symbol *
 cf_default_name(char *template, int *counter)
 {
diff --git a/conf/conf.h b/conf/conf.h
index b409750e..581ced71 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -26,6 +26,8 @@ struct config {
   list tests;				/* Configured unit tests (f_bt_test_suite) */
   list symbols;				/* Configured symbols in config order */
 
+  int symbols_min;			/* Mimimal name length to fit symbol buffer */
+
   int mrtdump_file;			/* Configured MRTDump file (sysdep, fd in unix) */
   const char *syslog_name;		/* Name used for syslog (NULL -> no syslog) */
   struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
@@ -116,6 +118,7 @@ struct symbol {
   struct sym_scope *scope;
   int class;				/* SYM_* */
   uint flags;				/* SYM_FLAG_* */
+  int len;				/* Name buffer length */
 
   union {
     struct proto_config *proto;		/* For SYM_PROTO and SYM_TEMPLATE */
@@ -192,6 +195,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);
+int cf_rename_symbol(struct symbol *sym, const char *name);
 
 static inline int cf_symbol_is_local(struct symbol *sym)
 { return (sym->scope == conf_this_scope) && !conf_this_scope->soft_scopes; }
diff --git a/nest/cmds.c b/nest/cmds.c
index bcc8d6c2..4dea7ebe 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -142,3 +142,24 @@ cmd_eval(const struct f_line *expr)
 
   cli_msg(23, "%s", buf.start);
 }
+
+void
+cmd_rename(struct symbol *sym, const char *name)
+{
+  if (!sym->class)
+    {
+      cli_msg(8010, "symbol is void");
+      return;
+    }
+
+  if (cf_find_symbol(config, name))
+    {
+      cli_msg(8010, "symbol name is taken");
+      return;
+    }
+
+  if (cf_rename_symbol(sym, name))
+    cli_msg(8010, "runtime error");
+  else
+    cli_msg(10, "ok");
+}
diff --git a/nest/cmds.h b/nest/cmds.h
index 194a9d7f..f4440a16 100644
--- a/nest/cmds.h
+++ b/nest/cmds.h
@@ -19,3 +19,5 @@ void cmd_show_memory(void);
 
 struct f_line;
 void cmd_eval(const struct f_line *expr);
+
+void cmd_rename(struct symbol *sym, const char *name);
diff --git a/nest/config.Y b/nest/config.Y
index b2aa0906..832cd5c9 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -122,7 +122,7 @@ CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, E
 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, FLUSH, AS, RENAME)
 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,6 +154,15 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
 
 CF_GRAMMAR
 
+conf: symbols_min ;
+
+symbols_min: SYMBOLS MIN expr ';'
+{
+  if (($3 < 0) || ($3 > SYM_MAX_LEN))
+    cf_error("Invalid symbols min length");
+  new_config->symbols_min = $3;
+};
+
 /* Setting of router ID */
 
 conf: rtrid ;
@@ -925,6 +934,9 @@ proto_patt2:
 
 dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ;
 
+CF_CLI(RENAME, CF_SYM_KNOWN TEXT, <sym> <name>, [[Rename symbol]])
+{ cmd_rename($2, $3); } ;
+
 
 CF_CODE
 

Reply via email to