Implements protocol templates.

Based on the patch from Alexander V. Chernikov.
Extended to support almost all protocols.
Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.
This commit is contained in:
Ondrej Zajicek 2011-11-07 00:31:23 +01:00
parent 74add5df17
commit a7f23f581f
34 changed files with 387 additions and 110 deletions

View file

@ -533,6 +533,8 @@ cf_symbol_class_name(struct symbol *sym)
return "routing table"; return "routing table";
case SYM_IPA: case SYM_IPA:
return "network address"; return "network address";
case SYM_TEMPLATE:
return "protocol template";
default: default:
return "unknown type"; return "unknown type";
} }

View file

@ -377,3 +377,18 @@ cfg_strdup(char *c)
memcpy(z, c, l); memcpy(z, c, l);
return z; 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);
}
}

View file

@ -84,6 +84,7 @@ extern linpool *cfg_mem;
#define cfg_allocu(size) lp_allocu(cfg_mem, size) #define cfg_allocu(size) lp_allocu(cfg_mem, size)
#define cfg_allocz(size) lp_allocz(cfg_mem, size) #define cfg_allocz(size) lp_allocz(cfg_mem, size)
char *cfg_strdup(char *c); char *cfg_strdup(char *c);
void cfg_copy_list(list *dest, list *src, unsigned node_size);
/* Lexer */ /* Lexer */
@ -108,6 +109,7 @@ struct symbol {
#define SYM_FILTER 4 #define SYM_FILTER 4
#define SYM_TABLE 5 #define SYM_TABLE 5
#define SYM_IPA 6 #define SYM_IPA 6
#define SYM_TEMPLATE 7
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */

View file

@ -202,3 +202,16 @@ protocol static {
# reject; # 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;
#}

View file

@ -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 <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. about functions in the following chapter.
<tag>protocol rip|ospf|bgp|... <m/[name]/ { <m>protocol options</m> }</tag> Define a protocol <tag>protocol rip|ospf|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
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 Define a protocol instance called <cf><m/name/</cf> (or with a name like "rip5" generated
about configuring protocols in their own chapters. You can run more than one instance of automatically if you don't specify any <cf><m/name/</cf>). You can learn more about
most protocols (like RIP or BGP). By default, no instances are configured. 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> <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. Define a constant. You can use it later in every place you could use a simple integer or an IP address.

View file

@ -26,7 +26,7 @@ static int password_id;
static inline void static inline void
reset_passwords(void) reset_passwords(void)
{ {
this_p_list = NULL; this_p_list = NULL;
} }
static inline list * static inline list *
@ -37,10 +37,11 @@ get_passwords(void)
return rv; return rv;
} }
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
CF_DECLS 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(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) 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 <r> rtable
%type <s> optsym %type <s> optsym
%type <ra> r_args %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 %type <ps> proto_patt proto_patt2
CF_GRAMMAR CF_GRAMMAR
@ -115,20 +116,30 @@ newtab: TABLE SYM {
CF_ADDTO(conf, proto) CF_ADDTO(conf, proto)
proto_start: PROTOCOL proto_start:
PROTOCOL { $$ = SYM_PROTO; }
| TEMPLATE { $$ = SYM_TEMPLATE; }
; ;
proto_name: proto_name:
/* EMPTY */ { /* EMPTY */ {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); 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; s->def = this_proto;
this_proto->name = s->name; this_proto->name = s->name;
} }
| SYM { | SYM {
cf_define_symbol($1, SYM_PROTO, this_proto); cf_define_symbol($1, this_proto->class, this_proto);
this_proto->name = $1->name; 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: proto_item:
@ -207,10 +218,9 @@ iface_patt_list:
CF_ADDTO(proto, dev_proto '}') CF_ADDTO(proto, dev_proto '}')
dev_proto_start: proto_start DIRECT { dev_proto_start: proto_start DIRECT {
struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config)); this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1);
this_proto = &p->c; this_proto->preference = DEF_PREF_DIRECT;
p->c.preference = DEF_PREF_DIRECT; init_list(&DIRECT_CFG->iface_list);
init_list(&p->iface_list);
} }
; ;
@ -222,9 +232,8 @@ dev_proto:
dev_iface_init: dev_iface_init:
/* EMPTY */ { /* EMPTY */ {
struct rt_dev_config *p = (void *) this_proto;
this_ipatt = cfg_allocz(sizeof(struct iface_patt)); 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); init_list(&this_ipatt->ipn_list);
} }
; ;

