From a7f23f581f5e3efe92ec97dfca7d01c66f31ab04 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 7 Nov 2011 00:31:23 +0100 Subject: Implements protocol templates. Based on the patch from Alexander V. Chernikov. Extended to support almost all protocols. Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax. --- nest/config.Y | 33 ++++++++++++++++++----------- nest/proto.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- nest/protocol.h | 11 +++++++++- nest/rt-dev.c | 17 ++++++++++++++- nest/rt-dev.h | 2 +- 5 files changed, 107 insertions(+), 20 deletions(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index dd4a9e0..a6baf4e 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -26,7 +26,7 @@ static int password_id; static inline void reset_passwords(void) { - this_p_list = NULL; + this_p_list = NULL; } static inline list * @@ -37,10 +37,11 @@ get_passwords(void) return rv; } +#define DIRECT_CFG ((struct rt_dev_config *) this_proto) CF_DECLS -CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) +CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) @@ -58,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULT %type rtable %type optsym %type r_args -%type echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport +%type proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport %type proto_patt proto_patt2 CF_GRAMMAR @@ -115,20 +116,30 @@ newtab: TABLE SYM { CF_ADDTO(conf, proto) -proto_start: PROTOCOL +proto_start: + PROTOCOL { $$ = SYM_PROTO; } + | TEMPLATE { $$ = SYM_TEMPLATE; } ; proto_name: /* EMPTY */ { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); - s->class = SYM_PROTO; + s->class = this_proto->class; s->def = this_proto; this_proto->name = s->name; } | SYM { - cf_define_symbol($1, SYM_PROTO, this_proto); + cf_define_symbol($1, this_proto->class, this_proto); this_proto->name = $1->name; } + | SYM FROM SYM { + if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); + + cf_define_symbol($1, this_proto->class, this_proto); + this_proto->name = $1->name; + + proto_copy_config(this_proto, $3->def); + } ; proto_item: @@ -207,10 +218,9 @@ iface_patt_list: CF_ADDTO(proto, dev_proto '}') dev_proto_start: proto_start DIRECT { - struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config)); - this_proto = &p->c; - p->c.preference = DEF_PREF_DIRECT; - init_list(&p->iface_list); + this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1); + this_proto->preference = DEF_PREF_DIRECT; + init_list(&DIRECT_CFG->iface_list); } ; @@ -222,9 +232,8 @@ dev_proto: dev_iface_init: /* EMPTY */ { - struct rt_dev_config *p = (void *) this_proto; this_ipatt = cfg_allocz(sizeof(struct iface_patt)); - add_tail(&p->iface_list, NODE this_ipatt); + add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt); init_list(&this_ipatt->ipn_list); } ; diff --git a/nest/proto.c b/nest/proto.c index 4a154d5..d55c348 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -175,6 +175,7 @@ proto_flush_hooks(struct proto *p) * proto_config_new - create a new protocol configuration * @pr: protocol the configuration will belong to * @size: size of the structure including generic data + * @class: SYM_PROTO or SYM_TEMPLATE * * Whenever the configuration file says that a new instance * of a routing protocol should be created, the parser calls @@ -183,16 +184,23 @@ proto_flush_hooks(struct proto *p) * containing all the generic items followed by protocol-specific * ones). Also, the configuration entry gets added to the list * of protocol instances kept in the configuration. + * + * The function is also used to create protocol templates (when class + * SYM_TEMPLATE is specified), the only difference is that templates + * are not added to the list of protocol instances and therefore not + * initialized during protos_commit()). */ void * -proto_config_new(struct protocol *pr, unsigned size) +proto_config_new(struct protocol *pr, unsigned size, int class) { struct proto_config *c = cfg_allocz(size); - add_tail(&new_config->protos, &c->n); + if (class == SYM_PROTO) + add_tail(&new_config->protos, &c->n); c->global = new_config; c->protocol = pr; c->name = pr->name; + c->class = class; c->out_filter = FILTER_REJECT; c->table = c->global->master_rtc; c->debug = new_config->proto_default_debug; @@ -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 */ diff --git a/nest/protocol.h b/nest/protocol.h index f95905a..a7518c2 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -53,6 +53,7 @@ struct protocol { void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */ int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */ + void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ }; void protos_build(void); @@ -85,12 +86,15 @@ struct proto_config { struct proto *proto; /* Instance we've created */ char *name; char *dsc; + int class; /* SYM_PROTO or SYM_TEMPLATE */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ unsigned preference, disabled; /* Generic parameters */ u32 router_id; /* Protocol specific router ID */ struct rtable_config *table; /* Table we're attached to */ struct filter *in_filter, *out_filter; /* Attached filters */ + /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */ + /* Protocol-specific data follow... */ }; @@ -203,9 +207,14 @@ struct proto_spec { void *proto_new(struct proto_config *, unsigned size); -void *proto_config_new(struct protocol *, unsigned size); +void *proto_config_new(struct protocol *, unsigned size, int class); +void proto_copy_config(struct proto_config *dest, struct proto_config *src); void proto_request_feeding(struct proto *p); +static inline void +proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size) +{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); } + void proto_cmd_show(struct proto *, unsigned int, int); void proto_cmd_disable(struct proto *, unsigned int, int); void proto_cmd_enable(struct proto *, unsigned int, int); diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 239bd26..497ee80 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -92,9 +92,24 @@ dev_reconfigure(struct proto *p, struct proto_config *new) return iface_patts_equal(&o->iface_list, &n->iface_list, NULL); } +static void +dev_copy_config(struct proto_config *dest, struct proto_config *src) +{ + struct rt_dev_config *d = (struct rt_dev_config *) dest; + struct rt_dev_config *s = (struct rt_dev_config *) src; + + /* + * We copy iface_list as ifaces can be shared by more direct protocols. + * Copy suffices to be is shallow, because new nodes can be added, but + * old nodes cannot be modified (although they contain internal lists). + */ + cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt)); +} + struct protocol proto_device = { name: "Direct", template: "direct%d", init: dev_init, - reconfigure: dev_reconfigure + reconfigure: dev_reconfigure, + copy_config: dev_copy_config }; diff --git a/nest/rt-dev.h b/nest/rt-dev.h index 64f2cd9..c36d074 100644 --- a/nest/rt-dev.h +++ b/nest/rt-dev.h @@ -11,7 +11,7 @@ struct rt_dev_config { struct proto_config c; - list iface_list; + list iface_list; /* list of struct iface_patt */ }; #endif -- cgit v1.2.3