0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-11 17:08:46 +00:00

Merge commit '13d4dd138d5dc6c884ded280f9244fac707c4f32' into integrated

This commit is contained in:
Ondrej Zajicek 2013-01-13 00:44:39 +01:00
commit 0596b3dbf9
30 changed files with 647 additions and 187 deletions

5
NEWS
View File

@ -1,5 +1,8 @@
Version 1.3.9 (2012-11-16)
Version 1.3.9 (2013-01-11)
o BIRD can be configured to keep and show filtered routes.
o Separate receive and import limits.
o Several new reconfiguration cmd options (undo, timeout, check).
o Configurable automatic router ID selection.
o Dragonfly BSD support.
o Fixed OSPFv3 vlinks.
o Several minor bugfixes.

2
README
View File

@ -3,7 +3,7 @@
(c) 1998--2008 Martin Mares <mj@ucw.cz>
(c) 1998--2000 Pavel Machek <pavel@ucw.cz>
(c) 1998--2008 Ondrej Filip <feela@network.cz>
(c) 2009--2011 CZ.NIC z.s.p.o.
(c) 2009--2013 CZ.NIC z.s.p.o.
================================================================================

View File

@ -25,14 +25,14 @@ protocol kernel {
protocol static {
# disabled;
route fec0:2::/64 reject;
route fec0:3::/64 reject;
route fec0:4::/64 reject;
route fec0:2::/64 blackhole;
route fec0:3::/64 unreachable;
route fec0:4::/64 prohibit;
# route 0.0.0.0/0 via 195.113.31.113;
# route 62.168.0.0/25 reject;
# route 62.168.0.0/25 unreachable;
# route 1.2.3.4/32 via 195.113.31.124;
# route 10.0.0.0/8 reject;
# route 10.0.0.0/8 unreachable;
# route 10.1.1.0:255.255.255.0 via 62.168.0.3;
# route 10.1.2.0:255.255.255.0 via 62.168.0.3;
# route 10.1.3.0:255.255.255.0 via 62.168.0.4;

View File

@ -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;
}
@ -155,7 +169,8 @@ cli_parse(struct config *c)
void
config_free(struct config *c)
{
rfree(c->pool);
if (c)
rfree(c->pool);
}
void
@ -171,10 +186,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
@ -189,25 +201,50 @@ global_commit(struct config *new, struct config *old)
log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD.");
if (!new->router_id)
new->router_id = old->router_id;
if (new->router_id != old->router_id)
return 1;
{
new->router_id = old->router_id;
if (new->router_id_from)
{
u32 id = if_choose_router_id(new->router_id_from, old->router_id);
if (!id)
log(L_WARN "Cannot determine router ID, using old one");
else
new->router_id = id;
}
}
return 0;
}
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");
@ -215,38 +252,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);
}
}
@ -254,6 +291,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.
@ -266,6 +304,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
@ -273,49 +315,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
*
@ -329,15 +469,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;
}
/**

View File

@ -26,6 +26,7 @@ struct config {
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
struct rtable_config *master_rtc; /* Configuration of master routing table */
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
u32 router_id; /* Our Router ID */
ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */
@ -54,28 +55,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 */

View File

@ -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)')

View File

@ -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

View File

@ -67,8 +67,8 @@ protocol static {
# debug { states, routes, filters, interfaces, events, packets };
# debug all;
# route 0.0.0.0/0 via 198.51.100.13;
# route 198.51.100.0/25 reject;
# route 10.0.0.0/8 reject;
# route 198.51.100.0/25 unreachable;
# route 10.0.0.0/8 unreachable;
# route 10.1.1.0:255.255.255.0 via 198.51.100.3;
# route 10.1.2.0:255.255.255.0 via 198.51.100.3;
# route 10.1.3.0:255.255.255.0 via 198.51.100.4;

View File

@ -337,7 +337,18 @@ protocol rip {
Besides, there are some predefined numeric constants based on /etc/iproute2/rt_* files.
A list of defined constants can be seen (together with other symbols) using 'show symbols' command.
<tag>router id <m/IPv4 address/</tag> Set BIRD's router ID. It's a world-wide unique identification of your router, usually one of router's IPv4 addresses. Default: in IPv4 version, the lowest IP address of a non-loopback interface. In IPv6 version, this option is mandatory.
<tag>router id <m/IPv4 address/</tag>
Set BIRD's router ID. It's a world-wide unique identification
of your router, usually one of router's IPv4 addresses.
Default: in IPv4 version, the lowest IP address of a
non-loopback interface. In IPv6 version, this option is
mandatory.
<tag>router id from [-] [ "<m/mask/" ] [ <m/prefix/ ] [, ...]</tag>
Set BIRD's router ID based on an IP address of an interface
specified by an interface pattern. The option is applicable
for IPv4 version only. See <ref id="dsc-iface" name="interface">
section for detailed description of interface patterns.
<tag>listen bgp [address <m/address/] [port <m/port/] [dual]</tag>
This option allows to specify address and port where BGP
@ -471,15 +482,23 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
Specify an import route limit (a maximum number of routes
imported from the protocol) and optionally the action to be
taken when the limit is hit. Warn action just prints warning
log message. Block action ignores new routes coming from the
log message. Block action discards new routes coming from the
protocol. Restart and disable actions shut the protocol down
like appropriate commands. Disable is the default action if an
action is not explicitly specified. Note that limits are reset
during protocol reconfigure, reload or restart. Also note that
if <cf/import keep filtered/ is active, filtered routes are
counted towards the limit and blocked routes are forgotten, as
the main purpose of the import limit is to protect routing
tables from overflow. Default: <cf/none/.
during protocol reconfigure, reload or restart. Default: <cf/none/.
<tag>receive limit <m/number/ [action warn | block | restart | disable]</tag>
Specify an receive route limit (a maximum number of routes
received from the protocol and remembered). It works almost
identically to <cf>import limit</cf> option, the only
difference is that if <cf/import keep filtered/ option is
active, filtered routes are counted towards the limit and
blocked routes are forgotten, as the main purpose of the
receive limit is to protect routing tables from
overflow. Import limit, on the contrary, counts accepted
routes only and routes blocked by the limit are handled like
filtered routes. Default: <cf/none/.
<tag>export limit <m/number/ [action warn | block | restart | disable]</tag>
Specify an export route limit, works similarly to
@ -702,19 +721,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>
@ -2733,9 +2781,10 @@ definition of the protocol contains mainly a list of static routes:
route through an interface to hosts on a directly connected network.
<tag>route <m/prefix/ recursive <m/ip/</tag> Static recursive route,
its nexthop depends on a route table lookup for given IP address.
<tag>route <m/prefix/ drop|reject|prohibit</tag> Special routes
specifying to drop the packet, return it as unreachable or return
it as administratively prohibited.
<tag>route <m/prefix/ blackhole|unreachable|prohibit</tag> Special routes
specifying to silently drop the packet, return it as unreachable or return
it as administratively prohibited. First two targets are also known
as <cf/drop/ and <cf/reject/.
<tag>check link <m/switch/</tag>
If set, hardware link states of network interfaces are taken
@ -2761,7 +2810,7 @@ protocol static {
via 198.51.100.10 weight 2
via 198.51.100.20
via 192.0.2.1;
route 203.0.113.0/24 reject; # Sink route
route 203.0.113.0/24 unreachable; # Sink route
route 10.2.0.0/24 via "arc0"; # Secondary network
}
</code>

View File

@ -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

View File

@ -622,9 +622,6 @@ interpret(struct f_inst *what)
case T_VOID: runtime( "Can't operate with values of type void" );
case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
res.val.i = v1.val.i / v2.val.i; break;
case T_IP: if (v2.type != T_INT)
runtime( "Incompatible types in / operator" );
break;
default: runtime( "Usage of unknown type" );
}
break;
@ -956,11 +953,25 @@ interpret(struct f_inst *what)
l->attrs[0].type = what->aux | EAF_ORIGINATED;
switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
case EAF_TYPE_ROUTER_ID:
if (v1.type != T_INT)
runtime( "Setting int attribute to non-int value" );
l->attrs[0].u.data = v1.val.i;
break;
case EAF_TYPE_ROUTER_ID:
#ifndef IPV6
/* IP->Quad implicit conversion */
if (v1.type == T_IP) {
l->attrs[0].u.data = ipa_to_u32(v1.val.px.ip);
break;
}
#endif
/* T_INT for backward compatibility */
if ((v1.type != T_QUAD) && (v1.type != T_INT))
runtime( "Setting quad attribute to non-quad value" );
l->attrs[0].u.data = v1.val.i;
break;
case EAF_TYPE_OPAQUE:
runtime( "Setting opaque attribute is not allowed" );
break;

View File

@ -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);
}

View File

@ -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 *, ...);

View File

@ -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");

View File

@ -45,7 +45,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPVX, VPN4, VPN6, MPLS)
CF_KEYWORDS(LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, AS, MAX, FLUSH)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
@ -76,9 +76,9 @@ CF_GRAMMAR
CF_ADDTO(conf, rtrid)
rtrid: ROUTER ID idval ';' {
new_config->router_id = $3;
}
rtrid:
ROUTER ID idval ';' { new_config->router_id = $3; }
| ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; }
;
idval:
@ -188,6 +188,7 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| RECEIVE LIMIT limit_spec { this_proto->rx_limit = $3; }
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
| IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; }
@ -271,6 +272,17 @@ iface_patt_list:
| iface_patt_list ',' iface_patt_node
;
iface_patt_init: {
/* Generic this_ipatt init */
this_ipatt = cfg_allocz(sizeof(struct iface_patt));
init_list(&this_ipatt->ipn_list);
}
;
iface_patt:
iface_patt_init iface_patt_list
;
/* Direct device route protocol */

View File

@ -35,8 +35,6 @@
static pool *if_pool;
static void auto_router_id(void);
list iface_list;
/**
@ -354,9 +352,6 @@ if_end_update(void)
struct iface *i;
struct ifa *a, *b;
if (!config->router_id)
auto_router_id();
WALK_LIST(i, iface_list)
{
if (!(i->flags & IF_UPDATED))
@ -581,27 +576,59 @@ ifa_delete(struct ifa *a)
}
}
static void
auto_router_id(void)
u32
if_choose_router_id(struct iface_patt *mask, u32 old_id)
{
// XXXX check this
#if 0
struct iface *i, *j;
struct iface *i;
struct ifa *a, *b;
j = NULL;
b = NULL;
WALK_LIST(i, iface_list)
if ((i->flags & IF_ADMIN_UP) &&
!(i->flags & (IF_IGNORE | IF_SHUTDOWN)) &&
i->addr &&
!(i->addr->flags & IA_PEER) &&
(!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
j = i;
if (!j)
die("Cannot determine router ID (no suitable network interface found), please configure it manually");
log(L_INFO "Guessed router ID %I according to interface %s", j->addr->ip, j->name);
config->router_id = ipa_to_u32(j->addr->ip);
{
if (!(i->flags & IF_ADMIN_UP) ||
(i->flags & (IF_IGNORE | IF_SHUTDOWN)))
continue;
WALK_LIST(a, i->addrs)
{
if (a->flags & IA_SECONDARY)
continue;
if (a->scope <= SCOPE_LINK)
continue;
/* FIXME: This should go away */
if (a->flags & IA_PEER)
continue;
/* FIXME: This should go away too */
if (!mask && (a != i->addr))
continue;
/* Check pattern if specified */
if (mask && !iface_patt_match(mask, i, a))
continue;
/* No pattern or pattern matched */
if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip))
b = a;
}
}
if (!b)
return 0;
u32 id = ipa_to_u32(b->ip);
if (id != old_id)
log(L_INFO "Chosen router ID %R according to interface %s", id, b->iface->name);
return id;
#else
return 0;
#endif
}

View File

@ -101,6 +101,7 @@ struct iface *if_find_by_name(char *);
struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void);
/* The Neighbor Cache */
typedef struct neighbor {
@ -161,4 +162,7 @@ int iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a);
struct iface_patt *iface_patt_find(list *l, struct iface *i, struct ifa *a);
int iface_patts_equal(list *, list *, int (*)(struct iface_patt *, struct iface_patt *));
u32 if_choose_router_id(struct iface_patt *mask, u32 old_id);
#endif

View File

