summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2000-01-16 17:44:50 +0100
committerMartin Mares <mj@ucw.cz>2000-01-16 17:44:50 +0100
commit50fe90edf3deab409ea7887c131bfe6ce89fa556 (patch)
treed9aad4ed34285a59cfcc0286a22ca5ccdb63a82f /nest
parent394aec8fdd112a81da1e2f6f0e09ee74256dc24e (diff)
downloadbird-50fe90edf3deab409ea7887c131bfe6ce89fa556.tar
bird-50fe90edf3deab409ea7887c131bfe6ce89fa556.zip
First attempt on dynamic reconfiguration. There are still lots of bugs
and problems to solve, but the hardest part works.
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c155
-rw-r--r--nest/protocol.h7
-rw-r--r--nest/route.h11
-rw-r--r--nest/rt-table.c67
4 files changed, 181 insertions, 59 deletions
diff --git a/nest/proto.c b/nest/proto.c
index a58c3f7..ecf0d90 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -1,7 +1,7 @@
/*
* 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.
*/
@@ -38,6 +38,7 @@ static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
static int proto_flush_all(void *);
+static void proto_rethink_goal(struct proto *p);
static void
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->attn = ev_new(p->pool);
p->attn->data = p;
+ rt_lock_table(p->table);
}
struct announce_hook *
@@ -185,42 +187,118 @@ protos_postconfig(struct config *c)
debug("\n");
}
+static struct proto *
+proto_init(struct proto_config *c)
+{
+ struct protocol *p = c->protocol;
+ struct proto *q = p->init(c);
+
+ q->proto_state = PS_DOWN;
+ 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 *c)
+protos_commit(struct config *new, struct config *old, int force_reconfig)
{
- struct proto_config *x;
- struct protocol *p;
- struct proto *q;
+ struct proto_config *oc, *nc;
+ struct proto *p, *n;
- debug("Protocol commit:");
- WALK_LIST(x, c->protos)
+ DBG("protos_commit:\n");
+ if (old)
{
- debug(" %s", x->name);
- p = x->protocol;
- q = p->init(x);
- q->proto_state = PS_DOWN;
- 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++;
+ WALK_LIST(oc, old->protos)
+ {
+ struct proto *p = oc->proto;
+ struct symbol *sym = cf_find_symbol(oc->name);
+ if (sym && sym->class == SYM_PROTO)
+ {
+ /* Found match, let's check if we can smoothly switch to new configuration */
+ nc = sym->def;
+ if (!force_reconfig
+ && nc->protocol == oc->protocol
+ && nc->preference == oc->preference
+ && nc->disabled == oc->disabled
+ && nc->table->table == oc->table->table
+ && nc->in_filter == oc->in_filter
+ && 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
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)
return;
+
+ q = p->proto;
if (p->core_goal == FS_HAPPY) /* Going up */
{
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
protos_shutdown(void)
{
@@ -271,12 +330,12 @@ protos_shutdown(void)
if (p->core_state != FS_HUNGRY || p->proto_state != PS_DOWN)
{
proto_shutdown_counter++;
- proto_set_goal(p, FS_HUNGRY);
+ proto_rethink_goal(p);
}
WALK_LIST_BACKWARDS_DELSAFE(p, n, proto_list)
{
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)
{
DBG("Protocol %s down\n", p->name);
+ rt_unlock_table(p->table);
if (!--proto_shutdown_counter)
protos_shutdown_notify();
proto_rethink_goal(p);
@@ -363,7 +423,10 @@ proto_notify_state(struct proto *p, unsigned ps)
{
case PS_DOWN:
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 /* Need to start flushing */
diff --git a/nest/protocol.h b/nest/protocol.h
index 39d1cf5..72f88b6 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -41,7 +41,7 @@ struct protocol {
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
void (*postconfig)(struct proto_config *); /* After configuring each 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_attrs)(struct rte *); /* Dump protocol-dependent attributes */
int (*start)(struct proto *); /* Start the instance */
@@ -54,8 +54,7 @@ struct protocol {
void protos_build(void);
void protos_preconfig(struct config *);
void protos_postconfig(struct config *);
-void protos_commit(struct config *);
-void protos_start(void);
+void protos_commit(struct config *new, struct config *old, int force_restart);
void protos_dump_all(void);
void protos_shutdown(void);
@@ -92,6 +91,7 @@ struct proto {
node n;
struct protocol *proto; /* Protocol */
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 */
struct event *attn; /* "Pay attention" event */
@@ -103,6 +103,7 @@ struct proto {
unsigned proto_state; /* Protocol state machine (see below) */
unsigned core_state; /* Core state machine (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 */
/*
diff --git a/nest/route.h b/nest/route.h
index 903e9b9..da793d6 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -1,7 +1,7 @@
/*
* 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.
*/
@@ -121,6 +121,11 @@ typedef struct rtable {
char *name; /* Name of this table */
list hooks; /* List of announcement hooks */
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;
typedef struct network {
@@ -171,7 +176,9 @@ struct config;
void rt_init(void);
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 *);
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); }
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 401c5f8..b0d1e29 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -1,7 +1,7 @@
/*
* 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.
*/
@@ -480,17 +480,68 @@ rt_preconfig(struct config *c)
}
void
-rt_commit(struct config *c)
+rt_lock_table(rtable *r)
{
- struct rtable_config *r;
+ r->use_count++;
+}
+
+void
+rt_unlock_table(rtable *r)
+{
+ if (!--r->use_count && r->deleted)
+ {
+ struct config *conf = r->deleted;
+ DBG("Deleting routing table %s\n", r->name);
+ rem_node(&r->n);
+ 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;
- WALK_LIST(r, c->tables)
+ DBG("rt_commit:\n");
+ if (old)
{
- rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
- rt_setup(rt_table_pool, t, r->name);
- add_tail(&routing_tables, &t->n);
- r->table = t;
+ 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");
}
/*