View file

@ -175,6 +175,7 @@ proto_flush_hooks(struct proto *p)
* proto_config_new - create a new protocol configuration * proto_config_new - create a new protocol configuration
* @pr: protocol the configuration will belong to * @pr: protocol the configuration will belong to
* @size: size of the structure including generic data * @size: size of the structure including generic data
* @class: SYM_PROTO or SYM_TEMPLATE
* *
* Whenever the configuration file says that a new instance * Whenever the configuration file says that a new instance
* of a routing protocol should be created, the parser calls * 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 * containing all the generic items followed by protocol-specific
* ones). Also, the configuration entry gets added to the list * ones). Also, the configuration entry gets added to the list
* of protocol instances kept in the configuration. * 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 * 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); 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->global = new_config;
c->protocol = pr; c->protocol = pr;
c->name = pr->name; c->name = pr->name;
c->class = class;
c->out_filter = FILTER_REJECT; c->out_filter = FILTER_REJECT;
c->table = c->global->master_rtc; c->table = c->global->master_rtc;
c->debug = new_config->proto_default_debug; c->debug = new_config->proto_default_debug;
@ -200,6 +208,50 @@ proto_config_new(struct protocol *pr, unsigned size)
return c; 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 * protos_preconfig - pre-configuration processing
* @c: new configuration * @c: new configuration
@ -230,7 +282,8 @@ protos_preconfig(struct config *c)
* @c: new configuration * @c: new configuration
* *
* This function calls the postconfig() hooks of all protocol * 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 void
protos_postconfig(struct config *c) 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_config *oc, *nc;
struct proto *p, *n; struct proto *p, *n;
struct symbol *sym;
DBG("protos_commit:\n"); DBG("protos_commit:\n");
if (old) if (old)
{ {
WALK_LIST(oc, old->protos) WALK_LIST(oc, old->protos)
{ {
struct proto *p = oc->proto; p = oc->proto;
struct symbol *sym = cf_find_symbol(oc->name); sym = cf_find_symbol(oc->name);
if (sym && sym->class == SYM_PROTO && !new->shutdown) if (sym && sym->class == SYM_PROTO && !new->shutdown)
{ {
/* Found match, let's check if we can smoothly switch to new configuration */ /* Found match, let's check if we can smoothly switch to new configuration */

View file

@ -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) */ 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_*) */ 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 (*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); void protos_build(void);
@ -85,12 +86,15 @@ struct proto_config {
struct proto *proto; /* Instance we've created */ struct proto *proto; /* Instance we've created */
char *name; char *name;
char *dsc; char *dsc;
int class; /* SYM_PROTO or SYM_TEMPLATE */
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
unsigned preference, disabled; /* Generic parameters */ unsigned preference, disabled; /* Generic parameters */
u32 router_id; /* Protocol specific router ID */ u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */ struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */ struct filter *in_filter, *out_filter; /* Attached filters */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
/* Protocol-specific data follow... */ /* Protocol-specific data follow... */
}; };
@ -203,9 +207,14 @@ struct proto_spec {
void *proto_new(struct proto_config *, unsigned size); 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); 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_show(struct proto *, unsigned int, int);
void proto_cmd_disable(struct proto *, unsigned int, int); void proto_cmd_disable(struct proto *, unsigned int, int);
void proto_cmd_enable(struct proto *, unsigned int, int); void proto_cmd_enable(struct proto *, unsigned int, int);

View file

@ -92,9 +92,24 @@ dev_reconfigure(struct proto *p, struct proto_config *new)
return iface_patts_equal(&o->iface_list, &n->iface_list, NULL); 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 = { struct protocol proto_device = {
name: "Direct", name: "Direct",
template: "direct%d", template: "direct%d",
init: dev_init, init: dev_init,
reconfigure: dev_reconfigure reconfigure: dev_reconfigure,
copy_config: dev_copy_config
}; };

View file

@ -11,7 +11,7 @@
struct rt_dev_config { struct rt_dev_config {
struct proto_config c; struct proto_config c;
list iface_list; list iface_list; /* list of struct iface_patt */
}; };
#endif #endif

View file

@ -919,6 +919,73 @@ bgp_init(struct proto_config *C)
return P; 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 * bgp_error - report a protocol error
* @c: connection * @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; 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_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };
static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""}; 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" }; 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 = { struct protocol proto_bgp = {
name: "BGP", name: "BGP",
template: "bgp%d", template: "bgp%d",
@ -1155,6 +1168,7 @@ struct protocol proto_bgp = {
shutdown: bgp_shutdown, shutdown: bgp_shutdown,
cleanup: bgp_cleanup, cleanup: bgp_cleanup,
reconfigure: bgp_reconfigure, reconfigure: bgp_reconfigure,
copy_config: bgp_copy_config,
get_status: bgp_get_status, get_status: bgp_get_status,
get_attr: bgp_get_attr, get_attr: bgp_get_attr,
get_route_info: bgp_get_route_info, get_route_info: bgp_get_route_info,

View file

@ -141,7 +141,7 @@ extern struct linpool *bgp_linpool;
void bgp_start_timer(struct timer *t, int value); 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_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c); void bgp_close_conn(struct bgp_conn *c);
void bgp_update_startup_delay(struct bgp_proto *p); void bgp_update_startup_delay(struct bgp_proto *p);

View file

@ -29,10 +29,10 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
CF_GRAMMAR 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 { 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; this_proto->preference = DEF_PREF_BGP;
BGP_CFG->hold_time = 240; BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120; BGP_CFG->connect_retry_time = 120;

View file

@ -128,7 +128,7 @@ CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } ) CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
ospf_proto_start: proto_start OSPF { 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; this_proto->preference = DEF_PREF_OSPF;
init_list(&OSPF_CFG->area_list); init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list); init_list(&OSPF_CFG->vlink_list);

View file

@ -85,8 +85,8 @@ struct ospf_config
byte rfc1583; byte rfc1583;
byte abr; byte abr;
int ecmp; int ecmp;
list area_list; list area_list; /* list of struct ospf_area_config */
list vlink_list; list vlink_list; /* list of struct ospf_iface_patt */
}; };
struct nbma_node struct nbma_node

View file

@ -23,7 +23,7 @@ CF_GRAMMAR
CF_ADDTO(proto, pipe_proto '}') CF_ADDTO(proto, pipe_proto '}')
pipe_proto_start: proto_start PIPE { 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; this_proto->preference = DEF_PREF_PIPE;
PIPE_CFG->mode = PIPE_TRANSPARENT; PIPE_CFG->mode = PIPE_TRANSPARENT;
} }

View file

@ -165,14 +165,6 @@ pipe_postconfig(struct proto_config *C)
cf_error("Primary table and peer table must be different"); 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 static int
pipe_reconfigure(struct proto *P, struct proto_config *new) pipe_reconfigure(struct proto *P, struct proto_config *new)
{ {
@ -186,6 +178,21 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
return 1; 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 = { struct protocol proto_pipe = {
name: "Pipe", name: "Pipe",
@ -195,5 +202,6 @@ struct protocol proto_pipe = {
start: pipe_start, start: pipe_start,
cleanup: pipe_cleanup, cleanup: pipe_cleanup,
reconfigure: pipe_reconfigure, reconfigure: pipe_reconfigure,
copy_config: pipe_copy_config,
get_status: pipe_get_status, get_status: pipe_get_status,
}; };

View file

@ -318,6 +318,19 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
return 1; 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 = { struct protocol proto_radv = {
.name = "RAdv", .name = "RAdv",
@ -325,5 +338,6 @@ struct protocol proto_radv = {
.init = radv_init, .init = radv_init,
.start = radv_start, .start = radv_start,
.shutdown = radv_shutdown, .shutdown = radv_shutdown,
.reconfigure = radv_reconfigure .reconfigure = radv_reconfigure,
.copy_config = radv_copy_config
}; };

View file

@ -46,14 +46,14 @@
struct radv_config struct radv_config
{ {
struct proto_config c; struct proto_config c;
list patt_list; /* List of iface configs */ list patt_list; /* List of iface configs (struct radv_iface_config) */
list pref_list; /* Global list of prefix configs */ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
}; };
struct radv_iface_config struct radv_iface_config
{ {
struct iface_patt i; 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 min_ra_int; /* Standard options from RFC 4261 */
u32 max_ra_int; u32 max_ra_int;

View file

@ -37,7 +37,7 @@ CF_GRAMMAR
CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } ) CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } )
rip_cfg_start: proto_start RIP { 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); rip_init_config(RIP_CFG);
} }
; ;

