[PATCH 1/1] Add general protocol templates support. Permit BGP to use them
Alexander V. Chernikov
melifaro at ipfw.ru
Sat Oct 29 03:32:13 CEST 2011
---
conf/cf-lex.l | 2 ++
conf/conf.c | 32 ++++++++++++++++++++++++++++++++
conf/conf.h | 4 ++++
doc/bird.conf.example | 14 ++++++++++++++
doc/bird.sgml | 8 ++++++++
nest/config.Y | 16 +++++++++++-----
nest/proto.c | 18 +++++++++++++++---
nest/protocol.h | 5 +++++
proto/bgp/bgp.c | 16 +++++++++++++++-
proto/bgp/config.Y | 1 +
10 files changed, 107 insertions(+), 9 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 02ba4b3..ddfe8c7 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -533,6 +533,8 @@ cf_symbol_class_name(struct symbol *sym)
return "routing table";
case SYM_IPA:
return "network address";
+ case SYM_TEMPLATE:
+ return "protocol template";
default:
return "unknown type";
}
diff --git a/conf/conf.c b/conf/conf.c
index 5bdeece..fc789bf 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -143,6 +143,38 @@ cli_parse(struct config *c)
return 1;
}
+void
+config_inherit_cfg(struct proto_config *target, struct proto_config *source)
+{
+ int target_is_template = 0;
+ node target_n;
+ char *target_name;
+
+ if (target->protocol != source->protocol)
+ cf_error("Can't inherit configuration between different protocol types");
+
+ if (target->protocol->inherit_config == NULL)
+ cf_error("Inheriting configuration for %s is not supported");
+
+ DBG("Copying configuration from protocol %s template %s to %s\n", source->protocol->name, source->name, target->name);
+ /*
+ * Copy struct proto_config here.
+ * protocol-specific config inheritance is handled by protocol inherit_config() hook
+ */
+ /* save dst-specific data */
+ target_is_template = target->is_template;
+ target_n = target->n;
+ target_name = target->name;
+ /* copy entire proto_config structure */
+ memcpy(target, source, sizeof(struct proto_config));
+ /* restore dst-specific data */
+ target->is_template = target_is_template;
+ target->n = target_n;
+ target->name = target_name;
+
+ target->protocol->inherit_config(target, source);
+}
+
/**
* config_free - free a configuration
* @c: configuration to be freed
diff --git a/conf/conf.h b/conf/conf.h
index 142c6ad..6c2e017 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -59,9 +59,12 @@ extern struct config *future_config; /* New config held here if recon requested
extern int shutting_down;
extern bird_clock_t boot_time;
+struct proto_config;
+
struct config *config_alloc(byte *name);
int config_parse(struct config *);
int cli_parse(struct config *);
+void config_inherit_cfg(struct proto_config *target, struct proto_config *source);
void config_free(struct config *);
int config_commit(struct config *, int type);
#define RECONFIG_HARD 0
@@ -108,6 +111,7 @@ struct symbol {
#define SYM_FILTER 4
#define SYM_TABLE 5
#define SYM_IPA 6
+#define SYM_TEMPLATE 7
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */
diff --git a/doc/bird.conf.example b/doc/bird.conf.example
index 339898f..736afaf 100644
--- a/doc/bird.conf.example
+++ b/doc/bird.conf.example
@@ -202,3 +202,17 @@ protocol static {
# reject;
# };
#}
+#
+# Template usage example
+#template bgp rr_client {
+# disabled;
+# local as 65000;
+# multihop;
+# rr client;
+# rr cluster id 1.0.0.1;
+#}
+#
+#protocol bgp {
+# inherit rr_client;
+# neighbor 10.1.4.7 as 65000;
+#}
diff --git a/doc/bird.sgml b/doc/bird.sgml
index d454629..9419a90 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -301,6 +301,11 @@ protocol rip {
about configuring protocols in their own chapters. You can run more than one instance of
most protocols (like RIP or BGP). By default, no instances are configured.
+ <tag>template bgp|... <m/[name]/ { <m>protocol options</m> }</tag> Define a protocol template
+ instance called <cf><m/name/</cf> (or with a name like "bgp1" generated automatically if you don't specify any <cf><m/name/</cf>).
+ Protocol instance can refer to template by its name. Templates can inherit each other. At the moment templates are supported for
+ BGP only. See <cf/interit/ general protocol option for more information.
+
<tag>define <m/constant/ = (<m/expression/)|<m/number/|<m/IP address/</tag>
Define a constant. You can use it later in every place you could use a simple integer or an IP address.
Besides, there are some predefined numeric constants based on /etc/iproute2/rt_* files.
@@ -398,6 +403,9 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
to override global router id for a given protocol. Default:
uses global router id.
+ <tag>inherit <m/name/</tag> Inherits all configuration from template
+ <m/name/.
+
<tag>import all | none | filter <m/name/ | filter { <m/filter commands/ } | where <m/filter expression/</tag>
Specify a filter to be used for filtering routes coming from the protocol to the routing table. <cf/all/ is shorthand for <cf/where true/ and <cf/none/ is shorthand for <cf/where false/. Default: <cf/all/.
diff --git a/nest/config.Y b/nest/config.Y
index dd4a9e0..1b15ffe 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -21,7 +21,7 @@ static struct iface_patt *this_ipatt;
static struct iface_patt_node *this_ipn;
static list *this_p_list;
static struct password_item *this_p_item;
-static int password_id;
+static int password_id, is_template;
static inline void
reset_passwords(void)
@@ -40,7 +40,7 @@ get_passwords(void)
CF_DECLS
-CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
+CF_KEYWORDS(ROUTER, ID, PROTOCOL, INHERIT, 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)
@@ -115,18 +115,20 @@ newtab: TABLE SYM {
CF_ADDTO(conf, proto)
-proto_start: PROTOCOL
+proto_start:
+ PROTOCOL { is_template = 0; }
+ | TEMPLATE { is_template = 1; }
;
proto_name:
/* EMPTY */ {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
- s->class = SYM_PROTO;
+ s->class = is_template ? SYM_TEMPLATE : SYM_PROTO;
s->def = this_proto;
this_proto->name = s->name;
}
| SYM {
- cf_define_symbol($1, SYM_PROTO, this_proto);
+ cf_define_symbol($1, is_template ? SYM_TEMPLATE : SYM_PROTO, this_proto);
this_proto->name = $1->name;
}
;
@@ -145,6 +147,10 @@ proto_item:
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
+ | INHERIT SYM {
+ if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("template/protocol name expected");
+ config_inherit_cfg(this_proto, $2->def);
+ }
;
imexport:
diff --git a/nest/proto.c b/nest/proto.c
index 4a154d5..00e8cea 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -366,14 +366,26 @@ 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);
+ if (oc->is_template)
+ {
+ /*
+ * If template exists in new configuration we don't need to do anything:
+ * sym->def is already pointing to the right config.
+ *
+ * If template does not exist - old config gets removed automatically, symbol
+ * is already deleted.
+ */
+ continue;
+ }
+ 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 */
@@ -410,7 +422,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
}
WALK_LIST(nc, new->protos)
- if (!nc->proto)
+ if ((!nc->proto) && (!nc->is_template))
{
if (old_config) /* Not a first-time configuration */
log(L_INFO "Adding protocol %s", nc->name);
diff --git a/nest/protocol.h b/nest/protocol.h
index f95905a..60f5f9d 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 (*inherit_config)(struct proto_config *, struct proto_config *); /* Inherits config from given protocol instance */
};
void protos_build(void);
@@ -78,6 +79,9 @@ extern struct protocol
* Routing Protocol Instance
*/
+/*
+ * Check config_inherit_cfg() after changing
+ */
struct proto_config {
node n;
struct config *global; /* Global configuration data */
@@ -87,6 +91,7 @@ struct proto_config {
char *dsc;
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
unsigned preference, disabled; /* Generic parameters */
+ unsigned is_template; /* 1 if this is template config */
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 4e4ca9f..c410d66 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -988,6 +988,10 @@ bgp_check(struct bgp_config *c)
{
int internal = (c->local_as == c->remote_as);
+ /* Do not check templates at all */
+ if (c->c.is_template)
+ return;
+
if (!c->local_as)
cf_error("Local AS number must be set");
@@ -1015,6 +1019,15 @@ bgp_check(struct bgp_config *c)
c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
}
+void
+bgp_inherit_config(struct proto_config *_target, struct proto_config *_source)
+{
+ DBG("BGP INHERIT: %s <- %s\n", _target->name, _source->name);
+
+ /* We need to copy our procol-specific data only */
+ memcpy(_target + 1, _source + 1, sizeof(struct bgp_config) - sizeof(struct proto_config));
+}
+
static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };
static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""};
static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket" };
@@ -1158,5 +1171,6 @@ struct protocol proto_bgp = {
get_status: bgp_get_status,
get_attr: bgp_get_attr,
get_route_info: bgp_get_route_info,
- show_proto_info: bgp_show_proto_info
+ show_proto_info: bgp_show_proto_info,
+ inherit_config: bgp_inherit_config
};
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 19d757a..a5fa26b 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -34,6 +34,7 @@ CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
bgp_proto_start: proto_start BGP {
this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
this_proto->preference = DEF_PREF_BGP;
+ this_proto->is_template = is_template;
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
BGP_CFG->initial_hold_time = 240;
--
1.7.3.2
--------------020809060206090704030007--
More information about the Bird-users
mailing list