Commit 31b3e1bb authored by Martin Mareš's avatar Martin Mareš

Implemented new configuration/reconfiguration interface and defined protocol

state machines. Full explanation will follow soon.
parent c4c63eec
......@@ -6,6 +6,9 @@ Core
* logging and tracing; use appropriate log levels
* check log calls for trailing newlines
* Fix router ID calculation
* debug dump: dump router ID as well
- TOS not supported by kernel -> automatically drop routes with TOS<>0
- fake multipath?
......
source=cf-parse.tab.c cf-lex.c
source=cf-parse.tab.c cf-lex.c conf.c
root-rel=../
include ../Rules
......
/*
* BIRD -- Configuration Lexer
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -15,7 +15,6 @@
#include <stdarg.h>
#include "nest/bird.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "conf/cf-parse.tab.h"
......@@ -34,9 +33,10 @@ static struct keyword {
static struct keyword *kw_hash[KW_HASH_SIZE];
static struct symbol **sym_hash;
static int allow_new_symbols;
static int cf_lino;
static int default_counter;
int conf_lino;
static int cf_hash(byte *c);
static struct symbol *cf_find_sym(byte *c, unsigned int h0);
......@@ -121,11 +121,11 @@ WHITE [ \t]
{WHITE}+
\\\n {
cf_lino++;
conf_lino++;
}
\n {
cf_lino++;
conf_lino++;
return ';';
}
......@@ -136,14 +136,14 @@ WHITE [ \t]
. cf_error("Unknown character");
<COMMENT>\n {
cf_lino++;
conf_lino++;
BEGIN(INITIAL);
}
<COMMENT>.
<CCOMM>\*\/ BEGIN(INITIAL);
<CCOMM>\n cf_lino++;
<CCOMM>\n conf_lino++;
<CCOMM>\/\* cf_error("Comment nesting not supported");
<CCOMM><<EOF>> cf_error("Unterminated comment");
<CCOMM>.
......@@ -206,7 +206,7 @@ cf_lex_init(int flag)
{
if (allow_new_symbols = flag)
sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *));
cf_lino = 1;
conf_lino = 1;
default_counter = 1;
}
......@@ -222,34 +222,3 @@ cf_lex_init_tables(void)
kw_hash[h] = k;
}
}
void
cf_error(char *msg, ...)
{
/* FIXME */
char buf[1024];
va_list args;
va_start(args, msg);
bvsprintf(buf, msg, args);
die(PATH_CONFIG ", line %d: %s", cf_lino, buf);
}
void
cf_allocate(void)
{
if (cfg_pool)
rfree(cfg_pool);
cfg_pool = rp_new(&root_pool, "Config");
cfg_mem = lp_new(cfg_pool, 1024);
}
char *
cfg_strdup(char *c)
{
int l = strlen(c) + 1;
char *z = cfg_allocu(l);
memcpy(z, c, l);
return z;
}
/*
* BIRD Internet Routing Daemon -- Configuration File Handling
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <setjmp.h>
#include <stdarg.h>
#include "nest/bird.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "lib/resource.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "filter/filter.h"
static jmp_buf conf_jmpbuf;
struct config *config, *new_config;
struct config *
config_alloc(byte *name)
{
pool *p = rp_new(&root_pool, "Config");
linpool *l = lp_new(p, 1024);
struct config *c = lp_allocz(l, sizeof(struct config));
c->pool = p;
cfg_mem = c->mem = l;
init_list(&c->protos);
c->file_name = cfg_strdup(name);
return c;
}
int
config_parse(struct config *c)
{
struct proto_config *p;
debug("Parsing configuration file <%s>\n", c->file_name);
new_config = c;
cfg_pool = c->pool;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
return 0;
cf_lex_init(1);
cf_lex_init_tables();
protos_preconfig(c);
cf_parse();
#if 0 /* FIXME: We don't have interface list yet :( */
if (!c->router_id && !(c->router_id = auto_router_id()))
cf_error("Cannot determine router ID (no suitable network interface found), please configure it manually");
#endif
filters_postconfig(); /* FIXME: Do we really need this? */
protos_postconfig(c);
return 1;
}
void
config_free(struct config *c)
{
rfree(c->pool);
}
void
config_commit(struct config *c)
{
config = c;
protos_commit(c);
}
void
cf_error(char *msg, ...)
{
char buf[1024];
va_list args;
va_start(args, msg);
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
strcpy(buf, "<bug: error message too long>");
new_config->err_msg = cfg_strdup(buf);
new_config->err_lino = conf_lino;
longjmp(conf_jmpbuf, 1);
}
char *
cfg_strdup(char *c)
{
int l = strlen(c) + 1;
char *z = cfg_allocu(l);
memcpy(z, c, l);
return z;
}
/*
* BIRD Internet Routing Daemon -- Configuration File Handling
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -11,6 +11,28 @@
#include "lib/resource.h"
/* Configuration structure */
struct config {
pool *pool; /* Pool the configuration is stored in */
linpool *mem; /* Linear pool containing configuration data */
list protos; /* Configured protocol instances (struct proto_config) */
u32 router_id; /* Our Router ID */
u16 this_as; /* Our Autonomous System Number */
char *err_msg; /* Parser error message */
int err_lino; /* Line containing error */
char *file_name; /* Name of configuration file */
};
extern struct config *config, *new_config;
/* Please don't use these variables in protocols. Use proto_config->global instead. */
struct config *config_alloc(byte *name);
int config_parse(struct config *);
void config_free(struct config *);
void config_commit(struct config *);
void cf_error(char *msg, ...) NORET;
/* Pools */
extern pool *cfg_pool;
......@@ -41,11 +63,11 @@ struct symbol {
#define SYM_FUNCTION 5
#define SYM_FILTER 6
extern int conf_lino;
void cf_lex_init_tables(void);
int cf_lex(void);
void cf_lex_init(int flag);
void cf_error(char *msg, ...) NORET;
void cf_allocate(void);
struct symbol *cf_default_name(char *prefix);
/* Parser */
......
/*
* BIRD Internet Routing Daemon -- Basic Declarations
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -13,7 +13,4 @@
#include "lib/birdlib.h"
#include "lib/ip.h"
extern u32 router_id; /* Our Router ID */
extern u16 this_as; /* Our Autonomous System Number */
#endif
/*
* BIRD -- Core Configuration
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
CF_HDR
static struct proto *this_proto;
static struct proto_config *this_proto;
#include "nest/rt-dev.h"
......@@ -27,7 +27,7 @@ CF_GRAMMAR
CF_ADDTO(conf, rtrid)
rtrid: ROUTER ID idval {
router_id = $3;
new_config->router_id = $3;
}
;
......@@ -87,7 +87,7 @@ dev_proto:
dev_iface_list:
INTERFACE TEXT {
init_list(&((struct rt_dev_proto *) this_proto)->iface_list);
init_list(&((struct rt_dev_config *) this_proto)->iface_list);
rt_dev_add_iface($2);
}
| dev_iface_list ',' TEXT { rt_dev_add_iface($3); }
......@@ -98,7 +98,7 @@ CF_CODE
void
rt_dev_add_iface(char *n)
{
struct rt_dev_proto *p = (void *) this_proto;
struct rt_dev_config *p = (void *) this_proto;
struct iface_patt *k = cfg_alloc(sizeof(struct iface_patt));
k->pattern = cfg_strdup(n);
......
/*
* BIRD -- Management of Interfaces and Neighbor Cache
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -16,8 +16,6 @@
static pool *if_pool;
u32 router_id;
/*
* Neighbor Cache
*
......@@ -103,7 +101,7 @@ neigh_dump(neighbor *n)
debug("%s ", n->iface->name);
else
debug("[] ");
debug("%s %p", n->proto->name, n->data);
debug("%s %p", n->proto->cf->name, n->data);
if (n->flags & NEF_STICKY)
debug(" STICKY");
debug("\n");
......@@ -199,7 +197,6 @@ if_dump_all(void)
debug("Known network interfaces:\n");
WALK_LIST(i, iface_list)
if_dump(i);
debug("\nRouter ID: %08x\n\n", router_id);
}
static inline int
......@@ -322,28 +319,26 @@ if_feed_baby(struct proto *p)
if (!p->if_notify)
return;
debug("Announcing interfaces to new protocol %s\n", p->name);
debug("Announcing interfaces to new protocol %s\n", p->cf->name);
WALK_LIST(i, iface_list)
p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), NULL, i);
}
void
u32
auto_router_id(void) /* FIXME: What if we run IPv6??? */
{
struct iface *i, *j;
if (router_id)
return;
j = NULL;
WALK_LIST(i, iface_list)
if ((i->flags & IF_UP) &&
!(i->flags & (IF_UNNUMBERED | IF_LOOPBACK | IF_IGNORE)) &&
(!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip)))
j = i;
if (!j) /* FIXME: allow configuration or running without RID */
bug("Cannot determine router ID, please configure manually");
router_id = ipa_to_u32(j->ip);
debug("Router ID set to %08x (%s)\n", router_id, j->name);
if (!j)
return 0;
debug("Guessed router ID %I (%s)\n", j->ip, j->name);
return ipa_to_u32(j->ip);
}
void
......
/*
* BIRD Internet Routing Daemon -- Network Interfaces
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -54,7 +54,7 @@ void if_dump_all(void);
void if_update(struct iface *);
void if_end_update(void);
void if_feed_baby(struct proto *);
void auto_router_id(void);
u32 auto_router_id(void);
/*
* Neighbor Cache. We hold (direct neighbor, protocol) pairs we've seen
......
/*
* BIRD -- Protocols
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -23,47 +23,83 @@ list proto_list;
list inactive_proto_list;
void *
proto_new(struct protocol *pr, unsigned size)
proto_new(struct proto_config *c, unsigned size)
{
struct proto *p = cfg_allocz(size);
struct protocol *pr = c->proto;
struct proto *p = cfg_allocz(size); /* FIXME: Allocate from global pool */
debug("proto_new(%s)\n", pr->name);
p->cf = c;
p->debug = c->debug;
p->preference = c->preference;
p->disabled = c->disabled;
p->proto = pr;
p->name = pr->name;
p->debug = pr->debug;
p->pool = rp_new(&root_pool, pr->name);
add_tail(&inactive_proto_list, &p->n);
p->pool = rp_new(&root_pool, c->name);
return p;
}
void *
proto_config_new(struct protocol *pr, unsigned size)
{
struct proto_config *c = cfg_allocz(size);
add_tail(&new_config->protos, &c->n);
c->global = new_config;
c->proto = pr;
c->debug = pr->debug;
c->name = pr->name;
return c;
}
void
protos_preconfig(void)
protos_preconfig(struct config *c)
{
struct protocol *p;
init_list(&proto_list);
init_list(&inactive_proto_list);
debug("Protocol preconfig\n");
debug("Protocol preconfig:");
WALK_LIST(p, protocol_list)
{
debug("...%s\n", p->name);
debug(" %s", p->name);
if (p->preconfig)
p->preconfig(p);
p->preconfig(p, c);
}
debug("\n");
}
void
protos_postconfig(void)
protos_postconfig(struct config *c)
{
struct proto_config *x;
struct protocol *p;
debug("Protocol postconfig\n");
WALK_LIST(p, protocol_list)
debug("Protocol postconfig:");
WALK_LIST(x, c->protos)
{
debug("...%s\n", p->name);
debug(" %s", x->name);
p = x->proto;
if (p->postconfig)
p->postconfig(p);
p->postconfig(x);
}
debug("\n");
}
void
protos_commit(struct config *c)
{
struct proto_config *x;
struct protocol *p;
struct proto *q;
debug("Protocol commit:");
WALK_LIST(x, c->protos)
{
debug(" %s", x->name);
p = x->proto;
q = p->init(x);
add_tail(&inactive_proto_list, &q->n);
}
debug("\n");
}
static void
......@@ -72,12 +108,15 @@ proto_start(struct proto *p)
rem_node(&p->n);
if (p->disabled)
return;
p->state = PRS_STARTING;
if (p->start)
p->start(p);
p->proto_state = PS_DOWN;
p->core_state = FS_HUNGRY;
if (p->proto->start && p->proto->start(p) != PS_UP)
bug("Delayed protocol start not supported yet");
p->proto_state = PS_UP;
p->core_state = FS_FEEDING;
if_feed_baby(p);
rt_feed_baby(p);
p->state = PRS_UP;
p->core_state = FS_HAPPY;
add_tail(&proto_list, &p->n);
}
......@@ -89,7 +128,7 @@ protos_start(void)
debug("Protocol start\n");
WALK_LIST_DELSAFE(p, n, inactive_proto_list)
{
debug("...%s\n", p->name);
debug("Starting %s\n", p->cf->name);
proto_start(p);
}
}
......@@ -98,19 +137,21 @@ void
protos_dump_all(void)
{
struct proto *p;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
debug("Protocols:\n");
WALK_LIST(p, proto_list)
{
debug(" protocol %s:\n", p->name);
debug(" protocol %s: state %s/%s\n", p->cf->name, p_states[p->proto_state], c_states[p->core_state]);
if (p->disabled)
debug("\tDISABLED\n");
else if (p->dump)
p->dump(p);
else if (p->proto->dump)
p->proto->dump(p);
}
WALK_LIST(p, inactive_proto_list)
debug(" inactive %s\n", p->name);
debug(" inactive %s\n", p->cf->name);
}
void
......@@ -125,14 +166,3 @@ protos_build(void)
add_tail(&protocol_list, &proto_static.n);
#endif
}
void
protos_init(void)
{
struct protocol *p;
debug("Initializing protocols\n");
WALK_LIST(p, protocol_list)
if (p->init)
p->init(p);
}
/*
* BIRD Internet Routing Daemon -- Protocols
*
* (c) 1998 Martin Mares <mj@ucw.cz>
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -17,6 +17,9 @@ struct rte;
struct neighbor;
struct rtattr;
struct network;
struct proto_config;
struct config;
struct proto;
/*
* Routing Protocol
......@@ -27,15 +30,19 @@ struct protocol {
char *name;
unsigned debug; /* Default debugging flags */
void (*init)(struct protocol *); /* Boot time */
void (*preconfig)(struct protocol *); /* Just before configuring */
void (*postconfig)(struct protocol *); /* After configuring */
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 */
void (*dump)(struct proto *); /* Debugging dump */
int (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */
};
void protos_build(void);
void protos_init(void);
void protos_preconfig(void);
void protos_postconfig(void);
void protos_preconfig(struct config *);
void protos_postconfig(struct config *);
void protos_commit(struct config *);
void protos_start(void);
void protos_dump_all(void);
......@@ -53,47 +60,128 @@ extern struct protocol proto_static;
* Routing Protocol Instance
*/
struct proto_config {
node n;
struct config *global; /* Global configuration data */
struct protocol *proto; /* Protocol */
char *name;
unsigned debug, preference, disabled; /* Generic parameters */
/* Protocol-specific data follow... */
};
struct proto {
node n;
struct protocol *proto; /* Protocol */
char *name; /* Name of this instance */
struct proto_config *cf; /* Configuration data */
pool *pool; /* Pool containing local objects */
unsigned debug; /* Debugging flags */
pool *pool; /* Local objects */
unsigned preference; /* Default route preference */
unsigned state; /* PRS_... */
unsigned disabled; /* Manually disabled */
unsigned proto_state; /* Protocol state machine (see below) */
unsigned core_state; /* Core state machine (see below) */
void (*if_notify)(struct proto *, unsigned flags, struct iface *new, struct iface *old);
void (*rt_notify)(struct proto *, struct network *net, struct rte *new, struct rte *old);
void (*neigh_notify)(struct neighbor *neigh);
void (*dump)(struct proto *); /* Debugging dump */
void (*start)(struct proto *); /* Start the instance */
void (*shutdown)(struct proto *, int time); /* Stop the instance */
int (*rta_same)(struct rtattr *, struct rtattr *);
int (*rte_better)(struct rte *, struct rte *);
void (*rte_insert)(struct network *, struct rte *);
void (*rte_remove)(struct network *, struct rte *);
/* Reconfigure function? */
/* Input/output filters */
/* Connection to routing tables? */
/* Hic sunt protocol-specific data */
};
#define PRS_DOWN 0 /* Inactive */
#define PRS_STARTING 1
#define PRS_UP 2
void *proto_new(struct protocol *, unsigned size);
void proto_build(struct proto_config *);
void *proto_new(struct proto_config *, unsigned size);
void *proto_config_new(struct protocol *, unsigned size);
extern list proto_list, inactive_proto_list;
/*
* Each protocol instance runs two different state machines:
*
* [P] The protocol machine: (implemented inside protocol)
*
* DOWN ----> START
* ^ |
* | V
* STOP <---- UP
*
* States: DOWN Protocol is down and it's waiting for the core
* requesting protocol start.
* START Protocol is waiting for connection with the rest
* of the network and it's not willing to accept
* packets. When it connects, it goes to UP state.
* UP Protocol is up and running. When the network
* connection breaks down or the core requests
* protocol to be terminated, it goes to STOP state.
* STOP Protocol is disconnecting from the network.
* After it disconnects, it returns to DOWN state.
*
* In: start() Called in DOWN state to request protocol startup.
* Returns new state: either UP or START (in this
* case, the protocol will notify the core when it
* finally comes UP).
* stop() Called in START, UP or STOP state to request
* protocol shutdown. Returns new state: either
* DOWN or STOP (in this case, the protocol will
* notify the core when it finally comes DOWN).
*
* Out: proto_notify_state() -- called by protocol instance when
* it does any state transition not covered by
* return values of start() and stop(). This includes
* START->UP (delayed protocol startup), UP->STOP
* (spontaneous shutdown) and STOP->DOWN (delayed
* shutdown).
*/
#define PS_DOWN 0
#define PS_START 1
#define PS_UP 2
#define PS_STOP 3
void proto_notify_state(struct proto *p, unsigned state);
/*
* [F] The feeder machine: (implemented in core routines)
*
* HUNGRY ----> FEEDING
* ^ |
* | V
* FLUSHING <---- HAPPY
*
* States: HUNGRY Protocol either administratively down (i.e.,
* disabled by the user) or temporarily down
* (i.e., [P] is not UP)
* FEEDING The protocol came up and we're feeding it
* initial routes. [P] is UP.
* HAPPY The protocol is up and it's receiving normal
* routing updates. [P] is UP.
* FLUSHING The protocol is down and we're removing its
* routes from the table. [P] is STOP or DOWN.
*
* Normal lifecycle of a protocol looks like:
*
* HUNGRY/DOWN --> HUNGRY/START --> HUNGRY/UP -->
* FEEDING/UP --> HAPPY/UP --> FLUSHING/STOP|DOWN -->
* HUNGRY/STOP|DOWN --> HUNGRY/DOWN
*/
#define FS_HUNGRY 0
#define FS_FEEDING 1
#define FS_HAPPY 2
#define FS_FLUSHING 3
/*
* Known unique protocol instances as referenced by config routines
*/
extern struct proto *cf_dev_proto;
extern struct proto_config *cf_dev_proto;