*
* There can exist up to four different configurations at one time: an active
* one (pointed to by @config), configuration we are just switching from
- * (@old_config), one queued for the next reconfiguration (@future_config;
- * if there is one and the user wants to reconfigure once again, we just
- * free the previous queued config and replace it with the new one) and
- * finally a config being parsed (@new_config). The stored @old_config
- * is also used for undo reconfiguration, which works in a similar way.
- * Reconfiguration could also have timeout (using @config_timer) and undo
- * is automatically called if the new configuration is not confirmed later.
+ * (@old_config), one queued for the next reconfiguration (@future_config; if
+ * there is one and the user wants to reconfigure once again, we just free the
+ * previous queued config and replace it with the new one) and finally a config
+ * being parsed (@new_config). The stored @old_config is also used for undo
+ * reconfiguration, which works in a similar way. Reconfiguration could also
+ * have timeout (using @config_timer) and undo is automatically called if the
+ * new configuration is not confirmed later. The new config (@new_config) and
+ * associated linear pool (@cfg_mem) is non-NULL only during parsing.
*
- * Loading of new configuration is very simple: just call config_alloc()
- * to get a new &config structure, then use config_parse() to parse a
- * configuration file and fill all fields of the structure
- * and finally ask the config manager to switch to the new
- * config by calling config_commit().
+ * Loading of new configuration is very simple: just call config_alloc() to get
+ * a new &config structure, then use config_parse() to parse a configuration
+ * file and fill all fields of the structure and finally ask the config manager
+ * to switch to the new config by calling config_commit().
*
* CLI commands are parsed in a very similar way -- there is also a stripped-down
* &config structure associated with them and they are lex-ed and parsed by the
#include "conf/conf.h"
#include "filter/filter.h"
+
static jmp_buf conf_jmpbuf;
struct config *config, *new_config;
* further use. Returns a pointer to the structure.
*/
struct config *
-config_alloc(byte *name)
+config_alloc(const char *name)
{
pool *p = rp_new(&root_pool, "Config");
- linpool *l = lp_new(p, 4080);
+ linpool *l = lp_new_default(p);
struct config *c = lp_allocz(l, sizeof(struct config));
+ /* Duplication of name string in local linear pool */
+ uint nlen = strlen(name) + 1;
+ char *ndup = lp_allocu(l, nlen);
+ memcpy(ndup, name, nlen);
+
+ init_list(&c->tests);
+ init_list(&c->symbols);
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
c->pool = p;
- cfg_mem = c->mem = l;
- c->file_name = cfg_strdup(name);
- c->load_time = now;
- c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600};
- c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0};
+ c->mem = l;
+ c->file_name = ndup;
+ c->load_time = current_time();
+ c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
+ c->tf_base = c->tf_log = TM_ISO_LONG_MS;
c->gr_wait = DEFAULT_GR_WAIT;
return c;
int
config_parse(struct config *c)
{
+ int done = 0;
DBG("Parsing configuration file `%s'\n", c->file_name);
new_config = c;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
- return 0;
+ goto cleanup;
+
cf_lex_init(0, c);
sysdep_preconfig(c);
protos_preconfig(c);
rt_preconfig(c);
- roa_preconfig(c);
cf_parse();
- protos_postconfig(c);
+
if (EMPTY_LIST(c->protos))
cf_error("No protocol is specified in the config file");
-#ifdef IPV6
+
+ /*
if (!c->router_id)
- cf_error("Router ID must be configured manually on IPv6 routers");
-#endif
- return 1;
+ cf_error("Router ID must be configured manually");
+ */
+
+ done = 1;
+
+cleanup:
+ new_config = NULL;
+ cfg_mem = NULL;
+ return done;
}
/**
int
cli_parse(struct config *c)
{
+ int done = 0;
+ c->fallback = config;
new_config = c;
- c->sym_fallback = config->sym_hash;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
- return 0;
+ goto cleanup;
+
cf_lex_init(1, c);
cf_parse();
- return 1;
+ done = 1;
+
+cleanup:
+ c->fallback = NULL;
+ new_config = NULL;
+ cfg_mem = NULL;
+ return done;
}
/**
{
DBG("+++ deleting obstacle %d\n", c->obstacle_count);
c->obstacle_count--;
- if (!c->obstacle_count)
+ if (!c->obstacle_count && (c != config))
ev_schedule(config_event);
}
if (!old)
return 0;
- if (!ipa_equal(old->listen_bgp_addr, new->listen_bgp_addr) ||
- (old->listen_bgp_port != new->listen_bgp_port) ||
- (old->listen_bgp_flags != new->listen_bgp_flags))
- log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD.");
-
if (!new->router_id)
{
new->router_id = old->router_id;
if (old_config && !config->shutdown)
log(L_INFO "Reconfiguring");
- /* This should not be necessary, but it seems there are some
- functions that access new_config instead of config */
- new_config = config;
-
if (old_config)
old_config->obstacle_count++;
+ DBG("filter_commit\n");
+ filter_commit(c, old_config);
DBG("sysdep_commit\n");
int force_restart = sysdep_commit(c, old_config);
DBG("global_commit\n");
force_restart |= global_commit(c, old_config);
DBG("rt_commit\n");
rt_commit(c, old_config);
- roa_commit(c, old_config);
DBG("protos_commit\n");
protos_commit(c, old_config, force_restart, type);
- /* Just to be sure nobody uses that now */
- new_config = NULL;
-
int obs = 0;
if (old_config)
obs = --old_config->obstacle_count;
* config_commit - commit a configuration
* @c: new configuration
* @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
- * @timeout: timeout for undo (or 0 for no timeout)
+ * @timeout: timeout for undo (in seconds; or 0 for no timeout)
*
* When a configuration is parsed and prepared for use, the
* config_commit() function starts the process of reconfiguration.
* are accepted.
*/
int
-config_commit(struct config *c, int type, int timeout)
+config_commit(struct config *c, int type, uint timeout)
{
if (shutting_down)
{
}
undo_available = 1;
- if (timeout > 0)
- tm_start(config_timer, timeout);
+ if (timeout)
+ tm_start(config_timer, timeout S);
else
tm_stop(config_timer);
* if it's been queued due to another reconfiguration being in progress now,
* %CONF_UNQUEUED if a scheduled reconfiguration is removed, %CONF_NOTHING
* if there is no relevant configuration to undo (the previous config request
- * was config_undo() too) or %CONF_SHUTDOWN if BIRD is in shutdown mode and
+ * was config_undo() too) or %CONF_SHUTDOWN if BIRD is in shutdown mode and
* no new configuration changes are accepted.
*/
int
return CONF_PROGRESS;
}
+int
+config_status(void)
+{
+ if (shutting_down)
+ return CONF_SHUTDOWN;
+
+ if (configuring)
+ return future_cftype ? CONF_QUEUED : CONF_PROGRESS;
+
+ return CONF_DONE;
+}
+
+btime
+config_timer_status(void)
+{
+ return tm_active(config_timer) ? tm_remains(config_timer) : -1;
+}
+
extern void cmd_reconfig_undo_notify(void);
static void
-config_timeout(struct timer *t)
+config_timeout(timer *t UNUSED)
{
log(L_INFO "Config timeout expired, starting undo");
cmd_reconfig_undo_notify();
* for switching to an empty configuration.
*/
void
-order_shutdown(void)
+order_shutdown(int gr)
{
struct config *c;
if (shutting_down)
return;
- log(L_INFO "Shutting down");
+ if (!gr)
+ log(L_INFO "Shutting down");
+ else
+ log(L_INFO "Shutting down for graceful restart");
+
c = lp_alloc(config->mem, sizeof(struct config));
memcpy(c, config, sizeof(struct config));
init_list(&c->protos);
init_list(&c->tables);
c->shutdown = 1;
+ c->gr_down = gr;
config_commit(c, RECONFIG_HARD, 0);
shutting_down = 1;
* error in the configuration.
*/
void
-cf_error(char *msg, ...)
+cf_error(const char *msg, ...)
{
char buf[1024];
va_list args;
va_start(args, msg);
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
strcpy(buf, "<bug: error message too long>");
+ va_end(args);
new_config->err_msg = cfg_strdup(buf);
new_config->err_lino = ifs->lino;
+ new_config->err_chno = ifs->chno - ifs->toklen + 1;
new_config->err_file_name = ifs->file_name;
cf_lex_unwind();
longjmp(conf_jmpbuf, 1);
* and we want to preserve it for further use.
*/
char *
-cfg_strdup(char *c)
+cfg_strdup(const char *c)
{
int l = strlen(c) + 1;
char *z = cfg_allocu(l);