From 9e0ef5395bbe6d17e4836495ff66103892e4a8fe Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sun, 15 Feb 2015 14:13:55 +0300 Subject: [PATCH 7/8] Add api for dynamic protocol creation based on dynamic templates. --- conf/cf-lex.l | 2 + conf/conf.h | 1 + nest/config.Y | 4 +- nest/proto.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- nest/protocol.h | 6 ++- 5 files changed, 156 insertions(+), 3 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index b995e10..dfcee5f 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -657,6 +657,8 @@ cf_symbol_class_name(struct symbol *sym) return "protocol"; case SYM_TEMPLATE: return "protocol template"; + case SYM_DYNTEMPLATE: + return "dynamic template"; case SYM_FUNCTION: return "function"; case SYM_FILTER: diff --git a/conf/conf.h b/conf/conf.h index 71da2a1..9490377 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -124,6 +124,7 @@ struct symbol { #define SYM_FILTER 4 #define SYM_TABLE 5 #define SYM_ROA 6 +#define SYM_DYNTEMPLATE 7 #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ #define SYM_CONSTANT 0x200 /* 0x200-0x2ff are variable types */ diff --git a/nest/config.Y b/nest/config.Y index 481d9f5..095a8fe 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -63,7 +63,7 @@ CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFA CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE, ROA) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) -CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) +CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, DYNAMIC) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -171,6 +171,7 @@ CF_ADDTO(conf, proto) proto_start: PROTOCOL { $$ = SYM_PROTO; } | TEMPLATE { $$ = SYM_TEMPLATE; } + | DYNAMIC TEMPLATE { $$ = SYM_DYNTEMPLATE; } ; proto_name: @@ -191,6 +192,7 @@ proto_name: this_proto->name = $1->name; proto_copy_config(this_proto, $3->def); + this_proto->class = $1->class; } ; diff --git a/nest/proto.c b/nest/proto.c index 846d172..dda438c 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -398,6 +398,146 @@ proto_init(struct proto_config *c) return q; } +/** + * config_create_dynamic - Creates dynamic protocol configuration + * @tc = config template to use + * @pname - instance name + * @p - existing protocol instance, if reconfiguring + * @pi - pointer to protocol-specific data + * + * Function creates all attributes for protocol - symbol of + * appropriate type, protocol config and performs necessary bindings. + * + * Returns pointer to protocol config or NULL. + */ +static struct proto_config * +config_create_dynamic(struct proto_config *tc, char *pname, struct proto *p, void *pi) +{ + struct proto_config *c; + struct protocol *q; + struct symbol *sym; + + q = tc->protocol; + + if (!q->copy_dynconfig) + return NULL; + + config_start_edit(tc->global); + + sym = cf_find_symbol(tc->global, pname); + if (!sym || sym->class != SYM_VOID) + { + config_stop_edit(); + log(L_ERR "Unable to create symbol %s for dynamic %s protocol", pname, q->name); + return NULL; + } + sym->class = SYM_PROTO; + + c = proto_create_config(tc->global, q, SYM_PROTO); + proto_copy_config(c, tc); + sym->def = c; + c->name = sym->name; + c->dyn_parent = tc; + q->copy_dynconfig(c, p, pi); + + config_stop_edit(); + + return c; +} + +/** + * proto_create_dynamic - Creates dynamic protocol instance + * @tc = config template to use + * @pname - instance name + * @pi - pointer to protocol-specific data + * + * Function creates all atrributes for protocol - symbol of + * appropriate type, protocol config and protocol itself. + * Protocol is started after this. + * + * Returns pointer to protocol instance or NULL. + */ +struct proto * +proto_create_dynamic(struct proto_config *tc, char *pname, void *pi) +{ + struct proto_config *c; + struct proto *p = NULL; + struct protocol *q; + + q = tc->protocol; + + if (!q->copy_dynconfig) + return NULL; + + c = config_create_dynamic(tc, pname, NULL, pi); + if (!c) + { + log(L_ERR "Creating dynamic %s config for %s failed", q->name, pname); + return NULL; + } + + p = proto_init(c); + + if (!p) + { + log(L_ERR "Creating dynamic %s protocol instance %s failed", q->name, pname); + return NULL; + } + + /* Start protocol */ + proto_rethink_goal(p); + + return p; +} + +/** + * proto_reconfigure_dynamic - creates dynamic protocol configuration on request + * @p - protocol instance + * + * Function checks is the protocol is really dynamic and it dynamic + * template still exists in new config. If true, it checks if the original + * creation conditions still holds by running @retest_dynconfig callback. + * At the end, new configuration is created based on new template and running + * protocol data. + * + * Returns pointer to proto_config or NULL, + */ +static struct proto_config * +proto_reconfigure_dynamic(struct config *new, struct proto *p) +{ + struct proto_config *oc, *nc; + struct symbol *sym; + + DBG("Dynamic protocol %s reconfiguration check\n", p->name); + /* Try to find parent dynamic template in new config */ + oc = p->cf->dyn_parent; + sym = cf_find_symbol(new, oc->name); + if (!sym || sym->class != SYM_DYNTEMPLATE) + { + DBG("Wrong dyntemplate symbol %s class: %d\n", oc->name, sym ? sym->class : 0); + return NULL; + } + /* Found parent configuration */ + nc = sym->def; + + /* Check if dynamic template protocol is the same */ + if (oc->protocol != nc->protocol) + { + DBG("Wrong dyntemplate protocol: %s vs %s\n", oc->protocol->name, nc->protocol->name); + return NULL; + } + + /* Check if condition still holds */ + if (!nc->protocol->retest_dynconfig(p, nc)) + { + DBG("retest dynconfig failed\n"); + return NULL; + } + + DBG("Start of dynamic protocol %s reconfiguration\n", p->name); + return config_create_dynamic(nc, p->name, p, NULL); +} + int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */ static int @@ -521,13 +661,17 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty { WALK_LIST(oc, old->protos) { + nc = NULL; p = oc->proto; sym = cf_find_symbol(new, oc->name); if (sym && sym->class == SYM_PROTO && !new->shutdown) + nc = sym->def; + if (!nc && oc->dyn_parent) + nc = proto_reconfigure_dynamic(new, p); + if (nc) { /* Found match, let's check if we can smoothly switch to new configuration */ /* No need to check description */ - nc = sym->def; nc->proto = p; /* We will try to reconfigure protocol p */ diff --git a/nest/protocol.h b/nest/protocol.h index a20b053..0af8757 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -57,6 +57,8 @@ struct protocol { 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 (*copy_dynconfig)(struct proto_config *, struct proto *, void *); /* Clone config from given dynamic template */ + int (*retest_dynconfig)(struct proto *, struct proto_config *); }; void protos_build(void); @@ -65,6 +67,7 @@ void protos_preconfig(struct config *); void protos_postconfig(struct config *); void protos_commit(struct config *new, struct config *old, int force_restart, int type); void protos_dump_all(void); +struct proto *proto_create_dynamic(struct proto_config *tc, char *pname, void *pi); #define GA_UNKNOWN 0 /* Attribute not recognized */ #define GA_NAME 1 /* Result = name */ @@ -89,7 +92,7 @@ struct proto_config { struct proto *proto; /* Instance we've created */ char *name; char *dsc; - int class; /* SYM_PROTO or SYM_TEMPLATE */ + int class; /* SYM_PROTO or SYM_TEMPLATE or SYM_DYNTEMPLATE */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ unsigned preference, disabled; /* Generic parameters */ int in_keep_filtered; /* Routes rejected in import filter are kept */ @@ -100,6 +103,7 @@ struct proto_config { (relevant when in_keep_filtered is active) */ struct proto_limit *in_limit; /* Limit for importing routes from protocol */ struct proto_limit *out_limit; /* Limit for exporting routes to protocol */ + struct proto_config *dyn_parent; /* Parent dynamic template */ /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */ -- 2.1.2