@ -344,6 +344,7 @@ protos_postconfig(struct config *c)
WALK_LIST(x, c->protos)
{
DBG(" %s", x->name);
p = x->protocol;
if (p->postconfig)
p->postconfig(x);
@ -382,11 +383,9 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* If there is a too big change in core attributes, ... */
if ((nc->protocol != oc->protocol) ||
(nc->disabled != p->disabled) ||
(nc->table->table != oc->table->table) ||
(proto_get_router_id(nc) != proto_get_router_id(oc)))
(nc->table->table != oc->table->table))
return 0;
p->debug = nc->debug;
p->mrtdump = nc->mrtdump;
proto_reconfig_type = type;
@ -412,6 +411,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
{
p->main_ahook->in_filter = nc->in_filter;
p->main_ahook->out_filter = nc->out_filter;
p->main_ahook->rx_limit = nc->rx_limit;
p->main_ahook->in_limit = nc->in_limit;
p->main_ahook->out_limit = nc->out_limit;
p->main_ahook->in_keep_filtered = nc->in_keep_filtered;
@ -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);
}
@ -552,6 +552,16 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
initial_device_proto = NULL;
}
/* Determine router ID for the first time - it has to be here and not in
global_commit() because it is postponed after start of device protocol */
if (!config->router_id)
{
config->router_id = if_choose_router_id(config->router_id_from, 0);
if (!config->router_id)
die("Cannot determine router ID, please configure it manually");
}
/* Start all other protocols */
WALK_LIST_DELSAFE(p, n, initial_proto_list)
proto_rethink_goal(p);
}
@ -797,9 +807,11 @@ proto_schedule_feed(struct proto *p, int initial)
p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
p->main_ahook->in_filter = p->cf->in_filter;
p->main_ahook->out_filter = p->cf->out_filter;
p->main_ahook->rx_limit = p->cf->rx_limit;
p->main_ahook->in_limit = p->cf->in_limit;
p->main_ahook->out_limit = p->cf->out_limit;
p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
proto_reset_limit(p->main_ahook->rx_limit);
proto_reset_limit(p->main_ahook->in_limit);
proto_reset_limit(p->main_ahook->out_limit);
}
@ -971,6 +983,7 @@ proto_limit_name(struct proto_limit *l)
* proto_notify_limit: notify about limit hit and take appropriate action
* @ah: announce hook
* @l: limit being hit
* @dir: limit direction (PLD_*)
* @rt_count: the number of routes
*
* The function is called by the route processing core when limit @l
@ -978,10 +991,11 @@ proto_limit_name(struct proto_limit *l)
* according to @l->action.
*/
void
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count)
proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count)
{
const char *dir_name[PLD_MAX] = { "receive", "import" , "export" };
const byte dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
struct proto *p = ah->proto;
int dir = (ah->in_limit == l);
if (l->state == PLS_BLOCKED)
return;
@ -989,7 +1003,7 @@ proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count
/* For warning action, we want the log message every time we hit the limit */
if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));
p->name, dir_name[dir], l->limit, proto_limit_name(l));
switch (l->action)
{
@ -1004,8 +1018,7 @@ proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count
case PLA_RESTART:
case PLA_DISABLE:
l->state = PLS_BLOCKED;
proto_schedule_down(p, l->action == PLA_RESTART,
dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT);
proto_schedule_down(p, l->action == PLA_RESTART, dir_down[dir]);
break;
}
}
@ -1139,6 +1152,7 @@ proto_show_basic_info(struct proto *p)
cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
proto_show_limit(p->cf->rx_limit, "Receive limit:");
proto_show_limit(p->cf->in_limit, "Import limit:");
proto_show_limit(p->cf->out_limit, "Export limit:");
@ -1260,7 +1274,10 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
* Perhaps, but these hooks work asynchronously.
*/
if (!p->proto->multitable)
proto_reset_limit(p->main_ahook->in_limit);
{
proto_reset_limit(p->main_ahook->rx_limit);
proto_reset_limit(p->main_ahook->in_limit);
}
}
/* re-exporting routes */

View File

