First attempt on dynamic reconfiguration. There are still lots of bugs
and problems to solve, but the hardest part works.
This commit is contained in:
parent
394aec8fdd
commit
50fe90edf3
13 changed files with 434 additions and 90 deletions
17
TODO
17
TODO
|
@ -26,19 +26,21 @@ Core
|
||||||
- config: executable config files
|
- config: executable config files
|
||||||
- config: when parsing prefix, check zero bits
|
- config: when parsing prefix, check zero bits
|
||||||
- config: reconfiguration
|
- config: reconfiguration
|
||||||
|
- config: reconfiguration of filters
|
||||||
- config: useless rules when protocols disabled
|
- config: useless rules when protocols disabled
|
||||||
- config: remove protocol startup priority hacks?
|
- config: remove protocol startup priority hacks?
|
||||||
- config: better datetime format
|
- config: better datetime format
|
||||||
|
- config: treat shutdown as reconfiguration to null config? (what about config of logging etc. ?)
|
||||||
|
- config: fix auto_router_id
|
||||||
|
|
||||||
- krt: rescan interfaces when route addition fails?
|
- krt: rescan interfaces when route addition fails?
|
||||||
- krt: does PERSIST mode have any sense if kernel syncer is shut down as last?
|
- krt: does PERSIST mode have any sense if kernel syncer is shut down as last?
|
||||||
|
- krt: check behaviour wrt. reconfiguration of routing tables
|
||||||
|
|
||||||
- tagging of external routes?
|
- tagging of external routes?
|
||||||
|
|
||||||
- io: use poll if available
|
- io: use poll if available
|
||||||
|
|
||||||
- port to FreeBSD
|
|
||||||
|
|
||||||
Commands
|
Commands
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
shutdown # order system shutdown
|
shutdown # order system shutdown
|
||||||
|
@ -50,6 +52,17 @@ show <name> # show everything you know about symbol <name>
|
||||||
symbols
|
symbols
|
||||||
(disable|enable|restart) <protocol> # or ALL?
|
(disable|enable|restart) <protocol> # or ALL?
|
||||||
- showing of routing table as seen by given protocol
|
- showing of routing table as seen by given protocol
|
||||||
|
- showing of deleted routing tables and filters
|
||||||
|
|
||||||
|
Roadmap
|
||||||
|
~~~~~~~
|
||||||
|
- Dynamic reconfiguration
|
||||||
|
- Allocators and data structures
|
||||||
|
- Client
|
||||||
|
- Remaining bits of IPv6 support (radvd)
|
||||||
|
- RIPv6
|
||||||
|
- BGP?
|
||||||
|
- Logging and debugging messages
|
||||||
|
|
||||||
Client
|
Client
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
121
conf/conf.c
121
conf/conf.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Internet Routing Daemon -- Configuration File Handling
|
* BIRD Internet Routing Daemon -- Configuration File Handling
|
||||||
*
|
*
|
||||||
* (c) 1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -9,18 +9,22 @@
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define LOCAL_DEBUG
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "nest/route.h"
|
#include "nest/route.h"
|
||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
|
#include "lib/event.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
|
|
||||||
static jmp_buf conf_jmpbuf;
|
static jmp_buf conf_jmpbuf;
|
||||||
|
|
||||||
struct config *config, *new_config;
|
struct config *config, *new_config, *old_config, *future_config;
|
||||||
|
static event *config_event;
|
||||||
|
|
||||||
struct config *
|
struct config *
|
||||||
config_alloc(byte *name)
|
config_alloc(byte *name)
|
||||||
|
@ -77,12 +81,117 @@ config_free(struct config *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
config_add_obstacle(struct config *c)
|
||||||
|
{
|
||||||
|
DBG("+++ adding obstacle %d\n", c->obstacle_count);
|
||||||
|
c->obstacle_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
global_commit(struct config *c, struct config *old)
|
||||||
|
{
|
||||||
|
if (!old)
|
||||||
|
return 0;
|
||||||
|
if (c->router_id != old->router_id)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_do_commit(struct config *c)
|
||||||
|
{
|
||||||
|
int force_restart, nobs;
|
||||||
|
|
||||||
|
DBG("do_commit\n");
|
||||||
|
old_config = config;
|
||||||
|
config = c;
|
||||||
|
if (old_config)
|
||||||
|
old_config->obstacle_count++;
|
||||||
|
DBG("sysdep_commit\n");
|
||||||
|
force_restart = sysdep_commit(c, old_config);
|
||||||
|
DBG("global_commit\n");
|
||||||
|
force_restart |= global_commit(c, old_config);
|
||||||
|
DBG("rt_commit\n");
|
||||||
|
rt_commit(c, old_config);
|
||||||
|
DBG("protos_commit\n");
|
||||||
|
protos_commit(c, old_config, force_restart);
|
||||||
|
new_config = NULL; /* Just to be sure nobody uses that now */
|
||||||
|
if (old_config)
|
||||||
|
nobs = --old_config->obstacle_count;
|
||||||
|
else
|
||||||
|
nobs = 0;
|
||||||
|
DBG("do_commit finished with %d obstacles remaining\n", nobs);
|
||||||
|
return !nobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
config_done(void *unused)
|
||||||
|
{
|
||||||
|
struct config *c;
|
||||||
|
|
||||||
|
DBG("config_done\n");
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
log(L_INFO "Reconfigured");
|
||||||
|
if (old_config)
|
||||||
|
{
|
||||||
|
config_free(old_config);
|
||||||
|
old_config = NULL;
|
||||||
|
}
|
||||||
|
if (!future_config)
|
||||||
|
break;
|
||||||
|
c = future_config;
|
||||||
|
future_config = NULL;
|
||||||
|
log(L_INFO "Switching to queued configuration...");
|
||||||
|
if (!config_do_commit(c))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
config_commit(struct config *c)
|
config_commit(struct config *c)
|
||||||
{
|
{
|
||||||
config = c;
|
if (!config) /* First-time configuration */
|
||||||
sysdep_commit(c);
|
{
|
||||||
rt_commit(c);
|
config_do_commit(c);
|
||||||
protos_commit(c);
|
return CONF_DONE;
|
||||||
|
}
|
||||||
|
if (old_config) /* Reconfiguration already in progress */
|
||||||
|
{
|
||||||
|
if (future_config)
|
||||||
|
{
|
||||||
|
log(L_INFO "Queueing new configuration, ignoring the one already queued");
|
||||||
|
config_free(future_config);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log(L_INFO "Queued new configuration");
|
||||||
|
future_config = c;
|
||||||
|
return CONF_QUEUED;
|
||||||
|
}
|
||||||
|
if (config_do_commit(c))
|
||||||
|
{
|
||||||
|
config_done(NULL);
|
||||||
|
return CONF_DONE;
|
||||||
|
}
|
||||||
|
if (!config_event)
|
||||||
|
{
|
||||||
|
config_event = ev_new(&root_pool);
|
||||||
|
config_event->hook = config_done;
|
||||||
|
}
|
||||||
|
return CONF_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
18
conf/conf.h
18
conf/conf.h
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Internet Routing Daemon -- Configuration File Handling
|
* BIRD Internet Routing Daemon -- Configuration File Handling
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -26,17 +26,27 @@ struct config {
|
||||||
char *file_name; /* Name of configuration file */
|
char *file_name; /* Name of configuration file */
|
||||||
struct symbol **sym_hash; /* Lexer: symbol hash table */
|
struct symbol **sym_hash; /* Lexer: symbol hash table */
|
||||||
struct symbol **sym_fallback; /* Lexer: fallback symbol hash table */
|
struct symbol **sym_fallback; /* Lexer: fallback symbol hash table */
|
||||||
|
int obstacle_count; /* Number of items blocking freeing of this config */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct config *config, *new_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 *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 */
|
||||||
|
|
||||||
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 *);
|
||||||
void config_commit(struct config *);
|
int config_commit(struct config *);
|
||||||
void cf_error(char *msg, ...) NORET;
|
void cf_error(char *msg, ...) NORET;
|
||||||
|
void config_add_obstacle(struct config *);
|
||||||
|
void config_del_obstacle(struct config *);
|
||||||
|
|
||||||
|
#define CONF_DONE 0
|
||||||
|
#define CONF_PROGRESS 1
|
||||||
|
#define CONF_QUEUED 2
|
||||||
|
|
||||||
/* Pools */
|
/* Pools */
|
||||||
|
|
||||||
|
@ -87,6 +97,6 @@ int cf_parse(void);
|
||||||
/* Sysdep hooks */
|
/* Sysdep hooks */
|
||||||
|
|
||||||
void sysdep_preconfig(struct config *);
|
void sysdep_preconfig(struct config *);
|
||||||
void sysdep_commit(struct config *);
|
int sysdep_commit(struct config *, struct config *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@ Reply codes of BIRD command-line interface
|
||||||
|
|
||||||
0000 OK
|
0000 OK
|
||||||
0001 Welcome
|
0001 Welcome
|
||||||
|
0002 Reading configuration
|
||||||
|
|
||||||
1000 BIRD version
|
1000 BIRD version
|
||||||
1001 Interface list
|
1001 Interface list
|
||||||
|
@ -24,6 +25,7 @@ Reply codes of BIRD command-line interface
|
||||||
|
|
||||||
8000 Reply too long
|
8000 Reply too long
|
||||||
8001 Route not found
|
8001 Route not found
|
||||||
|
8002 Configuration file error
|
||||||
|
|
||||||
9000 Command too long
|
9000 Command too long
|
||||||
9001 Parse error
|
9001 Parse error
|
||||||
|
|
157
nest/proto.c
157
nest/proto.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Protocols
|
* BIRD -- Protocols
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,7 @@ static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
|
||||||
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
|
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
|
||||||
|
|
||||||
static int proto_flush_all(void *);
|
static int proto_flush_all(void *);
|
||||||
|
static void proto_rethink_goal(struct proto *p);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
proto_enqueue(list *l, struct proto *p)
|
proto_enqueue(list *l, struct proto *p)
|
||||||
|
@ -103,6 +104,7 @@ proto_init_instance(struct proto *p)
|
||||||
p->pool = rp_new(proto_pool, p->proto->name);
|
p->pool = rp_new(proto_pool, p->proto->name);
|
||||||
p->attn = ev_new(p->pool);
|
p->attn = ev_new(p->pool);
|
||||||
p->attn->data = p;
|
p->attn->data = p;
|
||||||
|
rt_lock_table(p->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct announce_hook *
|
struct announce_hook *
|
||||||
|
@ -185,42 +187,118 @@ protos_postconfig(struct config *c)
|
||||||
debug("\n");
|
debug("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static struct proto *
|
||||||
protos_commit(struct config *c)
|
proto_init(struct proto_config *c)
|
||||||
{
|
{
|
||||||
struct proto_config *x;
|
struct protocol *p = c->protocol;
|
||||||
struct protocol *p;
|
struct proto *q = p->init(c);
|
||||||
struct proto *q;
|
|
||||||
|
|
||||||
debug("Protocol commit:");
|
q->proto_state = PS_DOWN;
|
||||||
WALK_LIST(x, c->protos)
|
q->core_state = FS_HUNGRY;
|
||||||
|
proto_enqueue(&initial_proto_list, q);
|
||||||
|
/*
|
||||||
|
* HACK ALERT! In case of multiple kernel routing tables,
|
||||||
|
* the kernel syncer acts as multiple protocols which cooperate
|
||||||
|
* with each other. In order to speed up their initialization,
|
||||||
|
* we need to know when we're initializing the last one, hence
|
||||||
|
* the startup counter.
|
||||||
|
*/
|
||||||
|
if (!q->disabled)
|
||||||
|
p->startup_counter++;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
protos_commit(struct config *new, struct config *old, int force_reconfig)
|
||||||
|
{
|
||||||
|
struct proto_config *oc, *nc;
|
||||||
|
struct proto *p, *n;
|
||||||
|
|
||||||
|
DBG("protos_commit:\n");
|
||||||
|
if (old)
|
||||||
{
|
{
|
||||||
debug(" %s", x->name);
|
WALK_LIST(oc, old->protos)
|
||||||
p = x->protocol;
|
{
|
||||||
q = p->init(x);
|
struct proto *p = oc->proto;
|
||||||
q->proto_state = PS_DOWN;
|
struct symbol *sym = cf_find_symbol(oc->name);
|
||||||
q->core_state = FS_HUNGRY;
|
if (sym && sym->class == SYM_PROTO)
|
||||||
proto_enqueue(&initial_proto_list, q);
|
{
|
||||||
/*
|
/* Found match, let's check if we can smoothly switch to new configuration */
|
||||||
* HACK ALERT! In case of multiple kernel routing tables,
|
nc = sym->def;
|
||||||
* the kernel syncer acts as multiple protocols which cooperate
|
if (!force_reconfig
|
||||||
* with each other. In order to speed up their initialization,
|
&& nc->protocol == oc->protocol
|
||||||
* we need to know when we're initializing the last one, hence
|
&& nc->preference == oc->preference
|
||||||
* the startup counter.
|
&& nc->disabled == oc->disabled
|
||||||
*/
|
&& nc->table->table == oc->table->table
|
||||||
if (!q->disabled)
|
&& nc->in_filter == oc->in_filter
|
||||||
p->startup_counter++;
|
&& nc->out_filter == oc->out_filter
|
||||||
|
&& p->proto_state != PS_DOWN)
|
||||||
|
{
|
||||||
|
/* Generic attributes match, try converting them and then ask the protocol */
|
||||||
|
p->debug = nc->debug;
|
||||||
|
if (p->proto->reconfigure(p, nc))
|
||||||
|
{
|
||||||
|
DBG("\t%s: same\n", oc->name);
|
||||||
|
p->cf = nc;
|
||||||
|
nc->proto = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Unsuccessful, force reconfig */
|
||||||
|
DBG("\t%s: power cycling\n", oc->name);
|
||||||
|
p->cf_new = nc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG("\t%s: deleting\n", oc->name);
|
||||||
|
p->cf_new = NULL;
|
||||||
|
}
|
||||||
|
p->reconfiguring = 1;
|
||||||
|
config_add_obstacle(old);
|
||||||
|
proto_rethink_goal(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
debug("\n");
|
|
||||||
|
WALK_LIST(nc, new->protos)
|
||||||
|
if (!nc->proto)
|
||||||
|
{
|
||||||
|
DBG("\t%s: adding\n", nc->name);
|
||||||
|
proto_init(nc);
|
||||||
|
}
|
||||||
|
DBG("\tdone\n");
|
||||||
|
|
||||||
|
DBG("Protocol start\n");
|
||||||
|
WALK_LIST_DELSAFE(p, n, initial_proto_list)
|
||||||
|
proto_rethink_goal(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
proto_rethink_goal(struct proto *p)
|
proto_rethink_goal(struct proto *p)
|
||||||
{
|
{
|
||||||
struct protocol *q = p->proto;
|
struct protocol *q;
|
||||||
|
|
||||||
|
if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
|
||||||
|
{
|
||||||
|
struct proto_config *nc = p->cf_new;
|
||||||
|
DBG("%s has shut down for reconfiguration\n", p->name);
|
||||||
|
config_del_obstacle(p->cf->global);
|
||||||
|
rem_node(&p->n);
|
||||||
|
mb_free(p);
|
||||||
|
if (!nc)
|
||||||
|
return;
|
||||||
|
p = proto_init(nc); /* FIXME: What about protocol priorities??? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine what state we want to reach */
|
||||||
|
if (p->disabled || shutting_down || p->reconfiguring)
|
||||||
|
p->core_goal = FS_HUNGRY;
|
||||||
|
else
|
||||||
|
p->core_goal = FS_HAPPY;
|
||||||
|
|
||||||
if (p->core_state == p->core_goal)
|
if (p->core_state == p->core_goal)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
q = p->proto;
|
||||||
if (p->core_goal == FS_HAPPY) /* Going up */
|
if (p->core_goal == FS_HAPPY) /* Going up */
|
||||||
{
|
{
|
||||||
if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
|
if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
|
||||||
|
@ -242,25 +320,6 @@ proto_rethink_goal(struct proto *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
proto_set_goal(struct proto *p, unsigned goal)
|
|
||||||
{
|
|
||||||
if (p->disabled || shutting_down)
|
|
||||||
goal = FS_HUNGRY;
|
|
||||||
p->core_goal = goal;
|
|
||||||
proto_rethink_goal(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
protos_start(void)
|
|
||||||
{
|
|
||||||
struct proto *p, *n;
|
|
||||||
|
|
||||||
debug("Protocol start\n");
|
|
||||||
WALK_LIST_DELSAFE(p, n, initial_proto_list)
|
|
||||||
proto_set_goal(p, FS_HAPPY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
protos_shutdown(void)
|
protos_shutdown(void)
|
||||||
{
|
{
|
||||||
|
@ -271,12 +330,12 @@ protos_shutdown(void)
|
||||||
if (p->core_state != FS_HUNGRY || p->proto_state != PS_DOWN)
|
if (p->core_state != FS_HUNGRY || p->proto_state != PS_DOWN)
|
||||||
{
|
{
|
||||||
proto_shutdown_counter++;
|
proto_shutdown_counter++;
|
||||||
proto_set_goal(p, FS_HUNGRY);
|
proto_rethink_goal(p);
|
||||||
}
|
}
|
||||||
WALK_LIST_BACKWARDS_DELSAFE(p, n, proto_list)
|
WALK_LIST_BACKWARDS_DELSAFE(p, n, proto_list)
|
||||||
{
|
{
|
||||||
proto_shutdown_counter++;
|
proto_shutdown_counter++;
|
||||||
proto_set_goal(p, FS_HUNGRY);
|
proto_rethink_goal(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +388,7 @@ static void
|
||||||
proto_fell_down(struct proto *p)
|
proto_fell_down(struct proto *p)
|
||||||
{
|
{
|
||||||
DBG("Protocol %s down\n", p->name);
|
DBG("Protocol %s down\n", p->name);
|
||||||
|
rt_unlock_table(p->table);
|
||||||
if (!--proto_shutdown_counter)
|
if (!--proto_shutdown_counter)
|
||||||
protos_shutdown_notify();
|
protos_shutdown_notify();
|
||||||
proto_rethink_goal(p);
|
proto_rethink_goal(p);
|
||||||
|
@ -363,7 +423,10 @@ proto_notify_state(struct proto *p, unsigned ps)
|
||||||
{
|
{
|
||||||
case PS_DOWN:
|
case PS_DOWN:
|
||||||
if (cs == FS_HUNGRY) /* Shutdown finished */
|
if (cs == FS_HUNGRY) /* Shutdown finished */
|
||||||
proto_fell_down(p);
|
{
|
||||||
|
proto_fell_down(p);
|
||||||
|
return; /* The protocol might have ceased to exist */
|
||||||
|
}
|
||||||
else if (cs == FS_FLUSHING) /* Still flushing... */
|
else if (cs == FS_FLUSHING) /* Still flushing... */
|
||||||
;
|
;
|
||||||
else /* Need to start flushing */
|
else /* Need to start flushing */
|
||||||
|
|
|
@ -41,7 +41,7 @@ struct protocol {
|
||||||
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
|
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
|
||||||
void (*postconfig)(struct proto_config *); /* After configuring each instance */
|
void (*postconfig)(struct proto_config *); /* After configuring each instance */
|
||||||
struct proto * (*init)(struct proto_config *); /* Create new instance */
|
struct proto * (*init)(struct proto_config *); /* Create new instance */
|
||||||
int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance */
|
int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance, returns success */
|
||||||
void (*dump)(struct proto *); /* Debugging dump */
|
void (*dump)(struct proto *); /* Debugging dump */
|
||||||
void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */
|
void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */
|
||||||
int (*start)(struct proto *); /* Start the instance */
|
int (*start)(struct proto *); /* Start the instance */
|
||||||
|
@ -54,8 +54,7 @@ struct protocol {
|
||||||
void protos_build(void);
|
void protos_build(void);
|
||||||
void protos_preconfig(struct config *);
|
void protos_preconfig(struct config *);
|
||||||
void protos_postconfig(struct config *);
|
void protos_postconfig(struct config *);
|
||||||
void protos_commit(struct config *);
|
void protos_commit(struct config *new, struct config *old, int force_restart);
|
||||||
void protos_start(void);
|
|
||||||
void protos_dump_all(void);
|
void protos_dump_all(void);
|
||||||
void protos_shutdown(void);
|
void protos_shutdown(void);
|
||||||
|
|
||||||
|
@ -92,6 +91,7 @@ struct proto {
|
||||||
node n;
|
node n;
|
||||||
struct protocol *proto; /* Protocol */
|
struct protocol *proto; /* Protocol */
|
||||||
struct proto_config *cf; /* Configuration data */
|
struct proto_config *cf; /* Configuration data */
|
||||||
|
struct proto_config *cf_new; /* Configuration we want to switch to after shutdown (NULL=delete) */
|
||||||
pool *pool; /* Pool containing local objects */
|
pool *pool; /* Pool containing local objects */
|
||||||
struct event *attn; /* "Pay attention" event */
|
struct event *attn; /* "Pay attention" event */
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ struct proto {
|
||||||
unsigned proto_state; /* Protocol state machine (see below) */
|
unsigned proto_state; /* Protocol state machine (see below) */
|
||||||
unsigned core_state; /* Core state machine (see below) */
|
unsigned core_state; /* Core state machine (see below) */
|
||||||
unsigned core_goal; /* State we want to reach (see below) */
|
unsigned core_goal; /* State we want to reach (see below) */
|
||||||
|
unsigned reconfiguring; /* We're shutting down due to reconfiguration */
|
||||||
bird_clock_t last_state_change; /* Time of last state transition */
|
bird_clock_t last_state_change; /* Time of last state transition */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
11
nest/route.h
11
nest/route.h
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Internet Routing Daemon -- Routing Table
|
* BIRD Internet Routing Daemon -- Routing Table
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -121,6 +121,11 @@ typedef struct rtable {
|
||||||
char *name; /* Name of this table */
|
char *name; /* Name of this table */
|
||||||
list hooks; /* List of announcement hooks */
|
list hooks; /* List of announcement hooks */
|
||||||
int pipe_busy; /* Pipe loop detection */
|
int pipe_busy; /* Pipe loop detection */
|
||||||
|
int use_count; /* Number of protocols using this table */
|
||||||
|
struct config *deleted; /* Table doesn't exist in current configuration,
|
||||||
|
* delete as soon as use_count becomes 0 and remove
|
||||||
|
* obstacle from this routing table.
|
||||||
|
*/
|
||||||
} rtable;
|
} rtable;
|
||||||
|
|
||||||
typedef struct network {
|
typedef struct network {
|
||||||
|
@ -171,7 +176,9 @@ struct config;
|
||||||
|
|
||||||
void rt_init(void);
|
void rt_init(void);
|
||||||
void rt_preconfig(struct config *);
|
void rt_preconfig(struct config *);
|
||||||
void rt_commit(struct config *);
|
void rt_commit(struct config *new, struct config *old);
|
||||||
|
void rt_lock_table(rtable *);
|
||||||
|
void rt_unlock_table(rtable *);
|
||||||
void rt_setup(pool *, rtable *, char *);
|
void rt_setup(pool *, rtable *, char *);
|
||||||
static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); }
|
static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); }
|
||||||
static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); }
|
static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Routing Table
|
* BIRD -- Routing Table
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -480,19 +480,70 @@ rt_preconfig(struct config *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rt_commit(struct config *c)
|
rt_lock_table(rtable *r)
|
||||||
{
|
{
|
||||||
struct rtable_config *r;
|
r->use_count++;
|
||||||
|
}
|
||||||
|
|
||||||
WALK_LIST(r, c->tables)
|
void
|
||||||
|
rt_unlock_table(rtable *r)
|
||||||
|
{
|
||||||
|
if (!--r->use_count && r->deleted)
|
||||||
{
|
{
|
||||||
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
struct config *conf = r->deleted;
|
||||||
rt_setup(rt_table_pool, t, r->name);
|
DBG("Deleting routing table %s\n", r->name);
|
||||||
add_tail(&routing_tables, &t->n);
|
rem_node(&r->n);
|
||||||
r->table = t;
|
fib_free(&r->fib);
|
||||||
|
mb_free(r);
|
||||||
|
config_del_obstacle(conf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rt_commit(struct config *new, struct config *old)
|
||||||
|
{
|
||||||
|
struct rtable_config *o, *r;
|
||||||
|
|
||||||
|
DBG("rt_commit:\n");
|
||||||
|
if (old)
|
||||||
|
{
|
||||||
|
WALK_LIST(o, old->tables)
|
||||||
|
{
|
||||||
|
rtable *ot = o->table;
|
||||||
|
if (!ot->deleted)
|
||||||
|
{
|
||||||
|
struct symbol *sym = cf_find_symbol(o->name);
|
||||||
|
if (sym && sym->class == SYM_TABLE)
|
||||||
|
{
|
||||||
|
DBG("\t%s: same\n", o->name);
|
||||||
|
r = sym->def;
|
||||||
|
r->table = ot;
|
||||||
|
ot->name = r->name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG("\t%s: deleted", o->name);
|
||||||
|
ot->deleted = old;
|
||||||
|
config_add_obstacle(old);
|
||||||
|
rt_lock_table(ot);
|
||||||
|
rt_unlock_table(ot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WALK_LIST(r, new->tables)
|
||||||
|
if (!r->table)
|
||||||
|
{
|
||||||
|
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
||||||
|
DBG("\t%s: created\n", r->name);
|
||||||
|
rt_setup(rt_table_pool, t, r->name);
|
||||||
|
add_tail(&routing_tables, &t->n);
|
||||||
|
r->table = t;
|
||||||
|
}
|
||||||
|
DBG("\tdone\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CLI commands
|
* CLI commands
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
|
* BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
|
||||||
*
|
*
|
||||||
* (c) 1999 Martin Mares <mj@ucw.cz>
|
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -106,10 +106,20 @@ pipe_start(struct proto *P)
|
||||||
*/
|
*/
|
||||||
a = proto_add_announce_hook(P, p->peer);
|
a = proto_add_announce_hook(P, p->peer);
|
||||||
a->proto = &ph->p;
|
a->proto = &ph->p;
|
||||||
|
rt_lock_table(p->peer);
|
||||||
|
|
||||||
return PS_UP;
|
return PS_UP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pipe_shutdown(struct proto *P)
|
||||||
|
{
|
||||||
|
struct pipe_proto *p = (struct pipe_proto *) P;
|
||||||
|
|
||||||
|
rt_unlock_table(p->peer);
|
||||||
|
return PS_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
static struct proto *
|
static struct proto *
|
||||||
pipe_init(struct proto_config *C)
|
pipe_init(struct proto_config *C)
|
||||||
{
|
{
|
||||||
|
@ -147,5 +157,6 @@ struct protocol proto_pipe = {
|
||||||
postconfig: pipe_postconfig,
|
postconfig: pipe_postconfig,
|
||||||
init: pipe_init,
|
init: pipe_init,
|
||||||
start: pipe_start,
|
start: pipe_start,
|
||||||
|
shutdown: pipe_shutdown,
|
||||||
get_status: pipe_get_status,
|
get_status: pipe_get_status,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- UNIX Configuration
|
* BIRD -- UNIX Configuration
|
||||||
*
|
*
|
||||||
* (c) 1999 Martin Mares <mj@ucw.cz>
|
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@ CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH,
|
||||||
|
|
||||||
%type <i> log_mask log_mask_list log_cat
|
%type <i> log_mask log_mask_list log_cat
|
||||||
%type <g> log_file
|
%type <g> log_file
|
||||||
|
%type <t> cfg_name
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -61,6 +62,16 @@ log_cat:
|
||||||
| BUG { $$ = L_BUG[0]; }
|
| BUG { $$ = L_BUG[0]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Unix specific commands */
|
||||||
|
|
||||||
|
CF_CLI(CONFIGURE, cfg_name, [<file>], [[Reload configuration]])
|
||||||
|
{ cmd_reconfig($2); } ;
|
||||||
|
|
||||||
|
cfg_name:
|
||||||
|
/* empty */ { $$ = NULL; }
|
||||||
|
| TEXT
|
||||||
|
;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- UNIX Kernel Synchronization
|
* BIRD -- UNIX Kernel Synchronization
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -67,6 +67,12 @@ static struct kif_proto *kif_proto;
|
||||||
static timer *kif_scan_timer;
|
static timer *kif_scan_timer;
|
||||||
static bird_clock_t kif_last_shot;
|
static bird_clock_t kif_last_shot;
|
||||||
|
|
||||||
|
static void
|
||||||
|
kif_preconfig(struct protocol *P, struct config *c)
|
||||||
|
{
|
||||||
|
cf_kif = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
kif_scan(timer *t)
|
kif_scan(timer *t)
|
||||||
{
|
{
|
||||||
|
@ -137,6 +143,7 @@ kif_shutdown(struct proto *P)
|
||||||
struct protocol proto_unix_iface = {
|
struct protocol proto_unix_iface = {
|
||||||
name: "Device",
|
name: "Device",
|
||||||
priority: 100,
|
priority: 100,
|
||||||
|
preconfig: kif_preconfig,
|
||||||
init: kif_init,
|
init: kif_init,
|
||||||
start: kif_start,
|
start: kif_start,
|
||||||
shutdown: kif_shutdown,
|
shutdown: kif_shutdown,
|
||||||
|
@ -646,6 +653,7 @@ struct proto_config *cf_krt;
|
||||||
static void
|
static void
|
||||||
krt_preconfig(struct protocol *P, struct config *c)
|
krt_preconfig(struct protocol *P, struct config *c)
|
||||||
{
|
{
|
||||||
|
cf_krt = NULL;
|
||||||
krt_scan_preconfig(c);
|
krt_scan_preconfig(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Internet Routing Daemon -- Unix Entry Point
|
* BIRD Internet Routing Daemon -- Unix Entry Point
|
||||||
*
|
*
|
||||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -74,30 +74,89 @@ sysdep_preconfig(struct config *c)
|
||||||
init_list(&c->logfiles);
|
init_list(&c->logfiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
sysdep_commit(struct config *c)
|
sysdep_commit(struct config *new, struct config *old)
|
||||||
{
|
{
|
||||||
log_switch(&c->logfiles);
|
log_switch(&new->logfiles);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
unix_read_config(struct config **cp, char *name)
|
||||||
|
{
|
||||||
|
struct config *conf = config_alloc(name);
|
||||||
|
|
||||||
|
*cp = conf;
|
||||||
|
conf_fd = open(name, O_RDONLY);
|
||||||
|
if (conf_fd < 0)
|
||||||
|
return 0;
|
||||||
|
cf_read_hook = cf_read;
|
||||||
|
return config_parse(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_config(void)
|
read_config(void)
|
||||||
{
|
{
|
||||||
struct config *conf = config_alloc(config_name);
|
struct config *conf;
|
||||||
|
|
||||||
conf_fd = open(config_name, O_RDONLY);
|
if (!unix_read_config(&conf, config_name))
|
||||||
if (conf_fd < 0)
|
{
|
||||||
die("Unable to open configuration file %s: %m", config_name);
|
if (conf->err_msg)
|
||||||
cf_read_hook = cf_read;
|
die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
|
||||||
if (!config_parse(conf))
|
else
|
||||||
die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
|
die("Unable to open configuration file %s: %m", config_name);
|
||||||
|
}
|
||||||
config_commit(conf);
|
config_commit(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
async_config(void)
|
async_config(void)
|
||||||
{
|
{
|
||||||
debug("Asynchronous reconfigurations are not supported in demo version\n");
|
struct config *conf;
|
||||||
|
|
||||||
|
log(L_INFO "Reconfiguration requested by SIGHUP");
|
||||||
|
if (!unix_read_config(&conf, config_name))
|
||||||
|
{
|
||||||
|
if (conf->err_msg)
|
||||||
|
log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
|
||||||
|
else
|
||||||
|
log(L_ERR "Unable to open configuration file %s: %m", config_name);
|
||||||
|
config_free(conf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
config_commit(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cmd_reconfig(char *name)
|
||||||
|
{
|
||||||
|
struct config *conf;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = config_name;
|
||||||
|
cli_msg(-2, "Reading configuration from %s", name);
|
||||||
|
if (!unix_read_config(&conf, name))
|
||||||
|
{
|
||||||
|
if (conf->err_msg)
|
||||||
|
cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
|
||||||
|
else
|
||||||
|
cli_msg(8002, "%s: %m", name);
|
||||||
|
config_free(conf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (config_commit(conf))
|
||||||
|
{
|
||||||
|
case CONF_DONE:
|
||||||
|
cli_msg(3, "Reconfigured.");
|
||||||
|
break;
|
||||||
|
case CONF_PROGRESS:
|
||||||
|
cli_msg(4, "Reconfiguration in progress.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cli_msg(5, "Reconfiguration already in progress, queueing new config");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -350,8 +409,6 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
cli_init_unix();
|
cli_init_unix();
|
||||||
|
|
||||||
protos_start();
|
|
||||||
|
|
||||||
ev_run_list(&global_event_list);
|
ev_run_list(&global_event_list);
|
||||||
async_dump();
|
async_dump();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Declarations Common to Unix Port
|
* BIRD -- Declarations Common to Unix Port
|
||||||
*
|
*
|
||||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@ struct pool;
|
||||||
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);
|
||||||
|
|
||||||
/* io.c */
|
/* io.c */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue