From 50fe90edf3deab409ea7887c131bfe6ce89fa556 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 16 Jan 2000 16:44:50 +0000 Subject: [PATCH] First attempt on dynamic reconfiguration. There are still lots of bugs and problems to solve, but the hardest part works. --- TODO | 17 ++++- conf/conf.c | 121 +++++++++++++++++++++++++++++++-- conf/conf.h | 18 +++-- doc/reply_codes | 2 + nest/proto.c | 157 ++++++++++++++++++++++++++++++------------- nest/protocol.h | 7 +- nest/route.h | 11 ++- nest/rt-table.c | 67 +++++++++++++++--- proto/pipe/pipe.c | 13 +++- sysdep/unix/config.Y | 13 +++- sysdep/unix/krt.c | 10 ++- sysdep/unix/main.c | 85 +++++++++++++++++++---- sysdep/unix/unix.h | 3 +- 13 files changed, 434 insertions(+), 90 deletions(-) diff --git a/TODO b/TODO index 79efcb0d..c2a6fc88 100644 --- a/TODO +++ b/TODO @@ -26,19 +26,21 @@ Core - config: executable config files - config: when parsing prefix, check zero bits - config: reconfiguration +- config: reconfiguration of filters - config: useless rules when protocols disabled - config: remove protocol startup priority hacks? - 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: 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? - io: use poll if available -- port to FreeBSD - Commands ~~~~~~~~ shutdown # order system shutdown @@ -50,6 +52,17 @@ show # show everything you know about symbol symbols (disable|enable|restart) # or ALL? - 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 ~~~~~~ diff --git a/conf/conf.c b/conf/conf.c index ea65183b..1c5401bc 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -1,7 +1,7 @@ /* * BIRD Internet Routing Daemon -- Configuration File Handling * - * (c) 1999 Martin Mares + * (c) 1998--2000 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -9,18 +9,22 @@ #include #include +#define LOCAL_DEBUG + #include "nest/bird.h" #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" #include "lib/resource.h" #include "lib/string.h" +#include "lib/event.h" #include "conf/conf.h" #include "filter/filter.h" 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 * config_alloc(byte *name) @@ -77,12 +81,117 @@ config_free(struct config *c) } 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 = c; - sysdep_commit(c); - rt_commit(c); - protos_commit(c); + if (!config) /* First-time configuration */ + { + config_do_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 diff --git a/conf/conf.h b/conf/conf.h index b0a38118..7d13ae9c 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -1,7 +1,7 @@ /* * BIRD Internet Routing Daemon -- Configuration File Handling * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * 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 */ struct symbol **sym_hash; /* Lexer: 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. */ +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); int config_parse(struct config *); int cli_parse(struct config *); void config_free(struct config *); -void config_commit(struct config *); +int config_commit(struct config *); 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 */ @@ -87,6 +97,6 @@ int cf_parse(void); /* Sysdep hooks */ void sysdep_preconfig(struct config *); -void sysdep_commit(struct config *); +int sysdep_commit(struct config *, struct config *); #endif diff --git a/doc/reply_codes b/doc/reply_codes index 844ed435..9b74c5b1 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -10,6 +10,7 @@ Reply codes of BIRD command-line interface 0000 OK 0001 Welcome +0002 Reading configuration 1000 BIRD version 1001 Interface list @@ -24,6 +25,7 @@ Reply codes of BIRD command-line interface 8000 Reply too long 8001 Route not found +8002 Configuration file error 9000 Command too long 9001 Parse error diff --git a/nest/proto.c b/nest/proto.c index a58c3f71..ecf0d906 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1,7 +1,7 @@ /* * BIRD -- Protocols * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * 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"); } -void -protos_commit(struct config *c) +static struct proto * +proto_init(struct proto_config *c) { - struct proto_config *x; - struct protocol *p; - struct proto *q; + struct protocol *p = c->protocol; + struct proto *q = p->init(c); - debug("Protocol commit:"); - WALK_LIST(x, c->protos) + 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 *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); - 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 39d1cf5d..72f88b6b 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 903e9b93..da793d6c 100644 --- a/nest/route.h +++ b/nest/route.h @@ -1,7 +1,7 @@ /* * BIRD Internet Routing Daemon -- Routing Table * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * 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 401c5f85..b0d1e291 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1,7 +1,7 @@ /* * BIRD -- Routing Table * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -480,19 +480,70 @@ rt_preconfig(struct config *c) } 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)); - rt_setup(rt_table_pool, t, r->name); - add_tail(&routing_tables, &t->n); - r->table = t; + 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; + + 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 */ diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 0612f5f4..c6a8317d 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -1,7 +1,7 @@ /* * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe * - * (c) 1999 Martin Mares + * (c) 1999--2000 Martin Mares * * 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 = &ph->p; + rt_lock_table(p->peer); 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 * pipe_init(struct proto_config *C) { @@ -147,5 +157,6 @@ struct protocol proto_pipe = { postconfig: pipe_postconfig, init: pipe_init, start: pipe_start, + shutdown: pipe_shutdown, get_status: pipe_get_status, }; diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index f0a517e9..299cc41d 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -1,7 +1,7 @@ /* * BIRD -- UNIX Configuration * - * (c) 1999 Martin Mares + * (c) 1999--2000 Martin Mares * * 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 log_mask log_mask_list log_cat %type log_file +%type cfg_name CF_GRAMMAR @@ -61,6 +62,16 @@ log_cat: | BUG { $$ = L_BUG[0]; } ; +/* Unix specific commands */ + +CF_CLI(CONFIGURE, cfg_name, [], [[Reload configuration]]) +{ cmd_reconfig($2); } ; + +cfg_name: + /* empty */ { $$ = NULL; } + | TEXT + ; + CF_CODE CF_END diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index aa9a9c43..7c92c551 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -1,7 +1,7 @@ /* * BIRD -- UNIX Kernel Synchronization * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * 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 bird_clock_t kif_last_shot; +static void +kif_preconfig(struct protocol *P, struct config *c) +{ + cf_kif = NULL; +} + static void kif_scan(timer *t) { @@ -137,6 +143,7 @@ kif_shutdown(struct proto *P) struct protocol proto_unix_iface = { name: "Device", priority: 100, + preconfig: kif_preconfig, init: kif_init, start: kif_start, shutdown: kif_shutdown, @@ -646,6 +653,7 @@ struct proto_config *cf_krt; static void krt_preconfig(struct protocol *P, struct config *c) { + cf_krt = NULL; krt_scan_preconfig(c); } diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 4b9ab615..97b9dc60 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -1,7 +1,7 @@ /* * BIRD Internet Routing Daemon -- Unix Entry Point * - * (c) 1998--1999 Martin Mares + * (c) 1998--2000 Martin Mares * * 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); } -void -sysdep_commit(struct config *c) +int +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 read_config(void) { - struct config *conf = config_alloc(config_name); + struct config *conf; - conf_fd = open(config_name, O_RDONLY); - if (conf_fd < 0) - die("Unable to open configuration file %s: %m", config_name); - cf_read_hook = cf_read; - if (!config_parse(conf)) - die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg); + if (!unix_read_config(&conf, config_name)) + { + if (conf->err_msg) + die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg); + else + die("Unable to open configuration file %s: %m", config_name); + } config_commit(conf); } 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(); - protos_start(); - ev_run_list(&global_event_list); async_dump(); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 8dd72496..68850bcc 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -1,7 +1,7 @@ /* * BIRD -- Declarations Common to Unix Port * - * (c) 1998 Martin Mares + * (c) 1998--2000 Martin Mares * * 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_dump(void); void async_shutdown(void); +void cmd_reconfig(char *name); /* io.c */