# 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))
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
-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)
$(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
%{
#undef REJECT /* Avoid name clashes */
-#include <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <glob.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
#define PARSER 1
#include "nest/bird.h"
#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"
#endif
-static uint cf_hash(byte *c);
#define KW_KEY(n) n->name
#define KW_NEXT(n) n->next
#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__)
+
+#define cf_lval (* (cfx_get_lval(yyscanner)))
-static void cf_include(char *arg, int alen);
-static int check_eof(void);
+static void cf_include(char *arg, int alen, yyscan_t yyscanner);
+static int check_eof(yyscan_t yyscanner);
%}
%option nounput
%option noreject
+%option reentrant bison-bridge
+%option extra-type="struct cf_context *"
+
%x COMMENT CCOMM CLI
ALPHA [a-zA-Z_]
{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++;
*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}+ {
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)
{
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;
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;
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;
{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;
}
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;
}
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;
}
}
}
- cf_lval.s = cf_get_symbol(yytext);
+ cf_lval.s = cf_get_symbol(CTX, yytext);
return SYM;
}
["][^"\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");
-<INITIAL,COMMENT><<EOF>> { if (check_eof()) return END; }
+<INITIAL,COMMENT><<EOF>> { 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");
<COMMENT>\n {
- ifs->lino++;
+ CST->lino++;
BEGIN(INITIAL);
}
<COMMENT>.
<CCOMM>\*\/ BEGIN(INITIAL);
-<CCOMM>\n ifs->lino++;
-<CCOMM>\/\* cf_error("Comment nesting not supported");
-<CCOMM><<EOF>> cf_error("Unterminated comment");
+<CCOMM>\n CST->lino++;
+<CCOMM>\/\* YY_FATAL_ERROR("Comment nesting not supported");
+<CCOMM><<EOF>> YY_FATAL_ERROR("Unterminated comment");
<CCOMM>.
\!\= return NEQ;
%%
-static uint
+uint
cf_hash(byte *c)
{
uint h = 13 << 24;
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)
+static void
+cf_init_state(struct cf_context *ctx, struct conf_state *cs)
{
- yy_delete_buffer(old->buffer);
- close(old->fd);
- return old->prev;
+ cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
}
-static void
-enter_ifs(struct include_file_stack *new)
+struct conf_state *
+cf_new_state(struct cf_context *ctx, const char *name)
{
- 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);
+ 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)
-{
- if (ifs == ifs_head)
- {
- /* EOF in main config file */
- ifs->lino = 1; /* Why this? */
- return 1;
- }
-
- ifs = pop_ifs(ifs);
- enter_ifs(ifs);
- 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)
+check_eof(yyscan_t yyscanner)
{
- return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
-}
+ if (!COR->cf_outclude)
+ return 1;
-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");
-}
+ if (COR->cf_outclude(COR))
+ return 1;
-/**
- * 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;
+ yy_switch_to_buffer(CST->buffer, yyscanner);
+ return 0;
}
-static void
-cf_lex_init_kh(void)
+void
+cf_init_kh(void)
{
HASH_INIT(kw_hash, &root_pool, KW_ORDER);
}
/**
- * 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;
-}
-
-/**
- * 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)
-{
- struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
+ ctx->sym_scope = cfg_allocz(sizeof(struct sym_scope));
+ ctx->sym_scope->active = 1;
- s->next = conf_this_scope;
- conf_this_scope = s;
- s->active = 1;
- s->name = sym;
+ return ctx;
}
-/**
- * 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)
+cf_free_context(struct cf_context *ctx)
{
- conf_this_scope->active = 0;
- conf_this_scope = conf_this_scope->next;
- ASSERT(conf_this_scope);
+ cfx_lex_destroy(ctx->yyscanner);
}
-/**
- * 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
*
#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 */
* 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;
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);
+
+ if (!order->new_config)
+ order->new_config = config_alloc(order->pool, order->lp);
- cf_lex_init(0, c);
- sysdep_preconfig(c);
- protos_preconfig(c);
- rt_preconfig(c);
- cf_parse();
+ struct cf_context *ctx = cf_new_context(0, order);
+ int ret;
- if (EMPTY_LIST(c->protos))
- cf_error("No protocol is specified in the config file");
+ if (setjmp(ctx->jmpbuf))
+ {
+ if (order->cf_outclude)
+ while (! order->cf_outclude(order))
+ ;
- /*
- if (!c->router_id)
- cf_error("Router ID must be configured manually");
- */
+ ret = 0;
- done = 1;
+ 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;
}
/**
config_timer = tm_new(&root_pool);
config_timer->hook = config_timeout;
+
+ cf_init_kh();
}
/**
* 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, "<bug: error message too long>");
+ 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, "<bug: error message too long>");
+
+ 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
* 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);
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;
#define _BIRD_CONF_H_
#include "sysdep/config.h"
+#include "nest/cli.h"
#include "lib/ip.h"
#include "lib/hash.h"
#include "lib/resource.h"
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 */
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);
#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;
#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);
#include "nest/bird.h"
#include "conf/conf.h"
+#include "conf/parser.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "lib/timer.h"
/* 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;
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; }
;
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;
}
;
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;
}
;
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);
$$ = 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
$$ = 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
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;
}
;
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;
}
;
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 */
}
;
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");
}
;
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;
}
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;
}
;
#include "lib/flowspec.h"
-CF_DEFINES
+CF_CTX
struct flow_builder *this_flow;
-
CF_DECLS
%type <i32> flow_num_op flow_srcdst flow_logic_op flow_num_type_ flow_frag_val flow_neg
| 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; }
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
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);
}
;
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 */
}
;
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
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
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_ ;
--- /dev/null
+m4_divert(-1)m4_dnl
+#
+# BIRD -- Generator of Configuration Context
+#
+# (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+# 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([[,]])
+
# 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($@))]])')
# 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)')
# 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')
# 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
# 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, `')
m4_divert(0)DNL
%{
m4_undivert(1)DNL
+
+m4_undivert(3)DNL
%}
-m4_undivert(2)DNL
+m4_undivert(4)DNL
%%
-m4_undivert(3)DNL
+m4_undivert(5)DNL
%%
-m4_undivert(4)DNL
+m4_undivert(6)DNL
')
# As we are processing C source, we must access all M4 primitives via
--- /dev/null
+/*
+ * BIRD Internet Routing Daemon -- Configuration Parser Headers
+ *
+ * (c) 2018 Maria Matejka <mq@jmq.cz>
+ *
+ * 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
--- /dev/null
+/*
+ * BIRD Internet Routing Daemon -- Symbol Handling
+ *
+ * (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ * (c) 2018 Maria Matejka <mq@jmq.cz>
+ *
+ * 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;
+}
* BIRD - filters
*
* Copyright 1998--2000 Pavel Machek
+ * 2018 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
CF_HDR
+#include "filter/f-util.h"
+
CF_DEFINES
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
}
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;
}
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);
}
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;
}
#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) {
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;
}
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};
}
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:
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;
}
}
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;
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 */
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;
}
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;
}
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;
}
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;
}
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;
}
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;
* 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);
* @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
{
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);
}
;
break;
default:
- cf_error( "You can't create sets of this type." );
+ cf_error(ctx, "You can't create sets of this type." );
}
}
;
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;
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
/* 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;
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
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);
}
;
| 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:
;
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:
| 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); }
;
$$ = 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;
}
;
-/* 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; }
;
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); }
;
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;
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;
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
| 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'); } */
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;
;
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; }
;
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;
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
#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;
* 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;
}
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;
--- /dev/null
+/*
+ * BIRD Internet Routing Daemon -- Filters
+ *
+ * (c) 1999 Pavel Machek <pavel@ucw.cz>
+ * (c) 2018 Maria Matejka <mq@jmq.cz>
+ *
+ * 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
#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
}
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;
}
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);
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);
#include "lib/alloca.h"
#include "nest/bird.h"
#include "conf/conf.h"
+#include "conf/parser.h"
#include "filter/filter.h"
/**
}
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));
#include "nest/bird.h"
#include "lib/flowspec.h"
#include "conf/conf.h"
+#include "conf/parser.h"
static const char* flow4_type_str[] = {
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);
}
/**
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
* 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));
}
/**
* 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));
}
* 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;
}
/* 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 */
} 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);
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);
/*
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 */
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;
}
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, "<line overflow>");
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)
{
}
-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
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;
* 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;
void cmd_show_symbols(struct sym_show_data *sym);
void cmd_show_memory(void);
void cmd_eval(struct f_inst *expr);
+
+#endif
#include "lib/lists.h"
#include "lib/mac.h"
-CF_DEFINES
+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;
-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;
+CF_DEFINES
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
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))
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) */
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;
}
;
/* Definition of protocols */
-conf: proto { proto_postconfig(); } ;
+conf: proto { proto_postconfig(ctx); } ;
proto_start:
PROTOCOL { $$ = SYM_PROTO; }
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:
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;
rtable:
SYM {
- if ($1->class != SYM_TABLE) cf_error("Table expected");
+ if ($1->class != SYM_TABLE) cf_error(ctx, "Table expected");
$$ = $1->def;
}
;
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 */
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:
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:
;
/* 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);
}
;
;
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 */
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);
}
;
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);
}
;
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:
$$ = 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;
}
}
| 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 {
| 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;
| 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;
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");
}
;
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;
}
;
#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"
};
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;
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)
}
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;
{
/* 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);
* 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);
* 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;
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);
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);
}
/**
}
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
{
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;
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 */
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);
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);
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
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);
#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 *);
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;
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 */
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);
}
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;
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;
}
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;
* 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;
}
#include "nest/protocol.h"
#include "nest/cli.h"
#include "nest/iface.h"
+#include "conf/parser.h"
#include "filter/filter.h"
static void
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));
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;
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;
/* 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
/* 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);
#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"
}
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);
}
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;
}
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;
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;
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
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_;
};
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;
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 (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
- | UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_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 (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_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 (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_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:
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[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, [<name>] [\"<interface>\"], [[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, [<name>], [[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, [<name>], [[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
}
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;
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;
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;
};
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");
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];
}
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, [<name>], [[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
}
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;
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);
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;
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)
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");
}
}
}
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 */
}
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
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 */
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; }
;
| 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;
}
| 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; }
| 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; }
| 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:
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)
| 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");
}
;
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;
#include "proto/ospf/ospf.h"
-CF_DEFINES
+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;
-#define OSPF_CFG ((struct ospf_config *) this_proto)
-#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt)
+CF_DEFINES
-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;
+#define OSPF_CFG ((struct ospf_config *) ctx->this_proto)
+#define OSPF_PATT ((struct ospf_iface_patt *) ctx->this_ipatt)
-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;
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))
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 */
{ 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 */
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;
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)
{
}
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");
}
CF_GRAMMAR
-proto: ospf_proto '}' { ospf_proto_finish(); } ;
+proto: ospf_proto '}' { ospf_proto_finish(ctx); } ;
ospf_variant:
OSPF { $$ = 1; }
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);
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;
};
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;
-
- init_list(&this_area->patt_list);
- init_list(&this_area->net_list);
- init_list(&this_area->enet_list);
- init_list(&this_area->stubnet_list);
+ 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(&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:
;
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
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;
}
;
;
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:
;
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;
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 ; }
| 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
;
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:
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;
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:
;
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); } ;
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optsym, [<name>], [[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, [<name>] [\"<interface>\"], [[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, [<name>] [\"<interface>\"], [[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] [<name>], [[Show information about OSPF network topology]])
CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[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, [<name>], [[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] [<name>], [[Show information about OSPF network state]])
CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[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, [<name>], [[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 <id> | link] [type <num>] [lsid <id>] [self | router <id>] [<proto>], [[Show content of OSPF LSA database]])
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; }
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;
#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 */
CF_DEFINES
-#define PIPE_CFG ((struct pipe_config *) this_proto)
+#define PIPE_CFG ((struct pipe_config *) ctx->this_proto)
CF_DECLS
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;
}
};
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
}
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 */
}
#include "proto/radv/radv.h"
-CF_DEFINES
+CF_CTX
-#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)
+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 */
-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 */
+CF_DEFINES
+#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
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);
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; }
;
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);
};
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 {
| 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; }
;
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);
};
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;
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:
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;
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;
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:
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;
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:
}
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 *
}
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;
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
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");
}
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;
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;
{
/* 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");
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))
};
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:
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
CF_CLI(SHOW RIP INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[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, [<name>] [\"<interface>\"], [[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
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 *
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
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 */
| 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;
}
| 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));
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;
};
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
* 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;
}
}
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 */
}
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);
/*
#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
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)
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);
}
;
;
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:
CF_CLI(SHOW STATIC, optsym, [<name>], [[Show details of static protocol]])
-{ static_show(proto_get_named($3, &proto_static)); } ;
+{ static_show(proto_get_named(ctx, $3, &proto_static)); } ;
CF_CODE
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);
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 *
}
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;
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)
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;
}
-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)
--- /dev/null
+/*
+ * BIRD Internet Routing Daemon -- Unix Config Reader
+ *
+ * (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ * (c) 2018 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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);
+}
+
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);
}
;
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; }
;
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);
}
;
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; }
;
#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;
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)
proto: kern_proto '}' ;
kern_proto_start: proto_start KERNEL {
- this_proto = krt_init_config($1);
+ ctx->this_proto = krt_init_config(ctx, $1);
}
;
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 */
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; }
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
}
;
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 '{' ;
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:
*/
struct kif_proto *kif_proto;
-static struct kif_config *kif_cf;
static timer *kif_scan_timer;
static btime kif_last_shot;
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);
* 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)
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;
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) */
#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 */
*/
#ifdef DEBUGGING
-static int debug_flag = 1;
+int debug_flag = 1;
#else
-static int debug_flag = 0;
+int debug_flag = 0;
#endif
void
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
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 */