summaryrefslogtreecommitdiff
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
parent74add5df17c386bd109ebea7b1dac04d1651ae51 (diff)
Implements protocol templates.
Based on the patch from Alexander V. Chernikov. Extended to support almost all protocols. Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.
-rw-r--r--conf/cf-lex.l2
-rw-r--r--conf/conf.c15
-rw-r--r--conf/conf.h2
-rw-r--r--doc/bird.conf.example13
-rw-r--r--doc/bird.sgml19
-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
-rw-r--r--proto/bgp/bgp.c122
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/ospf/config.Y2
-rw-r--r--proto/ospf/ospf.h4
-rw-r--r--proto/pipe/config.Y2
-rw-r--r--proto/pipe/pipe.c24
-rw-r--r--proto/radv/radv.c16
-rw-r--r--proto/radv/radv.h8
-rw-r--r--proto/rip/config.Y2
-rw-r--r--proto/rip/rip.c14
-rw-r--r--proto/static/config.Y2
-rw-r--r--proto/static/static.c53
-rw-r--r--sysdep/bsd/krt-iface.h8
-rw-r--r--sysdep/bsd/krt-scan.h1
-rw-r--r--sysdep/bsd/krt-sock.h8
-rw-r--r--sysdep/linux/netlink/krt-iface.h1
-rw-r--r--sysdep/linux/netlink/krt-scan.h3
-rw-r--r--sysdep/linux/netlink/krt-set.h1
-rw-r--r--sysdep/unix/krt-iface.h3
-rw-r--r--sysdep/unix/krt-set.h1
-rw-r--r--sysdep/unix/krt.Y4
-rw-r--r--sysdep/unix/krt.c32
-rw-r--r--sysdep/unix/krt.h2
34 files changed, 387 insertions, 110 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 02ba4b39..ddfe8c77 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 5bdeece2..4b605b36 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -377,3 +377,18 @@ cfg_strdup(char *c)
memcpy(z, c, l);
return z;
}
+
+
+void
+cfg_copy_list(list *dest, list *src, unsigned node_size)
+{
+ node *dn, *sn;
+
+ init_list(dest);
+ WALK_LIST(sn, *src)
+ {
+ dn = cfg_alloc(node_size);
+ memcpy(dn, sn, node_size);
+ add_tail(dest, dn);
+ }
+}
diff --git a/conf/conf.h b/conf/conf.h
index 142c6ade..8753bafe 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -84,6 +84,7 @@ extern linpool *cfg_mem;
#define cfg_allocu(size) lp_allocu(cfg_mem, size)
#define cfg_allocz(size) lp_allocz(cfg_mem, size)
char *cfg_strdup(char *c);
+void cfg_copy_list(list *dest, list *src, unsigned node_size);
/* Lexer */
@@ -108,6 +109,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 339898f2..5e07ab5a 100644
--- a/doc/bird.conf.example
+++ b/doc/bird.conf.example
@@ -202,3 +202,16 @@ 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 rr_abcd from rr_client {
+# neighbor 10.1.4.7 as 65000;
+#}
diff --git a/doc/bird.sgml b/doc/bird.sgml
index d4546293..7f53f028 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -296,10 +296,21 @@ protocol rip {
<tag>function <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag> Define a function. You can learn more
about functions in the following chapter.
- <tag>protocol rip|ospf|bgp|... <m/[name]/ { <m>protocol options</m> }</tag> Define a protocol
- instance called <cf><m/name/</cf> (or with a name like "rip5" generated automatically if you don't specify any <cf><m/name/</cf>). You can learn more
- 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>protocol rip|ospf|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
+ Define a protocol instance called <cf><m/name/</cf> (or with a name like "rip5" generated
+ automatically if you don't specify any <cf><m/name/</cf>). You can learn more about
+ configuring protocols in their own chapters. When <cf>from <m/name2/</cf> expression is
+ used, initial protocol options are taken from protocol or template <cf><m/name2/</cf>
+ You can run more than one instance of most protocols (like RIP or BGP). By default, no
+ instances are configured.
+
+ <tag>template rip|bgp|... [<m/name/ [from <m/name2/]] { <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 templates can
+ be used to group common options when many similarly configured protocol instances are to be
+ defined. Protocol instances (and other templates) can use templates by using <cf/from/
+ expression and the name of the template. At the moment templates (and <cf/from/ expression)
+ are not implemented for OSPF protocol.
<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.
diff --git a/nest/config.Y b/nest/config.Y
index dd4a9e00..a6baf4ea 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 4a154d59..d55c348d 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 f95905ae..a7518c2a 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 239bd268..497ee808 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 64f2cd95..c36d0742 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
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 4e4ca9f3..675342de 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -919,6 +919,73 @@ bgp_init(struct proto_config *C)
return P;
}
+
+void
+bgp_check_config(struct bgp_config *c)
+{
+ int internal = (c->local_as == c->remote_as);
+
+ /* Do not check templates at all */
+ if (c->c.class == SYM_TEMPLATE)
+ return;
+
+ if (!c->local_as)
+ cf_error("Local AS number must be set");
+
+ if (!c->remote_as)
+ cf_error("Neighbor must be configured");
+
+ if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
+ cf_error("Neighbor AS number out of range (AS4 not available)");
+
+ if (!internal && c->rr_client)
+ cf_error("Only internal neighbor can be RR client");
+
+ if (internal && c->rs_client)
+ cf_error("Only external neighbor can be RS client");
+
+ if (c->multihop && (c->gw_mode == GW_DIRECT))
+ cf_error("Multihop BGP cannot use direct gateway mode");
+
+ /* Different default based on rs_client */
+ if (!c->missing_lladdr)
+ c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
+
+ /* Different default for gw_mode */
+ if (!c->gw_mode)
+ c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
+}
+
+static int
+bgp_reconfigure(struct proto *P, struct proto_config *C)
+{
+ struct bgp_config *new = (struct bgp_config *) C;
+ struct bgp_proto *p = (struct bgp_proto *) P;
+ struct bgp_config *old = p->cf;
+
+ int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
+ ((byte *) new) + sizeof(struct proto_config),
+ // password item is last and must be checked separately
+ OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
+ && ((!old->password && !new->password)
+ || (old->password && new->password && !strcmp(old->password, new->password)))
+ && (get_igp_table(old) == get_igp_table(new));
+
+ /* We should update our copy of configuration ptr as old configuration will be freed */
+ if (same)
+ p->cf = new;
+
+ return same;
+}
+
+static void
+bgp_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ /* Just a shallow copy */
+ proto_copy_rest(dest, src, sizeof(struct bgp_config));
+}
+
+
/**
* bgp_error - report a protocol error
* @c: connection
@@ -983,38 +1050,6 @@ bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code)
p->last_error_code = code;
}
-void
-bgp_check(struct bgp_config *c)
-{
- int internal = (c->local_as == c->remote_as);
-
- if (!c->local_as)
- cf_error("Local AS number must be set");
-
- if (!c->remote_as)
- cf_error("Neighbor must be configured");
-
- if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
- cf_error("Neighbor AS number out of range (AS4 not available)");
-
- if (!internal && c->rr_client)
- cf_error("Only internal neighbor can be RR client");
-
- if (internal && c->rs_client)
- cf_error("Only external neighbor can be RS client");
-
- if (c->multihop && (c->gw_mode == GW_DIRECT))
- cf_error("Multihop BGP cannot use direct gateway mode");
-
- /* Different default based on rs_client */
- if (!c->missing_lladdr)
- c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
-
- /* Different default for gw_mode */
- if (!c->gw_mode)
- c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
-}
-
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" };
@@ -1124,28 +1159,6 @@ bgp_show_proto_info(struct proto *P)
}
}
-static int
-bgp_reconfigure(struct proto *P, struct proto_config *C)
-{
- struct bgp_config *new = (struct bgp_config *) C;
- struct bgp_proto *p = (struct bgp_proto *) P;
- struct bgp_config *old = p->cf;
-
- int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
- ((byte *) new) + sizeof(struct proto_config),
- // password item is last and must be checked separately
- OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
- && ((!old->password && !new->password)
- || (old->password && new->password && !strcmp(old->password, new->password)))
- && (get_igp_table(old) == get_igp_table(new));
-
- /* We should update our copy of configuration ptr as old configuration will be freed */
- if (same)
- p->cf = new;
-
- return same;
-}
-
struct protocol proto_bgp = {
name: "BGP",
template: "bgp%d",
@@ -1155,6 +1168,7 @@ struct protocol proto_bgp = {
shutdown: bgp_shutdown,
cleanup: bgp_cleanup,
reconfigure: bgp_reconfigure,
+ copy_config: bgp_copy_config,
get_status: bgp_get_status,
get_attr: bgp_get_attr,
get_route_info: bgp_get_route_info,
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 16e8ea89..437ba335 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -141,7 +141,7 @@ extern struct linpool *bgp_linpool;
void bgp_start_timer(struct timer *t, int value);
-void bgp_check(struct bgp_config *c);
+void bgp_check_config(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c);
void bgp_update_startup_delay(struct bgp_proto *p);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 19d757a5..03c233d6 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -29,10 +29,10 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
CF_GRAMMAR
-CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
+CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } )
bgp_proto_start: proto_start BGP {
- this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
+ this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1);
this_proto->preference = DEF_PREF_BGP;
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index ec7da8e2..4ada41e8 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -128,7 +128,7 @@ CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
ospf_proto_start: proto_start OSPF {
- this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
+ this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
this_proto->preference = DEF_PREF_OSPF;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 2e99b0ff..60a34fba 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -85,8 +85,8 @@ struct ospf_config
byte rfc1583;
byte abr;
int ecmp;
- list area_list;
- list vlink_list;
+ list area_list; /* list of struct ospf_area_config */
+ list vlink_list; /* list of struct ospf_iface_patt */
};
struct nbma_node
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index e1c981bb..4478afe7 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -23,7 +23,7 @@ CF_GRAMMAR
CF_ADDTO(proto, pipe_proto '}')
pipe_proto_start: proto_start PIPE {
- this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config));
+ this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config), $1);
this_proto->preference = DEF_PREF_PIPE;
PIPE_CFG->mode = PIPE_TRANSPARENT;
}
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index e557097d..420c5a9d 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -165,14 +165,6 @@ pipe_postconfig(struct proto_config *C)
cf_error("Primary table and peer table must be different");
}
-static void
-pipe_get_status(struct proto *P, byte *buf)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
-
- bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
-}
-
static int
pipe_reconfigure(struct proto *P, struct proto_config *new)
{
@@ -186,6 +178,21 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
return 1;
}
+static void
+pipe_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ /* Just a shallow copy, not many items here */
+ proto_copy_rest(dest, src, sizeof(struct pipe_config));
+}
+
+static void
+pipe_get_status(struct proto *P, byte *buf)
+{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+
+ bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
+}
+
struct protocol proto_pipe = {
name: "Pipe",
@@ -195,5 +202,6 @@ struct protocol proto_pipe = {
start: pipe_start,
cleanup: pipe_cleanup,
reconfigure: pipe_reconfigure,
+ copy_config: pipe_copy_config,
get_status: pipe_get_status,
};
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 01cb6899..42d4bff9 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -318,6 +318,19 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
return 1;
}
+static void
+radv_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct radv_config *d = (struct radv_config *) dest;
+ struct radv_config *s = (struct radv_config *) src;
+
+ /* We clean up patt_list, ifaces are non-sharable */
+ init_list(&d->patt_list);
+
+ /* We copy pref_list, shallow copy suffices */
+ cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+}
+
struct protocol proto_radv = {
.name = "RAdv",
@@ -325,5 +338,6 @@ struct protocol proto_radv = {
.init = radv_init,
.start = radv_start,
.shutdown = radv_shutdown,
- .reconfigure = radv_reconfigure
+ .reconfigure = radv_reconfigure,
+ .copy_config = radv_copy_config
};
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index fe121f26..12bfe42e 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -46,14 +46,14 @@
struct radv_config
{
struct proto_config c;
- list patt_list; /* List of iface configs */
- list pref_list; /* Global list of prefix configs */
+ list patt_list; /* List of iface configs (struct radv_iface_config) */
+ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
};
struct radv_iface_config
{
struct iface_patt i;
- list pref_list; /* Local list of prefix configs */
+ list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */
u32 min_ra_int; /* Standard options from RFC 4261 */
u32 max_ra_int;
@@ -64,7 +64,7 @@ struct radv_iface_config
u32 link_mtu;
u32 reachable_time;
u32 retrans_timer;
- u32 current_hop_limit;
+ u32 current_hop_limit;
u32 default_lifetime;
};
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 2df0c5c8..cd4f30e7 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -37,7 +37,7 @@ CF_GRAMMAR
CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } )
rip_cfg_start: proto_start RIP {
- this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config));
+ this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config), $1);
rip_init_config(RIP_CFG);
}
;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 1266380d..543aa306 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -1015,6 +1015,19 @@ rip_reconfigure(struct proto *p, struct proto_config *c)
sizeof(struct rip_proto_config) - generic);
}
+static void
+rip_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ /* Shallow copy of everything */
+ proto_copy_rest(dest, src, sizeof(struct rip_proto_config));
+
+ /* We clean up iface_list, ifaces are non-sharable */
+ init_list(&((struct rip_proto_config *) dest)->iface_list);
+
+ /* Copy of passwords is OK, it just will be replaced in dest when used */
+}
+
+
struct protocol proto_rip = {
name: "RIP",
template: "rip%d",
@@ -1026,4 +1039,5 @@ struct protocol proto_rip = {
dump: rip_dump,
start: rip_start,
reconfigure: rip_reconfigure,
+ copy_config: rip_copy_config
};
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 77d2419f..621fdf9b 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -26,7 +26,7 @@ CF_GRAMMAR
CF_ADDTO(proto, static_proto '}')
static_proto_start: proto_start STATIC {
- this_proto = proto_config_new(&proto_static, sizeof(struct static_config));
+ this_proto = proto_config_new(&proto_static, sizeof(struct static_config), $1);
static_init_config((struct static_config *) this_proto);
}
;
diff --git a/proto/static/static.c b/proto/static/static.c
index 2f33d817..e5b293c0 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -470,6 +470,58 @@ static_reconfigure(struct proto *p, struct proto_config *new)
return 1;
}
+static void
+static_copy_routes(list *dlst, list *slst)
+{
+ struct static_route *dr, *sr;
+
+ init_list(dlst);
+ WALK_LIST(sr, *slst)
+ {
+ /* copy one route */
+ dr = cfg_alloc(sizeof(struct static_route));
+ memcpy(dr, sr, sizeof(struct static_route));
+
+ /* This fn is supposed to be called on fresh src routes, which have 'live'
+ fields (like .chain, .neigh or .installed) zero, so no need to zero them */
+
+ /* We need to copy multipath chain, because there are backptrs in 'if_name' */
+ if (dr->dest == RTD_MULTIPATH)
+ {
+ struct static_route *md, *ms, **mp_last;
+
+ mp_last = &(dr->mp_next);
+ for (ms = sr->mp_next; ms; ms = ms->mp_next)
+ {
+ md = cfg_alloc(sizeof(struct static_route));
+ memcpy(md, ms, sizeof(struct static_route));
+ md->if_name = (void *) dr; /* really */
+
+ *mp_last = md;
+ mp_last = &(md->mp_next);
+ }
+ *mp_last = NULL;
+ }
+
+ add_tail(dlst, (node *) dr);
+ }
+}
+
+static void
+static_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct static_config *d = (struct static_config *) dest;
+ struct static_config *s = (struct static_config *) src;
+
+ /* Shallow copy of everything */
+ proto_copy_rest(dest, src, sizeof(struct static_config));
+
+ /* Copy route lists */
+ static_copy_routes(&d->iface_routes, &s->iface_routes);
+ static_copy_routes(&d->other_routes, &s->other_routes);
+}
+
+
struct protocol proto_static = {
name: "Static",
template: "static%d",
@@ -479,6 +531,7 @@ struct protocol proto_static = {
shutdown: static_shutdown,
cleanup: static_cleanup,
reconfigure: static_reconfigure,
+ copy_config: static_copy_config
};
static void
diff --git a/sysdep/bsd/krt-iface.h b/sysdep/bsd/krt-iface.h
index 7d96fe88..7f0d52bd 100644
--- a/sysdep/bsd/krt-iface.h
+++ b/sysdep/bsd/krt-iface.h
@@ -12,6 +12,14 @@
/*
* We don't have split iface/scan/set parts. See krt-sock.h.
*/
+
+struct krt_if_params {
+};
+
+struct krt_if_status {
+};
+
static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
#endif
diff --git a/sysdep/bsd/krt-scan.h b/sysdep/bsd/krt-scan.h
index 284df5ea..19cd930d 100644
--- a/sysdep/bsd/krt-scan.h
+++ b/sysdep/bsd/krt-scan.h
@@ -17,5 +17,6 @@ struct krt_scan_status {
};
static inline int krt_scan_params_same(struct krt_scan_params *o UNUSED, struct krt_scan_params *n UNUSED) { return 1; }
+static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
#endif
diff --git a/sysdep/bsd/krt-sock.h b/sysdep/bsd/krt-sock.h
index d2a7efbc..aab639c4 100644
--- a/sysdep/bsd/krt-sock.h
+++ b/sysdep/bsd/krt-sock.h
@@ -34,13 +34,9 @@ struct krt_set_params {
struct krt_set_status {
};
-struct krt_if_params {
-};
-
-struct krt_if_status {
-};
-
static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
+
void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan);
#endif
diff --git a/sysdep/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h
index f44ca27f..770c6e2e 100644
--- a/sysdep/linux/netlink/krt-iface.h
+++ b/sysdep/linux/netlink/krt-iface.h
@@ -24,5 +24,6 @@ static inline void krt_if_shutdown(struct kif_proto *p UNUSED) { };
static inline void krt_if_io_init(void) { };
static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
#endif
diff --git a/sysdep/linux/netlink/krt-scan.h b/sysdep/linux/netlink/krt-scan.h
index 7885f078..9b5e075b 100644
--- a/sysdep/linux/netlink/krt-scan.h
+++ b/sysdep/linux/netlink/krt-scan.h
@@ -30,4 +30,7 @@ static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_sca
return o->table_id == n->table_id;
}
+static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
+/* table_id copied in krt_copy_config() */
+
#endif
diff --git a/sysdep/linux/netlink/krt-set.h b/sysdep/linux/netlink/krt-set.h
index 83d082d0..4a08217b 100644
--- a/sysdep/linux/netlink/krt-set.h
+++ b/sysdep/linux/netlink/krt-set.h
@@ -23,5 +23,6 @@ static inline void krt_set_construct(struct krt_config *c UNUSED) { };
static inline void krt_set_start(struct krt_proto *p UNUSED, int first UNUSED) { };
static inline void krt_set_shutdown(struct krt_proto *p UNUSED, int last UNUSED) { };
static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
#endif
diff --git a/sysdep/unix/krt-iface.h b/sysdep/unix/krt-iface.h
index 48075d6b..9e12bcc3 100644
--- a/sysdep/unix/krt-iface.h
+++ b/sysdep/unix/krt-iface.h
@@ -17,6 +17,7 @@ struct krt_if_status {
extern int if_scan_sock;
-static inline int kif_params_same(struct krt_if_params *old, struct krt_if_params *new) { return 1; }
+static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
#endif
diff --git a/sysdep/unix/krt-set.h b/sysdep/unix/krt-set.h
index 5d0b2134..87cffcfc 100644
--- a/sysdep/unix/krt-set.h
+++ b/sysdep/unix/krt-set.h
@@ -16,5 +16,6 @@ struct krt_set_status {
};
static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
#endif
diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y
index 0375a13b..86081966 100644
--- a/sysdep/unix/krt.Y
+++ b/sysdep/unix/krt.Y
@@ -30,7 +30,7 @@ kern_proto_start: proto_start KERNEL {
if (cf_krt)
cf_error("Kernel protocol already defined");
#endif
- cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config));
+ cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), $1);
this_proto->preference = DEF_PREF_INHERITED;
THIS_KRT->scan_time = 60;
THIS_KRT->learn = THIS_KRT->persist = 0;
@@ -66,7 +66,7 @@ CF_ADDTO(proto, kif_proto '}')
kif_proto_start: proto_start DEVICE {
if (cf_kif)
cf_error("Kernel device protocol already defined");
- cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config));
+ cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config), $1);
this_proto->preference = DEF_PREF_DIRECT;
THIS_KIF->scan_time = 60;
init_list(&THIS_KIF->primary);
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 70570703..e5a8ce17 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -216,6 +216,23 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
return 1;
}
+static void
+kif_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct kif_config *d = (struct kif_config *) dest;
+ struct kif_config *s = (struct kif_config *) src;
+
+ /* Shallow copy of everything (just scan_time currently) */
+ proto_copy_rest(dest, src, sizeof(struct krt_config));
+
+ /* Copy primary addr list */
+ cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
+
+ /* Fix sysdep parts */
+ kif_copy_params(&d->iface, &s->iface);
+}
+
+
struct protocol proto_unix_iface = {
name: "Device",
template: "device%d",
@@ -224,6 +241,7 @@ struct protocol proto_unix_iface = {
start: kif_start,
shutdown: kif_shutdown,
reconfigure: kif_reconfigure,
+ copy_config: kif_copy_config
};
/*
@@ -908,6 +926,19 @@ krt_reconfigure(struct proto *p, struct proto_config *new)
;
}
+static void
+krt_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct krt_config *d = (struct krt_config *) dest;
+ struct krt_config *s = (struct krt_config *) src;
+
+ /* Shallow copy of everything */
+ proto_copy_rest(dest, src, sizeof(struct krt_config));
+
+ /* Fix sysdep parts */
+ krt_set_copy_params(&d->set, &s->set);
+ krt_scan_copy_params(&d->scan, &s->scan);
+}
static int
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
@@ -936,6 +967,7 @@ struct protocol proto_unix_kernel = {
start: krt_start,
shutdown: krt_shutdown,
reconfigure: krt_reconfigure,
+ copy_config: krt_copy_config,
get_attr: krt_get_attr,
#ifdef KRT_ALLOW_LEARN
dump: krt_dump,
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index f83e6ee6..7bb4fe70 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -100,7 +100,7 @@ struct kif_config {
struct proto_config c;
struct krt_if_params iface;
int scan_time; /* How often we re-scan interfaces */
- list primary; /* Preferences for primary addresses */
+ list primary; /* Preferences for primary addresses (struct kif_primary_item) */
};
struct kif_proto {