@ -96,6 +96,8 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
struct proto_limit *rx_limit; /* Limit for receiving routes from protocol
(relevant when in_keep_filtered is active) */
struct proto_limit *in_limit; /* Limit for importing routes from protocol */
struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
@ -226,8 +228,9 @@ struct proto_spec {
#define PDC_CMD_DISABLE 0x11 /* Result of disable command */
#define PDC_CMD_RESTART 0x12 /* Result of restart command */
#define PDC_CMD_SHUTDOWN 0x13 /* Result of global shutdown */
#define PDC_IN_LIMIT_HIT 0x21 /* Route import limit reached */
#define PDC_OUT_LIMIT_HIT 0x22 /* Route export limit reached */
#define PDC_RX_LIMIT_HIT 0x21 /* Route receive limit reached */
#define PDC_IN_LIMIT_HIT 0x22 /* Route import limit reached */
#define PDC_OUT_LIMIT_HIT 0x23 /* Route export limit reached */
void *proto_new(struct proto_config *, unsigned size);
@ -374,6 +377,11 @@ extern struct proto_config *cf_dev_proto;
* Protocol limits
*/
#define PLD_RX 0 /* Receive limit */
#define PLD_IN 1 /* Import limit */
#define PLD_OUT 2 /* Export limit */
#define PLD_MAX 3
#define PLA_WARN 1 /* Issue log warning */
#define PLA_BLOCK 2 /* Block new routes */
#define PLA_RESTART 4 /* Force protocol restart */
@ -389,7 +397,7 @@ struct proto_limit {
byte state; /* State of limit (PLS_*) */
};
void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count);
void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, int dir, u32 rt_count);
static inline void
proto_reset_limit(struct proto_limit *l)
@ -409,6 +417,7 @@ struct announce_hook {
struct proto *proto;
struct filter *in_filter; /* Input filter */
struct filter *out_filter; /* Output filter */
struct proto_limit *rx_limit; /* Receive limit (for in_keep_filtered) */
struct proto_limit *in_limit; /* Input limit */
struct proto_limit *out_limit; /* Output limit */
struct proto_stats *stats; /* Per-table protocol statistics */

View File

@ -288,7 +288,7 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
if (l && new)
{
if ((!old || refeed) && (stats->exp_routes >= l->limit))
proto_notify_limit(ah, l, stats->exp_routes);
proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
if (l->state == PLS_BLOCKED)
{
@ -708,16 +708,22 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
return;
}
struct proto_limit *l = ah->in_limit;
int new_ok = rte_is_ok(new);
int old_ok = rte_is_ok(old);
struct proto_limit *l = ah->rx_limit;
if (l && !old && new)
{
u32 all_routes = stats->imp_routes + stats->filt_routes;
if (all_routes >= l->limit)
proto_notify_limit(ah, l, all_routes);
proto_notify_limit(ah, l, PLD_RX, all_routes);
if (l->state == PLS_BLOCKED)
{
/* In receive limit the situation is simple, old is NULL so
we just free new and exit like nothing happened */
stats->imp_updates_ignored++;
rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
rte_free_quick(new);
@ -725,8 +731,39 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
}
}
int new_ok = rte_is_ok(new);
int old_ok = rte_is_ok(old);
l = ah->in_limit;
if (l && !old_ok && new_ok)
{
if (stats->imp_routes >= l->limit)
proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
if (l->state == PLS_BLOCKED)
{
/* In import limit the situation is more complicated. We
shouldn't just drop the route, we should handle it like
it was filtered. We also have to continue the route
processing if old or new is non-NULL, but we should exit
if both are NULL as this case is probably assumed to be
already handled. */
stats->imp_updates_ignored++;
rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
if (ah->in_keep_filtered)
new->flags |= REF_FILTERED;
else
{ rte_free_quick(new); new = NULL; }
/* Note that old && !new could be possible when
ah->in_keep_filtered changed in the recent past. */
if (!old && !new)
return;
new_ok = 0;
goto skip_stats1;
}
}
if (new_ok)
stats->imp_updates_accepted++;
@ -735,6 +772,8 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
else
stats->imp_withdraws_ignored++;
skip_stats1:
if (new)
rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++;
if (old)

View File

@ -878,6 +878,7 @@ bgp_shutdown(struct proto *P)
subcode = 4; // Errcode 6, 4 - administrative reset
break;
case PDC_RX_LIMIT_HIT:
case PDC_IN_LIMIT_HIT:
subcode = 1; // Errcode 6, 1 - max number of prefixes reached
/* log message for compatibility */
@ -1009,6 +1010,9 @@ bgp_reconfigure(struct proto *P, struct proto_config *C)
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_config *old = p->cf;
if (proto_get_router_id(C) != p->local_id)
return 0;
int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
((byte *) new) + sizeof(struct proto_config),
// password item is last and must be checked separately

View File

@ -717,6 +717,9 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
struct ospf_iface *ifa, *ifx;
struct ospf_iface_patt *ip;
if (proto_get_router_id(c) != po->router_id)
return 0;
if (po->rfc1583 != new->rfc1583)
return 0;

View File

@ -200,6 +200,11 @@ pipe_postconfig(struct proto_config *C)
cf_error("Name of peer routing table not specified");
if (c->peer == C->table)
cf_error("Primary table and peer table must be different");
if (C->in_keep_filtered)
cf_error("Pipe protocol prohibits keeping filtered routes");
if (C->rx_limit)
cf_error("Pipe protocol does not support receive limits");
}
extern int proto_reconfig_type;

View File

@ -18,7 +18,7 @@ static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
CF_DECLS
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE)
CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE)
CF_GRAMMAR
@ -86,9 +86,12 @@ stat_route:
this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3;
}
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; }
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 UNREACHABLE { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; }
;
CF_CLI(SHOW STATIC, optsym, [<name>], [[Show details of static protocol]])

View File

@ -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

View File

@ -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)
@ -1553,6 +1553,7 @@ io_init(void)
krt_io_init();
init_times();
update_times();
boot_time = now;
srandom((int) now_real);
}
@ -1580,7 +1581,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)

View File

@ -901,7 +901,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;

View File

@ -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);

View File

@ -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)

View File

@ -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;