mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										253
									
								
								conf/conf.c
									
									
									
									
									
								
							
							
						
						
									
										253
									
								
								conf/conf.c
									
									
									
									
									
								
							@@ -21,9 +21,12 @@
 | 
			
		||||
 * 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 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
 | 
			
		||||
 * 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()
 | 
			
		||||
 * to get a new &config structure, then use config_parse() to parse a
 | 
			
		||||
@@ -55,10 +58,23 @@
 | 
			
		||||
 | 
			
		||||
static jmp_buf conf_jmpbuf;
 | 
			
		||||
 | 
			
		||||
struct config *config, *new_config, *old_config, *future_config;
 | 
			
		||||
static event *config_event;
 | 
			
		||||
int shutting_down, future_type;
 | 
			
		||||
bird_clock_t boot_time;
 | 
			
		||||
struct config *config, *new_config;
 | 
			
		||||
 | 
			
		||||
static struct config *old_config;	/* Old configuration */
 | 
			
		||||
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
 | 
			
		||||
@@ -82,8 +98,6 @@ config_alloc(byte *name)
 | 
			
		||||
  c->load_time = now;
 | 
			
		||||
  c->tf_base.fmt1 = c->tf_log.fmt1 = "%d-%m-%Y %T";
 | 
			
		||||
 | 
			
		||||
  if (!boot_time)
 | 
			
		||||
    boot_time = now;
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -154,7 +168,8 @@ cli_parse(struct config *c)
 | 
			
		||||
void
 | 
			
		||||
config_free(struct config *c)
 | 
			
		||||
{
 | 
			
		||||
  rfree(c->pool);
 | 
			
		||||
  if (c)
 | 
			
		||||
    rfree(c->pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -170,10 +185,7 @@ config_del_obstacle(struct config *c)
 | 
			
		||||
  DBG("+++ deleting obstacle %d\n", c->obstacle_count);
 | 
			
		||||
  c->obstacle_count--;
 | 
			
		||||
  if (!c->obstacle_count)
 | 
			
		||||
    {
 | 
			
		||||
      ASSERT(config_event);
 | 
			
		||||
      ev_schedule(config_event);
 | 
			
		||||
    }
 | 
			
		||||
    ev_schedule(config_event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
@@ -197,16 +209,31 @@ global_commit(struct config *new, struct config *old)
 | 
			
		||||
static int
 | 
			
		||||
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;
 | 
			
		||||
  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)
 | 
			
		||||
    old_config->obstacle_count++;
 | 
			
		||||
 | 
			
		||||
  DBG("sysdep_commit\n");
 | 
			
		||||
  force_restart = sysdep_commit(c, old_config);
 | 
			
		||||
  int force_restart = sysdep_commit(c, old_config);
 | 
			
		||||
  DBG("global_commit\n");
 | 
			
		||||
  force_restart |= global_commit(c, old_config);
 | 
			
		||||
  DBG("rt_commit\n");
 | 
			
		||||
@@ -214,38 +241,38 @@ config_do_commit(struct config *c, int type)
 | 
			
		||||
  roa_commit(c, old_config);
 | 
			
		||||
  DBG("protos_commit\n");
 | 
			
		||||
  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)
 | 
			
		||||
    nobs = --old_config->obstacle_count;
 | 
			
		||||
  else
 | 
			
		||||
    nobs = 0;
 | 
			
		||||
  DBG("do_commit finished with %d obstacles remaining\n", nobs);
 | 
			
		||||
  return !nobs;
 | 
			
		||||
    obs = --old_config->obstacle_count;
 | 
			
		||||
 | 
			
		||||
  DBG("do_commit finished with %d obstacles remaining\n", obs);
 | 
			
		||||
  return !obs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_done(void *unused UNUSED)
 | 
			
		||||
{
 | 
			
		||||
  struct config *c;
 | 
			
		||||
  if (config->shutdown)
 | 
			
		||||
    sysdep_shutdown_done();
 | 
			
		||||
 | 
			
		||||
  DBG("config_done\n");
 | 
			
		||||
  for(;;)
 | 
			
		||||
  configuring = 0;
 | 
			
		||||
  if (old_config)
 | 
			
		||||
    log(L_INFO "Reconfigured");
 | 
			
		||||
 | 
			
		||||
  if (future_cftype)
 | 
			
		||||
    {
 | 
			
		||||
      if (config->shutdown)
 | 
			
		||||
	sysdep_shutdown_done();
 | 
			
		||||
      log(L_INFO "Reconfigured");
 | 
			
		||||
      if (old_config)
 | 
			
		||||
	{
 | 
			
		||||
	  config_free(old_config);
 | 
			
		||||
	  old_config = NULL;
 | 
			
		||||
	}
 | 
			
		||||
      if (!future_config)
 | 
			
		||||
	break;
 | 
			
		||||
      c = future_config;
 | 
			
		||||
      int type = future_cftype;
 | 
			
		||||
      struct config *conf = future_config;
 | 
			
		||||
      future_cftype = RECONFIG_NONE;
 | 
			
		||||
      future_config = NULL;
 | 
			
		||||
 | 
			
		||||
      log(L_INFO "Reconfiguring to queued configuration");
 | 
			
		||||
      if (!config_do_commit(c, future_type))
 | 
			
		||||
	break;
 | 
			
		||||
      if (config_do_commit(conf, type))
 | 
			
		||||
	config_done(NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -253,6 +280,7 @@ config_done(void *unused UNUSED)
 | 
			
		||||
 * 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)
 | 
			
		||||
 *
 | 
			
		||||
 * When a configuration is parsed and prepared for use, the
 | 
			
		||||
 * 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
 | 
			
		||||
 * 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,
 | 
			
		||||
 * %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
 | 
			
		||||
@@ -272,49 +304,147 @@ config_done(void *unused UNUSED)
 | 
			
		||||
 * are accepted.
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
      config_free(c);
 | 
			
		||||
      return CONF_SHUTDOWN;
 | 
			
		||||
    }
 | 
			
		||||
  if (old_config)			/* Reconfiguration already in progress */
 | 
			
		||||
 | 
			
		||||
  undo_available = 1;
 | 
			
		||||
  if (timeout > 0)
 | 
			
		||||
    tm_start(config_timer, timeout);
 | 
			
		||||
  else
 | 
			
		||||
    tm_stop(config_timer);
 | 
			
		||||
 | 
			
		||||
  if (configuring)
 | 
			
		||||
    {
 | 
			
		||||
      if (shutting_down == 2)
 | 
			
		||||
	{
 | 
			
		||||
	  log(L_INFO "New configuration discarded due to shutdown");
 | 
			
		||||
	  config_free(c);
 | 
			
		||||
	  return CONF_SHUTDOWN;
 | 
			
		||||
	}
 | 
			
		||||
      if (future_config)
 | 
			
		||||
      if (future_cftype)
 | 
			
		||||
	{
 | 
			
		||||
	  log(L_INFO "Queueing new configuration, ignoring the one already queued");
 | 
			
		||||
	  config_free(future_config);
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	log(L_INFO "Queued new configuration");
 | 
			
		||||
	log(L_INFO "Queueing new configuration");
 | 
			
		||||
 | 
			
		||||
      future_cftype = type;
 | 
			
		||||
      future_config = c;
 | 
			
		||||
      future_type = type;
 | 
			
		||||
      return CONF_QUEUED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!shutting_down)
 | 
			
		||||
    log(L_INFO "Reconfiguring");
 | 
			
		||||
 | 
			
		||||
  if (config_do_commit(c, type))
 | 
			
		||||
    {
 | 
			
		||||
      config_done(NULL);
 | 
			
		||||
      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);
 | 
			
		||||
      config_event->hook = config_done;
 | 
			
		||||
      if (future_cftype)
 | 
			
		||||
	{
 | 
			
		||||
	  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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 *
 | 
			
		||||
@@ -328,15 +458,16 @@ order_shutdown(void)
 | 
			
		||||
 | 
			
		||||
  if (shutting_down)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  log(L_INFO "Shutting down");
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  config_commit(c, RECONFIG_HARD, 0);
 | 
			
		||||
  shutting_down = 1;
 | 
			
		||||
  config_commit(c, RECONFIG_HARD);
 | 
			
		||||
  shutting_down = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								conf/conf.h
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								conf/conf.h
									
									
									
									
									
								
							@@ -54,28 +54,33 @@ struct config {
 | 
			
		||||
/* Please don't use these variables in protocols. Use proto_config->global instead. */
 | 
			
		||||
extern struct config *config;		/* Currently active configuration */
 | 
			
		||||
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);
 | 
			
		||||
int config_parse(struct config *);
 | 
			
		||||
int cli_parse(struct config *);
 | 
			
		||||
void config_free(struct config *);
 | 
			
		||||
int config_commit(struct config *, int type);
 | 
			
		||||
#define RECONFIG_HARD 0
 | 
			
		||||
#define RECONFIG_SOFT 1
 | 
			
		||||
int config_commit(struct config *, int type, int timeout);
 | 
			
		||||
int config_confirm(void);
 | 
			
		||||
int config_undo(void);
 | 
			
		||||
void config_init(void);
 | 
			
		||||
void cf_error(char *msg, ...) NORET;
 | 
			
		||||
void config_add_obstacle(struct config *);
 | 
			
		||||
void config_del_obstacle(struct config *);
 | 
			
		||||
void order_shutdown(void);
 | 
			
		||||
 | 
			
		||||
#define CONF_DONE 0
 | 
			
		||||
#define CONF_PROGRESS 1
 | 
			
		||||
#define CONF_QUEUED 2
 | 
			
		||||
#define CONF_SHUTDOWN 3
 | 
			
		||||
#define RECONFIG_NONE	0
 | 
			
		||||
#define RECONFIG_HARD	1
 | 
			
		||||
#define RECONFIG_SOFT	2
 | 
			
		||||
#define RECONFIG_UNDO	3
 | 
			
		||||
 | 
			
		||||
#define CONF_DONE	0
 | 
			
		||||
#define CONF_PROGRESS	1
 | 
			
		||||
#define CONF_QUEUED	2
 | 
			
		||||
#define CONF_UNQUEUED	3
 | 
			
		||||
#define CONF_CONFIRM	4
 | 
			
		||||
#define CONF_SHUTDOWN	-1
 | 
			
		||||
#define CONF_NOTHING	-2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* 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_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_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(3)CF_ADDTO(cli_cmd, CF_cmd)
 | 
			
		||||
CF_cmd: $1 $2 END')
 | 
			
		||||
m4_define(CF_CLI_CMD, `')
 | 
			
		||||
m4_define(CF_CLI_HELP, `')
 | 
			
		||||
 | 
			
		||||
# 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>
 | 
			
		||||
	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
 | 
			
		||||
	switch itself to the new configuration, protocols are
 | 
			
		||||
	reconfigured if possible, restarted otherwise. Changes in
 | 
			
		||||
	filters usually lead to restart of affected protocols. If
 | 
			
		||||
	<cf/soft/ option is used, changes in filters does not cause
 | 
			
		||||
	filters usually lead to restart of affected protocols.
 | 
			
		||||
 | 
			
		||||
	If <cf/soft/ option is used, changes in filters does not cause
 | 
			
		||||
	BIRD to restart affected protocols, therefore already accepted
 | 
			
		||||
	routes (according to old filters) would be still propagated,
 | 
			
		||||
	but new routes would be processed according to the new
 | 
			
		||||
	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>
 | 
			
		||||
	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>
 | 
			
		||||
	
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,12 @@ Reply codes of BIRD command-line interface
 | 
			
		||||
0014	Route count
 | 
			
		||||
0015	Reloading
 | 
			
		||||
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
 | 
			
		||||
1001	Interface list
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								nest/cli.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								nest/cli.c
									
									
									
									
									
								
							@@ -122,6 +122,7 @@ cli_printf(cli *c, int code, char *msg, ...)
 | 
			
		||||
  va_list args;
 | 
			
		||||
  byte buf[CLI_LINE_SIZE];
 | 
			
		||||
  int cd = code;
 | 
			
		||||
  int errcode;
 | 
			
		||||
  int size, cnt;
 | 
			
		||||
 | 
			
		||||
  if (cd < 0)
 | 
			
		||||
@@ -131,16 +132,26 @@ cli_printf(cli *c, int code, char *msg, ...)
 | 
			
		||||
	size = bsprintf(buf, " ");
 | 
			
		||||
      else
 | 
			
		||||
	size = bsprintf(buf, "%04d-", cd);
 | 
			
		||||
      errcode = -8000;
 | 
			
		||||
    }
 | 
			
		||||
  else if (cd == CLI_ASYNC_CODE)
 | 
			
		||||
    {
 | 
			
		||||
      size = 1; buf[0] = '+'; 
 | 
			
		||||
      errcode = cd;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    size = bsprintf(buf, "%04d ", cd);
 | 
			
		||||
    {
 | 
			
		||||
      size = bsprintf(buf, "%04d ", cd);
 | 
			
		||||
      errcode = 8000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  c->last_reply = cd;
 | 
			
		||||
  va_start(args, msg);
 | 
			
		||||
  cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args);
 | 
			
		||||
  va_end(args);
 | 
			
		||||
  if (cnt < 0)
 | 
			
		||||
    {
 | 
			
		||||
      cli_printf(c, code < 0 ? -8000 : 8000, "<line overflow>");
 | 
			
		||||
      cli_printf(c, errcode, "<line overflow>");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  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
 | 
			
		||||
cli_free(cli *c)
 | 
			
		||||
{
 | 
			
		||||
  cli_set_log_echo(c, 0, 0);
 | 
			
		||||
  if (c->cleanup)
 | 
			
		||||
    c->cleanup(c);
 | 
			
		||||
  if (c == cmd_reconfig_stored_cli)
 | 
			
		||||
    cmd_reconfig_stored_cli = NULL;
 | 
			
		||||
  rfree(c->pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,8 @@ typedef struct cli {
 | 
			
		||||
extern pool *cli_pool;
 | 
			
		||||
extern struct cli *this_cli;		/* Used during parsing */
 | 
			
		||||
 | 
			
		||||
#define CLI_ASYNC_CODE 10000
 | 
			
		||||
 | 
			
		||||
/* Functions to be called by command handlers */
 | 
			
		||||
 | 
			
		||||
void cli_printf(cli *, int, char *, ...);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,9 @@
 | 
			
		||||
#include "lib/string.h"
 | 
			
		||||
#include "lib/resource.h"
 | 
			
		||||
 | 
			
		||||
extern int shutting_down;
 | 
			
		||||
extern int configuring;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
cmd_show_status(void)
 | 
			
		||||
{
 | 
			
		||||
@@ -27,9 +30,10 @@ cmd_show_status(void)
 | 
			
		||||
  cli_msg(-1011, "Last reboot on %s", tim);
 | 
			
		||||
  tm_format_datetime(tim, &config->tf_base, config->load_time);
 | 
			
		||||
  cli_msg(-1011, "Last reconfiguration on %s", tim);
 | 
			
		||||
 | 
			
		||||
  if (shutting_down)
 | 
			
		||||
    cli_msg(13, "Shutdown in progress");
 | 
			
		||||
  else if (old_config)
 | 
			
		||||
  else if (configuring)
 | 
			
		||||
    cli_msg(13, "Reconfiguration in progress");
 | 
			
		||||
  else
 | 
			
		||||
    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->cf_new = nc;
 | 
			
		||||
	    }
 | 
			
		||||
	  else if (!shutting_down)
 | 
			
		||||
	  else if (!new->shutdown)
 | 
			
		||||
	    {
 | 
			
		||||
	      log(L_INFO "Removing protocol %s", p->name);
 | 
			
		||||
	      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)
 | 
			
		||||
    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);
 | 
			
		||||
	proto_init(nc);
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ CF_HDR
 | 
			
		||||
CF_DECLS
 | 
			
		||||
 | 
			
		||||
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 <t> cfg_name
 | 
			
		||||
%type <tf> timeformat_which
 | 
			
		||||
@@ -104,13 +104,26 @@ timeformat_base:
 | 
			
		||||
 | 
			
		||||
/* 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]])
 | 
			
		||||
{ cmd_reconfig($2, RECONFIG_HARD); } ;
 | 
			
		||||
CF_CLI(CONFIGURE, cfg_name cfg_timeout, [\"<file>\"] [timeout [<sec>]], [[Reload configuration]])
 | 
			
		||||
{ cmd_reconfig($2, RECONFIG_HARD, $3); } ;
 | 
			
		||||
 | 
			
		||||
CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore changes in filters]])
 | 
			
		||||
{ cmd_reconfig($3, RECONFIG_SOFT); } ;
 | 
			
		||||
CF_CLI(CONFIGURE SOFT, cfg_name cfg_timeout, [\"<file>\"] [timeout [<sec>]], [[Reload configuration and ignore changes in filters]])
 | 
			
		||||
{ 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]])
 | 
			
		||||
{ cmd_shutdown(); } ;
 | 
			
		||||
@@ -120,6 +133,12 @@ cfg_name:
 | 
			
		||||
 | TEXT
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
cfg_timeout:
 | 
			
		||||
   /* empty */ { $$ = 0; }
 | 
			
		||||
 | TIMEOUT { $$ = UNIX_DEFAULT_CONFIGURE_TIMEOUT; }
 | 
			
		||||
 | TIMEOUT expr { $$ = $2; }
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
CF_CODE
 | 
			
		||||
 | 
			
		||||
CF_END
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@ static list near_timers, far_timers;
 | 
			
		||||
static bird_clock_t first_far_timer = TIME_INFINITY;
 | 
			
		||||
 | 
			
		||||
/* 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
 | 
			
		||||
update_times_plain(void)
 | 
			
		||||
@@ -1530,6 +1530,7 @@ io_init(void)
 | 
			
		||||
  krt_io_init();
 | 
			
		||||
  init_times();
 | 
			
		||||
  update_times();
 | 
			
		||||
  boot_time = now;
 | 
			
		||||
  srandom((int) now_real);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1557,7 +1558,7 @@ io_loop(void)
 | 
			
		||||
	  tm_shot();
 | 
			
		||||
	  continue;
 | 
			
		||||
	}
 | 
			
		||||
      timo.tv_sec = events ? 0 : tout - now;
 | 
			
		||||
      timo.tv_sec = events ? 0 : MIN(tout - now, 3);
 | 
			
		||||
      timo.tv_usec = 0;
 | 
			
		||||
 | 
			
		||||
      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;
 | 
			
		||||
 | 
			
		||||
  if (shutting_down)
 | 
			
		||||
  if (config->shutdown)
 | 
			
		||||
    return;
 | 
			
		||||
  if (!(net->n.flags & KRF_INSTALLED))
 | 
			
		||||
    old = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -210,7 +210,7 @@ read_config(void)
 | 
			
		||||
      else
 | 
			
		||||
	die("Unable to open configuration file %s: %m", config_name);
 | 
			
		||||
    }
 | 
			
		||||
  config_commit(conf, RECONFIG_HARD);
 | 
			
		||||
  config_commit(conf, RECONFIG_HARD, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -228,19 +228,17 @@ async_config(void)
 | 
			
		||||
      config_free(conf);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    config_commit(conf, RECONFIG_HARD);
 | 
			
		||||
    config_commit(conf, RECONFIG_HARD, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
cmd_reconfig(char *name, int type)
 | 
			
		||||
static struct config *
 | 
			
		||||
cmd_read_config(char *name)
 | 
			
		||||
{
 | 
			
		||||
  struct config *conf;
 | 
			
		||||
 | 
			
		||||
  if (cli_access_restricted())
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (!name)
 | 
			
		||||
    name = config_name;
 | 
			
		||||
 | 
			
		||||
  cli_msg(-2, "Reading configuration from %s", name);
 | 
			
		||||
  if (!unix_read_config(&conf, name))
 | 
			
		||||
    {
 | 
			
		||||
@@ -249,26 +247,96 @@ cmd_reconfig(char *name, int type)
 | 
			
		||||
      else
 | 
			
		||||
	cli_msg(8002, "%s: %m", name);
 | 
			
		||||
      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_SHUTDOWN:
 | 
			
		||||
	  cli_msg(6, "Reconfiguration ignored, shutting down.");
 | 
			
		||||
	  break;
 | 
			
		||||
	default:
 | 
			
		||||
	  cli_msg(5, "Reconfiguration already in progress, queueing new config");
 | 
			
		||||
	}
 | 
			
		||||
    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)
 | 
			
		||||
    {
 | 
			
		||||
      cli *c = cmd_reconfig_stored_cli;
 | 
			
		||||
      cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
 | 
			
		||||
      cli_write_trigger(c);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	Command-Line Interface
 | 
			
		||||
 */
 | 
			
		||||
@@ -623,6 +691,7 @@ main(int argc, char **argv)
 | 
			
		||||
  rt_init();
 | 
			
		||||
  if_init();
 | 
			
		||||
  roa_init();
 | 
			
		||||
  config_init();
 | 
			
		||||
 | 
			
		||||
  uid_t use_uid = get_uid(use_user);
 | 
			
		||||
  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_real;		/* Time in seconds since fixed known epoch */
 | 
			
		||||
extern bird_clock_t boot_time;
 | 
			
		||||
 | 
			
		||||
static inline bird_clock_t
 | 
			
		||||
tm_remains(timer *t)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,14 @@ extern char *bird_name;
 | 
			
		||||
void async_config(void);
 | 
			
		||||
void async_dump(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);
 | 
			
		||||
 | 
			
		||||
#define UNIX_DEFAULT_CONFIGURE_TIMEOUT 300
 | 
			
		||||
 | 
			
		||||
/* io.c */
 | 
			
		||||
 | 
			
		||||
volatile int async_config_flag;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user