diff --git a/Makefile.in b/Makefile.in index b755df44..7713bcb1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -75,7 +75,7 @@ $(daemon): LIBS += $(DAEMON_LIBS) # Include directories dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@ -conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) +conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h context.h) cf-local = $(conf-y-targets): $(s)config.Y src-o-files = $(patsubst %.c,$(o)%.o,$(src)) @@ -175,10 +175,10 @@ ifeq ($(MAKECMDGOALS),) endif tags: - cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]` + cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chYl]` cscope: - cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b + cd $(srcdir) ; find $(dirs) -name *.[chYl] > cscope.files ; cscope -b # Install diff --git a/conf/Makefile b/conf/Makefile index 39628bff..59207d88 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -1,4 +1,4 @@ -src := cf-parse.tab.c cf-lex.c conf.c +src := cf-parse.tab.c cf-lex.c conf.c symbols.c obj := $(src-o-files) $(all-daemon) @@ -15,17 +15,18 @@ $(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y $(o)cf-parse.y: | $(s)gen_parser.m4 $(o)keywords.h: | $(s)gen_keywords.m4 +$(o)context.h: | $(s)gen_context.m4 $(o)commands.h: | $(s)gen_commands.m4 $(srcdir)/client/cmds.m4 $(o)cf-parse.tab.h: $(o)cf-parse.tab.c -$(o)cf-parse.tab.c: $(o)cf-parse.y - $(BISON) $(BISON_DEBUG) $(BISONFLAGS) -dv -pcf_ -b $(@:.tab.c=) $< +$(o)cf-parse.tab.c: $(o)cf-parse.y $(o)context.h + $(BISON) $(BISON_DEBUG) $(BISONFLAGS) -dv -pcfx_ -b $(@:.tab.c=) $< $(o)cf-lex.c: $(s)cf-lex.l - $(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcf_ -o$@ $< + $(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcfx_ -o$@ $< -$(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h +$(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h $(o)context.h $(o)cf-lex.o: CFLAGS+=-Wno-sign-compare -Wno-unused-function $(addprefix $(o), cf-parse.y keywords.h commands.h cf-parse.tab.h cf-parse.tab.c cf-lex.c): $(objdir)/.dir-stamp diff --git a/conf/cf-lex.l b/conf/cf-lex.l index c3154b36..1a587dce 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -27,18 +27,6 @@ %{ #undef REJECT /* Avoid name clashes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #define PARSER 1 #include "nest/bird.h" @@ -46,6 +34,7 @@ #include "nest/protocol.h" #include "filter/filter.h" #include "conf/conf.h" +#include "conf/parser.h" #include "conf/cf-parse.tab.h" #include "lib/string.h" #include "lib/hash.h" @@ -64,7 +53,6 @@ struct keyword { #endif -static uint cf_hash(byte *c); #define KW_KEY(n) n->name #define KW_NEXT(n) n->next @@ -72,37 +60,19 @@ static uint cf_hash(byte *c); #define KW_FN(k) cf_hash(k) #define KW_ORDER 8 /* Fixed */ -#define SYM_KEY(n) n->name, n->scope->active -#define SYM_NEXT(n) n->next -#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2 -#define SYM_FN(k,s) cf_hash(k) -#define SYM_ORDER 6 /* Initial */ - -#define SYM_REHASH sym_rehash -#define SYM_PARAMS /8, *1, 2, 2, 6, 20 - - -HASH_DEFINE_REHASH_FN(SYM, struct symbol) - HASH(struct keyword) kw_hash; - -static struct sym_scope *conf_this_scope; - -linpool *cfg_mem; - -int (*cf_read_hook)(byte *buf, unsigned int max, int fd); -struct include_file_stack *ifs; -static struct include_file_stack *ifs_head; - -#define MAX_INCLUDE_DEPTH 8 - -#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd); #define YY_NO_UNPUT -#define YY_FATAL_ERROR(msg) cf_error(msg) +#define CTX cfx_get_extra(yyscanner) +#define COR (CTX->order) +#define CST (CTX->order->state) +#define YY_INPUT(buf,result,max) result = COR->cf_read_hook(COR, buf, max); +#define YY_FATAL_ERROR(...) cf_error(CTX, __VA_ARGS__) -static void cf_include(char *arg, int alen); -static int check_eof(void); +#define cf_lval (* (cfx_get_lval(yyscanner))) + +static void cf_include(char *arg, int alen, yyscan_t yyscanner); +static int check_eof(yyscan_t yyscanner); %} @@ -111,6 +81,9 @@ static int check_eof(void); %option nounput %option noreject +%option reentrant bison-bridge +%option extra-type="struct cf_context *" + %x COMMENT CCOMM CLI ALPHA [a-zA-Z_] @@ -124,8 +97,8 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; {include} { char *start, *end; - if (!ifs->depth) - cf_error("Include not allowed in CLI"); + if (!COR->cf_include) + YY_FATAL_ERROR("Include not allowed in CLI"); start = strchr(yytext, '"'); start++; @@ -134,9 +107,9 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; *end = 0; if (start == end) - cf_error("Include with empty argument"); + YY_FATAL_ERROR("Include with empty argument"); - cf_include(start, end-start); + cf_include(start, end-start, yyscanner); } {DIGIT}+:{DIGIT}+ { @@ -147,7 +120,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; errno = 0; l = strtoul(yytext, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> 32)) - cf_error("ASN out of range"); + YY_FATAL_ERROR("ASN out of range"); if (l >> 16) { @@ -165,7 +138,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; errno = 0; l = strtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) - cf_error("Number out of range"); + YY_FATAL_ERROR("Number out of range"); cf_lval.i64 |= l; return VPN_RD; @@ -192,13 +165,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; errno = 0; l = strtoul(yytext+2, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> len1)) - cf_error("ASN out of range"); + YY_FATAL_ERROR("ASN out of range"); cf_lval.i64 |= ((u64) l) << len2; errno = 0; l = strtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) - cf_error("Number out of range"); + YY_FATAL_ERROR("Number out of range"); cf_lval.i64 |= l; return VPN_RD; @@ -214,13 +187,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; e = strchr(yytext, ':'); *e++ = '\0'; if (!ip4_pton(yytext, &ip4)) - cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext); + YY_FATAL_ERROR("Invalid IPv4 address %s in Route Distinguisher", yytext); cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16; errno = 0; l = strtoul(e, &e, 10); if (e && *e || (errno == ERANGE) || (l >> 16)) - cf_error("Number out of range"); + YY_FATAL_ERROR("Number out of range"); cf_lval.i64 |= l; return VPN_RD; @@ -228,13 +201,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { if (!ip4_pton(yytext, &cf_lval.ip4)) - cf_error("Invalid IPv4 address %s", yytext); + YY_FATAL_ERROR("Invalid IPv4 address %s", yytext); return IP4; } ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { if (!ip6_pton(yytext, &cf_lval.ip6)) - cf_error("Invalid IPv6 address %s", yytext); + YY_FATAL_ERROR("Invalid IPv6 address %s", yytext); return IP6; } @@ -244,7 +217,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; errno = 0; l = strtoul(yytext+2, &e, 16); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) - cf_error("Number out of range"); + YY_FATAL_ERROR("Number out of range"); cf_lval.i = l; return NUM; } @@ -255,7 +228,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; errno = 0; l = strtoul(yytext, &e, 10); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) - cf_error("Number out of range"); + YY_FATAL_ERROR("Number out of range"); cf_lval.i = l; return NUM; } @@ -283,7 +256,7 @@ else: { } } - cf_lval.s = cf_get_symbol(yytext); + cf_lval.s = cf_get_symbol(CTX, yytext); return SYM; } @@ -302,36 +275,36 @@ else: { ["][^"\n]*["] { yytext[yyleng-1] = 0; - cf_lval.t = cfg_strdup(yytext+1); + cf_lval.t = cf_strdup(CTX, yytext+1); yytext[yyleng-1] = '"'; return TEXT; } -["][^"\n]*\n cf_error("Unterminated string"); +["][^"\n]*\n YY_FATAL_ERROR("Unterminated string"); -<> { if (check_eof()) return END; } +<> { if (check_eof(yyscanner)) return END; } {WHITE}+ -\n ifs->lino++; +\n CST->lino++; # BEGIN(COMMENT); \/\* BEGIN(CCOMM); -. cf_error("Unknown character"); +. YY_FATAL_ERROR("Unknown character"); \n { - ifs->lino++; + CST->lino++; BEGIN(INITIAL); } . \*\/ BEGIN(INITIAL); -\n ifs->lino++; -\/\* cf_error("Comment nesting not supported"); -<> cf_error("Unterminated comment"); +\n CST->lino++; +\/\* YY_FATAL_ERROR("Comment nesting not supported"); +<> YY_FATAL_ERROR("Unterminated comment"); . \!\= return NEQ; @@ -346,7 +319,7 @@ else: { %% -static uint +uint cf_hash(byte *c) { uint h = 13 << 24; @@ -356,283 +329,53 @@ cf_hash(byte *c) return h; } - -/* - * IFS stack - it contains structures needed for recursive processing - * of include in config files. On the top of the stack is a structure - * for currently processed file. Other structures are either for - * active files interrupted because of include directive (these have - * fd and flex buffer) or for inactive files scheduled to be processed - * later (when parent requested including of several files by wildcard - * match - these do not have fd and flex buffer yet). - * - * FIXME: Most of these ifs and include functions are really sysdep/unix. - */ - -static struct include_file_stack * -push_ifs(struct include_file_stack *old) -{ - struct include_file_stack *ret; - ret = cfg_allocz(sizeof(struct include_file_stack)); - ret->lino = 1; - ret->prev = old; - return ret; -} - -static struct include_file_stack * -pop_ifs(struct include_file_stack *old) -{ - yy_delete_buffer(old->buffer); - close(old->fd); - return old->prev; -} - static void -enter_ifs(struct include_file_stack *new) +cf_init_state(struct cf_context *ctx, struct conf_state *cs) { - if (!new->buffer) - { - new->fd = open(new->file_name, O_RDONLY); - if (new->fd < 0) - { - ifs = ifs->up; - cf_error("Unable to open included file %s: %m", new->file_name); - } - - new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE); - } - - yy_switch_to_buffer(new->buffer); + cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner); +} + +struct conf_state * +cf_new_state(struct cf_context *ctx, const char *name) +{ + struct conf_state *cs = cfg_alloc(sizeof(struct conf_state)); + *cs = (struct conf_state) { + .name = cfg_strdup(name), + .lino = 1, + }; + cf_init_state(ctx, cs); + return cs; } -/** - * cf_lex_unwind - unwind lexer state during error - * - * cf_lex_unwind() frees the internal state on IFS stack when the lexical - * analyzer is terminated by cf_error(). - */ void -cf_lex_unwind(void) +cf_free_state(struct cf_context *ctx, struct conf_state *cs) { - struct include_file_stack *n; - - for (n = ifs; n != ifs_head; n = n->prev) - { - /* Memory is freed automatically */ - if (n->buffer) - yy_delete_buffer(n->buffer); - if (n->fd) - close(n->fd); - } - - ifs = ifs_head; + yy_delete_buffer(cs->buffer, ctx->yyscanner); + /* The state structure is allocated from linpool, will be auto-freed. */ } static void -cf_include(char *arg, int alen) +cf_include(char *arg, int alen, yyscan_t yyscanner) { - struct include_file_stack *base_ifs = ifs; - int new_depth, rv, i; - char *patt; - glob_t g = {}; - - new_depth = ifs->depth + 1; - if (new_depth > MAX_INCLUDE_DEPTH) - cf_error("Max include depth reached"); - - /* expand arg to properly handle relative filenames */ - if (*arg != '/') - { - int dlen = strlen(ifs->file_name); - char *dir = alloca(dlen + 1); - patt = alloca(dlen + alen + 2); - memcpy(dir, ifs->file_name, dlen + 1); - sprintf(patt, "%s/%s", dirname(dir), arg); - } - else - patt = arg; - - /* Skip globbing if there are no wildcards, mainly to get proper - response when the included config file is missing */ - if (!strpbrk(arg, "?*[")) - { - ifs = push_ifs(ifs); - ifs->file_name = cfg_strdup(patt); - ifs->depth = new_depth; - ifs->up = base_ifs; - enter_ifs(ifs); - return; - } - - /* Expand the pattern */ - rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g); - if (rv == GLOB_ABORTED) - cf_error("Unable to match pattern %s: %m", patt); - if ((rv != 0) || (g.gl_pathc <= 0)) - return; - - /* - * Now we put all found files to ifs stack in reverse order, they - * will be activated and processed in order as ifs stack is popped - * by pop_ifs() and enter_ifs() in check_eof(). - */ - for(i = g.gl_pathc - 1; i >= 0; i--) - { - char *fname = g.gl_pathv[i]; - struct stat fs; - - if (stat(fname, &fs) < 0) - { - globfree(&g); - cf_error("Unable to stat included file %s: %m", fname); - } - - if (fs.st_mode & S_IFDIR) - continue; - - /* Prepare new stack item */ - ifs = push_ifs(ifs); - ifs->file_name = cfg_strdup(fname); - ifs->depth = new_depth; - ifs->up = base_ifs; - } - - globfree(&g); - enter_ifs(ifs); + COR->cf_include(COR, arg, alen); + yy_switch_to_buffer(CST->buffer, yyscanner); } static int -check_eof(void) +check_eof(yyscan_t yyscanner) { - if (ifs == ifs_head) - { - /* EOF in main config file */ - ifs->lino = 1; /* Why this? */ - return 1; - } + if (!COR->cf_outclude) + return 1; - ifs = pop_ifs(ifs); - enter_ifs(ifs); + if (COR->cf_outclude(COR)) + return 1; + + yy_switch_to_buffer(CST->buffer, yyscanner); return 0; } -static struct symbol * -cf_new_symbol(byte *c) -{ - struct symbol *s; - - uint l = strlen(c); - if (l > SYM_MAX_LEN) - cf_error("Symbol too long"); - - s = cfg_alloc(sizeof(struct symbol) + l); - s->scope = conf_this_scope; - s->class = SYM_VOID; - s->def = NULL; - s->aux = 0; - strcpy(s->name, c); - - if (!new_config->sym_hash.data) - HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER); - - HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s); - - return s; -} - -/** - * cf_find_symbol - find a symbol by name - * @cfg: specificed config - * @c: symbol name - * - * This functions searches the symbol table in the config @cfg for a symbol of - * given name. First it examines the current scope, then the second recent one - * and so on until it either finds the symbol and returns a pointer to its - * &symbol structure or reaches the end of the scope chain and returns %NULL to - * signify no match. - */ -struct symbol * -cf_find_symbol(struct config *cfg, byte *c) -{ - struct symbol *s; - - if (cfg->sym_hash.data && - (s = HASH_FIND(cfg->sym_hash, SYM, c, 1))) - return s; - - if (cfg->fallback && - cfg->fallback->sym_hash.data && - (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1))) - return s; - - return NULL; -} - -/** - * cf_get_symbol - get a symbol by name - * @c: symbol name - * - * This functions searches the symbol table of the currently parsed config - * (@new_config) for a symbol of given name. It returns either the already - * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no - * existing symbol is found. - */ -struct symbol * -cf_get_symbol(byte *c) -{ - return cf_find_symbol(new_config, c) ?: cf_new_symbol(c); -} - -struct symbol * -cf_default_name(char *template, int *counter) -{ - char buf[SYM_MAX_LEN]; - struct symbol *s; - char *perc = strchr(template, '%'); - - for(;;) - { - bsprintf(buf, template, ++(*counter)); - s = cf_get_symbol(buf); - if (s->class == SYM_VOID) - return s; - if (!perc) - break; - } - cf_error("Unable to generate default name"); -} - -/** - * cf_define_symbol - define meaning of a symbol - * @sym: symbol to be defined - * @type: symbol class to assign - * @def: class dependent data - * - * Defines new meaning of a symbol. If the symbol is an undefined - * one (%SYM_VOID), it's just re-defined to the new type. If it's defined - * in different scope, a new symbol in current scope is created and the - * meaning is assigned to it. If it's already defined in the current scope, - * an error is reported via cf_error(). - * - * Result: Pointer to the newly defined symbol. If we are in the top-level - * scope, it's the same @sym as passed to the function. - */ -struct symbol * -cf_define_symbol(struct symbol *sym, int type, void *def) -{ - if (sym->class) - { - if (sym->scope == conf_this_scope) - cf_error("Symbol already defined"); - sym = cf_new_symbol(sym->name); - } - sym->class = type; - sym->def = def; - return sym; -} - -static void -cf_lex_init_kh(void) +void +cf_init_kh(void) { HASH_INIT(kw_hash, &root_pool, KW_ORDER); @@ -642,108 +385,46 @@ cf_lex_init_kh(void) } /** - * cf_lex_init - initialize the lexer + * cf_new_context - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration * @c: configuration structure * - * cf_lex_init() initializes the lexical analyzer and prepares it for + * cf_new_context() initializes the lexical analyzer and prepares it for * parsing of a new input. */ -void -cf_lex_init(int is_cli, struct config *c) +struct cf_context * +cf_new_context(int is_cli, struct conf_order *order) { - if (!kw_hash.data) - cf_lex_init_kh(); + struct cf_context *ctx = order->ctx = lp_allocz(order->new_config->mem, sizeof(struct cf_context)); + *ctx = (struct cf_context) { + .new_config = order->new_config, + .cfg_mem = order->new_config->mem, + .order = order, + }; - ifs_head = ifs = push_ifs(NULL); - if (!is_cli) - { - ifs->file_name = c->file_name; - ifs->fd = c->file_fd; - ifs->depth = 1; - } + cfx_lex_init_extra(ctx, &(ctx->yyscanner)); + struct yyguts_t *yyg = ctx->yyscanner; - yyrestart(NULL); - ifs->buffer = YY_CURRENT_BUFFER; + cf_init_state(ctx, order->state); + yy_switch_to_buffer(order->state->buffer, yyg); if (is_cli) BEGIN(CLI); else BEGIN(INITIAL); - conf_this_scope = cfg_allocz(sizeof(struct sym_scope)); - conf_this_scope->active = 1; + ctx->sym_scope = cfg_allocz(sizeof(struct sym_scope)); + ctx->sym_scope->active = 1; + + return ctx; } -/** - * cf_push_scope - enter new scope - * @sym: symbol representing scope name - * - * If we want to enter a new scope to process declarations inside - * a nested block, we can just call cf_push_scope() to push a new - * scope onto the scope stack which will cause all new symbols to be - * defined in this scope and all existing symbols to be sought for - * in all scopes stored on the stack. - */ void -cf_push_scope(struct symbol *sym) +cf_free_context(struct cf_context *ctx) { - struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope)); - - s->next = conf_this_scope; - conf_this_scope = s; - s->active = 1; - s->name = sym; + cfx_lex_destroy(ctx->yyscanner); } -/** - * cf_pop_scope - leave a scope - * - * cf_pop_scope() pops the topmost scope from the scope stack, - * leaving all its symbols in the symbol table, but making them - * invisible to the rest of the config. - */ -void -cf_pop_scope(void) -{ - conf_this_scope->active = 0; - conf_this_scope = conf_this_scope->next; - ASSERT(conf_this_scope); -} - -/** - * cf_symbol_class_name - get name of a symbol class - * @sym: symbol - * - * This function returns a string representing the class - * of the given symbol. - */ -char * -cf_symbol_class_name(struct symbol *sym) -{ - if (cf_symbol_is_constant(sym)) - return "constant"; - - switch (sym->class) - { - case SYM_VOID: - return "undefined"; - case SYM_PROTO: - return "protocol"; - case SYM_TEMPLATE: - return "protocol template"; - case SYM_FUNCTION: - return "function"; - case SYM_FILTER: - return "filter"; - case SYM_TABLE: - return "routing table"; - default: - return "unknown type"; - } -} - - /** * DOC: Parser * diff --git a/conf/conf.c b/conf/conf.c index 885e2e7e..05b740f5 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -54,11 +54,10 @@ #include "lib/event.h" #include "lib/timer.h" #include "conf/conf.h" +#include "conf/parser.h" #include "filter/filter.h" -static jmp_buf conf_jmpbuf; - struct config *config, *new_config; static struct config *old_config; /* Old configuration */ @@ -85,23 +84,17 @@ int undo_available; /* Undo was not requested from last reconfiguration */ * pool and a linear memory pool to it and makes it available for * further use. Returns a pointer to the structure. */ -struct config * -config_alloc(const char *name) +static struct config * +config_alloc(struct pool *pp, struct linpool *lp) { - pool *p = rp_new(&root_pool, "Config"); - linpool *l = lp_new_default(p); + pool *p = rp_new(pp ?: &root_pool, "Config"); + linpool *l = lp ?: lp_new_default(p); struct config *c = lp_allocz(l, sizeof(struct config)); - /* Duplication of name string in local linear pool */ - uint nlen = strlen(name) + 1; - char *ndup = lp_allocu(l, nlen); - memcpy(ndup, name, nlen); - init_list(&c->tests); c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */ c->pool = p; c->mem = l; - c->file_name = ndup; c->load_time = current_time(); c->tf_route = c->tf_proto = TM_ISO_SHORT_MS; c->tf_base = c->tf_log = TM_ISO_LONG_MS; @@ -110,77 +103,73 @@ config_alloc(const char *name) return c; } -/** - * config_parse - parse a configuration - * @c: configuration - * - * config_parse() reads input by calling a hook function pointed to - * by @cf_read_hook and parses it according to the configuration - * grammar. It also calls all the preconfig and postconfig hooks - * before, resp. after parsing. - * - * Result: 1 if the config has been parsed successfully, 0 if any - * error has occurred (such as anybody calling cf_error()) and - * the @err_msg field has been set to the error message. - */ int -config_parse(struct config *c) +config_parse(struct conf_order *order) { - int done = 0; - DBG("Parsing configuration file `%s'\n", c->file_name); - new_config = c; - cfg_mem = c->mem; - if (setjmp(conf_jmpbuf)) - goto cleanup; + DBG("Parsing configuration named `%s'\n", order->state->name); - cf_lex_init(0, c); - sysdep_preconfig(c); - protos_preconfig(c); - rt_preconfig(c); - cf_parse(); + if (!order->new_config) + order->new_config = config_alloc(order->pool, order->lp); - if (EMPTY_LIST(c->protos)) - cf_error("No protocol is specified in the config file"); + struct cf_context *ctx = cf_new_context(0, order); + int ret; - /* - if (!c->router_id) - cf_error("Router ID must be configured manually"); - */ + if (setjmp(ctx->jmpbuf)) + { + if (order->cf_outclude) + while (! order->cf_outclude(order)) + ; - done = 1; + ret = 0; + + config_free(ctx->new_config); + order->new_config = NULL; + + goto cleanup; + } + + sysdep_preconfig(ctx); + protos_preconfig(ctx->new_config); + rt_preconfig(ctx); + cfx_parse(ctx, ctx->yyscanner); + + if (EMPTY_LIST((ctx->new_config)->protos)) + cf_error(ctx, "No protocol is specified in the config file"); + + ret = 1; cleanup: - new_config = NULL; - cfg_mem = NULL; - return done; + cf_free_context(ctx); + order->ctx = NULL; + return ret; } -/** - * cli_parse - parse a CLI command - * @c: temporary config structure - * - * cli_parse() is similar to config_parse(), but instead of a configuration, - * it parses a CLI command. See the CLI module for more information. - */ int -cli_parse(struct config *c) +cli_parse(struct conf_order *order) { - int done = 0; - c->fallback = config; - new_config = c; - cfg_mem = c->mem; - if (setjmp(conf_jmpbuf)) - goto cleanup; + DBG("Parsing command line\n"); - cf_lex_init(1, c); - cf_parse(); - done = 1; + struct config cc = {}; + cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config"); + cc.mem = order->lp ?: lp_new_default(cc.pool); -cleanup: - c->fallback = NULL; - new_config = NULL; - cfg_mem = NULL; - return done; + order->new_config = &cc; + + struct cf_context *ctx = cf_new_context(1, order); + + int ok = 0; + if (setjmp(ctx->jmpbuf)) + goto done; + + cfx_parse(ctx, ctx->yyscanner); + ok = 1; + +done: + cf_free_context(ctx); + config_free(&cc); + order->new_config = NULL; + order->ctx = NULL; + return ok; } /** @@ -465,6 +454,8 @@ config_init(void) config_timer = tm_new(&root_pool); config_timer->hook = config_timeout; + + cf_init_kh(); } /** @@ -501,22 +492,43 @@ order_shutdown(void) * error in the configuration. */ void -cf_error(const char *msg, ...) +cf_error(struct cf_context *ctx, const char *msg, ...) { - char buf[1024]; va_list args; va_start(args, msg); - if (bvsnprintf(buf, sizeof(buf), msg, args) < 0) - strcpy(buf, ""); + ctx->order->cf_error(ctx->order, msg, args); va_end(args); - new_config->err_msg = cfg_strdup(buf); - new_config->err_lino = ifs->lino; - new_config->err_file_name = ifs->file_name; - cf_lex_unwind(); - longjmp(conf_jmpbuf, 1); + + longjmp(ctx->jmpbuf, 1); } +#if 0 + if (bvsnprintf(ctx->order->err.msg, CONF_ERROR_MSG_LEN, msg, args) < 0) + strcpy(ctx->order->err.msg, ""); + + ctx->order->err.lino = ctx->order->state->lino; + + uint fnlen = strlen(ctx->order->state->name); + if (fnlen >= CONF_FILENAME_LEN) + { + uint l = (CONF_FILENAME_LEN - 6) / 2; + uint r = CONF_FILENAME_LEN - 6 - l; + + memcpy(ctx->order->err.file_name, ctx->order->state->name, l); + memcpy(ctx->order->err.file_name + l, " ... ", 5); + strncpy(ctx->order->err.file_name + l + 5, ctx->order->state->name + fnlen - r, r); + } + else + memcpy(ctx->order->err.file_name, ctx->order->state->name, fnlen + 1); + +} +#endif + +void *cf_alloc(struct cf_context *ctx, unsigned size) { return cfg_alloc(size); } +void *cf_allocu(struct cf_context *ctx, unsigned size) { return cfg_allocu(size); } +void *cf_allocz(struct cf_context *ctx, unsigned size) { return cfg_allocz(size); } + /** * cfg_strdup - copy a string to config memory * @c: string to copy @@ -527,7 +539,7 @@ cf_error(const char *msg, ...) * and we want to preserve it for further use. */ char * -cfg_strdup(const char *c) +cf_strdup(struct cf_context *ctx, const char *c) { int l = strlen(c) + 1; char *z = cfg_allocu(l); @@ -537,7 +549,7 @@ cfg_strdup(const char *c) void -cfg_copy_list(list *dest, list *src, unsigned node_size) +cf_copy_list(struct cf_context *ctx, list *dest, list *src, unsigned node_size) { node *dn, *sn; diff --git a/conf/conf.h b/conf/conf.h index f174d352..bbdb70ac 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -10,6 +10,7 @@ #define _BIRD_CONF_H_ #include "sysdep/config.h" +#include "nest/cli.h" #include "lib/ip.h" #include "lib/hash.h" #include "lib/resource.h" @@ -45,11 +46,6 @@ struct config { u32 latency_limit; /* Events with longer duration are logged (us) */ u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */ u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */ - char *err_msg; /* Parser error message */ - int err_lino; /* Line containing error */ - char *err_file_name; /* File name containing error */ - char *file_name; /* Name of main configuration file */ - int file_fd; /* File descriptor of main configuration file */ HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */ struct config *fallback; /* Link to regular config for CLI parsing */ int obstacle_count; /* Number of items blocking freeing of this config */ @@ -57,19 +53,61 @@ struct config { btime load_time; /* When we've got this configuration */ }; +struct conf_state { + void *buffer; /* Internal lexer state */ + const char *name; /* Current file name */ + uint lino; /* Current line */ +}; + +struct conf_order { + struct config *new_config; /* Store the allocated config here */ + struct cf_context *ctx; /* Internal config context, do not set */ + struct conf_state *state; + struct pool *pool; /* If set, use this resource pool */ + struct linpool *lp; /* If set, use this linpool */ + int (*cf_read_hook)(struct conf_order *order, byte *buf, uint max); + void (*cf_include)(struct conf_order *order, char *name, uint len); + int (*cf_outclude)(struct conf_order *order); + void (*cf_error)(struct conf_order *order, const char *msg, va_list args); +}; + /* Please don't use these variables in protocols. Use proto_config->global instead. */ extern struct config *config; /* Currently active configuration */ -extern struct config *new_config; /* Configuration being parsed */ -struct config *config_alloc(const char *name); -int config_parse(struct config *); -int cli_parse(struct config *); +/** + * Parse configuration + * + * Arguments: + * @order provides callbacks to read config files + * + * Return value: + * 1 on success; order->new_config is then set to the parsed config + * 0 on fail; order->new_config is undefined + **/ +int config_parse(struct conf_order *order); + +/** + * Parse CLI command + * + * Arguments: + * @order provides callbacks to read command line + * + * Return value: + * 1 on success + * 0 on fail + * + * Parsed config is never kept, order->new_config should be zero after return. + **/ +int cli_parse(struct conf_order *order); + +/** Callback for returning error from parser hooks */ +void cf_error(struct cf_context *, const char *msg, ...) NORET; + void config_free(struct config *); int config_commit(struct config *, int type, uint timeout); int config_confirm(void); int config_undo(void); void config_init(void); -void cf_error(const char *msg, ...) NORET; void config_add_obstacle(struct config *); void config_del_obstacle(struct config *); void order_shutdown(void); @@ -87,21 +125,16 @@ void order_shutdown(void); #define CONF_SHUTDOWN -1 #define CONF_NOTHING -2 - /* Pools */ -extern linpool *cfg_mem; - -#define cfg_alloc(size) lp_alloc(cfg_mem, size) -#define cfg_allocu(size) lp_allocu(cfg_mem, size) -#define cfg_allocz(size) lp_allocz(cfg_mem, size) -char *cfg_strdup(const char *c); -void cfg_copy_list(list *dest, list *src, unsigned node_size); +void *cf_alloc(struct cf_context *ctx, unsigned size); +void *cf_allocu(struct cf_context *ctx, unsigned size); +void *cf_allocz(struct cf_context *ctx, unsigned size); +void cf_copy_list(struct cf_context *ctx, list *dest, list *src, unsigned node_size); +char *cf_strdup(struct cf_context *ctx, const char *c); /* Lexer */ -extern int (*cf_read_hook)(byte *buf, uint max, int fd); - struct symbol { struct symbol *next; struct sym_scope *scope; @@ -134,45 +167,16 @@ struct sym_scope { #define SYM_TYPE(s) (((struct f_val *) (s)->def)->type) #define SYM_VAL(s) (((struct f_val *) (s)->def)->val) -struct include_file_stack { - void *buffer; /* Internal lexer state */ - char *file_name; /* File name */ - int fd; /* File descriptor */ - int lino; /* Current line num */ - int depth; /* Include depth, 0 = cannot include */ - - struct include_file_stack *prev; /* Previous record in stack */ - struct include_file_stack *up; /* Parent (who included this file) */ -}; - -extern struct include_file_stack *ifs; - - -int cf_lex(void); -void cf_lex_init(int is_cli, struct config *c); -void cf_lex_unwind(void); - struct symbol *cf_find_symbol(struct config *cfg, byte *c); -struct symbol *cf_get_symbol(byte *c); -struct symbol *cf_default_name(char *template, int *counter); -struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); -void cf_push_scope(struct symbol *); -void cf_pop_scope(void); char *cf_symbol_class_name(struct symbol *sym); static inline int cf_symbol_is_constant(struct symbol *sym) { return (sym->class & 0xff00) == SYM_CONSTANT; } - -/* Parser */ - -extern char *cf_text; -int cf_parse(void); - /* Sysdep hooks */ -void sysdep_preconfig(struct config *); +void sysdep_preconfig(struct cf_context *ctx); int sysdep_commit(struct config *, struct config *); void sysdep_shutdown_done(void); diff --git a/conf/confbase.Y b/conf/confbase.Y index 8fd72e5e..d9bcbad5 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -12,6 +12,7 @@ CF_HDR #include "nest/bird.h" #include "conf/conf.h" +#include "conf/parser.h" #include "lib/resource.h" #include "lib/socket.h" #include "lib/timer.h" @@ -24,17 +25,32 @@ CF_HDR /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */ +CF_CTX + +void *yyscanner; +struct sym_scope *sym_scope; +struct config *new_config; +jmp_buf jmpbuf; +linpool *cfg_mem; +struct conf_order *order; + CF_DEFINES -static void -check_u16(uint val) +#define BFD_CHECK(use) do { if (use) cf_error(ctx, "BFD not available"); } while (0) + +static inline void +check_u16(struct cf_context *ctx, uint val) { if (val > 0xFFFF) - cf_error("Value %u out of range (0-65535)", val); + cf_error(ctx, "Value %u out of range (0-65535)", val); } CF_DECLS +%define api.pure full +%parse-param {struct cf_context *ctx} +%param {void *yyscanner} + %union { uint i; u32 i32; @@ -123,17 +139,17 @@ conf: definition ; definition: DEFINE SYM '=' term ';' { struct f_val *val = cfg_alloc(sizeof(struct f_val)); - *val = f_eval($4, cfg_mem); - if (val->type == T_RETURN) cf_error("Runtime error"); - cf_define_symbol($2, SYM_CONSTANT | val->type, val); + *val = f_eval($4, ctx->cfg_mem); + if (val->type == T_RETURN) cf_error(ctx, "Runtime error"); + cf_define_symbol(ctx, $2, SYM_CONSTANT | val->type, val); } ; expr: NUM - | '(' term ')' { $$ = f_eval_int($2); } + | '(' term ')' { $$ = f_eval_int($2, ctx); } | SYM { - if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected"); + if ($1->class != (SYM_CONSTANT | T_INT)) cf_error(ctx, "Number expected"); $$ = SYM_VAL($1).i; } ; @@ -162,7 +178,7 @@ ipa: IP4 { $$ = ipa_from_ip4($1); } | IP6 { $$ = ipa_from_ip6($1); } | SYM { - if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected"); + if ($1->class != (SYM_CONSTANT | T_IP)) cf_error(ctx, "IP address expected"); $$ = SYM_VAL($1).ip; } ; @@ -177,7 +193,7 @@ ipa_scope: pxlen4: '/' NUM { - if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2); + if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error(ctx, "Invalid prefix length %u", $2); $$ = $2; } ; @@ -188,37 +204,37 @@ net_ip4_: IP4 pxlen4 net_addr_ip4 *n = (void *) &($$); if (!net_validate_ip4(n)) - cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d", + cf_error(ctx, "Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d", n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen); }; net_ip6_: IP6 '/' NUM { if ($3 > IP6_MAX_PREFIX_LENGTH) - cf_error("Invalid prefix length %u", $3); + cf_error(ctx, "Invalid prefix length %u", $3); net_fill_ip6(&($$), $1, $3); net_addr_ip6 *n = (void *) &($$); if (!net_validate_ip6(n)) - cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d", + cf_error(ctx, "Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d", n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen); }; net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM { if ($3 > IP6_MAX_PREFIX_LENGTH) - cf_error("Invalid prefix length %u", $3); + cf_error(ctx, "Invalid prefix length %u", $3); if ($7 > IP6_MAX_PREFIX_LENGTH) - cf_error("Invalid prefix length %u", $7); + cf_error(ctx, "Invalid prefix length %u", $7); $$ = cfg_alloc(sizeof(net_addr_ip6_sadr)); net_fill_ip6_sadr($$, $1, $3, $5, $7); net_addr_ip6_sadr *n = (void *) $$; if (!net_validate_ip6_sadr(n)) - cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d", + cf_error(ctx, "Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d", n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen, ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen, ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen); @@ -241,7 +257,7 @@ net_roa4_: net_ip4_ MAX NUM AS NUM $$ = cfg_alloc(sizeof(net_addr_roa4)); net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5); if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH) - cf_error("Invalid max prefix length %u", $3); + cf_error(ctx, "Invalid max prefix length %u", $3); }; net_roa6_: net_ip6_ MAX NUM AS NUM @@ -249,7 +265,7 @@ net_roa6_: net_ip6_ MAX NUM AS NUM $$ = cfg_alloc(sizeof(net_addr_roa6)); net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5); if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH) - cf_error("Invalid max prefix length %u", $3); + cf_error(ctx, "Invalid max prefix length %u", $3); }; net_mpls_: MPLS NUM @@ -278,7 +294,7 @@ net_ip6: net_ip6_ | SYM { if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6)) - cf_error("IPv6 network expected"); + cf_error(ctx, "IPv6 network expected"); $$ = * SYM_VAL($1).net; } ; @@ -287,7 +303,7 @@ net_ip: net_ip_ | SYM { if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net)) - cf_error("IP network expected"); + cf_error(ctx, "IP network expected"); $$ = * SYM_VAL($1).net; } ; @@ -296,7 +312,7 @@ net_any: net_ | SYM { if ($1->class != (SYM_CONSTANT | T_NET)) - cf_error("Network expected"); + cf_error(ctx, "Network expected"); $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */ } ; @@ -312,7 +328,7 @@ net_or_ipa: else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net)) $$ = * SYM_VAL($1).net; else - cf_error("IP address or network expected"); + cf_error(ctx, "IP address or network expected"); } ; @@ -327,7 +343,7 @@ label_stack: label_stack_start | label_stack '/' NUM { if ($1->len >= MPLS_MAX_LABEL_STACK) - cf_error("Too many labels in stack"); + cf_error(ctx, "Too many labels in stack"); $1->stack[$1->len++] = $3; $$ = $1; } @@ -337,14 +353,14 @@ time: TEXT { $$ = tm_parse_time($1); if (!$$) - cf_error("Invalid date/time"); + cf_error(ctx, "Invalid date/time"); } ; text: TEXT | SYM { - if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected"); + if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error(ctx, "String expected"); $$ = SYM_VAL($1).s; } ; diff --git a/conf/flowspec.Y b/conf/flowspec.Y index 4d259763..700ac38c 100644 --- a/conf/flowspec.Y +++ b/conf/flowspec.Y @@ -14,11 +14,10 @@ CF_HDR #include "lib/flowspec.h" -CF_DEFINES +CF_CTX struct flow_builder *this_flow; - CF_DECLS %type flow_num_op flow_srcdst flow_logic_op flow_num_type_ flow_frag_val flow_neg @@ -61,10 +60,10 @@ flow_num_type_: | DSCP { $$ = FLOW_TYPE_DSCP; } ; -flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); }; -flow_flag_type: TCP FLAGS { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); }; -flow_frag_type: FRAGMENT { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); }; -flow_label_type: LABEL { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); }; +flow_num_type: flow_num_type_{ flow_builder_set_type(ctx->this_flow, $1); }; +flow_flag_type: TCP FLAGS { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_TCP_FLAGS); }; +flow_frag_type: FRAGMENT { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_FRAGMENT); }; +flow_label_type: LABEL { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_LABEL); }; flow_srcdst: DST { $$ = FLOW_TYPE_DST_PREFIX; } @@ -73,12 +72,12 @@ flow_srcdst: flow_num_opts: flow_num_op expr { - flow_check_cf_value_length(this_flow, $2); - flow_builder_add_op_val(this_flow, $1, $2); + flow_check_cf_value_length(ctx->this_flow, $2); + flow_builder_add_op_val(ctx->this_flow, $1, $2); } | flow_num_opts flow_logic_op flow_num_op expr { - flow_check_cf_value_length(this_flow, $4); - flow_builder_add_op_val(this_flow, $2 | $3, $4); + flow_check_cf_value_length(ctx->this_flow, $4); + flow_builder_add_op_val(ctx->this_flow, $2 | $3, $4); } | flow_num_opt_ext | flow_num_opts OR flow_num_opt_ext @@ -86,14 +85,14 @@ flow_num_opts: flow_num_opt_ext_expr: expr { - flow_check_cf_value_length(this_flow, $1); - flow_builder_add_op_val(this_flow, FLOW_OP_EQ, $1); + flow_check_cf_value_length(ctx->this_flow, $1); + flow_builder_add_op_val(ctx->this_flow, FLOW_OP_EQ, $1); } | expr DDOT expr { - flow_check_cf_value_length(this_flow, $1); - flow_check_cf_value_length(this_flow, $3); - flow_builder_add_op_val(this_flow, FLOW_OP_GEQ, $1); - flow_builder_add_op_val(this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3); + flow_check_cf_value_length(ctx->this_flow, $1); + flow_check_cf_value_length(ctx->this_flow, $3); + flow_builder_add_op_val(ctx->this_flow, FLOW_OP_GEQ, $1); + flow_builder_add_op_val(ctx->this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3); } ; @@ -104,16 +103,16 @@ flow_num_opt_ext: flow_bmk_opts: flow_neg expr '/' expr { - flow_check_cf_bmk_values(this_flow, $1, $2, $4); - flow_builder_add_val_mask(this_flow, $1, $2, $4); + flow_check_cf_bmk_values(ctx->this_flow, $1, $2, $4); + flow_builder_add_val_mask(ctx->this_flow, $1, $2, $4); } | flow_bmk_opts flow_logic_op flow_neg expr '/' expr { - flow_check_cf_bmk_values(this_flow, $3, $4, $6); - flow_builder_add_val_mask(this_flow, $2 | $3, $4, $6); + flow_check_cf_bmk_values(ctx->this_flow, $3, $4, $6); + flow_builder_add_val_mask(ctx->this_flow, $2 | $3, $4, $6); } | flow_bmk_opts ',' flow_neg expr '/' expr { - flow_check_cf_bmk_values(this_flow, $3, $4, $6); - flow_builder_add_val_mask(this_flow, 0x40 | $3, $4, $6); /* AND */ + flow_check_cf_bmk_values(ctx->this_flow, $3, $4, $6); + flow_builder_add_val_mask(ctx->this_flow, 0x40 | $3, $4, $6); /* AND */ } ; @@ -131,20 +130,20 @@ flow_frag_val: flow_frag_opts: flow_neg flow_frag_val { - flow_builder_add_val_mask(this_flow, 0, ($1 ? 0 : $2), $2); + flow_builder_add_val_mask(ctx->this_flow, 0, ($1 ? 0 : $2), $2); } | flow_frag_opts flow_logic_op flow_neg flow_frag_val { - flow_builder_add_val_mask(this_flow, $2, ($3 ? 0 : $4), $4); + flow_builder_add_val_mask(ctx->this_flow, $2, ($3 ? 0 : $4), $4); } | flow_frag_opts ',' flow_neg flow_frag_val { - flow_builder_add_val_mask(this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */ + flow_builder_add_val_mask(ctx->this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */ } ; flow4_item: flow_srcdst net_ip { - flow_builder_set_type(this_flow, $1); - flow_builder4_add_pfx(this_flow, (net_addr_ip4 *) &($2)); + flow_builder_set_type(ctx->this_flow, $1); + flow_builder4_add_pfx(ctx->this_flow, (net_addr_ip4 *) &($2)); } | flow_num_type flow_num_opts | flow_flag_type flow_bmk_opts @@ -153,14 +152,14 @@ flow4_item: flow6_item: flow_srcdst net_ip6 { - flow_builder_set_type(this_flow, $1); - flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), 0); + flow_builder_set_type(ctx->this_flow, $1); + flow_builder6_add_pfx(ctx->this_flow, (net_addr_ip6 *) &($2), 0); } | flow_srcdst net_ip6 OFFSET NUM { if ($4 > $2.pxlen) - cf_error("Prefix offset is higher than prefix length"); - flow_builder_set_type(this_flow, $1); - flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), $4); + cf_error(ctx, "Prefix offset is higher than prefix length"); + flow_builder_set_type(ctx->this_flow, $1); + flow_builder6_add_pfx(ctx->this_flow, (net_addr_ip6 *) &($2), $4); } | flow_num_type flow_num_opts | flow_flag_type flow_bmk_opts @@ -180,25 +179,25 @@ flow6_opts: flow_builder_init: { - if (this_flow == NULL) - this_flow = flow_builder_init(&root_pool); + if (ctx->this_flow == NULL) + ctx->this_flow = flow_builder_init(ctx); else - flow_builder_clear(this_flow); + flow_builder_clear(ctx->this_flow); }; -flow_builder_set_ipv4: { this_flow->ipv6 = 0; }; -flow_builder_set_ipv6: { this_flow->ipv6 = 1; }; +flow_builder_set_ipv4: { ctx->this_flow->ipv6 = 0; }; +flow_builder_set_ipv6: { ctx->this_flow->ipv6 = 1; }; net_flow4_: FLOW4 '{' flow_builder_init flow_builder_set_ipv4 flow4_opts '}' { - $$ = (net_addr *) flow_builder4_finalize(this_flow, cfg_mem); - flow4_validate_cf((net_addr_flow4 *) $$); + $$ = (net_addr *) flow_builder4_finalize(ctx->this_flow, ctx->cfg_mem); + flow4_validate_cf(ctx->this_flow, (net_addr_flow4 *) $$); }; net_flow6_: FLOW6 '{' flow_builder_init flow_builder_set_ipv6 flow6_opts '}' { - $$ = (net_addr *) flow_builder6_finalize(this_flow, cfg_mem); - flow6_validate_cf((net_addr_flow6 *) $$); + $$ = (net_addr *) flow_builder6_finalize(ctx->this_flow, ctx->cfg_mem); + flow6_validate_cf(ctx->this_flow, (net_addr_flow6 *) $$); }; net_flow_: net_flow4_ | net_flow6_ ; diff --git a/conf/gen_context.m4 b/conf/gen_context.m4 new file mode 100644 index 00000000..79640cc3 --- /dev/null +++ b/conf/gen_context.m4 @@ -0,0 +1,33 @@ +m4_divert(-1)m4_dnl +# +# BIRD -- Generator of Configuration Context +# +# (c) 2018 Maria Matejka +# +# Can be freely distributed and used under the terms of the GNU GPL. +# + +# Common aliases +m4_define(DNL, `m4_dnl') + +# Diversions used: +# 2 context + +# We include all the headers +m4_define(CF_HDR, `m4_divert(0)') +m4_define(CF_CTX, `m4_divert(2)') +m4_define(CF_DECLS, `m4_divert(-1)') +m4_define(CF_DEFINES, `m4_divert(-1)') + +# After all configuration templates end, we generate the +m4_m4wrap(` +m4_divert(0) +struct cf_context { +m4_undivert(2) +}; +') + +# As we are processing C source, we must access all M4 primitives via +# m4_* and also set different quoting convention: `[[' and ']]' +m4_changequote([[,]]) + diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index cf3fb58e..0598e5cd 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -12,6 +12,7 @@ m4_define(DNL, `m4_dnl') # Diversions used: # 1 keywords +# 2 context # Simple iterator m4_define(CF_itera, `m4_ifelse($#, 1, [[CF_iter($1)]], [[CF_iter($1)[[]]CF_itera(m4_shift($@))]])') @@ -19,6 +20,7 @@ m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)') # We include all the headers m4_define(CF_HDR, `m4_divert(0)') +m4_define(CF_CTX, `m4_divert(2)') m4_define(CF_DECLS, `m4_divert(-1)') m4_define(CF_DEFINES, `m4_divert(-1)') diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4 index af43d96f..7625ce25 100644 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@ -9,9 +9,12 @@ m4_divert(-1)m4_dnl # Diversions used: # 1 includes -# 2 types etc. -# 3 rules -# 4 C code +# 2 context structure +# 3 inline C code and macros +# 4 parser declarations +# 5 grammar rules +# 6 C code + # Common aliases m4_define(DNL, `m4_dnl') @@ -19,10 +22,11 @@ m4_define(DNL, `m4_dnl') # Define macros for defining sections m4_define(CF_ZONE, `m4_divert($1)/* $2 from m4___file__ */') m4_define(CF_HDR, `CF_ZONE(1, Headers)') -m4_define(CF_DEFINES, `CF_ZONE(1, Defines)') -m4_define(CF_DECLS, `CF_ZONE(2, Declarations)') -m4_define(CF_GRAMMAR, `CF_ZONE(3, Grammar)') -m4_define(CF_CODE, `CF_ZONE(4, C Code)') +m4_define(CF_CTX, `CF_ZONE(2, Context)') +m4_define(CF_DEFINES, `CF_ZONE(3, Defines)') +m4_define(CF_DECLS, `CF_ZONE(4, Bison Declarations)') +m4_define(CF_GRAMMAR, `CF_ZONE(5, Grammar)') +m4_define(CF_CODE, `CF_ZONE(6, C Code)') m4_define(CF_END, `m4_divert(-1)') # Simple iterator @@ -36,8 +40,8 @@ m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@ # CLI commands m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL -m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) -m4_divert(3)cli_cmd: CF_cmd +m4_divert(4)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) +m4_divert(5)cli_cmd: CF_cmd CF_cmd: $1 $2 END') m4_define(CF_CLI_CMD, `') m4_define(CF_CLI_HELP, `') @@ -50,15 +54,17 @@ m4_m4wrap(` m4_divert(0)DNL %{ m4_undivert(1)DNL + +m4_undivert(3)DNL %} -m4_undivert(2)DNL - -%% -m4_undivert(3)DNL - -%% m4_undivert(4)DNL + +%% +m4_undivert(5)DNL + +%% +m4_undivert(6)DNL ') # As we are processing C source, we must access all M4 primitives via diff --git a/conf/parser.h b/conf/parser.h new file mode 100644 index 00000000..36cd2349 --- /dev/null +++ b/conf/parser.h @@ -0,0 +1,61 @@ +/* + * BIRD Internet Routing Daemon -- Configuration Parser Headers + * + * (c) 2018 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_CONF_PARSER_H_ +#define _BIRD_CONF_PARSER_H_ + +#include "conf/context.h" + +/* Pools */ + +#define cfg_alloc(size) lp_alloc(ctx->cfg_mem, size) +#define cfg_allocu(size) lp_allocu(ctx->cfg_mem, size) +#define cfg_allocz(size) lp_allocz(ctx->cfg_mem, size) +#define cfg_strdup(str) cf_strdup(ctx, str) +#define cfg_copy_list(dest, src, node_size) cf_copy_list(ctx, dest, src, node_size) + +/* Lexer */ + +/* Generated lexer entry point */ +typedef void * yyscan_t; +union YYSTYPE; +int cfx_lex(union YYSTYPE *, yyscan_t); + +/* Config context alloc and free */ +struct cf_context *cf_new_context(int, struct conf_order *); +void cf_free_context(struct cf_context *); + +/* Lexer state alloc and free */ +struct conf_state *cf_new_state(struct cf_context *ctx, const char *name); +void cf_free_state(struct cf_context *ctx, struct conf_state *cs); + +/* Init keyword hash is called once from global init */ +void cf_init_kh(void); + +/* Hash function is common for keywords and symbols */ +uint cf_hash(byte *c); + + +/* Parser */ + +extern char *cf_text; +int cfx_parse(struct cf_context *ctx, void *yyscanner); + +/* Generated error callback */ +#define cfx_error(ctx, yyscanner, ...) cf_error(ctx, __VA_ARGS__) + +/* Symbols */ + +void cf_push_scope(struct cf_context *, struct symbol *); +void cf_pop_scope(struct cf_context *); + +struct symbol *cf_get_symbol(struct cf_context *ctx, byte *c); +struct symbol *cf_default_name(struct cf_context *ctx, char *template, int *counter); +struct symbol *cf_define_symbol(struct cf_context *ctx, struct symbol *symbol, int type, void *def); + +#endif diff --git a/conf/symbols.c b/conf/symbols.c new file mode 100644 index 00000000..ca66573c --- /dev/null +++ b/conf/symbols.c @@ -0,0 +1,208 @@ +/* + * BIRD Internet Routing Daemon -- Symbol Handling + * + * (c) 1998--2000 Martin Mares + * (c) 2018 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "conf/conf.h" +#include "conf/parser.h" +#include "lib/hash.h" + +/** + * cf_push_scope - enter new scope + * @sym: symbol representing scope name + * + * If we want to enter a new scope to process declarations inside + * a nested block, we can just call cf_push_scope() to push a new + * scope onto the scope stack which will cause all new symbols to be + * defined in this scope and all existing symbols to be sought for + * in all scopes stored on the stack. + */ +void +cf_push_scope(struct cf_context *ctx, struct symbol *sym) +{ + struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope)); + + s->next = ctx->sym_scope; + ctx->sym_scope = s; + s->active = 1; + s->name = sym; +} + +/** + * cf_pop_scope - leave a scope + * + * cf_pop_scope() pops the topmost scope from the scope stack, + * leaving all its symbols in the symbol table, but making them + * invisible to the rest of the config. + */ +void +cf_pop_scope(struct cf_context *ctx) +{ + ctx->sym_scope->active = 0; + ctx->sym_scope = ctx->sym_scope->next; + ASSERT(ctx->sym_scope); +} + +/** + * cf_symbol_class_name - get name of a symbol class + * @sym: symbol + * + * This function returns a string representing the class + * of the given symbol. + */ +char * +cf_symbol_class_name(struct symbol *sym) +{ + if (cf_symbol_is_constant(sym)) + return "constant"; + + switch (sym->class) + { + case SYM_VOID: + return "undefined"; + case SYM_PROTO: + return "protocol"; + case SYM_TEMPLATE: + return "protocol template"; + case SYM_FUNCTION: + return "function"; + case SYM_FILTER: + return "filter"; + case SYM_TABLE: + return "routing table"; + default: + return "unknown type"; + } +} + +#define SYM_KEY(n) n->name, n->scope->active +#define SYM_NEXT(n) n->next +#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2 +#define SYM_FN(k,s) cf_hash(k) +#define SYM_ORDER 6 /* Initial */ + +#define SYM_REHASH sym_rehash +#define SYM_PARAMS /8, *1, 2, 2, 6, 20 + +HASH_DEFINE_REHASH_FN(SYM, struct symbol) + + +static struct symbol * +cf_new_symbol(struct cf_context *ctx, byte *c) +{ + struct symbol *s; + + uint l = strlen(c); + if (l > SYM_MAX_LEN) + cf_error(ctx, "Symbol too long"); + + s = cfg_alloc(sizeof(struct symbol) + l); + s->scope = ctx->sym_scope; + s->class = SYM_VOID; + s->def = NULL; + s->aux = 0; + strcpy(s->name, c); + + if (!ctx->new_config->sym_hash.data) + HASH_INIT(ctx->new_config->sym_hash, ctx->new_config->pool, SYM_ORDER); + + HASH_INSERT2(ctx->new_config->sym_hash, SYM, ctx->new_config->pool, s); + + return s; +} + +/** + * cf_find_symbol - find a symbol by name + * @cfg: specificed config + * @c: symbol name + * + * This functions searches the symbol table in the config @cfg for a symbol of + * given name. First it examines the current scope, then the second recent one + * and so on until it either finds the symbol and returns a pointer to its + * &symbol structure or reaches the end of the scope chain and returns %NULL to + * signify no match. + */ +struct symbol * +cf_find_symbol(struct config *cfg, byte *c) +{ + struct symbol *s; + + if (cfg->sym_hash.data && + (s = HASH_FIND(cfg->sym_hash, SYM, c, 1))) + return s; + + if (cfg->fallback && + cfg->fallback->sym_hash.data && + (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1))) + return s; + + return NULL; +} + +/** + * cf_get_symbol - get a symbol by name + * @c: symbol name + * + * This functions searches the symbol table of the currently parsed config + * (@new_config) for a symbol of given name. It returns either the already + * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no + * existing symbol is found. + */ +struct symbol * +cf_get_symbol(struct cf_context *ctx, byte *c) +{ + return cf_find_symbol(ctx->new_config, c) ?: cf_new_symbol(ctx, c); +} + +struct symbol * +cf_default_name(struct cf_context *ctx, char *template, int *counter) +{ + char buf[SYM_MAX_LEN]; + struct symbol *s; + char *perc = strchr(template, '%'); + + for(;;) + { + bsprintf(buf, template, ++(*counter)); + s = cf_get_symbol(ctx, buf); + if (s->class == SYM_VOID) + return s; + if (!perc) + break; + } + cf_error(ctx, "Unable to generate default name"); +} + +/** + * cf_define_symbol - define meaning of a symbol + * @sym: symbol to be defined + * @type: symbol class to assign + * @def: class dependent data + * + * Defines new meaning of a symbol. If the symbol is an undefined + * one (%SYM_VOID), it's just re-defined to the new type. If it's defined + * in different scope, a new symbol in current scope is created and the + * meaning is assigned to it. If it's already defined in the current scope, + * an error is reported via YY_FATAL_ERROR(). + * + * Result: Pointer to the newly defined symbol. If we are in the top-level + * scope, it's the same @sym as passed to the function. + */ +struct symbol * +cf_define_symbol(struct cf_context *ctx, struct symbol *sym, int type, void *def) +{ + if (sym->class) + { + if (sym->scope == ctx->sym_scope) + cf_error(ctx, "Symbol already defined"); + sym = cf_new_symbol(ctx, sym->name); + } + sym->class = type; + sym->def = def; + return sym; +} diff --git a/filter/config.Y b/filter/config.Y index bbb8a640..59ba42f9 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -2,6 +2,7 @@ * BIRD - filters * * Copyright 1998--2000 Pavel Machek + * 2018 Maria Matejka * * Can be freely distributed and used under the terms of the GNU GPL. * @@ -10,6 +11,8 @@ CF_HDR +#include "filter/f-util.h" + CF_DEFINES static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } @@ -43,9 +46,9 @@ f_valid_set_type(int type) } static inline struct f_tree * -f_new_item(struct f_val from, struct f_val to) +f_new_item(struct cf_context *ctx, struct f_val from, struct f_val to) { - struct f_tree *t = f_new_tree(); + struct f_tree *t = f_new_tree(ctx); t->right = t; t->from = from; t->to = to; @@ -63,17 +66,17 @@ f_merge_items(struct f_tree *a, struct f_tree *b) } static inline struct f_tree * -f_new_pair_item(int fa, int ta, int fb, int tb) +f_new_pair_item(struct cf_context *ctx, int fa, int ta, int fb, int tb) { - check_u16(fa); - check_u16(ta); - check_u16(fb); - check_u16(tb); + check_u16(ctx, fa); + check_u16(ctx, ta); + check_u16(ctx, fb); + check_u16(ctx, tb); if ((ta < fa) || (tb < fb)) - cf_error( "From value cannot be higher that To value in pair sets"); + cf_error(ctx, "From value cannot be higher that To value in pair sets"); - struct f_tree *t = f_new_tree(); + struct f_tree *t = f_new_tree(ctx); t->right = t; t->from.type = t->to.type = T_PAIR; t->from.val.i = pair(fa, fb); @@ -82,21 +85,21 @@ f_new_pair_item(int fa, int ta, int fb, int tb) } static inline struct f_tree * -f_new_pair_set(int fa, int ta, int fb, int tb) +f_new_pair_set(struct cf_context *ctx, int fa, int ta, int fb, int tb) { - check_u16(fa); - check_u16(ta); - check_u16(fb); - check_u16(tb); + check_u16(ctx, fa); + check_u16(ctx, ta); + check_u16(ctx, fb); + check_u16(ctx, tb); if ((ta < fa) || (tb < fb)) - cf_error( "From value cannot be higher that To value in pair sets"); + cf_error(ctx, "From value cannot be higher that To value in pair sets"); struct f_tree *lst = NULL; int i; for (i = fa; i <= ta; i++) - lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb)); + lst = f_merge_items(lst, f_new_pair_item(ctx, i, i, fb, tb)); return lst; } @@ -106,16 +109,16 @@ f_new_pair_set(int fa, int ta, int fb, int tb) #define LC_ALL 0xFFFFFFFF static struct f_tree * -f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) +f_new_ec_item(struct cf_context *ctx, u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) { u64 fm, to; if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) { - check_u16(vf); + check_u16(ctx, vf); if (vt == EC_ALL) vt = 0xFFFF; else - check_u16(vt); + check_u16(ctx, vt); } if (kind == EC_GENERIC) { @@ -135,7 +138,7 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) to = ec_as4(kind, key, vt); } - struct f_tree *t = f_new_tree(); + struct f_tree *t = f_new_tree(ctx); t->right = t; t->from.type = t->to.type = T_EC; t->from.val.ec = fm; @@ -144,9 +147,9 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) } static struct f_tree * -f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) +f_new_lc_item(struct cf_context *ctx, u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) { - struct f_tree *t = f_new_tree(); + struct f_tree *t = f_new_tree(ctx); t->right = t; t->from.type = t->to.type = T_LC; t->from.val.lc = (lcomm) {f1, f2, f3}; @@ -155,9 +158,9 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) } static inline struct f_inst * -f_generate_empty(struct f_dynamic_attr dyn) +f_generate_empty(struct cf_context *ctx, struct f_dynamic_attr dyn) { - struct f_inst *e = f_new_inst(FI_EMPTY); + struct f_inst *e = f_new_inst(ctx, FI_EMPTY); switch (dyn.type & EAF_TYPE_MASK) { case EAF_TYPE_AS_PATH: @@ -173,33 +176,33 @@ f_generate_empty(struct f_dynamic_attr dyn) e->aux = T_LCLIST; break; default: - cf_error("Can't empty that attribute"); + cf_error(ctx, "Can't empty that attribute"); } - struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn); + struct f_inst *s = f_new_inst_da(ctx, FI_EA_SET, dyn); s->a1.p = e; return s; } static inline struct f_inst * -f_generate_dpair(struct f_inst *t1, struct f_inst *t2) +f_generate_dpair(struct cf_context *ctx, struct f_inst *t1, struct f_inst *t2) { struct f_inst *rv; if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) { if ((t1->aux != T_INT) || (t2->aux != T_INT)) - cf_error( "Can't operate with value of non-integer type in pair constructor"); + cf_error(ctx, "Can't operate with value of non-integer type in pair constructor"); - check_u16(t1->a2.i); - check_u16(t2->a2.i); + check_u16(ctx, t1->a2.i); + check_u16(ctx, t2->a2.i); - rv = f_new_inst(FI_CONSTANT); + rv = f_new_inst(ctx, FI_CONSTANT); rv->aux = T_PAIR; rv->a2.i = pair(t1->a2.i, t2->a2.i); } else { - rv = f_new_inst(FI_PAIR_CONSTRUCT); + rv = f_new_inst(ctx, FI_PAIR_CONSTRUCT); rv->a1.p = t1; rv->a2.p = t2; } @@ -208,7 +211,7 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2) } static inline struct f_inst * -f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) +f_generate_ec(struct cf_context *ctx, u16 kind, struct f_inst *tk, struct f_inst *tv) { struct f_inst *rv; int c1 = 0, c2 = 0, ipv4_used = 0; @@ -224,7 +227,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) ipv4_used = 1; key = tk->a2.i; } else - cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); + cf_error(ctx, "Can't operate with key of non-integer/IPv4 type in EC constructor"); } /* IP->Quad implicit conversion */ @@ -242,12 +245,12 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) ipv4_used = 1; key = ipa_to_u32(val->val.ip); } else - cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); + cf_error(ctx, "Can't operate with key of non-integer/IPv4 type in EC constructor"); } if (tv->fi_code == FI_CONSTANT) { if (tv->aux != T_INT) - cf_error("Can't operate with value of non-integer type in EC constructor"); + cf_error(ctx, "Can't operate with value of non-integer type in EC constructor"); c2 = 1; val2 = tv->a2.i; } @@ -259,25 +262,25 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) ec = ec_generic(key, val2); } else if (ipv4_used) { - check_u16(val2); + check_u16(ctx, val2); ec = ec_ip4(kind, key, val2); } else if (key < 0x10000) { ec = ec_as2(kind, key, val2); } else { - check_u16(val2); + check_u16(ctx, val2); ec = ec_as4(kind, key, val2); } NEW_F_VAL; - rv = f_new_inst(FI_CONSTANT_INDIRECT); + rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT); rv->a1.p = val; val->type = T_EC; val->val.ec = ec; } else { - rv = f_new_inst(FI_EC_CONSTRUCT); + rv = f_new_inst(ctx, FI_EC_CONSTRUCT); rv->aux = kind; rv->a1.p = tk; rv->a2.p = tv; @@ -287,15 +290,15 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) } static inline struct f_inst * -f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) +f_generate_lc(struct cf_context *ctx, struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) { struct f_inst *rv; if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) { if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) - cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); + cf_error(ctx, "LC - Can't operate with value of non-integer type in tuple constructor"); - rv = f_new_inst(FI_CONSTANT_INDIRECT); + rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT); NEW_F_VAL; rv->a1.p = val; @@ -304,7 +307,7 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) } else { - rv = f_new_inst(FI_LC_CONSTRUCT); + rv = f_new_inst(ctx, FI_LC_CONSTRUCT); rv->a1.p = t1; rv->a2.p = t2; rv->a3.p = t3; @@ -314,11 +317,11 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) } static inline struct f_inst * -f_generate_path_mask(struct f_path_mask *t) +f_generate_path_mask(struct cf_context *ctx, struct f_path_mask *t) { for (struct f_path_mask *tt = t; tt; tt = tt->next) { if (tt->kind == PM_ASN_EXPR) { - struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT); + struct f_inst *mrv = f_new_inst(ctx, FI_PATHMASK_CONSTRUCT); mrv->a1.p = t; return mrv; } @@ -328,7 +331,7 @@ f_generate_path_mask(struct f_path_mask *t) val->type = T_PATH_MASK; val->val.path_mask = t; - struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT); + struct f_inst *rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT); rv->a1.p = val; return rv; @@ -340,7 +343,7 @@ f_generate_path_mask(struct f_path_mask *t) * and return a copy of string */ char * -assert_copy_expr(const char *start, size_t len) +assert_copy_expr(struct cf_context *ctx, const char *start, size_t len) { /* XXX: Allocates maybe a little more memory than we really finally need */ char *str = cfg_alloc(len + 1); @@ -380,15 +383,15 @@ assert_copy_expr(const char *start, size_t len) * @end: pointer to the last char of test expression */ static struct f_inst * -assert_done(struct f_inst *expr, const char *start, const char *end) +assert_done(struct cf_context *ctx, struct f_inst *expr, const char *start, const char *end) { struct f_inst *i; - i = f_new_inst(FI_ASSERT); + i = f_new_inst(ctx, FI_ASSERT); i->a1.p = expr; if (end >= start) { - i->a2.p = assert_copy_expr(start, end - start + 1); + i->a2.p = assert_copy_expr(ctx, start, end - start + 1); } else { @@ -440,32 +443,32 @@ CF_GRAMMAR conf: filter_def ; filter_def: - FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } + FILTER SYM { $2 = cf_define_symbol(ctx, $2, SYM_FILTER, NULL); cf_push_scope(ctx, $2); } filter_body { $2->def = $4; $4->name = $2->name; DBG( "We have new filter defined (%s)\n", $2->name ); - cf_pop_scope(); + cf_pop_scope(ctx); } ; conf: filter_eval ; filter_eval: - EVAL term { f_eval_int($2); } + EVAL term { f_eval_int($2, ctx); } ; conf: bt_test_suite ; bt_test_suite: BT_TEST_SUITE '(' SYM ',' text ')' { if (!($3->class & SYM_FUNCTION)) - cf_error("Function expected"); + cf_error(ctx, "Function expected"); struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite)); t->fn = $3->def; t->fn_name = $3->name; t->dsc = $5; - add_tail(&new_config->tests, &t->n); + add_tail(&ctx->new_config->tests, &t->n); } ; @@ -501,7 +504,7 @@ type: break; default: - cf_error( "You can't create sets of this type." ); + cf_error(ctx, "You can't create sets of this type." ); } } ; @@ -510,7 +513,7 @@ one_decl: type SYM { struct f_val * val = cfg_alloc(sizeof(struct f_val)); val->type = T_VOID; - $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); + $2 = cf_define_symbol(ctx, $2, SYM_VARIABLE | $1, val); DBG( "New variable %s type %x\n", $2->name, $1 ); $2->aux2 = NULL; $$=$2; @@ -544,7 +547,7 @@ filter_body: filter: SYM { - if ($1->class != SYM_FILTER) cf_error("No such filter."); + if ($1->class != SYM_FILTER) cf_error(ctx, "No such filter."); $$ = $1->def; } | filter_body @@ -555,13 +558,13 @@ where_filter: /* Construct 'IF term THEN ACCEPT; REJECT;' */ struct filter *f = cfg_alloc(sizeof(struct filter)); struct f_inst *i, *acc, *rej; - acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */ + acc = f_new_inst(ctx, FI_PRINT_AND_DIE); /* ACCEPT */ acc->a1.p = NULL; acc->a2.i = F_ACCEPT; - rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */ + rej = f_new_inst(ctx, FI_PRINT_AND_DIE); /* REJECT */ rej->a1.p = NULL; rej->a2.i = F_REJECT; - i = f_new_inst(FI_CONDITION); /* IF */ + i = f_new_inst(ctx, FI_CONDITION); /* IF */ i->a1.p = $2; i->a2.p = acc; i->next = rej; @@ -580,7 +583,7 @@ function_body: decls '{' cmds '}' { if ($1) { /* Prepend instruction to clear local variables */ - $$ = f_new_inst(FI_CLEAR_LOCAL_VARS); + $$ = f_new_inst(ctx, FI_CLEAR_LOCAL_VARS); $$->a1.p = $1; $$->next = $3; } else @@ -591,13 +594,13 @@ function_body: conf: function_def ; function_def: FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); - $2 = cf_define_symbol($2, SYM_FUNCTION, NULL); - cf_push_scope($2); + $2 = cf_define_symbol(ctx, $2, SYM_FUNCTION, NULL); + cf_push_scope(ctx, $2); } function_params function_body { $2->def = $5; $2->aux2 = $4; DBG("Hmm, we've got one function here - %s\n", $2->name); - cf_pop_scope(); + cf_pop_scope(ctx); } ; @@ -645,38 +648,38 @@ set_atom: | fipa { $$ = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - $$ = f_eval($2, cfg_mem); - if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); + $$ = f_eval($2, ctx->cfg_mem); + if (!f_valid_set_type($$.type)) cf_error(ctx, "Set-incompatible type"); } | SYM { - if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name); - if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); + if (!cf_symbol_is_constant($1)) cf_error(ctx, "%s: constant expected", $1->name); + if (!f_valid_set_type(SYM_TYPE($1))) cf_error(ctx, "%s: set-incompatible type", $1->name); $$ = *(struct f_val *)($1->def); } ; switch_atom: NUM { $$.type = T_INT; $$.val.i = $1; } - | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); } + | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2, ctx); } | fipa { $$ = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } ; cnum: - term { $$ = f_eval_int($1); } + term { $$ = f_eval_int($1, ctx); } pair_item: - '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } - | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); } - | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); } - | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); } - | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); } - | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); } - | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); } - | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); } - | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); } + '(' cnum ',' cnum ')' { $$ = f_new_pair_item(ctx, $2, $2, $4, $4); } + | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item(ctx, $2, $2, $4, $6); } + | '(' cnum ',' '*' ')' { $$ = f_new_pair_item(ctx, $2, $2, 0, CC_ALL); } + | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set(ctx, $2, $4, $6, $6); } + | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(ctx, $2, $4, $6, $8); } + | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item(ctx, $2, $4, 0, CC_ALL); } + | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(ctx, 0, CC_ALL, $4, $4); } + | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(ctx, 0, CC_ALL, $4, $6); } + | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(ctx, 0, CC_ALL, 0, CC_ALL); } | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')' - { $$ = f_new_pair_item($2, $8, $4, $10); } + { $$ = f_new_pair_item(ctx, $2, $8, $4, $10); } ; ec_kind: @@ -687,37 +690,37 @@ ec_kind: ; ec_item: - '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } - | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } - | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } + '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, $6, $6); } + | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, $6, $8); } + | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, 0, EC_ALL); } ; lc_item: - '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); } - | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); } - | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); } - | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); } - | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); } - | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); } - | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); } + '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, $6, $6); } + | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, $6, $8); } + | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, 0, LC_ALL); } + | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $6, 0, LC_ALL); } + | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, 0, LC_ALL, 0, LC_ALL); } + | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $4, 0, LC_ALL, 0, LC_ALL); } + | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, 0, LC_ALL, 0, LC_ALL, 0, LC_ALL); } | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')' - { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } + { $$ = f_new_lc_item(ctx, $2, $10, $4, $12, $6, $14); } ; set_item: pair_item | ec_item | lc_item - | set_atom { $$ = f_new_item($1, $1); } - | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } + | set_atom { $$ = f_new_item(ctx, $1, $1); } + | set_atom DDOT set_atom { $$ = f_new_item(ctx, $1, $3); } ; switch_item: pair_item | ec_item | lc_item - | switch_atom { $$ = f_new_item($1, $1); } - | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } + | switch_atom { $$ = f_new_item(ctx, $1, $1); } + | switch_atom DDOT switch_atom { $$ = f_new_item(ctx, $1, $3); } ; set_items: @@ -737,12 +740,12 @@ fprefix: | net_ip_ '{' NUM ',' NUM '}' { $$.net = $1; $$.lo = $3; $$.hi = $5; if (($3 > $5) || ($5 > net_max_prefix_length[$1.type])) - cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5); + cf_error(ctx, "Invalid prefix pattern range: {%u, %u}", $3, $5); } ; fprefix_set: - fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); } + fprefix { $$ = f_new_trie(ctx->cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); } | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); } ; @@ -755,7 +758,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } $$ = f_merge_items($1, $2); } | switch_body ELSECOL cmds { - struct f_tree *t = f_new_tree(); + struct f_tree *t = f_new_tree(ctx); t->from.type = t->to.type = T_VOID; t->right = t; t->data = $3; @@ -763,7 +766,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } } ; -/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */ +/* CONST '(' expr ')' { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */ bgp_path_expr: symbol { $$ = $1; } @@ -784,23 +787,23 @@ bgp_path_tail: ; constant: - NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; } - | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; } - | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; } - | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; } - | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; } - | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } - | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; } - | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } - | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; } - | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } + NUM { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; } + | TRUE { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; } + | FALSE { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; } + | TEXT { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; } + | fipa { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; } + | VPN_RD { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } + | net_ { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; } + | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } + | '[' fprefix_set ']' { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; } + | ENUM { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } ; constructor: - '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } - | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } - | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } - | bgp_path { $$ = f_generate_path_mask($1); } + '(' term ',' term ')' { $$ = f_generate_dpair(ctx, $2, $4); } + | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec(ctx, $2, $4, $6); } + | '(' term ',' term ',' term ')' { $$ = f_generate_lc(ctx, $2, $4, $6); } + | bgp_path { $$ = f_generate_path_mask(ctx, $1); } ; @@ -812,15 +815,15 @@ function_call: struct symbol *sym; struct f_inst *inst = $3; if ($1->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); + cf_error(ctx, "You can't call something which is not a function. Really."); DBG("You are calling function %s\n", $1->name); - $$ = f_new_inst(FI_CALL); + $$ = f_new_inst(ctx, FI_CALL); $$->a1.p = inst; $$->a2.p = $1->def; sym = $1->aux2; while (sym || inst) { if (!sym || !inst) - cf_error("Wrong number of arguments for function %s.", $1->name); + cf_error(ctx, "Wrong number of arguments for function %s.", $1->name); DBG( "You should pass parameter called %s\n", sym->name); inst->a1.p = sym; sym = sym->aux2; @@ -832,9 +835,9 @@ function_call: symbol: SYM { switch ($1->class & 0xff00) { - case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break; - case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break; - default: cf_error("%s: variable expected.", $1->name); + case SYM_CONSTANT: $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); break; + case SYM_VARIABLE: $$ = f_new_inst(ctx, FI_VARIABLE); break; + default: cf_error(ctx, "%s: variable expected.", $1->name); } $$->a1.p = $1->def; @@ -855,45 +858,45 @@ static_attr: term: '(' term ')' { $$ = $2; } - | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; } - | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; } - | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; } - | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; } - | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; } - | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; } - | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; } - | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; } - | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; } - | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; } - | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; } - | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; } - | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; } - | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; } - | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; } - | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; } + | term '+' term { $$ = f_new_inst(ctx, FI_ADD); $$->a1.p = $1; $$->a2.p = $3; } + | term '-' term { $$ = f_new_inst(ctx, FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; } + | term '*' term { $$ = f_new_inst(ctx, FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; } + | term '/' term { $$ = f_new_inst(ctx, FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; } + | term AND term { $$ = f_new_inst(ctx, FI_AND); $$->a1.p = $1; $$->a2.p = $3; } + | term OR term { $$ = f_new_inst(ctx, FI_OR); $$->a1.p = $1; $$->a2.p = $3; } + | term '=' term { $$ = f_new_inst(ctx, FI_EQ); $$->a1.p = $1; $$->a2.p = $3; } + | term NEQ term { $$ = f_new_inst(ctx, FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; } + | term '<' term { $$ = f_new_inst(ctx, FI_LT); $$->a1.p = $1; $$->a2.p = $3; } + | term LEQ term { $$ = f_new_inst(ctx, FI_LTE); $$->a1.p = $1; $$->a2.p = $3; } + | term '>' term { $$ = f_new_inst(ctx, FI_LT); $$->a1.p = $3; $$->a2.p = $1; } + | term GEQ term { $$ = f_new_inst(ctx, FI_LTE); $$->a1.p = $3; $$->a2.p = $1; } + | term '~' term { $$ = f_new_inst(ctx, FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; } + | term NMA term { $$ = f_new_inst(ctx, FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; } + | '!' term { $$ = f_new_inst(ctx, FI_NOT); $$->a1.p = $2; } + | DEFINED '(' term ')' { $$ = f_new_inst(ctx, FI_DEFINED); $$->a1.p = $3; } | symbol { $$ = $1; } | constant { $$ = $1; } | constructor { $$ = $1; } - | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); } + | PREFERENCE { $$ = f_new_inst(ctx, FI_PREF_GET); } - | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); } + | rtadot static_attr { $$ = f_new_inst_sa(ctx, FI_RTA_GET, $2); } - | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); } + | rtadot dynamic_attr { $$ = f_new_inst_da(ctx, FI_EA_GET, $2); } - | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; } - | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; } - | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; } - | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; } - | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; } - | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; } - | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; } - | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a1.p = $1; } - | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; } - | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; } - | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; } - | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; } + | term '.' IS_V4 { $$ = f_new_inst(ctx, FI_IS_V4); $$->a1.p = $1; } + | term '.' TYPE { $$ = f_new_inst(ctx, FI_TYPE); $$->a1.p = $1; } + | term '.' IP { $$ = f_new_inst(ctx, FI_IP); $$->a1.p = $1; $$->aux = T_IP; } + | term '.' RD { $$ = f_new_inst(ctx, FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; } + | term '.' LEN { $$ = f_new_inst(ctx, FI_LENGTH); $$->a1.p = $1; } + | term '.' MAXLEN { $$ = f_new_inst(ctx, FI_ROA_MAXLEN); $$->a1.p = $1; } + | term '.' ASN { $$ = f_new_inst(ctx, FI_ROA_ASN); $$->a1.p = $1; } + | term '.' SRC { $$ = f_new_inst(ctx, FI_SADR_SRC); $$->a1.p = $1; } + | term '.' MASK '(' term ')' { $$ = f_new_inst(ctx, FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; } + | term '.' FIRST { $$ = f_new_inst(ctx, FI_AS_PATH_FIRST); $$->a1.p = $1; } + | term '.' LAST { $$ = f_new_inst(ctx, FI_AS_PATH_LAST); $$->a1.p = $1; } + | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(ctx, FI_AS_PATH_LAST_NAG); $$->a1.p = $1; } /* Communities */ /* This causes one shift/reduce conflict @@ -903,19 +906,19 @@ term: | rtadot dynamic_attr '.' RESET{ } */ - | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; } - | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; } - | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; } - | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; } - | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; } - | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } - | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } - | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } + | '+' EMPTY '+' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_PATH; } + | '-' EMPTY '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_CLIST; } + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_ECLIST; } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_LCLIST; } + | PREPEND '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; } + | ADD '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } + | DELETE '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } + | FILTER '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } - | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } - | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } + | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check(ctx, $3, NULL, NULL); } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check(ctx, $3, $5, $7); } - | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; } + | FORMAT '(' term ')' { $$ = f_new_inst(ctx, FI_FORMAT); $$->a1.p = $3; } /* | term '.' LEN { $$->code = P('P','l'); } */ @@ -924,15 +927,15 @@ term: struct symbol *sym; struct f_inst *inst = $3; if ($1->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); + cf_error(ctx, "You can't call something which is not a function. Really."); DBG("You are calling function %s\n", $1->name); - $$ = f_new_inst(FI_CALL); + $$ = f_new_inst(ctx, FI_CALL); $$->a1.p = inst; $$->a2.p = $1->def; sym = $1->aux2; while (sym || inst) { if (!sym || !inst) - cf_error("Wrong number of arguments for function %s.", $1->name); + cf_error(ctx, "Wrong number of arguments for function %s.", $1->name); DBG( "You should pass parameter called %s\n", sym->name); inst->a1.p = sym; sym = sym->aux2; @@ -951,7 +954,7 @@ break_command: ; print_one: - term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; } + term { $$ = f_new_inst(ctx, FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; } ; print_list: /* EMPTY */ { $$ = NULL; } @@ -965,13 +968,13 @@ print_list: /* EMPTY */ { $$ = NULL; } ; var_listn: term { - $$ = f_new_inst(FI_SET); + $$ = f_new_inst(ctx, FI_SET); $$->a1.p = NULL; $$->a2.p = $1; $$->next = NULL; } | term ',' var_listn { - $$ = f_new_inst(FI_SET); + $$ = f_new_inst(ctx, FI_SET); $$->a1.p = NULL; $$->a2.p = $1; $$->next = $3; @@ -984,70 +987,75 @@ var_list: /* EMPTY */ { $$ = NULL; } cmd: IF term THEN block { - $$ = f_new_inst(FI_CONDITION); + $$ = f_new_inst(ctx, FI_CONDITION); $$->a1.p = $2; $$->a2.p = $4; } | IF term THEN block ELSE block { - struct f_inst *i = f_new_inst(FI_CONDITION); + struct f_inst *i = f_new_inst(ctx, FI_CONDITION); i->a1.p = $2; i->a2.p = $4; - $$ = f_new_inst(FI_CONDITION); + $$ = f_new_inst(ctx, FI_CONDITION); $$->a1.p = i; $$->a2.p = $6; } | SYM '=' term ';' { DBG( "Ook, we'll set value\n" ); if (($1->class & ~T_MASK) != SYM_VARIABLE) - cf_error( "You may set only variables." ); - $$ = f_new_inst(FI_SET); + cf_error(ctx, "You may set only variables." ); + $$ = f_new_inst(ctx, FI_SET); $$->a1.p = $1; $$->a2.p = $3; } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); - $$ = f_new_inst(FI_RETURN); + $$ = f_new_inst(ctx, FI_RETURN); $$->a1.p = $2; } | rtadot dynamic_attr '=' term ';' { - $$ = f_new_inst_da(FI_EA_SET, $2); + $$ = f_new_inst_da(ctx, FI_EA_SET, $2); $$->a1.p = $4; } | rtadot static_attr '=' term ';' { - $$ = f_new_inst_sa(FI_RTA_SET, $2); + $$ = f_new_inst_sa(ctx, FI_RTA_SET, $2); if (!$$->a1.i) - cf_error( "This static attribute is read-only."); + cf_error(ctx, "This static attribute is read-only."); $$->a1.p = $4; } | PREFERENCE '=' term ';' { - $$ = f_new_inst(FI_PREF_SET); + $$ = f_new_inst(ctx, FI_PREF_SET); $$->a1.p = $3; } | UNSET '(' rtadot dynamic_attr ')' ';' { - $$ = f_new_inst_da(FI_EA_SET, $4); + $$ = f_new_inst_da(ctx, FI_EA_SET, $4); $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; $$->a1.p = NULL; } - | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; } + | break_command print_list ';' { $$ = f_new_inst(ctx, FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; } | function_call ';' { $$ = $1; } | CASE term '{' switch_body '}' { - $$ = f_new_inst(FI_SWITCH); + $$ = f_new_inst(ctx, FI_SWITCH); $$->a1.p = $2; $$->a2.p = build_tree( $4 ); } - | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } - | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); } - | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); } - | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); } - | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); } - | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } + | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty(ctx, $2); } + | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_PATH_PREPEND, 'x', $2, $6 ); } + | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'a', $2, $6 ); } + | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'd', $2, $6 ); } + | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'f', $2, $6 ); } + ; + +/* +TODO: BT_ASSERT shall be done in completely different way. + | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done(ctx, $4, $3 + 1, $5 - 1); } ; get_cf_position: { $$ = cf_text; }; +*/ CF_END diff --git a/filter/f-util.c b/filter/f-util.c index 6170760b..4b335571 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -9,33 +9,35 @@ #include "nest/bird.h" #include "conf/conf.h" +#include "conf/parser.h" #include "filter/filter.h" +#include "filter/f-util.h" #define P(a,b) ((a<<8) | b) struct f_inst * -f_new_inst(enum f_instruction_code fi_code) +f_new_inst(struct cf_context *ctx, enum f_instruction_code fi_code) { struct f_inst * ret; ret = cfg_allocz(sizeof(struct f_inst)); ret->fi_code = fi_code; - ret->lineno = ifs->lino; + ret->lineno = ctx->order->state->lino; return ret; } struct f_inst * -f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da) +f_new_inst_da(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_dynamic_attr da) { - struct f_inst *ret = f_new_inst(fi_code); + struct f_inst *ret = f_new_inst(ctx, fi_code); ret->aux = (da.f_type << 8) | da.type; ret->a2.i = da.ea_code; return ret; } struct f_inst * -f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa) +f_new_inst_sa(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_static_attr sa) { - struct f_inst *ret = f_new_inst(fi_code); + struct f_inst *ret = f_new_inst(ctx, fi_code); ret->aux = sa.f_type; ret->a2.i = sa.sa_code; ret->a1.i = sa.readonly; @@ -46,11 +48,11 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa) * Generate set_dynamic( operation( get_dynamic(), argument ) ) */ struct f_inst * -f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument) +f_generate_complex(struct cf_context *ctx, int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument) { - struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da), - *oper = f_new_inst(operation), - *get_dyn = f_new_inst_da(FI_EA_GET, da); + struct f_inst *set_dyn = f_new_inst_da(ctx, FI_EA_SET, da), + *oper = f_new_inst(ctx, operation), + *get_dyn = f_new_inst_da(ctx, FI_EA_GET, da); oper->aux = operation_aux; oper->a1.p = get_dyn; @@ -61,17 +63,17 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s } struct f_inst * -f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) +f_generate_roa_check(struct cf_context *ctx, struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) { struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check)); ret->i.fi_code = FI_ROA_CHECK; - ret->i.lineno = ifs->lino; + ret->i.lineno = ctx->order->state->lino; ret->i.arg1 = prefix; ret->i.arg2 = asn; /* prefix == NULL <-> asn == NULL */ if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) - cf_error("%s is not a ROA table", table->name); + cf_error(ctx, "%s is not a ROA table", table->name); ret->rtc = table; return &ret->i; diff --git a/filter/f-util.h b/filter/f-util.h new file mode 100644 index 00000000..8c0f0887 --- /dev/null +++ b/filter/f-util.h @@ -0,0 +1,26 @@ +/* + * BIRD Internet Routing Daemon -- Filters + * + * (c) 1999 Pavel Machek + * (c) 2018 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_FILTER_UTIL_H_ +#define _BIRD_FILTER_UTIL_H_ + +struct f_inst *f_new_inst(struct cf_context *ctx, enum f_instruction_code fi_code); +struct f_inst *f_new_inst_da(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_dynamic_attr da); +struct f_inst *f_new_inst_sa(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_static_attr sa); +static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ +{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ +static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly) +{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; } +struct f_tree *f_new_tree(struct cf_context *ctx); +struct f_inst *f_generate_complex(struct cf_context *ctx, int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument); +struct f_inst *f_generate_roa_check(struct cf_context *ctx, struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); + +uint f_eval_int(struct f_inst *expr, struct cf_context *ctx); + +#endif diff --git a/filter/filter.c b/filter/filter.c index 0a2c26b8..ec360e25 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -46,7 +46,9 @@ #include "nest/iface.h" #include "nest/attrs.h" #include "conf/conf.h" +#include "conf/parser.h" #include "filter/filter.h" +#include "filter/f-util.h" #define CMP_ERROR 999 @@ -1824,13 +1826,13 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool) } uint -f_eval_int(struct f_inst *expr) +f_eval_int(struct f_inst *expr, struct cf_context *ctx) { /* Called independently in parse-time to eval expressions */ - struct f_val res = f_eval(expr, cfg_mem); + struct f_val res = f_eval(expr, ctx->cfg_mem); if (res.type != T_INT) - cf_error("Integer expression expected"); + cf_error(ctx, "Integer expression expected"); return res.val.i; } diff --git a/filter/filter.h b/filter/filter.h index febfdc65..99ffe8d8 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -149,17 +149,6 @@ struct filter { struct f_inst *root; }; -struct f_inst *f_new_inst(enum f_instruction_code fi_code); -struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da); -struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa); -static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ -{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ -static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly) -{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; } -struct f_tree *f_new_tree(void); -struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument); -struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); - struct f_tree *build_tree(struct f_tree *); struct f_tree *find_tree(struct f_tree *t, struct f_val val); @@ -178,7 +167,6 @@ struct rte; int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); -uint f_eval_int(struct f_inst *expr); char *filter_name(struct filter *filter); int filter_same(struct filter *new, struct filter *old); diff --git a/filter/tree.c b/filter/tree.c index f8379fa8..8e44a758 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -9,6 +9,7 @@ #include "lib/alloca.h" #include "nest/bird.h" #include "conf/conf.h" +#include "conf/parser.h" #include "filter/filter.h" /** @@ -100,7 +101,7 @@ build_tree(struct f_tree *from) } struct f_tree * -f_new_tree(void) +f_new_tree(struct cf_context *ctx) { struct f_tree * ret; ret = cfg_alloc(sizeof(struct f_tree)); diff --git a/lib/flowspec.c b/lib/flowspec.c index 87ce0206..2b549588 100644 --- a/lib/flowspec.c +++ b/lib/flowspec.c @@ -34,6 +34,7 @@ #include "nest/bird.h" #include "lib/flowspec.h" #include "conf/conf.h" +#include "conf/parser.h" static const char* flow4_type_str[] = { @@ -331,16 +332,16 @@ flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask) flow_check_cf_value_length(fb, mask); if (neg && !(val == 0 || val == mask)) - cf_error("For negation, value must be zero or bitmask"); + cf_error(fb->ctx, "For negation, value must be zero or bitmask"); if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000)) - cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask); + cf_error(fb->ctx, "Invalid mask 0x%x, must not exceed 0xfff", mask); if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01)) - cf_error("Invalid mask 0x%x, bit 0 must be 0", mask); + cf_error(fb->ctx, "Invalid mask 0x%x, bit 0 must be 0", mask); if (val & ~mask) - cf_error("Value 0x%x outside bitmask 0x%x", val, mask); + cf_error(fb->ctx, "Value 0x%x outside bitmask 0x%x", val, mask); } /** @@ -359,13 +360,13 @@ flow_check_cf_value_length(struct flow_builder *fb, u32 val) u8 max = flow_max_value_length(t, fb->ipv6); if (t == FLOW_TYPE_DSCP && val > 0x3f) - cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val); + cf_error(fb->ctx, "%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val); if (max == 1 && (val > 0xff)) - cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val); + cf_error(fb->ctx, "%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val); if (max == 2 && (val > 0xffff)) - cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val); + cf_error(fb->ctx, "%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val); } static enum flow_validated_state @@ -538,12 +539,12 @@ flow6_validate(const byte *nlri, uint len) * with a textual description of reason to failing of validation. */ void -flow4_validate_cf(net_addr_flow4 *f) +flow4_validate_cf(struct flow_builder *fb, net_addr_flow4 *f) { enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data)); if (r != FLOW_ST_VALID) - cf_error("Invalid flow route: %s", flow_validated_state_str(r)); + cf_error(fb->ctx, "Invalid flow route: %s", flow_validated_state_str(r)); } /** @@ -554,12 +555,12 @@ flow4_validate_cf(net_addr_flow4 *f) * with a textual description of reason to failing of validation. */ void -flow6_validate_cf(net_addr_flow6 *f) +flow6_validate_cf(struct flow_builder *fb, net_addr_flow6 *f) { enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data)); if (r != FLOW_ST_VALID) - cf_error("Invalid flow route: %s", flow_validated_state_str(r)); + cf_error(fb->ctx, "Invalid flow route: %s", flow_validated_state_str(r)); } @@ -574,10 +575,10 @@ flow6_validate_cf(net_addr_flow6 *f) * This function prepares flowspec builder instance using memory pool @pool. */ struct flow_builder * -flow_builder_init(pool *pool) +flow_builder_init(struct cf_context *ctx) { - struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder)); - BUFFER_INIT(fb->data, pool, 4); + struct flow_builder *fb = mb_allocz(ctx->new_config->pool, sizeof(struct flow_builder)); + BUFFER_INIT(fb->data, ctx->new_config->pool, 4); return fb; } diff --git a/lib/flowspec.h b/lib/flowspec.h index fa90c70d..1ba2584f 100644 --- a/lib/flowspec.h +++ b/lib/flowspec.h @@ -92,6 +92,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end); /* A data structure for keep a state of flow builder */ struct flow_builder { BUFFER_(byte) data; + struct cf_context *ctx; enum flow_type this_type; enum flow_type last_type; u16 last_op_offset; /* Position of last operator in data.data */ @@ -102,7 +103,7 @@ struct flow_builder { } parts[FLOW_TYPE_MAX]; /* Indexing all components */ }; -struct flow_builder *flow_builder_init(pool *pool); +struct flow_builder *flow_builder_init(struct cf_context *ctx); void flow_builder_clear(struct flow_builder *fb); void flow_builder_set_type(struct flow_builder *fb, enum flow_type p); int flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4); @@ -138,8 +139,8 @@ enum flow_validated_state flow4_validate(const byte *nlri, uint len); enum flow_validated_state flow6_validate(const byte *nlri, uint len); void flow_check_cf_value_length(struct flow_builder *fb, u32 expr); void flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask); -void flow4_validate_cf(net_addr_flow4 *f); -void flow6_validate_cf(net_addr_flow6 *f); +void flow4_validate_cf(struct flow_builder *fb, net_addr_flow4 *f); +void flow6_validate_cf(struct flow_builder *fb, net_addr_flow6 *f); /* diff --git a/nest/bfd.h b/nest/bfd.h index 04d6c001..f11daa35 100644 --- a/nest/bfd.h +++ b/nest/bfd.h @@ -42,14 +42,10 @@ struct bfd_request { struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data); -static inline void cf_check_bfd(int use UNUSED) { } - #else static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; } -static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); } - #endif /* CONFIG_BFD */ diff --git a/nest/cli.c b/nest/cli.c index c421cc7e..9d0e4f30 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -98,28 +98,9 @@ cli_alloc_out(cli *c, int size) return o->wpos - size; } -/** - * cli_printf - send reply to a CLI connection - * @c: CLI connection - * @code: numeric code of the reply, negative for continuation lines - * @msg: a printf()-like formatting string. - * - * This function send a single line of reply to a given CLI connection. - * In works in all aspects like bsprintf() except that it automatically - * prepends the reply line prefix. - * - * Please note that if the connection can be already busy sending some - * data in which case cli_printf() stores the output to a temporary buffer, - * so please avoid sending a large batch of replies without waiting - * for the buffers to be flushed. - * - * If you want to write to the current CLI output, you can use the cli_msg() - * macro instead. - */ -void -cli_printf(cli *c, int code, char *msg, ...) +static void +cli_vprintf(cli *c, int code, const char *msg, va_list args) { - va_list args; byte buf[CLI_LINE_SIZE]; int cd = code; int errcode; @@ -146,9 +127,7 @@ cli_printf(cli *c, int code, char *msg, ...) } c->last_reply = cd; - va_start(args, msg); cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args); - va_end(args); if (cnt < 0) { cli_printf(c, errcode, ""); @@ -159,6 +138,35 @@ cli_printf(cli *c, int code, char *msg, ...) memcpy(cli_alloc_out(c, size), buf, size); } +/** + * cli_printf - send reply to a CLI connection + * @c: CLI connection + * @code: numeric code of the reply, negative for continuation lines + * @msg: a printf()-like formatting string. + * + * This function send a single line of reply to a given CLI connection. + * In works in all aspects like bsprintf() except that it automatically + * prepends the reply line prefix. + * + * Please note that if the connection can be already busy sending some + * data in which case cli_printf() stores the output to a temporary buffer, + * so please avoid sending a large batch of replies without waiting + * for the buffers to be flushed. + * + * If you want to write to the current CLI output, you can use the cli_msg() + * macro instead. + * + * If you want to pass a va_list, use cli_vprintf(). + */ +void +cli_printf(cli *c, int code, char *msg, ...) +{ + va_list args; + va_start(args, msg); + cli_vprintf(c, code, msg, args); + va_end(args); +} + static void cli_copy_message(cli *c) { @@ -229,50 +237,79 @@ cli_written(cli *c) } -static byte *cli_rh_pos; -static uint cli_rh_len; -static int cli_rh_trick_flag; struct cli *this_cli; +struct cli_conf_order { + struct conf_order co; + struct cli *cli; + const char *pos; + uint len; + int lexer_hack; +}; + static int -cli_cmd_read_hook(byte *buf, uint max, UNUSED int fd) +cli_cmd_read_hook(struct conf_order *co, byte *buf, uint max) { - if (!cli_rh_trick_flag) + struct cli_conf_order *cco = (struct cli_conf_order *) co; + + if (cco->lexer_hack) { - cli_rh_trick_flag = 1; - buf[0] = '!'; + /* Lexer needs at least one character to be read + * to transition between states. Feeding a dummy + * character which is dropped to make Flex produce + * a dummy "CLIENT" token */ + cco->lexer_hack = 0; + buf[0] = '"'; return 1; } - if (max > cli_rh_len) - max = cli_rh_len; - memcpy(buf, cli_rh_pos, max); - cli_rh_pos += max; - cli_rh_len -= max; + + if (max > cco->len) + max = cco->len; + + memcpy(buf, cco->pos, cco->len); + cco->pos += max; + cco->len -= max; return max; } +static void +cli_cmd_error(struct conf_order *co, const char *msg, va_list args) +{ + struct cli_conf_order *cco = (struct cli_conf_order *) co; + cli_vprintf(cco->cli, 9001, msg, args); +} + static void cli_command(struct cli *c) { - struct config f; - int res; + struct conf_state state = { + .name = "", + .lino = 1 + }; + + struct cli_conf_order o = { + .co = { + .ctx = NULL, + .state = &state, + .cf_read_hook = cli_cmd_read_hook, + .cf_include = NULL, + .cf_outclude = NULL, + .cf_error = cli_cmd_error, + .lp = c->parser_pool, + .pool = c->pool, + }, + .lexer_hack = 1, + .pos = c->rx_buf, + .len = strlen(c->rx_buf), + .cli = c, + }; if (config->cli_debug > 1) log(L_TRACE "CLI: %s", c->rx_buf); - bzero(&f, sizeof(f)); - f.mem = c->parser_pool; - f.pool = rp_new(c->pool, "Config"); - cf_read_hook = cli_cmd_read_hook; - cli_rh_pos = c->rx_buf; - cli_rh_len = strlen(c->rx_buf); - cli_rh_trick_flag = 0; - this_cli = c; + lp_flush(c->parser_pool); - res = cli_parse(&f); - if (!res) - cli_printf(c, 9001, f.err_msg); - - config_free(&f); + this_cli = c; + cli_parse(&(o.co)); } static void @@ -316,8 +353,8 @@ cli_new(void *priv) c->event->hook = cli_event; c->event->data = c; c->cont = cli_hello; - c->parser_pool = lp_new_default(c->pool); c->show_pool = lp_new_default(c->pool); + c->parser_pool = lp_new_default(c->pool); c->rx_buf = mb_alloc(c->pool, CLI_RX_BUF_SIZE); ev_schedule(c->event); return c; diff --git a/nest/cmds.h b/nest/cmds.h index 4cf8fb1b..3904da0f 100644 --- a/nest/cmds.h +++ b/nest/cmds.h @@ -6,6 +6,9 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#ifndef _NEST_CMDS_H_ +#define _NEST_CMDS_H_ + struct sym_show_data { int type; /* Symbols type to show */ struct symbol *sym; @@ -17,3 +20,5 @@ void cmd_show_status(void); void cmd_show_symbols(struct sym_show_data *sym); void cmd_show_memory(void); void cmd_eval(struct f_inst *expr); + +#endif diff --git a/nest/config.Y b/nest/config.Y index 88f74b96..4721d4c8 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -15,52 +15,53 @@ CF_HDR #include "lib/lists.h" #include "lib/mac.h" +CF_CTX + +struct proto_config *this_proto; +struct channel_config *this_channel; +struct iface_patt *this_ipatt; +struct iface_patt_node *this_ipn; +list *this_p_list; +struct password_item *this_p_item; +int password_id; + CF_DEFINES -static struct proto_config *this_proto; -static struct channel_config *this_channel; -static struct iface_patt *this_ipatt; -static struct iface_patt_node *this_ipn; -/* static struct roa_table_config *this_roa_table; */ -static list *this_p_list; -static struct password_item *this_p_item; -static int password_id; - static void -iface_patt_check(void) +iface_patt_check(struct cf_context *ctx) { struct iface_patt_node *pn; - WALK_LIST(pn, this_ipatt->ipn_list) + WALK_LIST(pn, ctx->this_ipatt->ipn_list) if (!pn->pattern || pn->prefix.type) - cf_error("Interface name/mask expected, not IP prefix"); + cf_error(ctx, "Interface name/mask expected, not IP prefix"); } static inline void -reset_passwords(void) +reset_passwords(struct cf_context *ctx) { - this_p_list = NULL; + ctx->this_p_list = NULL; } static inline list * -get_passwords(void) +get_passwords(struct cf_context *ctx) { - list *rv = this_p_list; - this_p_list = NULL; + list *rv = ctx->this_p_list; + ctx->this_p_list = NULL; return rv; } static void -proto_postconfig(void) +proto_postconfig(struct cf_context *ctx) { - CALL(this_proto->protocol->postconfig, this_proto); - this_channel = NULL; - this_proto = NULL; + CALL(ctx->this_proto->protocol->postconfig, ctx, ctx->this_proto); + ctx->this_channel = NULL; + ctx->this_proto = NULL; } -#define DIRECT_CFG ((struct rt_dev_config *) this_proto) +#define DIRECT_CFG ((struct rt_dev_config *) ctx->this_proto) CF_DECLS @@ -106,13 +107,13 @@ CF_GRAMMAR conf: rtrid ; rtrid: - ROUTER ID idval ';' { new_config->router_id = $3; } - | ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; } + ROUTER ID idval ';' { ctx->new_config->router_id = $3; } + | ROUTER ID FROM iface_patt ';' { ctx->new_config->router_id_from = ctx->this_ipatt; } ; idval: NUM { $$ = $1; } - | '(' term ')' { $$ = f_eval_int($2); } + | '(' term ')' { $$ = f_eval_int($2, ctx); } | IP4 { $$ = ip4_to_u32($1); } | SYM { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) @@ -120,13 +121,13 @@ idval: else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip)) $$ = ipa_to_u32(SYM_VAL($1).ip); else - cf_error("Number or IPv4 address constant expected"); + cf_error(ctx, "Number or IPv4 address constant expected"); } ; conf: gr_opts ; -gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ; +gr_opts: GRACEFUL RESTART WAIT expr ';' { ctx->new_config->gr_wait = $4; } ; /* Network types (for tables, channels) */ @@ -158,7 +159,7 @@ table_sorted: table: net_type TABLE SYM table_sorted { struct rtable_config *cf; - cf = rt_new_table($3, $1); + cf = rt_new_table(ctx, $3, $1); cf->sorted = $4; } ; @@ -166,7 +167,7 @@ table: net_type TABLE SYM table_sorted { /* Definition of protocols */ -conf: proto { proto_postconfig(); } ; +conf: proto { proto_postconfig(ctx); } ; proto_start: PROTOCOL { $$ = SYM_PROTO; } @@ -175,62 +176,62 @@ proto_start: proto_name: /* EMPTY */ { - struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); - s->class = this_proto->class; - s->def = this_proto; - this_proto->name = s->name; + struct symbol *s = cf_default_name(ctx, ctx->this_proto->protocol->template, &ctx->this_proto->protocol->name_counter); + s->class = ctx->this_proto->class; + s->def = ctx->this_proto; + ctx->this_proto->name = s->name; } | SYM { - cf_define_symbol($1, this_proto->class, this_proto); - this_proto->name = $1->name; + cf_define_symbol(ctx, $1, ctx->this_proto->class, ctx->this_proto); + ctx->this_proto->name = $1->name; } | FROM SYM { - struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); - s->class = this_proto->class; - s->def = this_proto; - this_proto->name = s->name; + struct symbol *s = cf_default_name(ctx, ctx->this_proto->protocol->template, &ctx->this_proto->protocol->name_counter); + s->class = ctx->this_proto->class; + s->def = ctx->this_proto; + ctx->this_proto->name = s->name; - if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); - proto_copy_config(this_proto, $2->def); + if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error(ctx, "Template or protocol name expected"); + proto_copy_config(ctx, ctx->this_proto, $2->def); } | SYM FROM SYM { - cf_define_symbol($1, this_proto->class, this_proto); - this_proto->name = $1->name; + cf_define_symbol(ctx, $1, ctx->this_proto->class, ctx->this_proto); + ctx->this_proto->name = $1->name; - if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); - proto_copy_config(this_proto, $3->def); + if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error(ctx, "Template or protocol name expected"); + proto_copy_config(ctx, ctx->this_proto, $3->def); } ; proto_item: /* EMPTY */ - | DISABLED bool { this_proto->disabled = $2; } - | DEBUG debug_mask { this_proto->debug = $2; } - | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; } - | ROUTER ID idval { this_proto->router_id = $3; } - | DESCRIPTION text { this_proto->dsc = $2; } - | VRF text { this_proto->vrf = if_get_by_name($2); } + | DISABLED bool { ctx->this_proto->disabled = $2; } + | DEBUG debug_mask { ctx->this_proto->debug = $2; } + | MRTDUMP mrtdump_mask { ctx->this_proto->mrtdump = $2; } + | ROUTER ID idval { ctx->this_proto->router_id = $3; } + | DESCRIPTION text { ctx->this_proto->dsc = $2; } + | VRF text { ctx->this_proto->vrf = if_get_by_name($2); } ; channel_start: net_type { - $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto); + $$ = ctx->this_channel = channel_config_get(ctx, NULL, net_label[$1], $1, ctx->this_proto); }; channel_item: TABLE rtable { - if (this_channel->net_type && ($2->addr_type != this_channel->net_type)) - cf_error("Incompatible table type"); - this_channel->table = $2; + if (ctx->this_channel->net_type && ($2->addr_type != ctx->this_channel->net_type)) + cf_error(ctx, "Incompatible table type"); + ctx->this_channel->table = $2; } - | IMPORT imexport { this_channel->in_filter = $2; } - | EXPORT imexport { this_channel->out_filter = $2; } - | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; } - | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; } - | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; } - | PREFERENCE expr { this_channel->preference = $2; check_u16($2); } - | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; } + | IMPORT imexport { ctx->this_channel->in_filter = $2; } + | EXPORT imexport { ctx->this_channel->out_filter = $2; } + | RECEIVE LIMIT limit_spec { ctx->this_channel->rx_limit = $3; } + | IMPORT LIMIT limit_spec { ctx->this_channel->in_limit = $3; } + | EXPORT LIMIT limit_spec { ctx->this_channel->out_limit = $3; } + | PREFERENCE expr { ctx->this_channel->preference = $2; check_u16(ctx, $2); } + | IMPORT KEEP FILTERED bool { ctx->this_channel->in_keep_filtered = $4; } ; channel_opts: @@ -245,10 +246,10 @@ channel_opt_list: channel_end: { - if (!this_channel->table) - cf_error("Routing table not specified"); + if (!ctx->this_channel->table) + cf_error(ctx, "Routing table not specified"); - this_channel = NULL; + ctx->this_channel = NULL; }; proto_channel: channel_start channel_opt_list channel_end; @@ -256,7 +257,7 @@ proto_channel: channel_start channel_opt_list channel_end; rtable: SYM { - if ($1->class != SYM_TABLE) cf_error("Table expected"); + if ($1->class != SYM_TABLE) cf_error(ctx, "Table expected"); $$ = $1->def; } ; @@ -285,8 +286,8 @@ limit_spec: conf: debug_default ; debug_default: - DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; } - | DEBUG COMMANDS expr { new_config->cli_debug = $3; } + DEBUG PROTOCOLS debug_mask { ctx->new_config->proto_default_debug = $3; } + | DEBUG COMMANDS expr { ctx->new_config->cli_debug = $3; } ; /* MRTDUMP PROTOCOLS is in systep/unix/config.Y */ @@ -294,10 +295,10 @@ debug_default: conf: timeformat_base ; timeformat_which: - ROUTE { $$ = &new_config->tf_route; } - | PROTOCOL { $$ = &new_config->tf_proto; } - | BASE { $$ = &new_config->tf_base; } - | LOG { $$ = &new_config->tf_log; } + ROUTE { $$ = &ctx->new_config->tf_route; } + | PROTOCOL { $$ = &ctx->new_config->tf_proto; } + | BASE { $$ = &ctx->new_config->tf_base; } + | LOG { $$ = &ctx->new_config->tf_log; } ; timeformat_spec: @@ -321,19 +322,19 @@ timeformat_base: iface_patt_node_init: /* EMPTY */ { struct iface_patt_node *ipn = cfg_allocz(sizeof(struct iface_patt_node)); - add_tail(&this_ipatt->ipn_list, NODE ipn); - this_ipn = ipn; + add_tail(&ctx->this_ipatt->ipn_list, NODE ipn); + ctx->this_ipn = ipn; } ; iface_patt_node_body: - TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ } - | opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; } + TEXT { ctx->this_ipn->pattern = $1; /* ctx->this_ipn->prefix stays zero */ } + | opttext net_or_ipa { ctx->this_ipn->pattern = $1; ctx->this_ipn->prefix = $2; } ; iface_negate: - { this_ipn->positive = 1; } - | '-' { this_ipn->positive = 0; } + { ctx->this_ipn->positive = 1; } + | '-' { ctx->this_ipn->positive = 0; } ; iface_patt_node: @@ -347,12 +348,12 @@ iface_patt_list: ; /* For name/mask-only iface patterns */ -iface_patt_list_nopx: iface_patt_list { iface_patt_check(); } +iface_patt_list_nopx: iface_patt_list { iface_patt_check(ctx); } iface_patt_init: { /* Generic this_ipatt init */ - this_ipatt = cfg_allocz(sizeof(struct iface_patt)); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct iface_patt)); + init_list(&ctx->this_ipatt->ipn_list); } ; @@ -361,8 +362,8 @@ iface_patt: ; tos: - CLASS expr { $$ = $2 & 0xfc; if ($2 > 255) cf_error("TX class must be in range 0-255"); } - | DSCP expr { $$ = ($2 & 0x3f) << 2; if ($2 > 63) cf_error("TX DSCP must be in range 0-63"); } + CLASS expr { $$ = $2 & 0xfc; if ($2 > 255) cf_error(ctx, "TX class must be in range 0-255"); } + | DSCP expr { $$ = ($2 & 0x3f) << 2; if ($2 > 63) cf_error(ctx, "TX DSCP must be in range 0-63"); } ; /* Direct device route protocol */ @@ -370,7 +371,7 @@ tos: proto: dev_proto '}' ; dev_proto_start: proto_start DIRECT { - this_proto = proto_config_new(&proto_device, $1); + ctx->this_proto = proto_config_new(ctx, &proto_device, $1); init_list(&DIRECT_CFG->iface_list); } ; @@ -385,9 +386,9 @@ dev_proto: dev_iface_init: /* EMPTY */ { - this_ipatt = cfg_allocz(sizeof(struct iface_patt)); - add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct iface_patt)); + add_tail(&DIRECT_CFG->iface_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); } ; @@ -454,34 +455,37 @@ password_item: password_item_begin: PASSWORD text { - if (!this_p_list) { - this_p_list = cfg_alloc(sizeof(list)); - init_list(this_p_list); - password_id = 1; + if (!ctx->this_p_list) { + ctx->this_p_list = cfg_alloc(sizeof(list)); + init_list(ctx->this_p_list); + ctx->password_id = 1; } - this_p_item = cfg_alloc(sizeof (struct password_item)); - this_p_item->password = $2; - this_p_item->length = strlen($2); - this_p_item->genfrom = 0; - this_p_item->gento = TIME_INFINITY; - this_p_item->accfrom = 0; - this_p_item->accto = TIME_INFINITY; - this_p_item->id = password_id++; - this_p_item->alg = ALG_UNDEFINED; - add_tail(this_p_list, &this_p_item->n); + struct password_item *pi = cfg_alloc(sizeof (struct password_item)); + *pi = (struct password_item) { + .password = $2, + .length = strlen($2), + .genfrom = 0, + .gento = TIME_INFINITY, + .accfrom = 0, + .accto = TIME_INFINITY, + .id = ctx->password_id++, + .alg = ALG_UNDEFINED, + }; + ctx->this_p_item = pi; + add_tail(ctx->this_p_list, &pi->n); } ; password_item_params: /* empty */ { } - | GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; } - | GENERATE TO time ';' password_item_params { this_p_item->gento = $3; } - | ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; } - | ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; } - | FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; } - | TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; } - | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); } - | ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; } + | GENERATE FROM time ';' password_item_params { ctx->this_p_item->genfrom = $3; } + | GENERATE TO time ';' password_item_params { ctx->this_p_item->gento = $3; } + | ACCEPT FROM time ';' password_item_params { ctx->this_p_item->accfrom = $3; } + | ACCEPT TO time ';' password_item_params { ctx->this_p_item->accto = $3; } + | FROM time ';' password_item_params { ctx->this_p_item->genfrom = ctx->this_p_item->accfrom = $2; } + | TO time ';' password_item_params { ctx->this_p_item->gento = ctx->this_p_item->accto = $2; } + | ID expr ';' password_item_params { ctx->this_p_item->id = $2; if ($2 <= 0) cf_error(ctx, "Password ID has to be greated than zero."); } + | ALGORITHM password_algorithm ';' password_item_params { ctx->this_p_item->alg = $2; } ; password_algorithm: @@ -532,21 +536,22 @@ r_args: $$ = cfg_allocz(sizeof(struct rt_show_data)); init_list(&($$->tables)); $$->filter = FILTER_ACCEPT; + $$->ctx = ctx; } | r_args net_any { $$ = $1; - if ($$->addr) cf_error("Only one prefix expected"); + if ($$->addr) cf_error(ctx, "Only one prefix expected"); $$->addr = $2; } | r_args FOR r_args_for { $$ = $1; - if ($$->addr) cf_error("Only one prefix expected"); + if ($$->addr) cf_error(ctx, "Only one prefix expected"); $$->show_for = 1; $$->addr = $3; } | r_args TABLE SYM { $$ = $1; - if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name); + if ($3->class != SYM_TABLE) cf_error(ctx, "%s is not a table", $3->name); rt_show_add_table($$, ((struct rtable_config *)$3->def)->table); $$->tables_defined_by = RSD_TDB_DIRECT; } @@ -559,12 +564,12 @@ r_args: } | r_args FILTER filter { $$ = $1; - if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice"); + if ($$->filter != FILTER_ACCEPT) cf_error(ctx, "Filter specified twice"); $$->filter = $3; } | r_args where_filter { $$ = $1; - if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice"); + if ($$->filter != FILTER_ACCEPT) cf_error(ctx, "Filter specified twice"); $$->filter = $2; } | r_args ALL { @@ -582,8 +587,8 @@ r_args: | r_args export_mode SYM { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; - if ($$->export_mode) cf_error("Export specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if ($$->export_mode) cf_error(ctx, "Export specified twice"); + if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name); $$->export_mode = $2; $$->export_protocol = c->proto; $$->running_on_config = c->proto->cf->global; @@ -592,19 +597,19 @@ r_args: | r_args export_mode SYM '.' r_args_channel { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; - if ($$->export_mode) cf_error("Export specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if ($$->export_mode) cf_error(ctx, "Export specified twice"); + if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name); $$->export_mode = $2; $$->export_channel = proto_find_channel_by_name(c->proto, $5); - if (!$$->export_channel) cf_error("Export channel not found"); + if (!$$->export_channel) cf_error(ctx, "Export channel not found"); $$->running_on_config = c->proto->cf->global; $$->tables_defined_by = RSD_TDB_INDIRECT; } | r_args PROTOCOL SYM { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; - if ($$->show_protocol) cf_error("Protocol specified twice"); - if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name); + if ($$->show_protocol) cf_error(ctx, "Protocol specified twice"); + if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name); $$->show_protocol = c->proto; $$->running_on_config = c->proto->cf->global; $$->tables_defined_by = RSD_TDB_INDIRECT; @@ -648,7 +653,7 @@ r_args_for: else if (($1->class == (SYM_CONSTANT | T_NET)) && net_type_match(SYM_VAL($1).net, NB_IP | NB_VPN)) $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */ else - cf_error("IP address or network expected"); + cf_error(ctx, "IP address or network expected"); } ; @@ -741,7 +746,7 @@ echo_mask: echo_size: /* empty */ { $$ = 4096; } | NUM { - if ($1 < 256 || $1 > 65536) cf_error("Invalid log buffer size"); + if ($1 < 256 || $1 > 65536) cf_error(ctx, "Invalid log buffer size"); $$ = $1; } ; diff --git a/nest/proto.c b/nest/proto.c index 8a8221a8..176c7066 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -16,6 +16,7 @@ #include "lib/timer.h" #include "lib/string.h" #include "conf/conf.h" +#include "conf/parser.h" #include "nest/route.h" #include "nest/iface.h" #include "nest/cli.h" @@ -457,7 +458,7 @@ const struct channel_class channel_basic = { }; void * -channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto) +channel_config_new(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto) { struct channel_config *cf = NULL; struct rtable_config *tab = NULL; @@ -465,12 +466,12 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty if (net_type) { if (!net_val_match(net_type, proto->protocol->channel_mask)) - cf_error("Unsupported channel type"); + cf_error(ctx, "Unsupported channel type"); if (proto->net_type && (net_type != proto->net_type)) - cf_error("Different channel type"); + cf_error(ctx, "Different channel type"); - tab = new_config->def_tables[net_type]; + tab = ctx->new_config->def_tables[net_type]; } if (!cc) @@ -493,7 +494,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty } void * -channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto) +channel_config_get(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto) { struct channel_config *cf; @@ -503,17 +504,17 @@ channel_config_get(const struct channel_class *cc, const char *name, uint net_ty { /* Allow to redefine channel only if inherited from template */ if (cf->parent == proto) - cf_error("Multiple %s channels", name); + cf_error(ctx, "Multiple %s channels", name); cf->parent = proto; return cf; } - return channel_config_new(cc, name, net_type, proto); + return channel_config_new(ctx, cc, name, net_type, proto); } struct channel_config * -channel_copy_config(struct channel_config *src, struct proto_config *proto) +channel_copy_config(struct cf_context *ctx, struct channel_config *src, struct proto_config *proto) { struct channel_config *dst = cfg_alloc(src->channel->config_size); @@ -741,19 +742,19 @@ proto_start(struct proto *p) * initialized during protos_commit()). */ void * -proto_config_new(struct protocol *pr, int class) +proto_config_new(struct cf_context *ctx, struct protocol *pr, int class) { struct proto_config *cf = cfg_allocz(pr->config_size); if (class == SYM_PROTO) - add_tail(&new_config->protos, &cf->n); + add_tail(&ctx->new_config->protos, &cf->n); - cf->global = new_config; + cf->global = ctx->new_config; cf->protocol = pr; cf->name = pr->name; cf->class = class; - cf->debug = new_config->proto_default_debug; - cf->mrtdump = new_config->proto_default_mrtdump; + cf->debug = ctx->new_config->proto_default_debug; + cf->mrtdump = ctx->new_config->proto_default_mrtdump; init_list(&cf->channels); @@ -773,7 +774,7 @@ proto_config_new(struct protocol *pr, int class) * copy_config() protocol hook is used to copy protocol-specific data. */ void -proto_copy_config(struct proto_config *dest, struct proto_config *src) +proto_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src) { struct channel_config *cc; node old_node; @@ -781,10 +782,10 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src) char *old_name; if (dest->protocol != src->protocol) - cf_error("Can't copy configuration from a different protocol type"); + cf_error(ctx, "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); + cf_error(ctx, "Inheriting configuration for %s is not supported", src->protocol->name); DBG("Copying configuration from %s to %s\n", src->name, dest->name); @@ -805,10 +806,10 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src) init_list(&dest->channels); WALK_LIST(cc, src->channels) - channel_copy_config(cc, dest); + channel_copy_config(ctx, cc, dest); /* FIXME: allow for undefined copy_config */ - dest->protocol->copy_config(dest, src); + dest->protocol->copy_config(ctx, dest, src); } /** @@ -1870,18 +1871,18 @@ proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, in } struct proto * -proto_get_named(struct symbol *sym, struct protocol *pr) +proto_get_named(struct cf_context *ctx, struct symbol *sym, struct protocol *pr) { struct proto *p, *q; if (sym) { if (sym->class != SYM_PROTO) - cf_error("%s: Not a protocol", sym->name); + cf_error(ctx, "%s: Not a protocol", sym->name); p = ((struct proto_config *) sym->def)->proto; if (!p || p->proto != pr) - cf_error("%s: Not a %s protocol", sym->name, pr->name); + cf_error(ctx, "%s: Not a %s protocol", sym->name, pr->name); } else { @@ -1890,11 +1891,11 @@ proto_get_named(struct symbol *sym, struct protocol *pr) if ((q->proto == pr) && (q->proto_state != PS_DOWN)) { if (p) - cf_error("There are multiple %s protocols running", pr->name); + cf_error(ctx, "There are multiple %s protocols running", pr->name); p = q; } if (!p) - cf_error("There is no %s protocol running", pr->name); + cf_error(ctx, "There is no %s protocol running", pr->name); } return p; diff --git a/nest/protocol.h b/nest/protocol.h index 343ce523..1071a364 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -68,7 +68,7 @@ struct protocol { uint config_size; /* Size of protocol config data structure */ void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ - void (*postconfig)(struct proto_config *); /* After configuring each instance */ + void (*postconfig)(struct cf_context *ctx, struct proto_config *); /* After configuring each instance */ struct proto * (*init)(struct proto_config *); /* Create new instance */ int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance, returns success */ void (*dump)(struct proto *); /* Debugging dump */ @@ -80,7 +80,7 @@ struct protocol { void (*get_route_info)(struct rte *, byte *buf); /* 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 (*copy_config)(struct cf_context *ctx, struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ }; void protos_build(void); @@ -257,8 +257,8 @@ struct proto_spec { void *proto_new(struct proto_config *); -void *proto_config_new(struct protocol *, int class); -void proto_copy_config(struct proto_config *dest, struct proto_config *src); +void *proto_config_new(struct cf_context *ctx, struct protocol *, int class); +void proto_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src); void proto_set_message(struct proto *p, char *msg, int len); void graceful_restart_recovery(void); @@ -281,7 +281,7 @@ void proto_cmd_debug(struct proto *, uintptr_t, int); void proto_cmd_mrtdump(struct proto *, uintptr_t, int); void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg); -struct proto *proto_get_named(struct symbol *, struct protocol *); +struct proto *proto_get_named(struct cf_context *ctx, struct symbol *, struct protocol *); #define CMD_RELOAD 0 #define CMD_RELOAD_IN 1 @@ -611,8 +611,8 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP) static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); } void channel_request_feeding(struct channel *c); -void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); -void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); +void *channel_config_new(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); +void *channel_config_get(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); int channel_reconfigure(struct channel *c, struct channel_config *cf); diff --git a/nest/route.h b/nest/route.h index 2ec1dc7f..335a130e 100644 --- a/nest/route.h +++ b/nest/route.h @@ -278,9 +278,10 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); #define RIC_DROP -2 /* Silently dropped by protocol */ struct config; +struct cf_context; void rt_init(void); -void rt_preconfig(struct config *); +void rt_preconfig(struct cf_context *); void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); @@ -310,7 +311,7 @@ void rt_dump(rtable *); void rt_dump_all(void); int rt_feed_channel(struct channel *c); void rt_feed_channel_abort(struct channel *c); -struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); +struct rtable_config *rt_new_table(struct cf_context *ctx, struct symbol *s, uint addr_type); /* Default limit for ECMP next hops, defined in sysdep code */ extern const int rt_default_ecmp; @@ -324,6 +325,7 @@ struct rt_show_data_rtable { struct rt_show_data { net_addr *addr; list tables; + struct cf_context *ctx; /* Parent parser context */ struct rt_show_data_rtable *tab; /* Iterator over table list */ struct rt_show_data_rtable *last_table; /* Last table in output */ struct fib_iterator fit; /* Iterator over networks in table */ @@ -340,6 +342,8 @@ struct rt_show_data { int net_counter_last, rt_counter_last, show_counter_last; }; +struct cf_context; + void rt_show(struct rt_show_data *); struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t); diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 61f025ce..8b7b1fa2 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -116,7 +116,7 @@ dev_if_notify(struct proto *p, uint c, struct iface *iface) } static void -dev_postconfig(struct proto_config *CF) +dev_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct rt_dev_config *cf = (void *) CF; struct channel_config *ip4, *ip6, *ip6_sadr; @@ -126,7 +126,7 @@ dev_postconfig(struct proto_config *CF) ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR); if (ip6 && ip6_sadr) - cf_error("Both ipv6 and ipv6-sadr channels"); + cf_error(ctx, "Both ipv6 and ipv6-sadr channels"); cf->ip4_channel = ip4; cf->ip6_channel = ip6 ?: ip6_sadr; @@ -167,7 +167,7 @@ dev_reconfigure(struct proto *P, struct proto_config *CF) } static void -dev_copy_config(struct proto_config *dest, struct proto_config *src) +dev_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src) { struct rt_dev_config *d = (void *) dest; struct rt_dev_config *s = (void *) src; @@ -177,7 +177,7 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src) * 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)); + cf_copy_list(ctx, &d->iface_list, &s->iface_list, sizeof(struct iface_patt)); d->check_link = s->check_link; } diff --git a/nest/rt-show.c b/nest/rt-show.c index 90165c57..2eeab6d3 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -14,6 +14,7 @@ #include "nest/protocol.h" #include "nest/cli.h" #include "nest/iface.h" +#include "conf/parser.h" #include "filter/filter.h" static void @@ -275,6 +276,7 @@ done: struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t) { + struct cf_context *ctx = d->ctx; struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable)); tab->table = t; add_tail(&(d->tables), &(tab->n)); @@ -344,7 +346,7 @@ rt_show_prepare_tables(struct rt_show_data *d) if (!tab->export_channel) { if (d->tables_defined_by & RSD_TDB_NMN) - cf_error("No export channel for table %s", tab->table->name); + cf_error(d->ctx, "No export channel for table %s", tab->table->name); rem_node(&(tab->n)); continue; @@ -355,7 +357,7 @@ rt_show_prepare_tables(struct rt_show_data *d) if (d->addr && (tab->table->addr_type != d->addr->type)) { if (d->tables_defined_by & RSD_TDB_NMN) - cf_error("Incompatible type of prefix/ip for table %s", tab->table->name); + cf_error(d->ctx, "Incompatible type of prefix/ip for table %s", tab->table->name); rem_node(&(tab->n)); continue; @@ -364,7 +366,7 @@ rt_show_prepare_tables(struct rt_show_data *d) /* Ensure there is at least one table */ if (EMPTY_LIST(d->tables)) - cf_error("No valid tables"); + cf_error(d->ctx, "No valid tables"); } void @@ -375,7 +377,7 @@ rt_show(struct rt_show_data *d) /* Filtered routes are neither exported nor have sensible ordering */ if (d->filtered && (d->export_mode || d->primary_only)) - cf_error("Incompatible show route options"); + cf_error(d->ctx, "Incompatible show route options"); rt_show_prepare_tables(d); diff --git a/nest/rt-table.c b/nest/rt-table.c index 036b34c4..bde18c53 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -38,6 +38,7 @@ #include "lib/event.h" #include "lib/string.h" #include "conf/conf.h" +#include "conf/parser.h" #include "filter/filter.h" #include "lib/hash.h" #include "lib/string.h" @@ -1823,12 +1824,12 @@ again: } void -rt_preconfig(struct config *c) +rt_preconfig(struct cf_context *ctx) { - init_list(&c->tables); + init_list(&ctx->new_config->tables); - rt_new_table(cf_get_symbol("master4"), NET_IP4); - rt_new_table(cf_get_symbol("master6"), NET_IP6); + rt_new_table(ctx, cf_get_symbol(ctx, "master4"), NET_IP4); + rt_new_table(ctx, cf_get_symbol(ctx, "master6"), NET_IP6); } @@ -2060,27 +2061,27 @@ rt_next_hop_update(rtable *tab) struct rtable_config * -rt_new_table(struct symbol *s, uint addr_type) +rt_new_table(struct cf_context *ctx, struct symbol *s, uint addr_type) { /* Hack that allows to 'redefine' the master table */ if ((s->class == SYM_TABLE) && - (s->def == new_config->def_tables[addr_type]) && + (s->def == ctx->new_config->def_tables[addr_type]) && ((addr_type == NET_IP4) || (addr_type == NET_IP6))) return s->def; struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config)); - cf_define_symbol(s, SYM_TABLE, c); + cf_define_symbol(ctx, s, SYM_TABLE, c); c->name = s->name; c->addr_type = addr_type; c->gc_max_ops = 1000; c->gc_min_time = 5; - add_tail(&new_config->tables, &c->n); + add_tail(&ctx->new_config->tables, &c->n); /* First table of each type is kept as default */ - if (! new_config->def_tables[addr_type]) - new_config->def_tables[addr_type] = c; + if (!ctx->new_config->def_tables[addr_type]) + ctx->new_config->def_tables[addr_type] = c; return c; } diff --git a/proto/babel/babel.c b/proto/babel/babel.c index afa482bb..59fb58f2 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -2187,7 +2187,7 @@ babel_rte_same(struct rte *new, struct rte *old) static void -babel_postconfig(struct proto_config *CF) +babel_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct babel_config *cf = (void *) CF; struct channel_config *ip4, *ip6, *ip6_sadr; @@ -2197,7 +2197,7 @@ babel_postconfig(struct proto_config *CF) ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR); if (ip6 && ip6_sadr) - cf_error("Both ipv6 and ipv6-sadr channels"); + cf_error(ctx, "Both ipv6 and ipv6-sadr channels"); cf->ip4_channel = ip4; cf->ip6_channel = ip6 ?: ip6_sadr; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index 3af79fd6..e21b424d 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -17,8 +17,8 @@ CF_HDR CF_DEFINES -#define BABEL_CFG ((struct babel_config *) this_proto) -#define BABEL_IFACE ((struct babel_iface_config *) this_ipatt) +#define BABEL_CFG ((struct babel_config *) ctx->this_proto) +#define BABEL_IFACE ((struct babel_iface_config *) ctx->this_ipatt) CF_DECLS @@ -33,7 +33,7 @@ proto: babel_proto ; babel_proto_start: proto_start BABEL { - this_proto = proto_config_new(&proto_babel, $1); + ctx->this_proto = proto_config_new(ctx, &proto_babel, $1); init_list(&BABEL_CFG->iface_list); BABEL_CFG->hold_time = 1 S_; }; @@ -56,9 +56,9 @@ babel_proto: babel_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct babel_iface_config)); - add_tail(&BABEL_CFG->iface_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct babel_iface_config)); + add_tail(&BABEL_CFG->iface_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); BABEL_IFACE->port = BABEL_PORT; BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; BABEL_IFACE->limit = BABEL_HELLO_LIMIT; @@ -95,20 +95,20 @@ babel_iface_finish: babel_iface_item: - | PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); } - | RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); } - | LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); } + | PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid port number"); } + | RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid rxcost"); } + | LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error(ctx, "Limit must be in range 1-16"); } | TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; } | TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; } - | HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); } - | UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); } - | RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); } - | TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); } + | HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3BABEL_MAX_INTERVAL)) cf_error(ctx, "Hello interval must be in range 10 ms - 655 s"); } + | UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3BABEL_MAX_INTERVAL)) cf_error(ctx, "Update interval must be in range 10 ms - 655 s"); } + | RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "RX buffer must be in range 256-65535"); } + | TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "TX length must be in range 256-65535"); } | TX tos { BABEL_IFACE->tx_tos = $2; } | TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; } | CHECK LINK bool { BABEL_IFACE->check_link = $3; } - | NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); } - | NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); } + | NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error(ctx, "Must be an IPv4 address"); } + | NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error(ctx, "Must be an IPv6 address"); } ; babel_iface_opts: @@ -130,16 +130,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BAB CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [] [\"\"], [[Show information about Babel interfaces]]) -{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); }; +{ babel_show_interfaces(proto_get_named(ctx, $4, &proto_babel), $5); }; CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about Babel neighbors]]) -{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); }; +{ babel_show_neighbors(proto_get_named(ctx, $4, &proto_babel), $5); }; CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [], [[Show information about Babel prefix entries]]) -{ babel_show_entries(proto_get_named($4, &proto_babel)); }; +{ babel_show_entries(proto_get_named(ctx, $4, &proto_babel)); }; CF_CLI(SHOW BABEL ROUTES, optsym opttext, [], [[Show information about Babel route entries]]) -{ babel_show_routes(proto_get_named($4, &proto_babel)); }; +{ babel_show_routes(proto_get_named(ctx, $4, &proto_babel)); }; CF_CODE diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index fdcd7225..17b85f6f 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1061,7 +1061,7 @@ bfd_preconfig(struct protocol *P UNUSED, struct config *c UNUSED) } static void -bfd_copy_config(struct proto_config *dest, struct proto_config *src UNUSED) +bfd_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest, struct proto_config *src UNUSED) { struct bfd_config *d = (struct bfd_config *) dest; // struct bfd_config *s = (struct bfd_config *) src; diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 3f5714fd..cf2e43c9 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -11,8 +11,12 @@ CF_HDR CF_DEFINES -#define BFD_CFG ((struct bfd_config *) this_proto) -#define BFD_IFACE ((struct bfd_iface_config *) this_ipatt) +/* BFD is available, override the trap in conf/confbase.Y */ +#undef BFD_CHECK +#define BFD_CHECK(x) + +#define BFD_CFG ((struct bfd_config *) ctx->this_proto) +#define BFD_IFACE ((struct bfd_iface_config *) ctx->this_ipatt) #define BFD_NEIGHBOR this_bfd_neighbor static struct bfd_neighbor *this_bfd_neighbor; @@ -35,12 +39,12 @@ proto: bfd_proto ; bfd_proto_start: proto_start BFD { - this_proto = proto_config_new(&proto_bfd, $1); + ctx->this_proto = proto_config_new(ctx, &proto_bfd, $1); init_list(&BFD_CFG->patt_list); init_list(&BFD_CFG->neigh_list); if (bfd_cf) - cf_error("Only one BFD instance allowed"); + cf_error(ctx, "Only one BFD instance allowed"); bfd_cf = BFD_CFG; }; @@ -62,21 +66,21 @@ bfd_proto: bfd_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config)); - add_tail(&BFD_CFG->patt_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config)); + add_tail(&BFD_CFG->patt_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); BFD_IFACE->min_rx_int = BFD_DEFAULT_MIN_RX_INT; BFD_IFACE->min_tx_int = BFD_DEFAULT_MIN_TX_INT; BFD_IFACE->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT; BFD_IFACE->multiplier = BFD_DEFAULT_MULTIPLIER; - reset_passwords(); + reset_passwords(ctx); }; bfd_iface_finish: { - BFD_IFACE->passwords = get_passwords(); + BFD_IFACE->passwords = get_passwords(ctx); if (!BFD_IFACE->auth_type != !BFD_IFACE->passwords) log(L_WARN "Authentication and password options should be used together"); @@ -87,7 +91,7 @@ bfd_iface_finish: WALK_LIST(pass, *BFD_IFACE->passwords) { if (pass->alg) - cf_error("Password algorithm option not available in BFD protocol"); + cf_error(ctx, "Password algorithm option not available in BFD protocol"); pass->alg = bfd_auth_type_to_hash_alg[BFD_IFACE->auth_type]; } @@ -159,16 +163,16 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop BFD_NEIGHBOR->multihop = $4; if ($4 && $2) - cf_error("Neighbor cannot set both interface and multihop"); + cf_error(ctx, "Neighbor cannot set both interface and multihop"); if ($4 && ipa_zero($3)) - cf_error("Multihop neighbor requires specified local address"); + cf_error(ctx, "Multihop neighbor requires specified local address"); }; CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]); CF_CLI(SHOW BFD SESSIONS, optsym, [], [[Show information about BFD sessions]]) -{ bfd_show_sessions(proto_get_named($4, &proto_bfd)); }; +{ bfd_show_sessions(proto_get_named(ctx, $4, &proto_bfd)); }; CF_CODE diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 6dea88c8..7f948791 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1681,7 +1681,7 @@ bgp_find_channel_config(struct bgp_config *cf, u32 afi) } struct rtable_config * -bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32 type) +bgp_default_igp_table(struct cf_context *ctx, struct bgp_config *cf, struct bgp_channel_config *cc, u32 type) { struct bgp_channel_config *cc2; struct rtable_config *tab; @@ -1706,12 +1706,12 @@ bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32 if (tab = cf->c.global->def_tables[type]) return tab; - cf_error("Undefined IGP table"); + cf_error(ctx, "Undefined IGP table"); } void -bgp_postconfig(struct proto_config *CF) +bgp_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct bgp_config *cf = (void *) CF; int internal = (cf->local_as == cf->remote_as); @@ -1736,44 +1736,44 @@ bgp_postconfig(struct proto_config *CF) if (!cf->local_as) - cf_error("Local AS number must be set"); + cf_error(ctx, "Local AS number must be set"); if (ipa_zero(cf->remote_ip)) - cf_error("Neighbor must be configured"); + cf_error(ctx, "Neighbor must be configured"); if (!cf->remote_as) - cf_error("Remote AS number must be set"); + cf_error(ctx, "Remote AS number must be set"); if (ipa_is_link_local(cf->remote_ip) && !cf->iface) - cf_error("Link-local neighbor address requires specified interface"); + cf_error(ctx, "Link-local neighbor address requires specified interface"); if (!(cf->capabilities && cf->enable_as4) && (cf->remote_as > 0xFFFF)) - cf_error("Neighbor AS number out of range (AS4 not available)"); + cf_error(ctx, "Neighbor AS number out of range (AS4 not available)"); if (!internal && cf->rr_client) - cf_error("Only internal neighbor can be RR client"); + cf_error(ctx, "Only internal neighbor can be RR client"); if (internal && cf->rs_client) - cf_error("Only external neighbor can be RS client"); + cf_error(ctx, "Only external neighbor can be RS client"); if (!cf->confederation && cf->confederation_member) - cf_error("Confederation ID must be set for member sessions"); + cf_error(ctx, "Confederation ID must be set for member sessions"); if (cf->multihop && (ipa_is_link_local(cf->local_ip) || ipa_is_link_local(cf->remote_ip))) - cf_error("Multihop BGP cannot be used with link-local addresses"); + cf_error(ctx, "Multihop BGP cannot be used with link-local addresses"); if (cf->multihop && cf->iface) - cf_error("Multihop BGP cannot be bound to interface"); + cf_error(ctx, "Multihop BGP cannot be bound to interface"); if (cf->multihop && cf->check_link) - cf_error("Multihop BGP cannot depend on link state"); + cf_error(ctx, "Multihop BGP cannot depend on link state"); if (cf->multihop && cf->bfd && ipa_zero(cf->local_ip)) - cf_error("Multihop BGP with BFD requires specified local address"); + cf_error(ctx, "Multihop BGP with BFD requires specified local address"); if (!cf->gr_mode && cf->llgr_mode) - cf_error("Long-lived graceful restart requires basic graceful restart"); + cf_error(ctx, "Long-lived graceful restart requires basic graceful restart"); struct bgp_channel_config *cc; @@ -1784,14 +1784,14 @@ bgp_postconfig(struct proto_config *CF) if (interior) cc->c.in_filter = FILTER_ACCEPT; else - cf_error("EBGP requires explicit import policy"); + cf_error(ctx, "EBGP requires explicit import policy"); /* Handle undefined export filter */ if (cc->c.out_filter == FILTER_UNDEF) if (interior) cc->c.out_filter = FILTER_REJECT; else - cf_error("EBGP requires explicit export policy"); + cf_error(ctx, "EBGP requires explicit export policy"); /* Disable after error incompatible with restart limit action */ if ((cc->c.in_limit.action == PLA_RESTART) && cf->disable_after_error) @@ -1819,29 +1819,29 @@ bgp_postconfig(struct proto_config *CF) if ((cc->gw_mode == GW_RECURSIVE) && !cc->desc->no_igp) { if (!cc->igp_table_ip4 && (bgp_cc_is_ipv4(cc) || cc->ext_next_hop)) - cc->igp_table_ip4 = bgp_default_igp_table(cf, cc, NET_IP4); + cc->igp_table_ip4 = bgp_default_igp_table(ctx, cf, cc, NET_IP4); if (!cc->igp_table_ip6 && (bgp_cc_is_ipv6(cc) || cc->ext_next_hop)) - cc->igp_table_ip6 = bgp_default_igp_table(cf, cc, NET_IP6); + cc->igp_table_ip6 = bgp_default_igp_table(ctx, cf, cc, NET_IP6); if (cc->igp_table_ip4 && bgp_cc_is_ipv6(cc) && !cc->ext_next_hop) - cf_error("Mismatched IGP table type"); + cf_error(ctx, "Mismatched IGP table type"); if (cc->igp_table_ip6 && bgp_cc_is_ipv4(cc) && !cc->ext_next_hop) - cf_error("Mismatched IGP table type"); + cf_error(ctx, "Mismatched IGP table type"); } if (cf->multihop && (cc->gw_mode == GW_DIRECT)) - cf_error("Multihop BGP cannot use direct gateway mode"); + cf_error(ctx, "Multihop BGP cannot use direct gateway mode"); if ((cc->gw_mode == GW_RECURSIVE) && cc->c.table->sorted) - cf_error("BGP in recursive mode prohibits sorted table"); + cf_error(ctx, "BGP in recursive mode prohibits sorted table"); if (cf->deterministic_med && cc->c.table->sorted) - cf_error("BGP with deterministic MED prohibits sorted table"); + cf_error(ctx, "BGP with deterministic MED prohibits sorted table"); if (cc->secondary && !cc->c.table->sorted) - cf_error("BGP with secondary option requires sorted table"); + cf_error(ctx, "BGP with secondary option requires sorted table"); } } @@ -1916,7 +1916,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC) } static void -bgp_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED) +bgp_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED) { /* Just a shallow copy */ } diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 120b1e88..53f8ff0e 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -12,8 +12,8 @@ CF_HDR CF_DEFINES -#define BGP_CFG ((struct bgp_config *) this_proto) -#define BGP_CC ((struct bgp_channel_config *) this_channel) +#define BGP_CFG ((struct bgp_config *) ctx->this_proto) +#define BGP_CC ((struct bgp_channel_config *) ctx->this_channel) CF_DECLS @@ -44,7 +44,7 @@ CF_GRAMMAR proto: bgp_proto '}' ; bgp_proto_start: proto_start BGP { - this_proto = proto_config_new(&proto_bgp, $1); + ctx->this_proto = proto_config_new(ctx, &proto_bgp, $1); BGP_CFG->local_port = BGP_PORT; BGP_CFG->remote_port = BGP_PORT; BGP_CFG->multihop = -1; /* undefined */ @@ -73,13 +73,13 @@ bgp_proto_start: proto_start BGP { bgp_loc_opts: /* empty */ - | bgp_loc_opts PORT expr { BGP_CFG->local_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); } + | bgp_loc_opts PORT expr { BGP_CFG->local_port = $3; if (($3<1) || ($3>65535)) cf_error(ctx, "Invalid port number"); } | bgp_loc_opts AS expr { BGP_CFG->local_as = $3; } ; bgp_nbr_opts: /* empty */ - | bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); } + | bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error(ctx, "Invalid port number"); } | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; } ; @@ -118,7 +118,7 @@ bgp_proto: | bgp_proto NEIGHBOR bgp_nbr_opts ';' | bgp_proto NEIGHBOR ipa ipa_scope bgp_nbr_opts ';' { if (ipa_nonzero(BGP_CFG->remote_ip)) - cf_error("Only one neighbor per BGP instance is allowed"); + cf_error(ctx, "Only one neighbor per BGP instance is allowed"); BGP_CFG->remote_ip = $3; if ($4) BGP_CFG->iface = $4; } @@ -132,7 +132,7 @@ bgp_proto: | bgp_proto STARTUP HOLD TIME expr ';' { BGP_CFG->initial_hold_time = $5; } | bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; } | bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; } - | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); } + | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error(ctx, "Multihop must be in range 1-255"); } | bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; } | bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; } | bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; } @@ -142,7 +142,7 @@ bgp_proto: | bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; } | bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; } | bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->local_ip = $4; } - | bgp_proto START DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; log(L_WARN "%s: Start delay time option is deprecated, use connect delay time", this_proto->name); } + | bgp_proto START DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; log(L_WARN "%s: Start delay time option is deprecated, use connect delay time", ctx->this_proto->name); } | bgp_proto CONNECT DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; } | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; } | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; } @@ -169,8 +169,8 @@ bgp_proto: | bgp_proto LONG LIVED STALE TIME expr ';' { BGP_CFG->llgr_time = $6; } | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; } | bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; } - | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); } - | bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; cf_check_bfd(1); } + | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; BFD_CHECK($3); } + | bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; BFD_CHECK(1); } ; bgp_afi: @@ -193,9 +193,9 @@ bgp_channel_start: bgp_afi const struct bgp_af_desc *desc = bgp_get_af_desc($1); if (!desc) - cf_error("Unknown AFI/SAFI"); + cf_error(ctx, "Unknown AFI/SAFI"); - this_channel = channel_config_get(&channel_bgp, desc->name, desc->net, this_proto); + ctx->this_channel = channel_config_get(ctx, &channel_bgp, desc->name, desc->net, ctx->this_proto); /* New channel */ if (!BGP_CC->desc) @@ -231,14 +231,14 @@ bgp_channel_item: | ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; } | IGP TABLE rtable { if (BGP_CC->desc->no_igp) - cf_error("IGP table not allowed here"); + cf_error(ctx, "IGP table not allowed here"); if ($3->addr_type == NET_IP4) BGP_CC->igp_table_ip4 = $3; else if ($3->addr_type == NET_IP6) BGP_CC->igp_table_ip6 = $3; else - cf_error("Mismatched IGP table type"); + cf_error(ctx, "Mismatched IGP table type"); } ; @@ -254,10 +254,10 @@ bgp_channel_opt_list: bgp_channel_end: { - if (!this_channel->table) - cf_error("Routing table not specified"); + if (!ctx->this_channel->table) + cf_error(ctx, "Routing table not specified"); - this_channel = NULL; + ctx->this_channel = NULL; }; bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index b89584e1..a065ba8d 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -10,22 +10,24 @@ CF_HDR #include "proto/ospf/ospf.h" +CF_CTX + +struct ospf_area_config *this_area; +struct nbma_node *this_nbma; +list *this_nets; +struct area_net_config *this_pref; +struct ospf_stubnet_config *this_stubnet; + CF_DEFINES -#define OSPF_CFG ((struct ospf_config *) this_proto) -#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt) +#define OSPF_CFG ((struct ospf_config *) ctx->this_proto) +#define OSPF_PATT ((struct ospf_iface_patt *) ctx->this_ipatt) -static struct ospf_area_config *this_area; -static struct nbma_node *this_nbma; -static list *this_nets; -static struct area_net_config *this_pref; -static struct ospf_stubnet_config *this_stubnet; - -static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; } -static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; } +static inline int ospf_cfg_is_v2(struct cf_context *ctx) { return OSPF_CFG->ospf2; } +static inline int ospf_cfg_is_v3(struct cf_context *ctx) { return ! OSPF_CFG->ospf2; } static void -ospf_iface_finish(void) +ospf_iface_finish(struct cf_context *ctx) { struct ospf_iface_patt *ip = OSPF_PATT; @@ -35,9 +37,9 @@ ospf_iface_finish(void) if (ip->waitint == 0) ip->waitint = ip->deadc * ip->helloint; - ip->passwords = get_passwords(); + ip->passwords = get_passwords(ctx); - if (ospf_cfg_is_v2() && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5)) + if (ospf_cfg_is_v2(ctx) && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5)) log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks"); if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL)) @@ -49,46 +51,46 @@ ospf_iface_finish(void) WALK_LIST(pass, *ip->passwords) { if (pass->alg && (ip->autype != OSPF_AUTH_CRYPT)) - cf_error("Password algorithm option requires cryptographic authentication"); + cf_error(ctx, "Password algorithm option requires cryptographic authentication"); /* Set default OSPF crypto algorithms */ if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT)) - pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256; + pass->alg = ospf_cfg_is_v2(ctx) ? ALG_MD5 : ALG_HMAC_SHA256; - if (ospf_cfg_is_v3() && ip->autype && (pass->alg < ALG_HMAC)) - cf_error("Keyed hash algorithms are not allowed, use HMAC algorithms"); + if (ospf_cfg_is_v3(ctx) && ip->autype && (pass->alg < ALG_HMAC)) + cf_error(ctx, "Keyed hash algorithms are not allowed, use HMAC algorithms"); } } } static void -ospf_area_finish(void) +ospf_area_finish(struct cf_context *ctx) { - if ((this_area->areaid == 0) && (this_area->type != OPT_E)) - cf_error("Backbone area cannot be stub/NSSA"); + if ((ctx->this_area->areaid == 0) && (ctx->this_area->type != OPT_E)) + cf_error(ctx, "Backbone area cannot be stub/NSSA"); - if (this_area->summary && (this_area->type == OPT_E)) - cf_error("Only stub/NSSA areas can use summary propagation"); + if (ctx->this_area->summary && (ctx->this_area->type == OPT_E)) + cf_error(ctx, "Only stub/NSSA areas can use summary propagation"); - if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary)) - cf_error("Only NSSA areas with summary propagation can use NSSA default route"); + if (ctx->this_area->default_nssa && ((ctx->this_area->type != OPT_N) || ! ctx->this_area->summary)) + cf_error(ctx, "Only NSSA areas with summary propagation can use NSSA default route"); - if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa) - cf_error("Only NSSA default route can use type 2 metric"); + if ((ctx->this_area->default_cost & LSA_EXT3_EBIT) && ! ctx->this_area->default_nssa) + cf_error(ctx, "Only NSSA default route can use type 2 metric"); } static void -ospf_proto_finish(void) +ospf_proto_finish(struct cf_context *ctx) { struct ospf_config *cf = OSPF_CFG; struct ospf_area_config *ac; struct ospf_iface_patt *ic; /* Define default channel */ - if (EMPTY_LIST(this_proto->channels)) + if (EMPTY_LIST(ctx->this_proto->channels)) { - uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6; - channel_config_new(NULL, net_label[net_type], net_type, this_proto); + uint net_type = ctx->this_proto->net_type = ospf_cfg_is_v2(ctx) ? NET_IP4 : NET_IP6; + channel_config_new(ctx, NULL, net_label[net_type], net_type, ctx->this_proto); } /* Propagate global instance ID to interfaces */ @@ -104,9 +106,9 @@ ospf_proto_finish(void) { ic->instance_id = cf->instance_id; ic->instance_id_set = 1; } } - if (ospf_cfg_is_v3()) + if (ospf_cfg_is_v3(ctx)) { - uint ipv4 = (this_proto->net_type == NET_IP4); + uint ipv4 = (ctx->this_proto->net_type == NET_IP4); uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0); /* RFC 5838 - OSPFv3-AF */ @@ -121,22 +123,22 @@ ospf_proto_finish(void) else if (ic->instance_id >= 128) log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id); else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32))) - cf_error("Instance ID %d invalid for given channel type", ic->instance_id); + cf_error(ctx, "Instance ID %d invalid for given channel type", ic->instance_id); } /* RFC 5838 2.8 - vlinks limited to IPv6 unicast */ if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list)) - cf_error("Vlinks not supported in AFs other than IPv6 unicast"); + cf_error(ctx, "Vlinks not supported in AFs other than IPv6 unicast"); } else { if (ipv4 || cf->af_mc) - cf_error("Different channel type"); + cf_error(ctx, "Different channel type"); } } if (EMPTY_LIST(cf->area_list)) - cf_error("No configured areas in OSPF"); + cf_error(ctx, "No configured areas in OSPF"); int areano = 0; int backbone = 0; @@ -153,7 +155,7 @@ ospf_proto_finish(void) cf->abr = areano > 1; /* Route export or NSSA translation (RFC 3101 3.1) */ - cf->asbr = (proto_cf_main_channel(this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr); + cf->asbr = (proto_cf_main_channel(ctx->this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr); if (cf->abr && !backbone) { @@ -167,24 +169,24 @@ ospf_proto_finish(void) } if (!cf->abr && !EMPTY_LIST(cf->vlink_list)) - cf_error("Vlinks cannot be used on single area router"); + cf_error(ctx, "Vlinks cannot be used on single area router"); - if (cf->asbr && (areano == 1) && (this_area->type == 0)) - cf_error("ASBR must be in non-stub area"); + if (cf->asbr && (areano == 1) && (ctx->this_area->type == 0)) + cf_error(ctx, "ASBR must be in non-stub area"); } static inline void -ospf_check_defcost(int cost) +ospf_check_defcost(struct cf_context *ctx, int cost) { if ((cost <= 0) || (cost >= LSINFINITY)) - cf_error("Default cost must be in range 1-%u", LSINFINITY-1); + cf_error(ctx, "Default cost must be in range 1-%u", LSINFINITY-1); } static inline void -ospf_check_auth(void) +ospf_check_auth(struct cf_context *ctx) { - if (ospf_cfg_is_v3()) - cf_error("Plaintext authentication not supported in OSPFv3"); + if (ospf_cfg_is_v3(ctx)) + cf_error(ctx, "Plaintext authentication not supported in OSPFv3"); } @@ -207,7 +209,7 @@ CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838) CF_GRAMMAR -proto: ospf_proto '}' { ospf_proto_finish(); } ; +proto: ospf_proto '}' { ospf_proto_finish(ctx); } ; ospf_variant: OSPF { $$ = 1; } @@ -217,8 +219,8 @@ ospf_variant: ospf_proto_start: proto_start ospf_variant { - this_proto = proto_config_new(&proto_ospf, $1); - this_proto->net_type = $2 ? NET_IP4 : 0; + ctx->this_proto = proto_config_new(ctx, &proto_ospf, $1); + ctx->this_proto->net_type = $2 ? NET_IP4 : 0; init_list(&OSPF_CFG->area_list); init_list(&OSPF_CFG->vlink_list); @@ -242,10 +244,10 @@ ospf_af_mc: ospf_channel_start: net_type ospf_af_mc { /* TODO: change name for multicast channels */ - $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto); + $$ = ctx->this_channel = channel_config_get(ctx, NULL, net_label[$1], $1, ctx->this_proto); /* Save the multicast flag */ - if (this_channel == proto_cf_main_channel(this_proto)) + if (ctx->this_channel == proto_cf_main_channel(ctx->this_proto)) OSPF_CFG->af_mc = $2; }; @@ -253,34 +255,34 @@ ospf_channel: ospf_channel_start channel_opt_list channel_end; ospf_proto_item: proto_item - | ospf_channel { this_proto->net_type = $1->net_type; } + | ospf_channel { ctx->this_proto->net_type = $1->net_type; } | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } - | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); } + | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3(ctx)) cf_error(ctx, "RFC5838 option requires OSPFv3"); } | STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; } | MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; } - | TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); } - | INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); } + | TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error(ctx, "Tick must be greater than zero"); } + | INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error(ctx, "Instance ID must be in range 0-255"); } | ospf_area ; ospf_area_start: AREA idval { - this_area = cfg_allocz(sizeof(struct ospf_area_config)); - add_tail(&OSPF_CFG->area_list, NODE this_area); - this_area->areaid = $2; - this_area->default_cost = OSPF_DEFAULT_STUB_COST; - this_area->type = OPT_E; - this_area->transint = OSPF_DEFAULT_TRANSINT; + ctx->this_area = cfg_allocz(sizeof(struct ospf_area_config)); + add_tail(&OSPF_CFG->area_list, NODE ctx->this_area); + ctx->this_area->areaid = $2; + ctx->this_area->default_cost = OSPF_DEFAULT_STUB_COST; + ctx->this_area->type = OPT_E; + ctx->this_area->transint = OSPF_DEFAULT_TRANSINT; - init_list(&this_area->patt_list); - init_list(&this_area->net_list); - init_list(&this_area->enet_list); - init_list(&this_area->stubnet_list); + init_list(&ctx->this_area->patt_list); + init_list(&ctx->this_area->net_list); + init_list(&ctx->this_area->enet_list); + init_list(&ctx->this_area->stubnet_list); } ; -ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); } +ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(ctx); } ; ospf_area_opts: @@ -289,17 +291,17 @@ ospf_area_opts: ; ospf_area_item: - STUB bool { this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ } - | NSSA { this_area->type = OPT_N; } - | SUMMARY bool { this_area->summary = $2; } - | DEFAULT NSSA bool { this_area->default_nssa = $3; } - | DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); } - | DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); } - | STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); } - | TRANSLATOR bool { this_area->translator = $2; } - | TRANSLATOR STABILITY expr { this_area->transint = $3; } - | NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}' - | EXTERNAL { this_nets = &this_area->enet_list; } '{' pref_list '}' + STUB bool { ctx->this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ } + | NSSA { ctx->this_area->type = OPT_N; } + | SUMMARY bool { ctx->this_area->summary = $2; } + | DEFAULT NSSA bool { ctx->this_area->default_nssa = $3; } + | DEFAULT COST expr { ctx->this_area->default_cost = $3; ospf_check_defcost(ctx, $3); } + | DEFAULT COST2 expr { ctx->this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost(ctx, $3); } + | STUB COST expr { ctx->this_area->default_cost = $3; ospf_check_defcost(ctx, $3); } + | TRANSLATOR bool { ctx->this_area->translator = $2; } + | TRANSLATOR STABILITY expr { ctx->this_area->transint = $3; } + | NETWORKS { ctx->this_nets = &ctx->this_area->net_list; } '{' pref_list '}' + | EXTERNAL { ctx->this_nets = &ctx->this_area->enet_list; } '{' pref_list '}' | STUBNET ospf_stubnet | INTERFACE ospf_iface | ospf_vlink @@ -312,10 +314,10 @@ ospf_stubnet: ospf_stubnet_start: net_ip { - this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config)); - add_tail(&this_area->stubnet_list, NODE this_stubnet); - this_stubnet->prefix = $1; - this_stubnet->cost = COST_D; + ctx->this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config)); + add_tail(&ctx->this_area->stubnet_list, NODE ctx->this_stubnet); + ctx->this_stubnet->prefix = $1; + ctx->this_stubnet->cost = COST_D; } ; @@ -325,14 +327,14 @@ ospf_stubnet_opts: ; ospf_stubnet_item: - HIDDEN bool { this_stubnet->hidden = $2; } - | SUMMARY bool { this_stubnet->summary = $2; } - | COST expr { this_stubnet->cost = $2; } + HIDDEN bool { ctx->this_stubnet->hidden = $2; } + | SUMMARY bool { ctx->this_stubnet->summary = $2; } + | COST expr { ctx->this_stubnet->cost = $2; } ; ospf_vlink: - ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(); } - | ospf_vlink_start ospf_instance_id { ospf_iface_finish(); } + ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(ctx); } + | ospf_vlink_start ospf_instance_id { ospf_iface_finish(ctx); } ; ospf_vlink_opts: @@ -341,25 +343,25 @@ ospf_vlink_opts: ; ospf_vlink_item: - | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); } - | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); } - | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } - | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); } - | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); } - | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); } + | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Hello interval must be in range 1-65535"); } + | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error(ctx, "Retransmit int must be greater than one"); } + | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error(ctx, "Transmit delay must be in range 1-65535"); } + | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error(ctx, "Wait interval must be greater than one"); } + | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error(ctx, "Dead interval must be greater than one"); } + | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error(ctx, "Dead count must be greater than one"); } | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(ctx); } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; } | password_list ; ospf_vlink_start: VIRTUAL LINK idval { - if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone"); - this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); - add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); - OSPF_PATT->voa = this_area->areaid; + if (ctx->this_area->areaid == 0) cf_error(ctx, "Virtual link cannot be in backbone"); + ctx->this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); + add_tail(&OSPF_CFG->vlink_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); + OSPF_PATT->voa = ctx->this_area->areaid; OSPF_PATT->vid = $3; OSPF_PATT->helloint = HELLOINT_D; OSPF_PATT->rxmtint = RXMTINT_D; @@ -367,18 +369,18 @@ ospf_vlink_start: VIRTUAL LINK idval OSPF_PATT->deadc = DEADC_D; OSPF_PATT->type = OSPF_IT_VLINK; init_list(&OSPF_PATT->nbma_list); - reset_passwords(); + reset_passwords(ctx); } ; ospf_iface_item: - COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); } - | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); } - | POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); } - | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); } - | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); } - | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); } - | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); } + COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Cost must be in range 1-65535"); } + | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Hello interval must be in range 1-65535"); } + | POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error(ctx, "Poll int must be greater than zero"); } + | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error(ctx, "Retransmit int must be greater than one"); } + | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error(ctx, "Wait interval must be greater than one"); } + | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error(ctx, "Dead interval must be greater than one"); } + | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error(ctx, "Dead count must be greater than one"); } | TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; } | TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; } | TYPE NONBROADCAST { OSPF_PATT->type = OSPF_IT_NBMA ; } @@ -387,28 +389,28 @@ ospf_iface_item: | TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; } | TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; } | TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; } - | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); } - | PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); } - | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } - | PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error("Priority must be in range 0-255"); } + | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2(ctx)) cf_error(ctx, "Real broadcast option requires OSPFv2"); } + | PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2(ctx)) cf_error(ctx, "PtP netmask option requires OSPFv2"); } + | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error(ctx, "Transmit delay must be in range 1-65535"); } + | PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error(ctx, "Priority must be in range 0-255"); } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STUB bool { OSPF_PATT->stub = $2 ; } | CHECK LINK bool { OSPF_PATT->check_link = $3; } - | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } - | LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); } + | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error(ctx, "ECMP weight must be in range 1-256"); } + | LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3(ctx)) cf_error(ctx, "Link LSA suppression option requires OSPFv3"); } | NEIGHBORS '{' nbma_list '}' | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(ctx); } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; } | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; } | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; } - | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } + | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error(ctx, "Buffer size must be in range 256-65535"); } | TX tos { OSPF_PATT->tx_tos = $2; } | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; } - | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); } + | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error(ctx, "TX length must be in range 256-65535"); } | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } - | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } + | BFD bool { OSPF_PATT->bfd = $2; BFD_CHECK($2); } | password_list ; @@ -421,16 +423,16 @@ pref_item: pref_base pref_opt ';' ; pref_base: net_ip { - this_pref = cfg_allocz(sizeof(struct area_net_config)); - add_tail(this_nets, NODE this_pref); - this_pref->prefix = $1; + ctx->this_pref = cfg_allocz(sizeof(struct area_net_config)); + add_tail(ctx->this_nets, NODE ctx->this_pref); + ctx->this_pref->prefix = $1; } ; pref_opt: /* empty */ - | HIDDEN { this_pref->hidden = 1; } - | TAG expr { this_pref->tag = $2; } + | HIDDEN { ctx->this_pref->hidden = 1; } + | TAG expr { ctx->this_pref->tag = $2; } ; nbma_list: @@ -445,18 +447,18 @@ nbma_eligible: nbma_item: ipa nbma_eligible ';' { - this_nbma = cfg_allocz(sizeof(struct nbma_node)); - add_tail(&OSPF_PATT->nbma_list, NODE this_nbma); - this_nbma->ip=$1; - this_nbma->eligible=$2; + ctx->this_nbma = cfg_allocz(sizeof(struct nbma_node)); + add_tail(&OSPF_PATT->nbma_list, NODE ctx->this_nbma); + ctx->this_nbma->ip=$1; + ctx->this_nbma->eligible=$2; } ; ospf_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); - add_tail(&this_area->patt_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); + add_tail(&ctx->this_area->patt_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); OSPF_PATT->cost = COST_D; OSPF_PATT->helloint = HELLOINT_D; OSPF_PATT->pollint = POLLINT_D; @@ -470,17 +472,17 @@ ospf_iface_start: OSPF_PATT->ptp_netmask = 2; /* not specified */ OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL; OSPF_PATT->tx_priority = sk_priority_control; - reset_passwords(); + reset_passwords(ctx); } ; ospf_instance_id: /* empty */ - | INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); } + | INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error(ctx, "Instance ID must be in range 0-255"); } ; ospf_iface_patt_list: - iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id + iface_patt_list { if (ospf_cfg_is_v3(ctx)) iface_patt_check(ctx); } ospf_instance_id ; ospf_iface_opts: @@ -494,7 +496,7 @@ ospf_iface_opt_list: ; ospf_iface: - ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } + ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(ctx); } ; dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ; @@ -504,29 +506,29 @@ dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUA CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); CF_CLI(SHOW OSPF, optsym, [], [[Show information about OSPF protocol]]) -{ ospf_sh(proto_get_named($3, &proto_ospf)); }; +{ ospf_sh(proto_get_named(ctx, $3, &proto_ospf)); }; CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about OSPF neighbors]]) -{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); }; +{ ospf_sh_neigh(proto_get_named(ctx, $4, &proto_ospf), $5); }; CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [] [\"\"], [[Show information about interface]]) -{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); }; +{ ospf_sh_iface(proto_get_named(ctx, $4, &proto_ospf), $5); }; CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [], [[Show information about OSPF network topology]]) CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [], [[Show information about reachable OSPF network topology]]) -{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); }; +{ ospf_sh_state(proto_get_named(ctx, $4, &proto_ospf), 0, 1); }; CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [], [[Show information about all OSPF network topology]]) -{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); }; +{ ospf_sh_state(proto_get_named(ctx, $5, &proto_ospf), 0, 0); }; CF_CLI_HELP(SHOW OSPF STATE, [all] [], [[Show information about OSPF network state]]) CF_CLI(SHOW OSPF STATE, optsym opttext, [], [[Show information about reachable OSPF network state]]) -{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); }; +{ ospf_sh_state(proto_get_named(ctx, $4, &proto_ospf), 1, 1); }; CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [], [[Show information about all OSPF network state]]) -{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); }; +{ ospf_sh_state(proto_get_named(ctx, $5, &proto_ospf), 1, 0); }; CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]); CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area | link] [type ] [lsid ] [self | router ] [], [[Show content of OSPF LSA database]]) @@ -535,6 +537,7 @@ CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area | link] [type ] [ls lsadb_args: /* empty */ { $$ = cfg_allocz(sizeof(struct lsadb_show_data)); + $$->ctx = ctx; } | lsadb_args GLOBAL { $$ = $1; $$->scope = LSA_SCOPE_AS; } | lsadb_args AREA idval { $$ = $1; $$->scope = LSA_SCOPE_AREA; $$->area = $3; } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 150f519f..7ec3fdc5 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1374,7 +1374,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2) void ospf_sh_lsadb(struct lsadb_show_data *ld) { - struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf); + struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->ctx, ld->name, &proto_ospf); uint num = p->gr->hash_entries; uint i, j; int last_dscope = -1; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index ff55621a..d89ed68c 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -854,6 +854,7 @@ struct ospf_lsreq_header #define SH_ROUTER_SELF 0xffffffff struct lsadb_show_data { + struct cf_context *ctx; /* Config context */ struct symbol *name; /* Protocol to request data from */ u16 type; /* LSA Type, 0 -> all */ u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */ diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y index 18e1d0fc..84fa7a00 100644 --- a/proto/pipe/config.Y +++ b/proto/pipe/config.Y @@ -12,7 +12,7 @@ CF_HDR CF_DEFINES -#define PIPE_CFG ((struct pipe_config *) this_proto) +#define PIPE_CFG ((struct pipe_config *) ctx->this_proto) CF_DECLS @@ -20,19 +20,19 @@ CF_KEYWORDS(PIPE, PEER, TABLE) CF_GRAMMAR -proto: pipe_proto '}' { this_channel = NULL; } ; +proto: pipe_proto '}' { ctx->this_channel = NULL; } ; pipe_proto_start: proto_start PIPE { - this_proto = proto_config_new(&proto_pipe, $1); + ctx->this_proto = proto_config_new(ctx, &proto_pipe, $1); } proto_name { - this_channel = proto_cf_main_channel(this_proto); - if (!this_channel) { - this_channel = channel_config_new(NULL, NULL, 0, this_proto); - this_channel->in_filter = FILTER_ACCEPT; - this_channel->out_filter = FILTER_ACCEPT; + ctx->this_channel = proto_cf_main_channel(ctx->this_proto); + if (!ctx->this_channel) { + ctx->this_channel = channel_config_new(ctx, NULL, NULL, 0, ctx->this_proto); + ctx->this_channel->in_filter = FILTER_ACCEPT; + ctx->this_channel->out_filter = FILTER_ACCEPT; } }; diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 82ccf38a..8cf09e75 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -119,28 +119,28 @@ pipe_reload_routes(struct channel *C) static void -pipe_postconfig(struct proto_config *CF) +pipe_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct pipe_config *cf = (void *) CF; struct channel_config *cc = proto_cf_main_channel(CF); if (!cc->table) - cf_error("Primary routing table not specified"); + cf_error(ctx, "Primary routing table not specified"); if (!cf->peer) - cf_error("Secondary routing table not specified"); + cf_error(ctx, "Secondary routing table not specified"); if (cc->table == cf->peer) - cf_error("Primary table and peer table must be different"); + cf_error(ctx, "Primary table and peer table must be different"); if (cc->table->addr_type != cf->peer->addr_type) - cf_error("Primary table and peer table must have the same type"); + cf_error(ctx, "Primary table and peer table must have the same type"); if (cc->rx_limit.action) - cf_error("Pipe protocol does not support receive limits"); + cf_error(ctx, "Pipe protocol does not support receive limits"); if (cc->in_keep_filtered) - cf_error("Pipe protocol prohibits keeping filtered routes"); + cf_error(ctx, "Pipe protocol prohibits keeping filtered routes"); } static int @@ -197,7 +197,7 @@ pipe_reconfigure(struct proto *P, struct proto_config *CF) } static void -pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED) +pipe_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED) { /* Just a shallow copy, not many items here */ } diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 53715f77..727c8dac 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -9,20 +9,21 @@ CF_HDR #include "proto/radv/radv.h" +CF_CTX + +struct radv_prefix_config *this_radv_prefix; +struct radv_rdnss_config this_radv_rdnss; +struct radv_dnssl_config this_radv_dnssl; +list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */ +u8 radv_mult_val; /* Used by radv_mult for second return value */ + CF_DEFINES -#define RADV_CFG ((struct radv_config *) this_proto) -#define RADV_IFACE ((struct radv_iface_config *) this_ipatt) -#define RADV_PREFIX this_radv_prefix -#define RADV_RDNSS (&this_radv_rdnss) -#define RADV_DNSSL (&this_radv_dnssl) - -static struct radv_prefix_config *this_radv_prefix; -static struct radv_rdnss_config this_radv_rdnss; -static struct radv_dnssl_config this_radv_dnssl; -static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */ -static u8 radv_mult_val; /* Used by radv_mult for second return value */ - +#define RADV_CFG ((struct radv_config *) ctx->this_proto) +#define RADV_IFACE ((struct radv_iface_config *) ctx->this_ipatt) +#define RADV_PREFIX ctx->this_radv_prefix +#define RADV_RDNSS (&ctx->this_radv_rdnss) +#define RADV_DNSSL (&ctx->this_radv_dnssl) CF_DECLS @@ -43,7 +44,7 @@ proto: radv_proto ; radv_proto_start: proto_start RADV { - this_proto = proto_config_new(&proto_radv, $1); + ctx->this_proto = proto_config_new(ctx, &proto_radv, $1); init_list(&RADV_CFG->patt_list); init_list(&RADV_CFG->pref_list); @@ -55,9 +56,9 @@ radv_proto_item: proto_item | proto_channel | INTERFACE radv_iface - | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } - | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } - | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } + | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE ctx->this_radv_prefix); } + | RDNSS { init_list(&ctx->radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &ctx->radv_dns_list); } + | DNSSL { init_list(&ctx->radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &ctx->radv_dns_list); } | TRIGGER net_ip6 { RADV_CFG->trigger = $2; } | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; } ; @@ -73,9 +74,9 @@ radv_proto: radv_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct radv_iface_config)); - add_tail(&RADV_CFG->patt_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct radv_iface_config)); + add_tail(&RADV_CFG->patt_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); init_list(&RADV_IFACE->pref_list); init_list(&RADV_IFACE->rdnss_list); init_list(&RADV_IFACE->dnssl_list); @@ -95,18 +96,18 @@ radv_iface_start: }; radv_iface_item: - MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); } - | MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); } - | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); } + MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error(ctx, "Min RA interval must be at least 3"); } + | MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error(ctx, "Max RA interval must be in range 4-1800"); } + | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error(ctx, "Min delay must be positive"); } | MANAGED bool { RADV_IFACE->managed = $2; } | OTHER CONFIG bool { RADV_IFACE->other_config = $3; } | LINK MTU expr { RADV_IFACE->link_mtu = $3; } - | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); } + | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error(ctx, "Reachable time must be in range 0-3600000"); } | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; } - | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); } + | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error(ctx, "Current hop limit must be in range 0-255"); } | DEFAULT LIFETIME expr radv_sensitive { RADV_IFACE->default_lifetime = $3; - if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000"); + if ($3 > 9000) cf_error(ctx, "Default lifetime must be in range 0-9000"); if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4; } | ROUTE LIFETIME expr radv_sensitive { @@ -117,9 +118,9 @@ radv_iface_item: | ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; } | PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; } | ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; } - | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } - | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } - | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } + | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE ctx->this_radv_prefix); } + | RDNSS { init_list(&ctx->radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &ctx->radv_dns_list); } + | DNSSL { init_list(&ctx->radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &ctx->radv_dns_list); } | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; } | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } ; @@ -150,19 +151,19 @@ radv_iface_finish: if ((ic->min_ra_int > 3) && (ic->min_ra_int > (ic->max_ra_int * 3 / 4))) - cf_error("Min RA interval must be at most 3/4 * Max RA interval"); + cf_error(ctx, "Min RA interval must be at most 3/4 * Max RA interval"); if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int)) - cf_error("Default lifetime must be either 0 or at least Max RA interval"); + cf_error(ctx, "Default lifetime must be either 0 or at least Max RA interval"); if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int)) - cf_error("Route lifetime must be either 0 or at least Max RA interval"); + cf_error(ctx, "Route lifetime must be either 0 or at least Max RA interval"); if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int)) - cf_error("Prefix linger time must be either 0 or at least Max RA interval"); + cf_error(ctx, "Prefix linger time must be either 0 or at least Max RA interval"); if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int)) - cf_error("Route linger time must be either 0 or at least Max RA interval"); + cf_error(ctx, "Route linger time must be either 0 or at least Max RA interval"); RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time); }; @@ -184,7 +185,7 @@ radv_iface: radv_prefix_start: net_ip6 { - this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config)); + ctx->this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config)); RADV_PREFIX->prefix = *(net_addr_ip6 *) &($1); RADV_PREFIX->onlink = 1; @@ -210,10 +211,10 @@ radv_prefix_item: radv_prefix_finish: { if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime) - cf_error("Preferred lifetime must be at most Valid lifetime"); + cf_error(ctx, "Preferred lifetime must be at most Valid lifetime"); if (RADV_PREFIX->valid_lifetime_sensitive > RADV_PREFIX->preferred_lifetime_sensitive) - cf_error("Valid lifetime sensitive requires that Preferred lifetime is sensitive too"); + cf_error(ctx, "Valid lifetime sensitive requires that Preferred lifetime is sensitive too"); }; radv_prefix_opts: @@ -234,7 +235,7 @@ radv_prefix: radv_rdnss_node: ipa { struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config)); - add_tail(&radv_dns_list, NODE cf); + add_tail(&ctx->radv_dns_list, NODE cf); cf->server = $1; cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; @@ -248,16 +249,16 @@ radv_rdnss_start: radv_rdnss_item: | NS radv_rdnss_node - | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; } + | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = ctx->radv_mult_val; } ; radv_rdnss_finish: { - if (EMPTY_LIST(radv_dns_list)) - cf_error("No nameserver in RDNSS section"); + if (EMPTY_LIST(ctx->radv_dns_list)) + cf_error(ctx, "No nameserver in RDNSS section"); struct radv_rdnss_config *cf; - WALK_LIST(cf, radv_dns_list) + WALK_LIST(cf, ctx->radv_dns_list) { cf->lifetime = RADV_RDNSS->lifetime; cf->lifetime_mult = RADV_RDNSS->lifetime_mult; @@ -278,13 +279,13 @@ radv_rdnss: radv_dnssl_node: TEXT { struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config)); - add_tail(&radv_dns_list, NODE cf); + add_tail(&ctx->radv_dns_list, NODE cf); cf->domain = $1; cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; if (radv_process_domain(cf) < 0) - cf_error("Invalid domain dame"); + cf_error(ctx, "Invalid domain dame"); }; radv_dnssl_start: @@ -295,16 +296,16 @@ radv_dnssl_start: radv_dnssl_item: | DOMAIN radv_dnssl_node - | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; } + | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = ctx->radv_mult_val; } ; radv_dnssl_finish: { - if (EMPTY_LIST(radv_dns_list)) - cf_error("No domain in DNSSL section"); + if (EMPTY_LIST(ctx->radv_dns_list)) + cf_error(ctx, "No domain in DNSSL section"); struct radv_dnssl_config *cf; - WALK_LIST(cf, radv_dns_list) + WALK_LIST(cf, ctx->radv_dns_list) { cf->lifetime = RADV_DNSSL->lifetime; cf->lifetime_mult = RADV_DNSSL->lifetime_mult; @@ -323,8 +324,8 @@ radv_dnssl: radv_mult: - expr { $$ = $1; radv_mult_val = 0; } - | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); } + expr { $$ = $1; ctx->radv_mult_val = 0; } + | MULT expr { $$ = 0; ctx->radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error(ctx, "Multiplier must be in range 1-254"); } ; radv_sensitive: diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 389f598c..ed70501b 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -563,13 +563,13 @@ radv_check_active(struct radv_proto *p) } static void -radv_postconfig(struct proto_config *CF) +radv_postconfig(struct cf_context *ctx, struct proto_config *CF) { // struct radv_config *cf = (void *) CF; /* Define default channel */ if (EMPTY_LIST(CF->channels)) - channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF); + channel_config_new(ctx, NULL, net_label[NET_IP6], NET_IP6, CF); } static struct proto * @@ -705,7 +705,7 @@ radv_reconfigure(struct proto *P, struct proto_config *CF) } static void -radv_copy_config(struct proto_config *dest, struct proto_config *src) +radv_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src) { struct radv_config *d = (struct radv_config *) dest; struct radv_config *s = (struct radv_config *) src; @@ -714,7 +714,7 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src) init_list(&d->patt_list); /* We copy pref_list, shallow copy suffices */ - cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config)); + cf_copy_list(ctx, &d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config)); } static void diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 172299d0..71dfedd7 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -16,17 +16,17 @@ CF_HDR CF_DEFINES -#define RIP_CFG ((struct rip_config *) this_proto) -#define RIP_IFACE ((struct rip_iface_config *) this_ipatt) +#define RIP_CFG ((struct rip_config *) ctx->this_proto) +#define RIP_IFACE ((struct rip_iface_config *) ctx->this_ipatt) -static inline int rip_cfg_is_v2(void) { return RIP_CFG->rip2; } -static inline int rip_cfg_is_ng(void) { return ! RIP_CFG->rip2; } +static inline int rip_cfg_is_v2(struct cf_context *ctx) { return RIP_CFG->rip2; } +static inline int rip_cfg_is_ng(struct cf_context *ctx) { return ! RIP_CFG->rip2; } static inline void -rip_check_auth(void) +rip_check_auth(struct cf_context *ctx) { - if (rip_cfg_is_ng()) - cf_error("Authentication not supported in RIPng"); + if (rip_cfg_is_ng(ctx)) + cf_error(ctx, "Authentication not supported in RIPng"); } @@ -51,8 +51,8 @@ rip_variant: rip_proto_start: proto_start rip_variant { - this_proto = proto_config_new(&proto_rip, $1); - this_proto->net_type = $2 ? NET_IP4 : NET_IP6; + ctx->this_proto = proto_config_new(ctx, &proto_rip, $1); + ctx->this_proto->net_type = $2 ? NET_IP4 : NET_IP6; init_list(&RIP_CFG->patt_list); RIP_CFG->rip2 = $2; @@ -82,21 +82,21 @@ rip_proto: rip_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct rip_iface_config)); - add_tail(&RIP_CFG->patt_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); - reset_passwords(); + ctx->this_ipatt = cfg_allocz(sizeof(struct rip_iface_config)); + add_tail(&RIP_CFG->patt_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); + reset_passwords(ctx); RIP_IFACE->metric = 1; - RIP_IFACE->port = rip_cfg_is_v2() ? RIP_PORT : RIP_NG_PORT; - RIP_IFACE->version = rip_cfg_is_v2() ? RIP_V2 : RIP_V1; + RIP_IFACE->port = rip_cfg_is_v2(ctx) ? RIP_PORT : RIP_NG_PORT; + RIP_IFACE->version = rip_cfg_is_v2(ctx) ? RIP_V2 : RIP_V1; RIP_IFACE->split_horizon = 1; RIP_IFACE->poison_reverse = 1; RIP_IFACE->check_zero = 1; RIP_IFACE->check_link = 1; - RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1; - RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0; - RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0; + RIP_IFACE->ttl_security = rip_cfg_is_v2(ctx) ? 0 : 1; + RIP_IFACE->rx_buffer = rip_cfg_is_v2(ctx) ? RIP_MAX_PKT_LENGTH : 0; + RIP_IFACE->tx_length = rip_cfg_is_v2(ctx) ? RIP_MAX_PKT_LENGTH : 0; RIP_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL; RIP_IFACE->tx_priority = sk_priority_control; RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME; @@ -108,10 +108,10 @@ rip_iface_finish: { /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */ if (!RIP_IFACE->mode) - RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ? + RIP_IFACE->mode = (rip_cfg_is_v2(ctx) && (RIP_IFACE->version == RIP_V1)) ? RIP_IM_BROADCAST : RIP_IM_MULTICAST; - RIP_IFACE->passwords = get_passwords(); + RIP_IFACE->passwords = get_passwords(ctx); if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords) log(L_WARN "Authentication and password options should be used together"); @@ -122,7 +122,7 @@ rip_iface_finish: WALK_LIST(pass, *RIP_IFACE->passwords) { if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO)) - cf_error("Password algorithm option requires cryptographic authentication"); + cf_error(ctx, "Password algorithm option requires cryptographic authentication"); /* Set default crypto algorithm (MD5) */ if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO)) @@ -135,34 +135,34 @@ rip_iface_finish: }; rip_iface_item: - METRIC expr { RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error("Metric must be in range 1-255"); } + METRIC expr { RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error(ctx, "Metric must be in range 1-255"); } | MODE MULTICAST { RIP_IFACE->mode = RIP_IM_MULTICAST; } - | MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); } + | MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng(ctx)) cf_error(ctx, "Broadcast not supported in RIPng"); } | PASSIVE bool { RIP_IFACE->passive = $2; } - | ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); } - | PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); } + | ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2(ctx)) cf_error(ctx, "IP address version mismatch"); } + | PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid port number"); } | VERSION expr { RIP_IFACE->version = $2; - if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng"); - if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error("Unsupported version"); + if (rip_cfg_is_ng(ctx)) cf_error(ctx, "Version not supported in RIPng"); + if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error(ctx, "Unsupported version"); } | VERSION ONLY bool { RIP_IFACE->version_only = $3; } | SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; } | POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; } | CHECK ZERO bool { RIP_IFACE->check_zero = $3; } - | UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); } - | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); } - | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); } - | ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } - | RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); } - | TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); } + | UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error(ctx, "Update time must be positive"); } + | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error(ctx, "Timeout time must be positive"); } + | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error(ctx, "Garbage time must be positive"); } + | ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error(ctx, "ECMP weight must be in range 1-256"); } + | RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "RX length must be in range 256-65535"); } + | TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "TX length must be in range 256-65535"); } | TX tos { RIP_IFACE->tx_tos = $2; } | TX PRIORITY expr { RIP_IFACE->tx_priority = $3; } | TTL SECURITY bool { RIP_IFACE->ttl_security = $3; } | TTL SECURITY TX ONLY { RIP_IFACE->ttl_security = 2; } | CHECK LINK bool { RIP_IFACE->check_link = $3; } - | BFD bool { RIP_IFACE->bfd = $2; cf_check_bfd($2); } - | AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(); } - | password_list { rip_check_auth(); } + | BFD bool { RIP_IFACE->bfd = $2; BFD_CHECK($2); } + | AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(ctx); } + | password_list { rip_check_auth(ctx); } ; rip_auth: @@ -192,10 +192,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG) CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); CF_CLI(SHOW RIP INTERFACES, optsym opttext, [] [\"\"], [[Show information about RIP interfaces]]) -{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); }; +{ rip_show_interfaces(proto_get_named(ctx, $4, &proto_rip), $5); }; CF_CLI(SHOW RIP NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about RIP neighbors]]) -{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); }; +{ rip_show_neighbors(proto_get_named(ctx, $4, &proto_rip), $5); }; CF_CODE diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 2838d425..af224477 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -1062,13 +1062,13 @@ rip_rte_same(struct rte *new, struct rte *old) static void -rip_postconfig(struct proto_config *CF) +rip_postconfig(struct cf_context *ctx, struct proto_config *CF) { // struct rip_config *cf = (void *) CF; /* Define default channel */ if (EMPTY_LIST(CF->channels)) - channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF); + channel_config_new(ctx, NULL, net_label[CF->net_type], CF->net_type, CF); } static struct proto * diff --git a/proto/rpki/config.Y b/proto/rpki/config.Y index a88a29a1..00df2f1d 100644 --- a/proto/rpki/config.Y +++ b/proto/rpki/config.Y @@ -12,21 +12,21 @@ CF_HDR CF_DEFINES -#define RPKI_CFG ((struct rpki_config *) this_proto) +#define RPKI_CFG ((struct rpki_config *) ctx->this_proto) #define RPKI_TR_SSH_CFG ((struct rpki_tr_ssh_config *) RPKI_CFG->tr_config.spec) static void -rpki_check_unused_hostname(void) +rpki_check_unused_hostname(struct cf_context *ctx) { if (RPKI_CFG->hostname != NULL) - cf_error("Only one cache server per protocol allowed"); + cf_error(ctx, "Only one cache server per protocol allowed"); } static void -rpki_check_unused_transport(void) +rpki_check_unused_transport(struct cf_context *ctx) { if (RPKI_CFG->tr_config.spec != NULL) - cf_error("At the most one transport per protocol allowed"); + cf_error(ctx, "At the most one transport per protocol allowed"); } CF_DECLS @@ -41,13 +41,13 @@ CF_GRAMMAR proto: rpki_proto ; rpki_proto_start: proto_start RPKI { - this_proto = proto_config_new(&proto_rpki, $1); + ctx->this_proto = proto_config_new(ctx, &proto_rpki, $1); RPKI_CFG->retry_interval = RPKI_RETRY_INTERVAL; RPKI_CFG->refresh_interval = RPKI_REFRESH_INTERVAL; RPKI_CFG->expire_interval = RPKI_EXPIRE_INTERVAL; }; -rpki_proto: rpki_proto_start proto_name '{' rpki_proto_opts '}' { rpki_check_config(RPKI_CFG); }; +rpki_proto: rpki_proto_start proto_name '{' rpki_proto_opts '}' { rpki_check_config(ctx, RPKI_CFG); }; rpki_proto_opts: /* empty */ @@ -63,19 +63,19 @@ rpki_proto_item: | TRANSPORT rpki_transport | REFRESH rpki_keep_interval expr { if (rpki_check_refresh_interval($3)) - cf_error(rpki_check_refresh_interval($3)); + cf_error(ctx, rpki_check_refresh_interval($3)); RPKI_CFG->refresh_interval = $3; RPKI_CFG->keep_refresh_interval = $2; } | RETRY rpki_keep_interval expr { if (rpki_check_retry_interval($3)) - cf_error(rpki_check_retry_interval($3)); + cf_error(ctx, rpki_check_retry_interval($3)); RPKI_CFG->retry_interval = $3; RPKI_CFG->keep_retry_interval = $2; } | EXPIRE rpki_keep_interval expr { if (rpki_check_expire_interval($3)) - cf_error(rpki_check_expire_interval($3)); + cf_error(ctx, rpki_check_expire_interval($3)); RPKI_CFG->expire_interval = $3; RPKI_CFG->keep_expire_interval = $2; } @@ -86,15 +86,15 @@ rpki_keep_interval: | KEEP { $$ = 1; } ; -rpki_proto_item_port: PORT expr { check_u16($2); RPKI_CFG->port = $2; }; +rpki_proto_item_port: PORT expr { check_u16(ctx, $2); RPKI_CFG->port = $2; }; rpki_cache_addr: text { - rpki_check_unused_hostname(); + rpki_check_unused_hostname(ctx); RPKI_CFG->hostname = $1; } | ipa { - rpki_check_unused_hostname(); + rpki_check_unused_hostname(ctx); RPKI_CFG->ip = $1; /* Ensure hostname is filled */ char *hostname = cfg_allocz(sizeof(INET6_ADDRSTRLEN + 1)); @@ -110,14 +110,14 @@ rpki_transport: rpki_transport_tcp_init: { - rpki_check_unused_transport(); + rpki_check_unused_transport(ctx); RPKI_CFG->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_tcp_config)); RPKI_CFG->tr_config.type = RPKI_TR_TCP; }; rpki_transport_ssh_init: { - rpki_check_unused_transport(); + rpki_check_unused_transport(ctx); RPKI_CFG->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_ssh_config)); RPKI_CFG->tr_config.type = RPKI_TR_SSH; }; @@ -136,7 +136,7 @@ rpki_transport_ssh_item: rpki_transport_ssh_check: { if (RPKI_TR_SSH_CFG->user == NULL) - cf_error("User must be set"); + cf_error(ctx, "User must be set"); }; CF_CODE diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 36097dc5..347eecbf 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -866,19 +866,19 @@ rpki_show_proto_info(struct proto *P) * This function is called at the end of parsing RPKI protocol configuration. */ void -rpki_check_config(struct rpki_config *cf) +rpki_check_config(struct cf_context *ctx, struct rpki_config *cf) { /* Do not check templates at all */ if (cf->c.class == SYM_TEMPLATE) return; if (ipa_zero(cf->ip) && cf->hostname == NULL) - cf_error("IP address or hostname of cache server must be set"); + cf_error(ctx, "IP address or hostname of cache server must be set"); /* Set default transport type */ if (cf->tr_config.spec == NULL) { - cf->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_tcp_config)); + cf->tr_config.spec = cf_allocz(ctx, sizeof(struct rpki_tr_tcp_config)); cf->tr_config.type = RPKI_TR_TCP; } @@ -897,15 +897,15 @@ rpki_check_config(struct rpki_config *cf) } static void -rpki_postconfig(struct proto_config *CF) +rpki_postconfig(struct cf_context *ctx, struct proto_config *CF) { /* Define default channel */ if (EMPTY_LIST(CF->channels)) - channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF); + channel_config_new(ctx, NULL, net_label[CF->net_type], CF->net_type, CF); } static void -rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED) +rpki_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED) { /* FIXME: Should copy transport */ } diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h index 8972b33a..bb694f90 100644 --- a/proto/rpki/rpki.h +++ b/proto/rpki/rpki.h @@ -127,7 +127,7 @@ struct rpki_config { u8 keep_expire_interval:1; /* Do not overwrite expire interval by cache server update */ }; -void rpki_check_config(struct rpki_config *cf); +void rpki_check_config(struct cf_context *ctx, struct rpki_config *cf); /* diff --git a/proto/static/config.Y b/proto/static/config.Y index d7a02961..067ac0d1 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -10,35 +10,38 @@ CF_HDR #include "proto/static/static.h" +CF_CTX + +struct static_route *this_srt, *this_snh; +struct f_inst **this_srt_last_cmd; + CF_DEFINES -#define STATIC_CFG ((struct static_config *) this_proto) -static struct static_route *this_srt, *this_snh; -static struct f_inst **this_srt_last_cmd; +#define STATIC_CFG ((struct static_config *) ctx->this_proto) static struct static_route * -static_nexthop_new(void) +static_nexthop_new(struct cf_context *ctx) { - struct static_route *nh = this_srt; + struct static_route *nh = ctx->this_srt; - if (this_snh) + if (ctx->this_snh) { /* Additional next hop */ nh = cfg_allocz(sizeof(struct static_route)); - nh->net = this_srt->net; - this_snh->mp_next = nh; + nh->net = ctx->this_srt->net; + ctx->this_snh->mp_next = nh; } nh->dest = RTD_UNICAST; - nh->mp_head = this_srt; + nh->mp_head = ctx->this_srt; return nh; }; static void -static_route_finish(void) +static_route_finish(struct cf_context *ctx) { - if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest) - cf_error("Unexpected or missing nexthop/type"); + if (net_type_match(ctx->this_srt->net, NB_DEST) == !ctx->this_srt->dest) + cf_error(ctx, "Unexpected or missing nexthop/type"); } CF_DECLS @@ -53,14 +56,14 @@ proto: static_proto '}' ; static_proto_start: proto_start STATIC { - this_proto = proto_config_new(&proto_static, $1); + ctx->this_proto = proto_config_new(ctx, &proto_static, $1); init_list(&STATIC_CFG->routes); }; static_proto: static_proto_start proto_name '{' | static_proto proto_item ';' - | static_proto proto_channel ';' { this_proto->net_type = $2->net_type; } + | static_proto proto_channel ';' { ctx->this_proto->net_type = $2->net_type; } | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } | static_proto IGP TABLE rtable ';' { if ($4->addr_type == NET_IP4) @@ -68,34 +71,34 @@ static_proto: else if ($4->addr_type == NET_IP6) STATIC_CFG->igp_table_ip6 = $4; else - cf_error("Incompatible IGP table type"); + cf_error(ctx, "Incompatible IGP table type"); } - | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } + | static_proto stat_route stat_route_opt_list ';' { static_route_finish(ctx); } ; stat_nexthop: VIA ipa ipa_scope { - this_snh = static_nexthop_new(); - this_snh->via = $2; - this_snh->iface = $3; + ctx->this_snh = static_nexthop_new(ctx); + ctx->this_snh->via = $2; + ctx->this_snh->iface = $3; } | VIA TEXT { - this_snh = static_nexthop_new(); - this_snh->via = IPA_NONE; - this_snh->iface = if_get_by_name($2); + ctx->this_snh = static_nexthop_new(ctx); + ctx->this_snh->via = IPA_NONE; + ctx->this_snh->iface = if_get_by_name($2); } | stat_nexthop MPLS label_stack { - this_snh->mls = $3; + ctx->this_snh->mls = $3; } | stat_nexthop ONLINK bool { - this_snh->onlink = $3; + ctx->this_snh->onlink = $3; } | stat_nexthop WEIGHT expr { - this_snh->weight = $3 - 1; - if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); + ctx->this_snh->weight = $3 - 1; + if (($3<1) || ($3>256)) cf_error(ctx, "Weight must be in range 1-256"); } | stat_nexthop BFD bool { - this_snh->use_bfd = $3; cf_check_bfd($3); + ctx->this_snh->use_bfd = $3; BFD_CHECK($3); } ; @@ -105,36 +108,36 @@ stat_nexthops: ; stat_route0: ROUTE net_any { - this_srt = cfg_allocz(sizeof(struct static_route)); - add_tail(&STATIC_CFG->routes, &this_srt->n); - this_srt->net = $2; - this_srt_last_cmd = &(this_srt->cmds); - this_srt->mp_next = NULL; - this_snh = NULL; + ctx->this_srt = cfg_allocz(sizeof(struct static_route)); + add_tail(&STATIC_CFG->routes, &ctx->this_srt->n); + ctx->this_srt->net = $2; + ctx->this_srt_last_cmd = &(ctx->this_srt->cmds); + ctx->this_srt->mp_next = NULL; + ctx->this_snh = NULL; } ; stat_route: stat_route0 stat_nexthops | stat_route0 RECURSIVE ipa { - this_srt->dest = RTDX_RECURSIVE; - this_srt->via = $3; + ctx->this_srt->dest = RTDX_RECURSIVE; + ctx->this_srt->via = $3; } | stat_route0 RECURSIVE ipa MPLS label_stack { - this_srt->dest = RTDX_RECURSIVE; - this_srt->via = $3; - this_srt->mls = $5; + ctx->this_srt->dest = RTDX_RECURSIVE; + ctx->this_srt->via = $3; + ctx->this_srt->mls = $5; } - | stat_route0 { this_srt->dest = RTD_NONE; } - | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } - | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } - | stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; } - | stat_route0 UNREACHABLE { this_srt->dest = RTD_UNREACHABLE; } - | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } + | stat_route0 { ctx->this_srt->dest = RTD_NONE; } + | stat_route0 DROP { ctx->this_srt->dest = RTD_BLACKHOLE; } + | stat_route0 REJECT { ctx->this_srt->dest = RTD_UNREACHABLE; } + | stat_route0 BLACKHOLE { ctx->this_srt->dest = RTD_BLACKHOLE; } + | stat_route0 UNREACHABLE { ctx->this_srt->dest = RTD_UNREACHABLE; } + | stat_route0 PROHIBIT { ctx->this_srt->dest = RTD_PROHIBIT; } ; stat_route_item: - cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); } + cmd { *ctx->this_srt_last_cmd = $1; ctx->this_srt_last_cmd = &($1->next); } ; stat_route_opts: @@ -149,7 +152,7 @@ stat_route_opt_list: CF_CLI(SHOW STATIC, optsym, [], [[Show details of static protocol]]) -{ static_show(proto_get_named($3, &proto_static)); } ; +{ static_show(proto_get_named(ctx, $3, &proto_static)); } ; CF_CODE diff --git a/proto/static/static.c b/proto/static/static.c index 40096c16..7af90342 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -360,13 +360,13 @@ static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED) static void -static_postconfig(struct proto_config *CF) +static_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct static_config *cf = (void *) CF; struct static_route *r; if (EMPTY_LIST(CF->channels)) - cf_error("Channel not specified"); + cf_error(ctx, "Channel not specified"); struct channel_config *cc = proto_cf_main_channel(CF); @@ -380,7 +380,7 @@ static_postconfig(struct proto_config *CF) WALK_LIST(r, cf->routes) if (r->net && (r->net->type != CF->net_type)) - cf_error("Route %N incompatible with channel type", r->net); + cf_error(ctx, "Route %N incompatible with channel type", r->net); } static struct proto * @@ -573,7 +573,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF) } static void -static_copy_config(struct proto_config *dest, struct proto_config *src) +static_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src) { struct static_config *d = (struct static_config *) dest; struct static_config *s = (struct static_config *) src; @@ -588,7 +588,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src) for (snh = srt; snh; snh = snh->mp_next) { - dnh = cfg_alloc(sizeof(struct static_route)); + dnh = cf_alloc(ctx, sizeof(struct static_route)); memcpy(dnh, snh, sizeof(struct static_route)); if (!drt) diff --git a/sysdep/bsd/krt-sock.Y b/sysdep/bsd/krt-sock.Y index 8581bd43..9d0a3d8f 100644 --- a/sysdep/bsd/krt-sock.Y +++ b/sysdep/bsd/krt-sock.Y @@ -19,9 +19,9 @@ kern_proto: kern_proto kern_sys_item ';' ; kern_sys_item: KERNEL TABLE expr { if ($3 && (krt_max_tables == 1)) - cf_error("Multiple kernel routing tables not supported"); + cf_error(ctx, "Multiple kernel routing tables not supported"); if ($3 >= krt_max_tables) - cf_error("Kernel table id must be in range 0-%u", krt_max_tables - 1); + cf_error(ctx, "Kernel table id must be in range 0-%u", krt_max_tables - 1); THIS_KRT->sys.table_id = $3; } diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile index f592399c..b74cfc47 100644 --- a/sysdep/unix/Makefile +++ b/sysdep/unix/Makefile @@ -1,4 +1,4 @@ -src := io.c krt.c log.c main.c random.c +src := io.c krt.c log.c main.c random.c conf.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/sysdep/unix/conf.c b/sysdep/unix/conf.c new file mode 100644 index 00000000..571909b2 --- /dev/null +++ b/sysdep/unix/conf.c @@ -0,0 +1,423 @@ +/* + * BIRD Internet Routing Daemon -- Unix Config Reader + * + * (c) 1998--2000 Martin Mares + * (c) 2018 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nest/bird.h" +#include "conf/conf.h" +#include "conf/parser.h" + +#ifdef PATH_IPROUTE_DIR + +static inline void +add_num_const(struct cf_context *ctx, char *name, int val) +{ + struct symbol *s = cf_get_symbol(ctx, name); + s->class = SYM_CONSTANT | T_INT; + s->def = cfg_allocz(sizeof(struct f_val)); + SYM_TYPE(s) = T_INT; + SYM_VAL(s).i = val; +} + +/* the code of read_iproute_table() is based on + rtnl_tab_initialize() from iproute2 package */ +static void +read_iproute_table(struct cf_context *ctx, char *file, char *prefix, int max) +{ + char buf[512], namebuf[512]; + char *name; + int val; + FILE *fp; + + strcpy(namebuf, prefix); + name = namebuf + strlen(prefix); + + fp = fopen(file, "r"); + if (!fp) + return; + + while (fgets(buf, sizeof(buf), fp)) + { + char *p = buf; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p == '#' || *p == '\n' || *p == 0) + continue; + + if (sscanf(p, "0x%x %s\n", &val, name) != 2 && + sscanf(p, "0x%x %s #", &val, name) != 2 && + sscanf(p, "%d %s\n", &val, name) != 2 && + sscanf(p, "%d %s #", &val, name) != 2) + continue; + + if (val < 0 || val > max) + continue; + + for(p = name; *p; p++) + if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_')) + *p = '_'; + + add_num_const(ctx, namebuf, val); + } + + fclose(fp); +} + +#endif // PATH_IPROUTE_DIR + + +char *config_name = PATH_CONFIG_FILE; + +void +sysdep_preconfig(struct cf_context *ctx) +{ + init_list(&ctx->new_config->logfiles); + + ctx->new_config->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT; + ctx->new_config->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING; + +#ifdef PATH_IPROUTE_DIR + read_iproute_table(ctx, PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256); + read_iproute_table(ctx, PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256); + read_iproute_table(ctx, PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256); + read_iproute_table(ctx, PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256); +#endif +} + +int +sysdep_commit(struct config *new, struct config *old UNUSED) +{ + log_switch(debug_flag, &new->logfiles, new->syslog_name); + return 0; +} + +struct unix_conf_order { + struct conf_order co; + struct unix_ifs *ifs; +}; + +struct unix_ifs { + struct unix_ifs *up; /* Who included this file */ + struct unix_ifs *next; /* Next file to include */ + + struct conf_state *state; /* Appropriate conf_state */ + int fd; /* File descriptor */ + byte depth; /* Include depth remaining, 0 = cannot include */ +}; + +static int +unix_cf_read(struct conf_order *co, byte *dest, uint len) +{ + struct unix_conf_order *uco = (struct unix_conf_order *) co; + + ASSERT(uco->ifs->state == co->state); + + if (uco->ifs->fd == -1) + uco->ifs->fd = open(co->state->name, O_RDONLY); + + if (uco->ifs->fd < 0) + if (uco->ifs->up) + { + const char *fn = co->state->name; + co->state = uco->ifs->up->state; /* We want to raise this error in the parent file */ + cf_error(co->ctx, "Unable to open included file %s: %m", fn); + } + else + cf_error(co->ctx, "Unable to open configuration file %s: %m", co->state->name); + + int l = read(uco->ifs->fd, dest, len); + if (l < 0) + cf_error(co->ctx, "Read error: %m"); + return l; +} + +static void +unix_cf_include(struct conf_order *co, char *name, uint len) +{ + struct unix_conf_order *uco = (struct unix_conf_order *) co; + + if (!uco->ifs) + cf_error(co->ctx, "Max include depth reached"); + + byte new_depth = uco->ifs->depth - 1; + + /* Includes are relative to the current file unless the path is absolute. + * Joining the current file dirname with the include relative path. */ + char *patt; + if (*name != '/') + { + /* dlen is upper bound of current file dirname length */ + int dlen = strlen(co->state->name); + char *dir = alloca(dlen + 1); + patt = alloca(dlen + len + 2); + + /* dirname() may overwrite its argument */ + memcpy(dir, co->state->name, dlen + 1); + sprintf(patt, "%s/%s", dirname(dir), name); + } + else + patt = name; + + /* Skip globbing if there are no wildcards, mainly to get proper + response when the included config file is missing */ + if (!strpbrk(name, "?*[")) + { + struct unix_ifs *uifs = cf_alloc(co->ctx, sizeof(struct unix_ifs)); + + *uifs = (struct unix_ifs) { + .next = uco->ifs, + .up = uco->ifs, + .state = cf_new_state(co->ctx, patt), + .fd = -1, + .depth = new_depth, + }; + + co->state = uifs->state; + uco->ifs = uifs; + + return; + } + + /* Expand the pattern */ + /* FIXME: glob() is not completely thread-safe, see the manpage */ + glob_t g = {}; + int rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g); + if (rv == GLOB_ABORTED) + cf_error(co->ctx, "Unable to match pattern %s: %m", patt); + if ((rv != 0) || (g.gl_pathc <= 0)) + return; + + /* + * Now we put all found files to ifs stack in reverse order, they + * will be activated and processed in order as ifs stack is popped + * by pop_ifs() and enter_ifs() in check_eof(). + */ + struct unix_ifs *last_uifs = uco->ifs; + for (int i = g.gl_pathc - 1; i >= 0; i--) + { + char *fname = g.gl_pathv[i]; + struct stat fs; + + if (stat(fname, &fs) < 0) + { + globfree(&g); + cf_error(co->ctx, "Unable to stat included file %s: %m", fname); + } + + if (fs.st_mode & S_IFDIR) + continue; + + /* Prepare new stack item */ + struct unix_ifs *uifs = cf_alloc(co->ctx, sizeof(struct unix_ifs)); + + *uifs = (struct unix_ifs) { + .next = last_uifs, + .up = uco->ifs, + .state = cf_new_state(co->ctx, fname), + .fd = -1, + .depth = new_depth, + }; + + last_uifs = uifs; + } + + globfree(&g); + + co->state = last_uifs->state; + uco->ifs = last_uifs; + + return; +} + +static int +unix_cf_outclude(struct conf_order *co) +{ + struct unix_conf_order *uco = (struct unix_conf_order *) co; + + close(uco->ifs->fd); + cf_free_state(co->ctx, uco->ifs->state); + + /* No more files to read */ + if (!uco->ifs->next) + return 1; + + uco->ifs = uco->ifs->next; + co->state = uco->ifs->state; + return 0; +} + +#define MAX_INCLUDE_DEPTH 8 + +typedef void (*cf_error_type)(struct conf_order *order, const char *msg, va_list args); + +static struct config * +unix_read_config(char *name, cf_error_type arg_cf_error) +{ + struct conf_state state = { .name = name }; + + struct unix_ifs uifs = { + .state = &state, + .depth = MAX_INCLUDE_DEPTH, + .fd = -1, + }; + + struct unix_conf_order uco = { + .co = { + .cf_read_hook = unix_cf_read, + .cf_include = unix_cf_include, + .cf_outclude = unix_cf_outclude, + .cf_error = arg_cf_error, + .state = &state, + }, + .ifs = &uifs, + }; + + if (config_parse(&uco.co)) + return uco.co.new_config; + else + return NULL; +} + +static void +unix_cf_error_die(struct conf_order *order, const char *msg, va_list args) +{ + die("%s, line %u: %V", order->state->name, order->state->lino, msg, &args); +} + +struct config * +read_config(void) +{ + return unix_read_config(config_name, unix_cf_error_die); +} + +static void +unix_cf_error_log(struct conf_order *order, const char *msg, va_list args) +{ + log(L_ERR "%s, line %u: %V", order->state->name, order->state->lino, msg, &args); +} + +void +async_config(void) +{ + log(L_INFO "Reconfiguration requested by SIGHUP"); + struct config *conf = unix_read_config(config_name, unix_cf_error_log); + + if (conf) + config_commit(conf, RECONFIG_HARD, 0); +} + +static void +unix_cf_error_cli(struct conf_order *order, const char *msg, va_list args) +{ + cli_msg(8002, "%s, line %d: %s", order->state->name, order->state->lino, msg, &args); +} + +static struct config * +cmd_read_config(char *name) +{ + if (!name) + name = config_name; + + cli_msg(-2, "Reading configuration from %s", name); + return unix_read_config(name, unix_cf_error_cli); +} + +void +cmd_check_config(char *name) +{ + struct config *conf = cmd_read_config(name); + if (!conf) + return; + + cli_msg(20, "Configuration OK"); + config_free(conf); +} + +static void +cmd_reconfig_msg(int r) +{ + switch (r) + { + case CONF_DONE: cli_msg( 3, "Reconfigured"); break; + case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break; + case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break; + case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break; + case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break; + case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break; + case CONF_NOTHING: cli_msg(19, "Nothing to do"); break; + default: break; + } +} + +/* Hack for scheduled undo notification */ +cli *cmd_reconfig_stored_cli; + +void +cmd_reconfig_undo_notify(void) +{ + if (cmd_reconfig_stored_cli) + { + cli *c = cmd_reconfig_stored_cli; + cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo"); + cli_write_trigger(c); + } +} + +void +cmd_reconfig(char *name, int type, uint timeout) +{ + if (cli_access_restricted()) + return; + + struct config *conf = cmd_read_config(name); + if (!conf) + return; + + int r = config_commit(conf, type, timeout); + + if ((r >= 0) && (timeout > 0)) + { + cmd_reconfig_stored_cli = this_cli; + cli_msg(-22, "Undo scheduled in %d s", timeout); + } + + cmd_reconfig_msg(r); +} + +void +cmd_reconfig_confirm(void) +{ + if (cli_access_restricted()) + return; + + int r = config_confirm(); + cmd_reconfig_msg(r); +} + +void +cmd_reconfig_undo(void) +{ + if (cli_access_restricted()) + return; + + cli_msg(-21, "Undo requested"); + + int r = config_undo(); + cmd_reconfig_msg(r); +} + diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 1bffa322..084f315b 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -30,7 +30,7 @@ log_config: LOG log_file log_mask ';' { struct log_config *c = cfg_allocz(sizeof(struct log_config)); c->fh = $2; c->mask = $3; - add_tail(&new_config->logfiles, &c->n); + add_tail(&ctx->new_config->logfiles, &c->n); } ; @@ -41,11 +41,11 @@ syslog_name: log_file: text { - FILE *f = tracked_fopen(new_config->pool, $1, "a"); - if (!f) cf_error("Unable to open log file `%s': %m", $1); + FILE *f = tracked_fopen(ctx->new_config->pool, $1, "a"); + if (!f) cf_error(ctx, "Unable to open log file `%s': %m", $1); $$ = f; } - | SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; } + | SYSLOG syslog_name { $$ = NULL; ctx->new_config->syslog_name = $2; } | STDERR { $$ = stderr; } ; @@ -75,11 +75,11 @@ log_cat: conf: mrtdump_base ; mrtdump_base: - MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; } + MRTDUMP PROTOCOLS mrtdump_mask ';' { ctx->new_config->proto_default_mrtdump = $3; } | MRTDUMP text ';' { - FILE *f = tracked_fopen(new_config->pool, $2, "a"); - if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2); - new_config->mrtdump_file = fileno(f); + FILE *f = tracked_fopen(ctx->new_config->pool, $2, "a"); + if (!f) cf_error(ctx, "Unable to open MRTDump file '%s': %m", $2); + ctx->new_config->mrtdump_file = fileno(f); } ; @@ -87,10 +87,10 @@ mrtdump_base: conf: debug_unix ; debug_unix: - DEBUG LATENCY bool { new_config->latency_debug = $3; } - | DEBUG LATENCY LIMIT expr_us { new_config->latency_limit = $4; } - | WATCHDOG WARNING expr_us { new_config->watchdog_warning = $3; } - | WATCHDOG TIMEOUT expr_us { new_config->watchdog_timeout = ($3 + 999999) TO_S; } + DEBUG LATENCY bool { ctx->new_config->latency_debug = $3; } + | DEBUG LATENCY LIMIT expr_us { ctx->new_config->latency_limit = $4; } + | WATCHDOG WARNING expr_us { ctx->new_config->watchdog_warning = $3; } + | WATCHDOG TIMEOUT expr_us { ctx->new_config->watchdog_timeout = ($3 + 999999) TO_S; } ; diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 95b54d65..c4015370 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -10,14 +10,19 @@ CF_HDR #include "sysdep/unix/krt.h" +CF_CTX + +struct kif_config *kif_cf; +struct krt_config *krt_cf; + CF_DEFINES -#define THIS_KRT ((struct krt_config *) this_proto) -#define THIS_KIF ((struct kif_config *) this_proto) -#define KIF_IFACE ((struct kif_iface_config *) this_ipatt) +#define THIS_KRT ((struct krt_config *) ctx->this_proto) +#define THIS_KIF ((struct kif_config *) ctx->this_proto) +#define KIF_IFACE ((struct kif_iface_config *) ctx->this_ipatt) static void -kif_set_preferred(ip_addr ip) +kif_set_preferred(struct cf_context *ctx, ip_addr ip) { if (ipa_is_ip4(ip)) KIF_IFACE->pref_v4 = ip; @@ -27,6 +32,44 @@ kif_set_preferred(ip_addr ip) KIF_IFACE->pref_ll = ip; } +static struct proto_config * +kif_init_config(struct cf_context *ctx, int class) +{ + if (ctx->kif_cf) + cf_error(ctx, "Kernel device protocol already defined"); + + ctx->kif_cf = (struct kif_config *) proto_config_new(ctx, &proto_unix_iface, class); + ctx->kif_cf->scan_time = 60 S_; + init_list(&ctx->kif_cf->iface_list); + + kif_sys_init_config(ctx->kif_cf); + return (struct proto_config *) ctx->kif_cf; +} + +struct proto_config * +krt_init_config(struct cf_context *ctx, int class) +{ +#ifndef CONFIG_MULTIPLE_TABLES + if (ctx->krt_cf) + cf_error(ctx, "Kernel protocol already defined"); +#endif + + ctx->krt_cf = (struct krt_config *) proto_config_new(ctx, &proto_unix_kernel, class); + ctx->krt_cf->scan_time = 60 S_; + + krt_sys_init_config(ctx->krt_cf); + return (struct proto_config *) ctx->krt_cf; +} + +#ifdef CONFIG_ALL_TABLES_AT_ONCE +void +krt_check_scan_time(struct cf_context *ctx, struct krt_config *cf) +{ + if (ctx->krt_cf->scan_time != cf->scan_time) + cf_error(ctx, "All kernel syncers must use the same table scan interval"); +} +#endif + CF_DECLS CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS) @@ -41,7 +84,7 @@ CF_GRAMMAR proto: kern_proto '}' ; kern_proto_start: proto_start KERNEL { - this_proto = krt_init_config($1); + ctx->this_proto = krt_init_config(ctx, $1); } ; @@ -50,12 +93,12 @@ kern_proto: kern_proto kern_item ';' ; kern_mp_limit: /* empty */ { $$ = KRT_DEFAULT_ECMP_LIMIT; } - | LIMIT expr { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error("Merge paths limit must be in range 1-255"); } + | LIMIT expr { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error(ctx, "Merge paths limit must be in range 1-255"); } ; kern_item: proto_item - | proto_channel { this_proto->net_type = $1->net_type; } + | proto_channel { ctx->this_proto->net_type = $1->net_type; } | PERSIST bool { THIS_KRT->persist = $2; } | SCAN TIME expr { /* Scan time of 0 means scan on startup only */ @@ -65,7 +108,7 @@ kern_item: THIS_KRT->learn = $2; #ifndef KRT_ALLOW_LEARN if ($2) - cf_error("Learning of kernel routes not supported on this platform"); + cf_error(ctx, "Learning of kernel routes not supported on this platform"); #endif } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } @@ -73,7 +116,7 @@ kern_item: THIS_KRT->merge_paths = $3 ? $4 : 0; #ifndef KRT_ALLOW_MERGE_PATHS if ($3) - cf_error("Path merging not supported on this platform"); + cf_error(ctx, "Path merging not supported on this platform"); #endif } ; @@ -82,7 +125,7 @@ kern_item: proto: kif_proto '}' ; -kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); } +kif_proto_start: proto_start DEVICE { ctx->this_proto = kif_init_config(ctx, $1); } ; kif_proto: kif_proto_start proto_name '{' ; @@ -99,13 +142,13 @@ kif_item: kif_iface_start: { - this_ipatt = cfg_allocz(sizeof(struct kif_iface_config)); - add_tail(&THIS_KIF->iface_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); + ctx->this_ipatt = cfg_allocz(sizeof(struct kif_iface_config)); + add_tail(&THIS_KIF->iface_list, NODE ctx->this_ipatt); + init_list(&ctx->this_ipatt->ipn_list); } kif_iface_item: - PREFERRED ipa { kif_set_preferred($2); } + PREFERRED ipa { kif_set_preferred(ctx, $2); } ; kif_iface_opts: diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index a79df54e..a68ebc06 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -85,7 +85,6 @@ krt_io_init(void) */ struct kif_proto *kif_proto; -static struct kif_config *kif_cf; static timer *kif_scan_timer; static btime kif_last_shot; @@ -198,32 +197,17 @@ kif_reconfigure(struct proto *p, struct proto_config *new) static void kif_preconfig(struct protocol *P UNUSED, struct config *c) { - kif_cf = NULL; kif_sys_preconfig(c); } -struct proto_config * -kif_init_config(int class) -{ - if (kif_cf) - cf_error("Kernel device protocol already defined"); - - kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class); - kif_cf->scan_time = 60 S; - init_list(&kif_cf->iface_list); - - kif_sys_init_config(kif_cf); - return (struct proto_config *) kif_cf; -} - static void -kif_copy_config(struct proto_config *dest, struct proto_config *src) +kif_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src) { struct kif_config *d = (struct kif_config *) dest; struct kif_config *s = (struct kif_config *) src; /* Copy interface config list */ - cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config)); + cf_copy_list(ctx, &d->iface_list, &s->iface_list, sizeof(struct kif_iface_config)); /* Fix sysdep parts */ kif_sys_copy_config(d, s); @@ -1039,32 +1023,28 @@ krt_rte_same(rte *a, rte *b) * Protocol glue */ -struct krt_config *krt_cf; - static void krt_preconfig(struct protocol *P UNUSED, struct config *c) { - krt_cf = NULL; krt_sys_preconfig(c); } static void -krt_postconfig(struct proto_config *CF) +krt_postconfig(struct cf_context *ctx, struct proto_config *CF) { struct krt_config *cf = (void *) CF; if (EMPTY_LIST(CF->channels)) - cf_error("Channel not specified"); + cf_error(ctx, "Channel not specified"); #ifdef CONFIG_ALL_TABLES_AT_ONCE - if (krt_cf->scan_time != cf->scan_time) - cf_error("All kernel syncers must use the same table scan interval"); + krt_check_scan_time(ctx, cf); #endif struct channel_config *cc = proto_cf_main_channel(CF); struct rtable_config *tab = cc->table; if (tab->krt_attached) - cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name); + cf_error(ctx, "Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name); tab->krt_attached = CF; if (cf->merge_paths) @@ -1172,23 +1152,8 @@ krt_reconfigure(struct proto *p, struct proto_config *CF) return o->scan_time == n->scan_time && o->learn == n->learn; } -struct proto_config * -krt_init_config(int class) -{ -#ifndef CONFIG_MULTIPLE_TABLES - if (krt_cf) - cf_error("Kernel protocol already defined"); -#endif - - krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class); - krt_cf->scan_time = 60 S; - - krt_sys_init_config(krt_cf); - return (struct proto_config *) krt_cf; -} - static void -krt_copy_config(struct proto_config *dest, struct proto_config *src) +krt_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest, struct proto_config *src) { struct krt_config *d = (struct krt_config *) dest; struct krt_config *s = (struct krt_config *) src; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 6ace2a86..c7310db0 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -81,11 +81,12 @@ extern pool *krt_pool; if (pr->p.debug & fl) \ { log(L_TRACE "%s: " msg, pr->p.name , ## args); } } while(0) -struct proto_config * kif_init_config(int class); void kif_request_scan(void); void krt_got_route(struct krt_proto *p, struct rte *e); void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); +void krt_check_scan_time(struct cf_context *ctx, struct krt_config *cf); + /* Values for rte->u.krt_sync.src */ #define KRT_SRC_UNKNOWN -1 /* Nobody knows */ #define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */ @@ -121,7 +122,6 @@ extern struct kif_proto *kif_proto; #define KIF_CF ((struct kif_config *)p->p.cf) struct kif_iface_config * kif_get_iface_config(struct iface *iface); -struct proto_config * krt_init_config(int class); /* krt sysdep */ diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index ea1476e7..3b8fc3cc 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -45,9 +45,9 @@ */ #ifdef DEBUGGING -static int debug_flag = 1; +int debug_flag = 1; #else -static int debug_flag = 0; +int debug_flag = 0; #endif void @@ -90,260 +90,6 @@ drop_gid(gid_t gid) die("setgid: %m"); } -/* - * Reading the Configuration - */ - -#ifdef PATH_IPROUTE_DIR - -static inline void -add_num_const(char *name, int val) -{ - struct symbol *s = cf_get_symbol(name); - s->class = SYM_CONSTANT | T_INT; - s->def = cfg_allocz(sizeof(struct f_val)); - SYM_TYPE(s) = T_INT; - SYM_VAL(s).i = val; -} - -/* the code of read_iproute_table() is based on - rtnl_tab_initialize() from iproute2 package */ -static void -read_iproute_table(char *file, char *prefix, int max) -{ - char buf[512], namebuf[512]; - char *name; - int val; - FILE *fp; - - strcpy(namebuf, prefix); - name = namebuf + strlen(prefix); - - fp = fopen(file, "r"); - if (!fp) - return; - - while (fgets(buf, sizeof(buf), fp)) - { - char *p = buf; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p == '#' || *p == '\n' || *p == 0) - continue; - - if (sscanf(p, "0x%x %s\n", &val, name) != 2 && - sscanf(p, "0x%x %s #", &val, name) != 2 && - sscanf(p, "%d %s\n", &val, name) != 2 && - sscanf(p, "%d %s #", &val, name) != 2) - continue; - - if (val < 0 || val > max) - continue; - - for(p = name; *p; p++) - if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_')) - *p = '_'; - - add_num_const(namebuf, val); - } - - fclose(fp); -} - -#endif // PATH_IPROUTE_DIR - - -static char *config_name = PATH_CONFIG_FILE; - -static int -cf_read(byte *dest, uint len, int fd) -{ - int l = read(fd, dest, len); - if (l < 0) - cf_error("Read error"); - return l; -} - -void -sysdep_preconfig(struct config *c) -{ - init_list(&c->logfiles); - - c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT; - c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING; - -#ifdef PATH_IPROUTE_DIR - read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256); - read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256); - read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256); - read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256); -#endif -} - -int -sysdep_commit(struct config *new, struct config *old UNUSED) -{ - log_switch(debug_flag, &new->logfiles, new->syslog_name); - return 0; -} - -static int -unix_read_config(struct config **cp, char *name) -{ - struct config *conf = config_alloc(name); - int ret; - - *cp = conf; - conf->file_fd = open(name, O_RDONLY); - if (conf->file_fd < 0) - return 0; - cf_read_hook = cf_read; - ret = config_parse(conf); - close(conf->file_fd); - return ret; -} - -static struct config * -read_config(void) -{ - struct config *conf; - - if (!unix_read_config(&conf, config_name)) - { - if (conf->err_msg) - die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg); - else - die("Unable to open configuration file %s: %m", config_name); - } - - return conf; -} - -void -async_config(void) -{ - struct config *conf; - - log(L_INFO "Reconfiguration requested by SIGHUP"); - if (!unix_read_config(&conf, config_name)) - { - if (conf->err_msg) - log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg); - else - log(L_ERR "Unable to open configuration file %s: %m", config_name); - config_free(conf); - } - else - config_commit(conf, RECONFIG_HARD, 0); -} - -static struct config * -cmd_read_config(char *name) -{ - struct config *conf; - - if (!name) - name = config_name; - - cli_msg(-2, "Reading configuration from %s", name); - if (!unix_read_config(&conf, name)) - { - if (conf->err_msg) - cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg); - else - cli_msg(8002, "%s: %m", name); - config_free(conf); - conf = NULL; - } - - return conf; -} - -void -cmd_check_config(char *name) -{ - struct config *conf = cmd_read_config(name); - if (!conf) - return; - - cli_msg(20, "Configuration OK"); - config_free(conf); -} - -static void -cmd_reconfig_msg(int r) -{ - switch (r) - { - case CONF_DONE: cli_msg( 3, "Reconfigured"); break; - case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break; - case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break; - case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break; - case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break; - case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break; - case CONF_NOTHING: cli_msg(19, "Nothing to do"); break; - default: break; - } -} - -/* Hack for scheduled undo notification */ -cli *cmd_reconfig_stored_cli; - -void -cmd_reconfig_undo_notify(void) -{ - if (cmd_reconfig_stored_cli) - { - cli *c = cmd_reconfig_stored_cli; - cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo"); - cli_write_trigger(c); - } -} - -void -cmd_reconfig(char *name, int type, uint timeout) -{ - if (cli_access_restricted()) - return; - - struct config *conf = cmd_read_config(name); - if (!conf) - return; - - int r = config_commit(conf, type, timeout); - - if ((r >= 0) && (timeout > 0)) - { - cmd_reconfig_stored_cli = this_cli; - cli_msg(-22, "Undo scheduled in %d s", timeout); - } - - cmd_reconfig_msg(r); -} - -void -cmd_reconfig_confirm(void) -{ - if (cli_access_restricted()) - return; - - int r = config_confirm(); - cmd_reconfig_msg(r); -} - -void -cmd_reconfig_undo(void) -{ - if (cli_access_restricted()) - return; - - cli_msg(-21, "Undo requested"); - - int r = config_undo(); - cmd_reconfig_msg(r); -} /* * Command-Line Interface diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index cb12fad8..6e28cc24 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -105,12 +105,19 @@ int sk_open_unix(struct birdsock *s, char *name); void *tracked_fopen(struct pool *, char *name, char *mode); void test_old_bird(char *path); +/* conf.c */ + +extern char *config_name; +struct config *read_config(void); + /* krt.c bits */ void krt_io_init(void); /* log.c */ +extern int debug_flag; + void main_thread_init(void); void log_init_debug(char *); /* Initialize debug dump to given file (NULL=stderr, ""=off) */ void log_switch(int debug, list *l, char *); /* Use l=NULL for initial switch */