Commit a7f23f58 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Implements protocol templates.

Based on the patch from Alexander V. Chernikov.
Extended to support almost all protocols.
Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.
parent 74add5df
......@@ -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";
}
......
......@@ -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);
}
}
......@@ -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 */
......
......@@ -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;
#}
......@@ -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.
......
......@@ -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);
}
;
......
......@@ -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;
......@@ -200,6 +208,50 @@ proto_config_new(struct protocol *pr, unsigned size)
return c;
}
/**
* 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 */
......
......@@ -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);
......
......@@ -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
};
......@@ -11,7 +11,7 @@
struct rt_dev_config {
struct proto_config c;
list iface_list;
list iface_list; /* list of struct iface_patt */
};
#endif
......@@ -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,
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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,
};
......@@ -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
};
......@@ -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;
};
......
......@@ -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);
}
;
......
......@@ -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
};
......@@ -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);
}
;
......
......@@ -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;
}