Implements undo command and optional timeout for configuration
Several new configure command variants: configure undo - undo last reconfiguration configure timeout - configure with scheduled undo if not confirmed in timeout configure confirm - confirm last configuration configure check - just parse and validate config file
This commit is contained in:
parent
80a9cadc76
commit
a92cf57dd6
16 changed files with 407 additions and 115 deletions
243
conf/conf.c
243
conf/conf.c
|
@ -21,9 +21,12 @@
|
||||||
* There can exist up to four different configurations at one time: an active
|
* There can exist up to four different configurations at one time: an active
|
||||||
* one (pointed to by @config), configuration we are just switching from
|
* one (pointed to by @config), configuration we are just switching from
|
||||||
* (@old_config), one queued for the next reconfiguration (@future_config;
|
* (@old_config), one queued for the next reconfiguration (@future_config;
|
||||||
* if it's non-%NULL and the user wants to reconfigure once again, we just
|
* 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
|
* free the previous queued config and replace it with the new one) and
|
||||||
* finally a config being parsed (@new_config).
|
* 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.
|
||||||
*
|
*
|
||||||
* Loading of new configuration is very simple: just call config_alloc()
|
* Loading of new configuration is very simple: just call config_alloc()
|
||||||
* to get a new &config structure, then use config_parse() to parse a
|
* to get a new &config structure, then use config_parse() to parse a
|
||||||
|
@ -55,10 +58,23 @@
|
||||||
|
|
||||||
static jmp_buf conf_jmpbuf;
|
static jmp_buf conf_jmpbuf;
|
||||||
|
|
||||||
struct config *config, *new_config, *old_config, *future_config;
|
struct config *config, *new_config;
|
||||||
static event *config_event;
|
|
||||||
int shutting_down, future_type;
|
static struct config *old_config; /* Old configuration */
|
||||||
bird_clock_t boot_time;
|
static struct config *future_config; /* New config held here if recon requested during recon */
|
||||||
|
static int old_cftype; /* Type of transition old_config -> config (RECONFIG_SOFT/HARD) */
|
||||||
|
static int future_cftype; /* Type of scheduled transition, may also be RECONFIG_UNDO */
|
||||||
|
/* Note that when future_cftype is RECONFIG_UNDO, then future_config is NULL,
|
||||||
|
therefore proper check for future scheduled config checks future_cftype */
|
||||||
|
|
||||||
|
static event *config_event; /* Event for finalizing reconfiguration */
|
||||||
|
static timer *config_timer; /* Timer for scheduled configuration rollback */
|
||||||
|
|
||||||
|
/* These are public just for cmd_show_status(), should not be accessed elsewhere */
|
||||||
|
int shutting_down; /* Shutdown requested, do not accept new config changes */
|
||||||
|
int configuring; /* Reconfiguration is running */
|
||||||
|
int undo_available; /* Undo was not requested from last reconfiguration */
|
||||||
|
/* Note that both shutting_down and undo_available are related to requests, not processing */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* config_alloc - allocate a new configuration
|
* config_alloc - allocate a new configuration
|
||||||
|
@ -82,8 +98,6 @@ config_alloc(byte *name)
|
||||||
c->load_time = now;
|
c->load_time = now;
|
||||||
c->tf_base.fmt1 = c->tf_log.fmt1 = "%d-%m-%Y %T";
|
c->tf_base.fmt1 = c->tf_log.fmt1 = "%d-%m-%Y %T";
|
||||||
|
|
||||||
if (!boot_time)
|
|
||||||
boot_time = now;
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +168,7 @@ cli_parse(struct config *c)
|
||||||
void
|
void
|
||||||
config_free(struct config *c)
|
config_free(struct config *c)
|
||||||
{
|
{
|
||||||
|
if (c)
|
||||||
rfree(c->pool);
|
rfree(c->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,10 +185,7 @@ config_del_obstacle(struct config *c)
|
||||||
DBG("+++ deleting obstacle %d\n", c->obstacle_count);
|
DBG("+++ deleting obstacle %d\n", c->obstacle_count);
|
||||||
c->obstacle_count--;
|
c->obstacle_count--;
|
||||||
if (!c->obstacle_count)
|
if (!c->obstacle_count)
|
||||||
{
|
|
||||||
ASSERT(config_event);
|
|
||||||
ev_schedule(config_event);
|
ev_schedule(config_event);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -197,16 +209,31 @@ global_commit(struct config *new, struct config *old)
|
||||||
static int
|
static int
|
||||||
config_do_commit(struct config *c, int type)
|
config_do_commit(struct config *c, int type)
|
||||||
{
|
{
|
||||||
int force_restart, nobs;
|
if (type == RECONFIG_UNDO)
|
||||||
|
{
|
||||||
|
c = old_config;
|
||||||
|
type = old_cftype;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
config_free(old_config);
|
||||||
|
|
||||||
DBG("do_commit\n");
|
|
||||||
old_config = config;
|
old_config = config;
|
||||||
config = new_config = c;
|
old_cftype = type;
|
||||||
|
config = c;
|
||||||
|
|
||||||
|
configuring = 1;
|
||||||
|
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)
|
if (old_config)
|
||||||
old_config->obstacle_count++;
|
old_config->obstacle_count++;
|
||||||
|
|
||||||
DBG("sysdep_commit\n");
|
DBG("sysdep_commit\n");
|
||||||
force_restart = sysdep_commit(c, old_config);
|
int force_restart = sysdep_commit(c, old_config);
|
||||||
DBG("global_commit\n");
|
DBG("global_commit\n");
|
||||||
force_restart |= global_commit(c, old_config);
|
force_restart |= global_commit(c, old_config);
|
||||||
DBG("rt_commit\n");
|
DBG("rt_commit\n");
|
||||||
|
@ -214,38 +241,38 @@ config_do_commit(struct config *c, int type)
|
||||||
roa_commit(c, old_config);
|
roa_commit(c, old_config);
|
||||||
DBG("protos_commit\n");
|
DBG("protos_commit\n");
|
||||||
protos_commit(c, old_config, force_restart, type);
|
protos_commit(c, old_config, force_restart, type);
|
||||||
new_config = NULL; /* Just to be sure nobody uses that now */
|
|
||||||
|
/* Just to be sure nobody uses that now */
|
||||||
|
new_config = NULL;
|
||||||
|
|
||||||
|
int obs = 0;
|
||||||
if (old_config)
|
if (old_config)
|
||||||
nobs = --old_config->obstacle_count;
|
obs = --old_config->obstacle_count;
|
||||||
else
|
|
||||||
nobs = 0;
|
DBG("do_commit finished with %d obstacles remaining\n", obs);
|
||||||
DBG("do_commit finished with %d obstacles remaining\n", nobs);
|
return !obs;
|
||||||
return !nobs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_done(void *unused UNUSED)
|
config_done(void *unused UNUSED)
|
||||||
{
|
{
|
||||||
struct config *c;
|
|
||||||
|
|
||||||
DBG("config_done\n");
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
if (config->shutdown)
|
if (config->shutdown)
|
||||||
sysdep_shutdown_done();
|
sysdep_shutdown_done();
|
||||||
log(L_INFO "Reconfigured");
|
|
||||||
|
configuring = 0;
|
||||||
if (old_config)
|
if (old_config)
|
||||||
|
log(L_INFO "Reconfigured");
|
||||||
|
|
||||||
|
if (future_cftype)
|
||||||
{
|
{
|
||||||
config_free(old_config);
|
int type = future_cftype;
|
||||||
old_config = NULL;
|
struct config *conf = future_config;
|
||||||
}
|
future_cftype = RECONFIG_NONE;
|
||||||
if (!future_config)
|
|
||||||
break;
|
|
||||||
c = future_config;
|
|
||||||
future_config = NULL;
|
future_config = NULL;
|
||||||
|
|
||||||
log(L_INFO "Reconfiguring to queued configuration");
|
log(L_INFO "Reconfiguring to queued configuration");
|
||||||
if (!config_do_commit(c, future_type))
|
if (config_do_commit(conf, type))
|
||||||
break;
|
config_done(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +280,7 @@ config_done(void *unused UNUSED)
|
||||||
* config_commit - commit a configuration
|
* config_commit - commit a configuration
|
||||||
* @c: new configuration
|
* @c: new configuration
|
||||||
* @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
|
* @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
|
||||||
|
* @timeout: timeout for undo (or 0 for no timeout)
|
||||||
*
|
*
|
||||||
* When a configuration is parsed and prepared for use, the
|
* When a configuration is parsed and prepared for use, the
|
||||||
* config_commit() function starts the process of reconfiguration.
|
* config_commit() function starts the process of reconfiguration.
|
||||||
|
@ -265,6 +293,10 @@ config_done(void *unused UNUSED)
|
||||||
* using config_del_obstacle(), the old configuration is freed and
|
* using config_del_obstacle(), the old configuration is freed and
|
||||||
* everything runs according to the new one.
|
* everything runs according to the new one.
|
||||||
*
|
*
|
||||||
|
* When @timeout is nonzero, the undo timer is activated with given
|
||||||
|
* timeout. The timer is deactivated when config_commit(),
|
||||||
|
* config_confirm() or config_undo() is called.
|
||||||
|
*
|
||||||
* Result: %CONF_DONE if the configuration has been accepted immediately,
|
* Result: %CONF_DONE if the configuration has been accepted immediately,
|
||||||
* %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
|
* %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
|
||||||
* if it's been queued due to another reconfiguration being in progress now
|
* if it's been queued due to another reconfiguration being in progress now
|
||||||
|
@ -272,49 +304,147 @@ config_done(void *unused UNUSED)
|
||||||
* are accepted.
|
* are accepted.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
config_commit(struct config *c, int type)
|
config_commit(struct config *c, int type, int timeout)
|
||||||
{
|
{
|
||||||
if (!config) /* First-time configuration */
|
if (shutting_down)
|
||||||
{
|
{
|
||||||
config_do_commit(c, RECONFIG_HARD);
|
|
||||||
return CONF_DONE;
|
|
||||||
}
|
|
||||||
if (old_config) /* Reconfiguration already in progress */
|
|
||||||
{
|
|
||||||
if (shutting_down == 2)
|
|
||||||
{
|
|
||||||
log(L_INFO "New configuration discarded due to shutdown");
|
|
||||||
config_free(c);
|
config_free(c);
|
||||||
return CONF_SHUTDOWN;
|
return CONF_SHUTDOWN;
|
||||||
}
|
}
|
||||||
if (future_config)
|
|
||||||
|
undo_available = 1;
|
||||||
|
if (timeout > 0)
|
||||||
|
tm_start(config_timer, timeout);
|
||||||
|
else
|
||||||
|
tm_stop(config_timer);
|
||||||
|
|
||||||
|
if (configuring)
|
||||||
|
{
|
||||||
|
if (future_cftype)
|
||||||
{
|
{
|
||||||
log(L_INFO "Queueing new configuration, ignoring the one already queued");
|
log(L_INFO "Queueing new configuration, ignoring the one already queued");
|
||||||
config_free(future_config);
|
config_free(future_config);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
log(L_INFO "Queued new configuration");
|
log(L_INFO "Queueing new configuration");
|
||||||
|
|
||||||
|
future_cftype = type;
|
||||||
future_config = c;
|
future_config = c;
|
||||||
future_type = type;
|
|
||||||
return CONF_QUEUED;
|
return CONF_QUEUED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shutting_down)
|
|
||||||
log(L_INFO "Reconfiguring");
|
|
||||||
|
|
||||||
if (config_do_commit(c, type))
|
if (config_do_commit(c, type))
|
||||||
{
|
{
|
||||||
config_done(NULL);
|
config_done(NULL);
|
||||||
return CONF_DONE;
|
return CONF_DONE;
|
||||||
}
|
}
|
||||||
if (!config_event)
|
return CONF_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config_confirm - confirm a commited configuration
|
||||||
|
*
|
||||||
|
* When the undo timer is activated by config_commit() with nonzero timeout,
|
||||||
|
* this function can be used to deactivate it and therefore confirm
|
||||||
|
* the current configuration.
|
||||||
|
*
|
||||||
|
* Result: %CONF_CONFIRM when the current configuration is confirmed,
|
||||||
|
* %CONF_NONE when there is nothing to confirm (i.e. undo timer is not active).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
config_confirm(void)
|
||||||
|
{
|
||||||
|
if (config_timer->expires == 0)
|
||||||
|
return CONF_NOTHING;
|
||||||
|
|
||||||
|
tm_stop(config_timer);
|
||||||
|
|
||||||
|
return CONF_CONFIRM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config_undo - undo a configuration
|
||||||
|
*
|
||||||
|
* Function config_undo() can be used to change the current
|
||||||
|
* configuration back to stored %old_config. If no reconfiguration is
|
||||||
|
* running, this stored configuration is commited in the same way as a
|
||||||
|
* new configuration in config_commit(). If there is already a
|
||||||
|
* reconfiguration in progress and no next reconfiguration is
|
||||||
|
* scheduled, then the undo is scheduled for later processing as
|
||||||
|
* usual, but if another reconfiguration is already scheduled, then
|
||||||
|
* such reconfiguration is removed instead (i.e. undo is applied on
|
||||||
|
* the last commit that scheduled it).
|
||||||
|
*
|
||||||
|
* Result: %CONF_DONE if the configuration has been accepted immediately,
|
||||||
|
* %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
|
||||||
|
* 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
|
||||||
|
* no new configuration changes are accepted.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
config_undo(void)
|
||||||
|
{
|
||||||
|
if (shutting_down)
|
||||||
|
return CONF_SHUTDOWN;
|
||||||
|
|
||||||
|
if (!undo_available || !old_config)
|
||||||
|
return CONF_NOTHING;
|
||||||
|
|
||||||
|
undo_available = 0;
|
||||||
|
tm_stop(config_timer);
|
||||||
|
|
||||||
|
if (configuring)
|
||||||
{
|
{
|
||||||
config_event = ev_new(&root_pool);
|
if (future_cftype)
|
||||||
config_event->hook = config_done;
|
{
|
||||||
|
config_free(future_config);
|
||||||
|
future_config = NULL;
|
||||||
|
|
||||||
|
log(L_INFO "Removing queued configuration");
|
||||||
|
future_cftype = RECONFIG_NONE;
|
||||||
|
return CONF_UNQUEUED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log(L_INFO "Queueing undo configuration");
|
||||||
|
future_cftype = RECONFIG_UNDO;
|
||||||
|
return CONF_QUEUED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_do_commit(NULL, RECONFIG_UNDO))
|
||||||
|
{
|
||||||
|
config_done(NULL);
|
||||||
|
return CONF_DONE;
|
||||||
}
|
}
|
||||||
return CONF_PROGRESS;
|
return CONF_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void cmd_reconfig_undo_notify(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
config_timeout(struct timer *t)
|
||||||
|
{
|
||||||
|
log(L_INFO "Config timeout expired, starting undo");
|
||||||
|
cmd_reconfig_undo_notify();
|
||||||
|
|
||||||
|
int r = config_undo();
|
||||||
|
if (r < 0)
|
||||||
|
log(L_ERR "Undo request failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
config_init(void)
|
||||||
|
{
|
||||||
|
config_event = ev_new(&root_pool);
|
||||||
|
config_event->hook = config_done;
|
||||||
|
|
||||||
|
config_timer = tm_new(&root_pool);
|
||||||
|
config_timer->hook = config_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* order_shutdown - order BIRD shutdown
|
* order_shutdown - order BIRD shutdown
|
||||||
*
|
*
|
||||||
|
@ -328,15 +458,16 @@ order_shutdown(void)
|
||||||
|
|
||||||
if (shutting_down)
|
if (shutting_down)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log(L_INFO "Shutting down");
|
log(L_INFO "Shutting down");
|
||||||
c = lp_alloc(config->mem, sizeof(struct config));
|
c = lp_alloc(config->mem, sizeof(struct config));
|
||||||
memcpy(c, config, sizeof(struct config));
|
memcpy(c, config, sizeof(struct config));
|
||||||
init_list(&c->protos);
|
init_list(&c->protos);
|
||||||
init_list(&c->tables);
|
init_list(&c->tables);
|
||||||
c->shutdown = 1;
|
c->shutdown = 1;
|
||||||
|
|
||||||
|
config_commit(c, RECONFIG_HARD, 0);
|
||||||
shutting_down = 1;
|
shutting_down = 1;
|
||||||
config_commit(c, RECONFIG_HARD);
|
|
||||||
shutting_down = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
23
conf/conf.h
23
conf/conf.h
|
@ -54,28 +54,33 @@ struct config {
|
||||||
/* Please don't use these variables in protocols. Use proto_config->global instead. */
|
/* Please don't use these variables in protocols. Use proto_config->global instead. */
|
||||||
extern struct config *config; /* Currently active configuration */
|
extern struct config *config; /* Currently active configuration */
|
||||||
extern struct config *new_config; /* Configuration being parsed */
|
extern struct config *new_config; /* Configuration being parsed */
|
||||||
extern struct config *old_config; /* Old configuration when reconfiguration is in progress */
|
|
||||||
extern struct config *future_config; /* New config held here if recon requested during recon */
|
|
||||||
|
|
||||||
extern int shutting_down;
|
|
||||||
extern bird_clock_t boot_time;
|
|
||||||
|
|
||||||
struct config *config_alloc(byte *name);
|
struct config *config_alloc(byte *name);
|
||||||
int config_parse(struct config *);
|
int config_parse(struct config *);
|
||||||
int cli_parse(struct config *);
|
int cli_parse(struct config *);
|
||||||
void config_free(struct config *);
|
void config_free(struct config *);
|
||||||
int config_commit(struct config *, int type);
|
int config_commit(struct config *, int type, int timeout);
|
||||||
#define RECONFIG_HARD 0
|
int config_confirm(void);
|
||||||
#define RECONFIG_SOFT 1
|
int config_undo(void);
|
||||||
|
void config_init(void);
|
||||||
void cf_error(char *msg, ...) NORET;
|
void cf_error(char *msg, ...) NORET;
|
||||||
void config_add_obstacle(struct config *);
|
void config_add_obstacle(struct config *);
|
||||||
void config_del_obstacle(struct config *);
|
void config_del_obstacle(struct config *);
|
||||||
void order_shutdown(void);
|
void order_shutdown(void);
|
||||||
|
|
||||||
|
#define RECONFIG_NONE 0
|
||||||
|
#define RECONFIG_HARD 1
|
||||||
|
#define RECONFIG_SOFT 2
|
||||||
|
#define RECONFIG_UNDO 3
|
||||||
|
|
||||||
#define CONF_DONE 0
|
#define CONF_DONE 0
|
||||||
#define CONF_PROGRESS 1
|
#define CONF_PROGRESS 1
|
||||||
#define CONF_QUEUED 2
|
#define CONF_QUEUED 2
|
||||||
#define CONF_SHUTDOWN 3
|
#define CONF_UNQUEUED 3
|
||||||
|
#define CONF_CONFIRM 4
|
||||||
|
#define CONF_SHUTDOWN -1
|
||||||
|
#define CONF_NOTHING -2
|
||||||
|
|
||||||
|
|
||||||
/* Pools */
|
/* Pools */
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ m4_divert(-1)m4_dnl
|
||||||
m4_define(CF_CLI, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$3", "$4", 1 },
|
m4_define(CF_CLI, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$3", "$4", 1 },
|
||||||
m4_divert(-1)')
|
m4_divert(-1)')
|
||||||
|
|
||||||
|
m4_define(CF_CLI_CMD, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1 },
|
||||||
|
m4_divert(-1)')
|
||||||
|
|
||||||
m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
|
m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
|
||||||
m4_divert(-1)')
|
m4_divert(-1)')
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL
|
||||||
m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
|
m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
|
||||||
m4_divert(3)CF_ADDTO(cli_cmd, CF_cmd)
|
m4_divert(3)CF_ADDTO(cli_cmd, CF_cmd)
|
||||||
CF_cmd: $1 $2 END')
|
CF_cmd: $1 $2 END')
|
||||||
|
m4_define(CF_CLI_CMD, `')
|
||||||
m4_define(CF_CLI_HELP, `')
|
m4_define(CF_CLI_HELP, `')
|
||||||
|
|
||||||
# ENUM declarations are ignored
|
# ENUM declarations are ignored
|
||||||
|
|
|
@ -702,19 +702,48 @@ This argument can be omitted if there exists only a single instance.
|
||||||
<tag>flush roa [table <m/t/>]</tag>
|
<tag>flush roa [table <m/t/>]</tag>
|
||||||
Remove all dynamic ROA entries from a ROA table.
|
Remove all dynamic ROA entries from a ROA table.
|
||||||
|
|
||||||
<tag>configure [soft] ["<m/config file/"]</tag>
|
<tag>configure [soft] ["<m/config file/"] [timeout [<m/num/]]</tag>
|
||||||
Reload configuration from a given file. BIRD will smoothly
|
Reload configuration from a given file. BIRD will smoothly
|
||||||
switch itself to the new configuration, protocols are
|
switch itself to the new configuration, protocols are
|
||||||
reconfigured if possible, restarted otherwise. Changes in
|
reconfigured if possible, restarted otherwise. Changes in
|
||||||
filters usually lead to restart of affected protocols. If
|
filters usually lead to restart of affected protocols.
|
||||||
<cf/soft/ option is used, changes in filters does not cause
|
|
||||||
|
If <cf/soft/ option is used, changes in filters does not cause
|
||||||
BIRD to restart affected protocols, therefore already accepted
|
BIRD to restart affected protocols, therefore already accepted
|
||||||
routes (according to old filters) would be still propagated,
|
routes (according to old filters) would be still propagated,
|
||||||
but new routes would be processed according to the new
|
but new routes would be processed according to the new
|
||||||
filters.
|
filters.
|
||||||
|
|
||||||
|
If <cf/timeout/ option is used, config timer is activated. The
|
||||||
|
new configuration could be either confirmed using
|
||||||
|
<cf/configure confirm/ command, or it will be reverted to the
|
||||||
|
old one when the config timer expires. This is useful for cases
|
||||||
|
when reconfiguration breaks current routing and a router becames
|
||||||
|
inaccessible for an administrator. The config timeout expiration is
|
||||||
|
equivalent to <cf/configure undo/ command. The timeout duration
|
||||||
|
could be specified, default is 300 s.
|
||||||
|
|
||||||
|
<tag>configure confirm</tag>
|
||||||
|
Deactivate the config undo timer and therefore confirm the current
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
<tag>configure undo</tag>
|
||||||
|
Undo the last configuration change and smoothly switch back to
|
||||||
|
the previous (stored) configuration. If the last configuration
|
||||||
|
change was soft, the undo change is also soft. There is only
|
||||||
|
one level of undo, but in some specific cases when several
|
||||||
|
reconfiguration requests are given immediately in a row and
|
||||||
|
the intermediate ones are skipped then the undo also skips them back.
|
||||||
|
|
||||||
|
<tag>configure check ["<m/config file/"]</tag>
|
||||||
|
Read and parse given config file, but do not use it. useful
|
||||||
|
for checking syntactic and some semantic validity of an config
|
||||||
|
file.
|
||||||
|
|
||||||
<tag>enable|disable|restart <m/name/|"<m/pattern/"|all</tag>
|
<tag>enable|disable|restart <m/name/|"<m/pattern/"|all</tag>
|
||||||
Enable, disable or restart a given protocol instance, instances matching the <cf><m/pattern/</cf> or <cf/all/ instances.
|
Enable, disable or restart a given protocol instance,
|
||||||
|
instances matching the <cf><m/pattern/</cf> or
|
||||||
|
<cf/all/ instances.
|
||||||
|
|
||||||
<tag>reload [in|out] <m/name/|"<m/pattern/"|all</tag>
|
<tag>reload [in|out] <m/name/|"<m/pattern/"|all</tag>
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,12 @@ Reply codes of BIRD command-line interface
|
||||||
0014 Route count
|
0014 Route count
|
||||||
0015 Reloading
|
0015 Reloading
|
||||||
0016 Access restricted
|
0016 Access restricted
|
||||||
|
0017 Reconfiguration already in progress, removing queued config
|
||||||
|
0018 Reconfiguration confirmed
|
||||||
|
0019 Nothing to do (configure undo/confirm)
|
||||||
|
0020 Configuration OK
|
||||||
|
0021 Undo requested
|
||||||
|
0022 Undo scheduled
|
||||||
|
|
||||||
1000 BIRD version
|
1000 BIRD version
|
||||||
1001 Interface list
|
1001 Interface list
|
||||||
|
|
18
nest/cli.c
18
nest/cli.c
|
@ -122,6 +122,7 @@ cli_printf(cli *c, int code, char *msg, ...)
|
||||||
va_list args;
|
va_list args;
|
||||||
byte buf[CLI_LINE_SIZE];
|
byte buf[CLI_LINE_SIZE];
|
||||||
int cd = code;
|
int cd = code;
|
||||||
|
int errcode;
|
||||||
int size, cnt;
|
int size, cnt;
|
||||||
|
|
||||||
if (cd < 0)
|
if (cd < 0)
|
||||||
|
@ -131,16 +132,26 @@ cli_printf(cli *c, int code, char *msg, ...)
|
||||||
size = bsprintf(buf, " ");
|
size = bsprintf(buf, " ");
|
||||||
else
|
else
|
||||||
size = bsprintf(buf, "%04d-", cd);
|
size = bsprintf(buf, "%04d-", cd);
|
||||||
|
errcode = -8000;
|
||||||
|
}
|
||||||
|
else if (cd == CLI_ASYNC_CODE)
|
||||||
|
{
|
||||||
|
size = 1; buf[0] = '+';
|
||||||
|
errcode = cd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
size = bsprintf(buf, "%04d ", cd);
|
size = bsprintf(buf, "%04d ", cd);
|
||||||
|
errcode = 8000;
|
||||||
|
}
|
||||||
|
|
||||||
c->last_reply = cd;
|
c->last_reply = cd;
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args);
|
cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
if (cnt < 0)
|
if (cnt < 0)
|
||||||
{
|
{
|
||||||
cli_printf(c, code < 0 ? -8000 : 8000, "<line overflow>");
|
cli_printf(c, errcode, "<line overflow>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size += cnt;
|
size += cnt;
|
||||||
|
@ -385,12 +396,17 @@ cli_echo(unsigned int class, byte *msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hack for scheduled undo notification */
|
||||||
|
extern cli *cmd_reconfig_stored_cli;
|
||||||
|
|
||||||
void
|
void
|
||||||
cli_free(cli *c)
|
cli_free(cli *c)
|
||||||
{
|
{
|
||||||
cli_set_log_echo(c, 0, 0);
|
cli_set_log_echo(c, 0, 0);
|
||||||
if (c->cleanup)
|
if (c->cleanup)
|
||||||
c->cleanup(c);
|
c->cleanup(c);
|
||||||
|
if (c == cmd_reconfig_stored_cli)
|
||||||
|
cmd_reconfig_stored_cli = NULL;
|
||||||
rfree(c->pool);
|
rfree(c->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ typedef struct cli {
|
||||||
extern pool *cli_pool;
|
extern pool *cli_pool;
|
||||||
extern struct cli *this_cli; /* Used during parsing */
|
extern struct cli *this_cli; /* Used during parsing */
|
||||||
|
|
||||||
|
#define CLI_ASYNC_CODE 10000
|
||||||
|
|
||||||
/* Functions to be called by command handlers */
|
/* Functions to be called by command handlers */
|
||||||
|
|
||||||
void cli_printf(cli *, int, char *, ...);
|
void cli_printf(cli *, int, char *, ...);
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
|
||||||
|
extern int shutting_down;
|
||||||
|
extern int configuring;
|
||||||
|
|
||||||
void
|
void
|
||||||
cmd_show_status(void)
|
cmd_show_status(void)
|
||||||
{
|
{
|
||||||
|
@ -27,9 +30,10 @@ cmd_show_status(void)
|
||||||
cli_msg(-1011, "Last reboot on %s", tim);
|
cli_msg(-1011, "Last reboot on %s", tim);
|
||||||
tm_format_datetime(tim, &config->tf_base, config->load_time);
|
tm_format_datetime(tim, &config->tf_base, config->load_time);
|
||||||
cli_msg(-1011, "Last reconfiguration on %s", tim);
|
cli_msg(-1011, "Last reconfiguration on %s", tim);
|
||||||
|
|
||||||
if (shutting_down)
|
if (shutting_down)
|
||||||
cli_msg(13, "Shutdown in progress");
|
cli_msg(13, "Shutdown in progress");
|
||||||
else if (old_config)
|
else if (configuring)
|
||||||
cli_msg(13, "Reconfiguration in progress");
|
cli_msg(13, "Reconfiguration in progress");
|
||||||
else
|
else
|
||||||
cli_msg(13, "Daemon is up and running");
|
cli_msg(13, "Daemon is up and running");
|
||||||
|
|
|
@ -516,7 +516,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
|
p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
|
||||||
p->cf_new = nc;
|
p->cf_new = nc;
|
||||||
}
|
}
|
||||||
else if (!shutting_down)
|
else if (!new->shutdown)
|
||||||
{
|
{
|
||||||
log(L_INFO "Removing protocol %s", p->name);
|
log(L_INFO "Removing protocol %s", p->name);
|
||||||
p->down_code = PDC_CF_REMOVE;
|
p->down_code = PDC_CF_REMOVE;
|
||||||
|
@ -537,7 +537,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
|
||||||
WALK_LIST(nc, new->protos)
|
WALK_LIST(nc, new->protos)
|
||||||
if (!nc->proto)
|
if (!nc->proto)
|
||||||
{
|
{
|
||||||
if (old_config) /* Not a first-time configuration */
|
if (old) /* Not a first-time configuration */
|
||||||
log(L_INFO "Adding protocol %s", nc->name);
|
log(L_INFO "Adding protocol %s", nc->name);
|
||||||
proto_init(nc);
|
proto_init(nc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ CF_HDR
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
|
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
|
||||||
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, BASE, NAME)
|
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, BASE, NAME, CONFIRM, UNDO, CHECK, TIMEOUT)
|
||||||
|
|
||||||
%type <i> log_mask log_mask_list log_cat
|
%type <i> log_mask log_mask_list log_cat cfg_timeout
|
||||||
%type <g> log_file
|
%type <g> log_file
|
||||||
%type <t> cfg_name
|
%type <t> cfg_name
|
||||||
%type <tf> timeformat_which
|
%type <tf> timeformat_which
|
||||||
|
@ -104,13 +104,26 @@ timeformat_base:
|
||||||
|
|
||||||
/* Unix specific commands */
|
/* Unix specific commands */
|
||||||
|
|
||||||
CF_CLI_HELP(CONFIGURE, [soft] [\"<file>\"], [[Reload configuration]])
|
CF_CLI_HELP(CONFIGURE, ..., [[Reload configuration]])
|
||||||
|
|
||||||
CF_CLI(CONFIGURE, cfg_name, [\"<file>\"], [[Reload configuration]])
|
CF_CLI(CONFIGURE, cfg_name cfg_timeout, [\"<file>\"] [timeout [<sec>]], [[Reload configuration]])
|
||||||
{ cmd_reconfig($2, RECONFIG_HARD); } ;
|
{ cmd_reconfig($2, RECONFIG_HARD, $3); } ;
|
||||||
|
|
||||||
CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore changes in filters]])
|
CF_CLI(CONFIGURE SOFT, cfg_name cfg_timeout, [\"<file>\"] [timeout [<sec>]], [[Reload configuration and ignore changes in filters]])
|
||||||
{ cmd_reconfig($3, RECONFIG_SOFT); } ;
|
{ cmd_reconfig($3, RECONFIG_SOFT, $4); } ;
|
||||||
|
|
||||||
|
/* Hack to get input completion for 'timeout' */
|
||||||
|
CF_CLI_CMD(CONFIGURE TIMEOUT, [<sec>], [[Reload configuration with undo timeout]])
|
||||||
|
CF_CLI_CMD(CONFIGURE SOFT TIMEOUT, [<sec>], [[Reload configuration with undo timeout]])
|
||||||
|
|
||||||
|
CF_CLI(CONFIGURE CONFIRM,,, [[Confirm last configuration change - deactivate undo timeout]])
|
||||||
|
{ cmd_reconfig_confirm(); } ;
|
||||||
|
|
||||||
|
CF_CLI(CONFIGURE UNDO,,, [[Undo last configuration change]])
|
||||||
|
{ cmd_reconfig_undo(); } ;
|
||||||
|
|
||||||
|
CF_CLI(CONFIGURE CHECK, cfg_name, [\"<file>\"], [[Parse configuration and check its validity]])
|
||||||
|
{ cmd_check_config($3); } ;
|
||||||
|
|
||||||
CF_CLI(DOWN,,, [[Shut the daemon down]])
|
CF_CLI(DOWN,,, [[Shut the daemon down]])
|
||||||
{ cmd_shutdown(); } ;
|
{ cmd_shutdown(); } ;
|
||||||
|
@ -120,6 +133,12 @@ cfg_name:
|
||||||
| TEXT
|
| TEXT
|
||||||
;
|
;
|
||||||
|
|
||||||
|
cfg_timeout:
|
||||||
|
/* empty */ { $$ = 0; }
|
||||||
|
| TIMEOUT { $$ = UNIX_DEFAULT_CONFIGURE_TIMEOUT; }
|
||||||
|
| TIMEOUT expr { $$ = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
|
|
@ -121,7 +121,7 @@ static list near_timers, far_timers;
|
||||||
static bird_clock_t first_far_timer = TIME_INFINITY;
|
static bird_clock_t first_far_timer = TIME_INFINITY;
|
||||||
|
|
||||||
/* now must be different from 0, because 0 is a special value in timer->expires */
|
/* now must be different from 0, because 0 is a special value in timer->expires */
|
||||||
bird_clock_t now = 1, now_real;
|
bird_clock_t now = 1, now_real, boot_time;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_times_plain(void)
|
update_times_plain(void)
|
||||||
|
@ -1530,6 +1530,7 @@ io_init(void)
|
||||||
krt_io_init();
|
krt_io_init();
|
||||||
init_times();
|
init_times();
|
||||||
update_times();
|
update_times();
|
||||||
|
boot_time = now;
|
||||||
srandom((int) now_real);
|
srandom((int) now_real);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,7 +1558,7 @@ io_loop(void)
|
||||||
tm_shot();
|
tm_shot();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
timo.tv_sec = events ? 0 : tout - now;
|
timo.tv_sec = events ? 0 : MIN(tout - now, 3);
|
||||||
timo.tv_usec = 0;
|
timo.tv_usec = 0;
|
||||||
|
|
||||||
if (sock_recalc_fdsets_p)
|
if (sock_recalc_fdsets_p)
|
||||||
|
|
|
@ -900,7 +900,7 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
||||||
{
|
{
|
||||||
struct krt_proto *p = (struct krt_proto *) P;
|
struct krt_proto *p = (struct krt_proto *) P;
|
||||||
|
|
||||||
if (shutting_down)
|
if (config->shutdown)
|
||||||
return;
|
return;
|
||||||
if (!(net->n.flags & KRF_INSTALLED))
|
if (!(net->n.flags & KRF_INSTALLED))
|
||||||
old = NULL;
|
old = NULL;
|
||||||
|
|
|
@ -210,7 +210,7 @@ read_config(void)
|
||||||
else
|
else
|
||||||
die("Unable to open configuration file %s: %m", config_name);
|
die("Unable to open configuration file %s: %m", config_name);
|
||||||
}
|
}
|
||||||
config_commit(conf, RECONFIG_HARD);
|
config_commit(conf, RECONFIG_HARD, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -228,19 +228,17 @@ async_config(void)
|
||||||
config_free(conf);
|
config_free(conf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
config_commit(conf, RECONFIG_HARD);
|
config_commit(conf, RECONFIG_HARD, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static struct config *
|
||||||
cmd_reconfig(char *name, int type)
|
cmd_read_config(char *name)
|
||||||
{
|
{
|
||||||
struct config *conf;
|
struct config *conf;
|
||||||
|
|
||||||
if (cli_access_restricted())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
name = config_name;
|
name = config_name;
|
||||||
|
|
||||||
cli_msg(-2, "Reading configuration from %s", name);
|
cli_msg(-2, "Reading configuration from %s", name);
|
||||||
if (!unix_read_config(&conf, name))
|
if (!unix_read_config(&conf, name))
|
||||||
{
|
{
|
||||||
|
@ -249,24 +247,94 @@ cmd_reconfig(char *name, int type)
|
||||||
else
|
else
|
||||||
cli_msg(8002, "%s: %m", name);
|
cli_msg(8002, "%s: %m", name);
|
||||||
config_free(conf);
|
config_free(conf);
|
||||||
|
conf = NULL;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_check_config(char *name)
|
||||||
|
{
|
||||||
|
struct config *conf = cmd_read_config(name);
|
||||||
|
if (!conf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cli_msg(20, "Configuration OK");
|
||||||
|
config_free(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_reconfig_msg(int r)
|
||||||
|
{
|
||||||
|
switch (r)
|
||||||
{
|
{
|
||||||
switch (config_commit(conf, type))
|
case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
|
||||||
|
case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
|
||||||
|
case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
|
||||||
|
case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
|
||||||
|
case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
|
||||||
|
case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
|
||||||
|
case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hack for scheduled undo notification */
|
||||||
|
cli *cmd_reconfig_stored_cli;
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_reconfig_undo_notify(void)
|
||||||
|
{
|
||||||
|
if (cmd_reconfig_stored_cli)
|
||||||
{
|
{
|
||||||
case CONF_DONE:
|
cli *c = cmd_reconfig_stored_cli;
|
||||||
cli_msg(3, "Reconfigured.");
|
cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
|
||||||
break;
|
cli_write_trigger(c);
|
||||||
case CONF_PROGRESS:
|
|
||||||
cli_msg(4, "Reconfiguration in progress.");
|
|
||||||
break;
|
|
||||||
case CONF_SHUTDOWN:
|
|
||||||
cli_msg(6, "Reconfiguration ignored, shutting down.");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cli_msg(5, "Reconfiguration already in progress, queueing new config");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_reconfig(char *name, int type, int timeout)
|
||||||
|
{
|
||||||
|
if (cli_access_restricted())
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct config *conf = cmd_read_config(name);
|
||||||
|
if (!conf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int r = config_commit(conf, type, timeout);
|
||||||
|
|
||||||
|
if ((r >= 0) && (timeout > 0))
|
||||||
|
{
|
||||||
|
cmd_reconfig_stored_cli = this_cli;
|
||||||
|
cli_msg(-22, "Undo scheduled in %d s", timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd_reconfig_msg(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_reconfig_confirm(void)
|
||||||
|
{
|
||||||
|
if (cli_access_restricted())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int r = config_confirm();
|
||||||
|
cmd_reconfig_msg(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_reconfig_undo(void)
|
||||||
|
{
|
||||||
|
if (cli_access_restricted())
|
||||||
|
return;
|
||||||
|
|
||||||
|
cli_msg(-21, "Undo requested");
|
||||||
|
|
||||||
|
int r = config_undo();
|
||||||
|
cmd_reconfig_msg(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -623,6 +691,7 @@ main(int argc, char **argv)
|
||||||
rt_init();
|
rt_init();
|
||||||
if_init();
|
if_init();
|
||||||
roa_init();
|
roa_init();
|
||||||
|
config_init();
|
||||||
|
|
||||||
uid_t use_uid = get_uid(use_user);
|
uid_t use_uid = get_uid(use_user);
|
||||||
gid_t use_gid = get_gid(use_group);
|
gid_t use_gid = get_gid(use_group);
|
||||||
|
|
|
@ -32,6 +32,7 @@ void tm_dump_all(void);
|
||||||
|
|
||||||
extern bird_clock_t now; /* Relative, monotonic time in seconds */
|
extern bird_clock_t now; /* Relative, monotonic time in seconds */
|
||||||
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
|
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
|
||||||
|
extern bird_clock_t boot_time;
|
||||||
|
|
||||||
static inline bird_clock_t
|
static inline bird_clock_t
|
||||||
tm_remains(timer *t)
|
tm_remains(timer *t)
|
||||||
|
|
|
@ -19,9 +19,14 @@ extern char *bird_name;
|
||||||
void async_config(void);
|
void async_config(void);
|
||||||
void async_dump(void);
|
void async_dump(void);
|
||||||
void async_shutdown(void);
|
void async_shutdown(void);
|
||||||
void cmd_reconfig(char *name, int type);
|
void cmd_check_config(char *name);
|
||||||
|
void cmd_reconfig(char *name, int type, int timeout);
|
||||||
|
void cmd_reconfig_confirm(void);
|
||||||
|
void cmd_reconfig_undo(void);
|
||||||
void cmd_shutdown(void);
|
void cmd_shutdown(void);
|
||||||
|
|
||||||
|
#define UNIX_DEFAULT_CONFIGURE_TIMEOUT 300
|
||||||
|
|
||||||
/* io.c */
|
/* io.c */
|
||||||
|
|
||||||
volatile int async_config_flag;
|
volatile int async_config_flag;
|
||||||
|
|
Loading…
Reference in a new issue