View file

@ -1015,6 +1015,19 @@ rip_reconfigure(struct proto *p, struct proto_config *c)
sizeof(struct rip_proto_config) - generic); 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 = { struct protocol proto_rip = {
name: "RIP", name: "RIP",
template: "rip%d", template: "rip%d",
@ -1026,4 +1039,5 @@ struct protocol proto_rip = {
dump: rip_dump, dump: rip_dump,
start: rip_start, start: rip_start,
reconfigure: rip_reconfigure, reconfigure: rip_reconfigure,
copy_config: rip_copy_config
}; };

View file

@ -26,7 +26,7 @@ CF_GRAMMAR
CF_ADDTO(proto, static_proto '}') CF_ADDTO(proto, static_proto '}')
static_proto_start: proto_start STATIC { 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); static_init_config((struct static_config *) this_proto);
} }
; ;

View file

@ -470,6 +470,58 @@ static_reconfigure(struct proto *p, struct proto_config *new)
return 1; 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 = { struct protocol proto_static = {
name: "Static", name: "Static",
template: "static%d", template: "static%d",
@ -479,6 +531,7 @@ struct protocol proto_static = {
shutdown: static_shutdown, shutdown: static_shutdown,
cleanup: static_cleanup, cleanup: static_cleanup,
reconfigure: static_reconfigure, reconfigure: static_reconfigure,
copy_config: static_copy_config
}; };
static void static void

View file

@ -12,6 +12,14 @@
/* /*
* We don't have split iface/scan/set parts. See krt-sock.h. * 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 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 #endif

View file

@ -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 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 #endif

View file

@ -34,13 +34,9 @@ struct krt_set_params {
struct krt_set_status { 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 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); void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan);
#endif #endif

View file

@ -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 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 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 #endif

View file

@ -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; 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 #endif

View file

@ -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_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 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 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 #endif

View file

@ -17,6 +17,7 @@ struct krt_if_status {
extern int if_scan_sock; 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 #endif

View file

@ -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 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 #endif

View file

@ -30,7 +30,7 @@ kern_proto_start: proto_start KERNEL {
if (cf_krt) if (cf_krt)
cf_error("Kernel protocol already defined"); cf_error("Kernel protocol already defined");
#endif #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_proto->preference = DEF_PREF_INHERITED;
THIS_KRT->scan_time = 60; THIS_KRT->scan_time = 60;
THIS_KRT->learn = THIS_KRT->persist = 0; THIS_KRT->learn = THIS_KRT->persist = 0;
@ -66,7 +66,7 @@ CF_ADDTO(proto, kif_proto '}')
kif_proto_start: proto_start DEVICE { kif_proto_start: proto_start DEVICE {
if (cf_kif) if (cf_kif)
cf_error("Kernel device protocol already defined"); 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_proto->preference = DEF_PREF_DIRECT;
THIS_KIF->scan_time = 60; THIS_KIF->scan_time = 60;
init_list(&THIS_KIF->primary); init_list(&THIS_KIF->primary);

View file

@ -216,6 +216,23 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
return 1; 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 = { struct protocol proto_unix_iface = {
name: "Device", name: "Device",
template: "device%d", template: "device%d",
@ -224,6 +241,7 @@ struct protocol proto_unix_iface = {
start: kif_start, start: kif_start,
shutdown: kif_shutdown, shutdown: kif_shutdown,
reconfigure: kif_reconfigure, 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 static int
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED) krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
@ -936,6 +967,7 @@ struct protocol proto_unix_kernel = {
start: krt_start, start: krt_start,
shutdown: krt_shutdown, shutdown: krt_shutdown,
reconfigure: krt_reconfigure, reconfigure: krt_reconfigure,
copy_config: krt_copy_config,
get_attr: krt_get_attr, get_attr: krt_get_attr,
#ifdef KRT_ALLOW_LEARN #ifdef KRT_ALLOW_LEARN
dump: krt_dump, dump: krt_dump,

View file

@ -100,7 +100,7 @@ struct kif_config {
struct proto_config c; struct proto_config c;
struct krt_if_params iface; struct krt_if_params iface;
int scan_time; /* How often we re-scan interfaces */ 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 { struct kif_proto {