summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-11-07 00:31:23 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2011-11-07 00:31:23 +0100
commita7f23f581f5e3efe92ec97dfca7d01c66f31ab04 (patch)
tree3a8f7cffb7abce83b7bce8be87d21be8a2fbff72 /nest
parent74add5df17c386bd109ebea7b1dac04d1651ae51 (diff)
downloadbird-a7f23f581f5e3efe92ec97dfca7d01c66f31ab04.tar
bird-a7f23f581f5e3efe92ec97dfca7d01c66f31ab04.zip
Implements protocol templates.
Based on the patch from Alexander V. Chernikov. Extended to support almost all protocols. Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y33
-rw-r--r--nest/proto.c64
-rw-r--r--nest/protocol.h11
-rw-r--r--nest/rt-dev.c17
-rw-r--r--nest/rt-dev.h2
5 files changed, 107 insertions, 20 deletions
diff --git a/nest/config.Y b/nest/config.Y
index dd4a9e0..a6baf4e 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -26,7 +26,7 @@ static int password_id;
static inline void
reset_passwords(void)
{
- this_p_list = NULL;
+ this_p_list = NULL;
}
static inline list *
@@ -37,10 +37,11 @@ get_passwords(void)
return rv;
}
+#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
CF_DECLS
-CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
+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(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
@@ -58,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULT
%type <r> rtable
%type <s> optsym
%type <ra> r_args
-%type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
%type <ps> proto_patt proto_patt2
CF_GRAMMAR
@@ -115,20 +116,30 @@ newtab: TABLE SYM {
CF_ADDTO(conf, proto)
-proto_start: PROTOCOL
+proto_start:
+ PROTOCOL { $$ = SYM_PROTO; }
+ | TEMPLATE { $$ = SYM_TEMPLATE; }
;
proto_name:
/* EMPTY */ {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
- s->class = SYM_PROTO;
+ s->class = this_proto->class;
s->def = this_proto;
this_proto->name = s->name;
}
| SYM {
- cf_define_symbol($1, SYM_PROTO, this_proto);
+ cf_define_symbol($1, this_proto->class, this_proto);
this_proto->name = $1->name;
}
+ | SYM FROM SYM {
+ if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
+
+ cf_define_symbol($1, this_proto->class, this_proto);
+ this_proto->name = $1->name;
+
+ proto_copy_config(this_proto, $3->def);
+ }
;
proto_item:
@@ -207,10 +218,9 @@ iface_patt_list:
CF_ADDTO(proto, dev_proto '}')
dev_proto_start: proto_start DIRECT {
- struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config));
- this_proto = &p->c;
- p->c.preference = DEF_PREF_DIRECT;
- init_list(&p->iface_list);
+ this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1);
+ this_proto->preference = DEF_PREF_DIRECT;
+ init_list(&DIRECT_CFG->iface_list);
}
;
@@ -222,9 +232,8 @@ dev_proto:
dev_iface_init:
/* EMPTY */ {
- struct rt_dev_config *p = (void *) this_proto;
this_ipatt = cfg_allocz(sizeof(struct iface_patt));
- add_tail(&p->iface_list, NODE this_ipatt);
+ add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
}
;
diff --git a/nest/proto.c b/nest/proto.c
index 4a154d5..d55c348 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -175,6 +175,7 @@ proto_flush_hooks(struct proto *p)
* proto_config_new - create a new protocol configuration
* @pr: protocol the configuration will belong to
* @size: size of the structure including generic data
+ * @class: SYM_PROTO or SYM_TEMPLATE
*
* Whenever the configuration file says that a new instance
* of a routing protocol should be created, the parser calls
@@ -183,16 +184,23 @@ proto_flush_hooks(struct proto *p)
* containing all the generic items followed by protocol-specific
* ones). Also, the configuration entry gets added to the list
* of protocol instances kept in the configuration.
+ *
+ * The function is also used to create protocol templates (when class
+ * SYM_TEMPLATE is specified), the only difference is that templates
+ * are not added to the list of protocol instances and therefore not
+ * initialized during protos_commit()).
*/
void *
-proto_config_new(struct protocol *pr, unsigned size)
+proto_config_new(struct protocol *pr, unsigned size, int class)
{
struct proto_config *c = cfg_allocz(size);
- add_tail(&new_config->protos, &c->n);
+ if (class == SYM_PROTO)
+ add_tail(&new_config->protos, &c->n);
c->global = new_config;
c->protocol = pr;
c->name = pr->name;
+ c->class = class;
c->out_filter = FILTER_REJECT;
c->table = c->global->master_rtc;
c->debug = new_config->proto_default_debug;
@@ -201,6 +209,50 @@ proto_config_new(struct protocol *pr, unsigned size)
}
/**
+ * proto_copy_config - copy a protocol configuration
+ * @dest: destination protocol configuration
+ * @src: source protocol configuration
+ *
+ * Whenever a new instance of a routing protocol is created from the
+ * template, proto_copy_config() is called to copy a content of
+ * the source protocol configuration to the new protocol configuration.
+ * Name, class and a node in protos list of @dest are kept intact.
+ * copy_config() protocol hook is used to copy protocol-specific data.
+ */
+void
+proto_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ node old_node;
+ int old_class;
+ char *old_name;
+
+ if (dest->protocol != src->protocol)
+ cf_error("Can't copy configuration from a different protocol type");
+
+ if (dest->protocol->copy_config == NULL)
+ cf_error("Inheriting configuration for %s is not supported", src->protocol->name);
+
+ DBG("Copying configuration from %s to %s\n", src->name, dest->name);
+
+ /*
+ * Copy struct proto_config here. Keep original node, class and name.
+ * protocol-specific config copy is handled by protocol copy_config() hook
+ */
+
+ old_node = dest->n;
+ old_class = dest->class;
+ old_name = dest->name;
+
+ memcpy(dest, src, sizeof(struct proto_config));
+
+ dest->n = old_node;
+ dest->class = old_class;
+ dest->name = old_name;
+
+ dest->protocol->copy_config(dest, src);
+}
+
+/**
* protos_preconfig - pre-configuration processing
* @c: new configuration
*
@@ -230,7 +282,8 @@ protos_preconfig(struct config *c)
* @c: new configuration
*
* This function calls the postconfig() hooks of all protocol
- * instances specified in configuration @c.
+ * instances specified in configuration @c. The hooks are not
+ * called for protocol templates.
*/
void
protos_postconfig(struct config *c)
@@ -366,14 +419,15 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
{
struct proto_config *oc, *nc;
struct proto *p, *n;
+ struct symbol *sym;
DBG("protos_commit:\n");
if (old)
{
WALK_LIST(oc, old->protos)
{
- struct proto *p = oc->proto;
- struct symbol *sym = cf_find_symbol(oc->name);
+ p = oc->proto;
+ sym = cf_find_symbol(oc->name);
if (sym && sym->class == SYM_PROTO && !new->shutdown)
{
/* Found match, let's check if we can smoothly switch to new configuration */
diff --git a/nest/protocol.h b/nest/protocol.h
index f95905a..a7518c2 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -53,6 +53,7 @@ struct protocol {
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */
int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
+ void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
};
void protos_build(void);
@@ -85,12 +86,15 @@ struct proto_config {
struct proto *proto; /* Instance we've created */
char *name;
char *dsc;
+ int class; /* SYM_PROTO or SYM_TEMPLATE */
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
unsigned preference, disabled; /* Generic parameters */
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
+ /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
+
/* Protocol-specific data follow... */
};
@@ -203,9 +207,14 @@ struct proto_spec {
void *proto_new(struct proto_config *, unsigned size);
-void *proto_config_new(struct protocol *, unsigned size);
+void *proto_config_new(struct protocol *, unsigned size, int class);
+void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void proto_request_feeding(struct proto *p);
+static inline void
+proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size)
+{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
+
void proto_cmd_show(struct proto *, unsigned int, int);
void proto_cmd_disable(struct proto *, unsigned int, int);
void proto_cmd_enable(struct proto *, unsigned int, int);
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 239bd26..497ee80 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -92,9 +92,24 @@ dev_reconfigure(struct proto *p, struct proto_config *new)
return iface_patts_equal(&o->iface_list, &n->iface_list, NULL);
}
+static void
+dev_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct rt_dev_config *d = (struct rt_dev_config *) dest;
+ struct rt_dev_config *s = (struct rt_dev_config *) src;
+
+ /*
+ * We copy iface_list as ifaces can be shared by more direct protocols.
+ * Copy suffices to be is shallow, because new nodes can be added, but
+ * old nodes cannot be modified (although they contain internal lists).
+ */
+ cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+}
+
struct protocol proto_device = {
name: "Direct",
template: "direct%d",
init: dev_init,
- reconfigure: dev_reconfigure
+ reconfigure: dev_reconfigure,
+ copy_config: dev_copy_config
};
diff --git a/nest/rt-dev.h b/nest/rt-dev.h
index 64f2cd9..c36d074 100644
--- a/nest/rt-dev.h
+++ b/nest/rt-dev.h
@@ -11,7 +11,7 @@
struct rt_dev_config {
struct proto_config c;
- list iface_list;
+ list iface_list; /* list of struct iface_patt */
};
#endif