0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-31 14:11:54 +00:00

Config: Make the parser and lexer reentrant.

This is part of the multithreading journey. The parser and lexer were
using loads of global variables and all of these are now packed into
struct cf_context and others.

Note that the config API has changed:

* cfg_alloc[zu]?(size) is now cf_alloc[zu]?(ctx, size)
* cf_error(msg, ...) is now cf_error(ctx, msg, ...)
* config_parse() and cli_parse() are now called differently
* there is a brand new CF_CTX section in *.Y files which participates
  in struct cf_context construction
This commit is contained in:
Maria Jan Matejka 2018-08-13 11:41:27 +02:00 committed by Jan Maria Matejka
parent 64c5ad58d2
commit f93315c417
59 changed files with 2116 additions and 1817 deletions

View File

@ -75,7 +75,7 @@ $(daemon): LIBS += $(DAEMON_LIBS)
# Include directories
dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@
conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h)
conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h context.h)
cf-local = $(conf-y-targets): $(s)config.Y
src-o-files = $(patsubst %.c,$(o)%.o,$(src))
@ -175,10 +175,10 @@ ifeq ($(MAKECMDGOALS),)
endif
tags:
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chYl]`
cscope:
cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b
cd $(srcdir) ; find $(dirs) -name *.[chYl] > cscope.files ; cscope -b
# Install

View File

@ -1,4 +1,4 @@
src := cf-parse.tab.c cf-lex.c conf.c
src := cf-parse.tab.c cf-lex.c conf.c symbols.c
obj := $(src-o-files)
$(all-daemon)
@ -15,17 +15,18 @@ $(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y
$(o)cf-parse.y: | $(s)gen_parser.m4
$(o)keywords.h: | $(s)gen_keywords.m4
$(o)context.h: | $(s)gen_context.m4
$(o)commands.h: | $(s)gen_commands.m4 $(srcdir)/client/cmds.m4
$(o)cf-parse.tab.h: $(o)cf-parse.tab.c
$(o)cf-parse.tab.c: $(o)cf-parse.y
$(BISON) $(BISON_DEBUG) $(BISONFLAGS) -dv -pcf_ -b $(@:.tab.c=) $<
$(o)cf-parse.tab.c: $(o)cf-parse.y $(o)context.h
$(BISON) $(BISON_DEBUG) $(BISONFLAGS) -dv -pcfx_ -b $(@:.tab.c=) $<
$(o)cf-lex.c: $(s)cf-lex.l
$(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcf_ -o$@ $<
$(FLEX) $(FLEX_DEBUG) -s -B -8 -Pcfx_ -o$@ $<
$(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h
$(o)cf-lex.o: $(o)cf-parse.tab.h $(o)keywords.h $(o)context.h
$(o)cf-lex.o: CFLAGS+=-Wno-sign-compare -Wno-unused-function
$(addprefix $(o), cf-parse.y keywords.h commands.h cf-parse.tab.h cf-parse.tab.c cf-lex.c): $(objdir)/.dir-stamp

View File

@ -27,18 +27,6 @@
%{
#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"
@ -46,6 +34,7 @@
#include "nest/protocol.h"
#include "filter/filter.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "conf/cf-parse.tab.h"
#include "lib/string.h"
#include "lib/hash.h"
@ -64,7 +53,6 @@ struct keyword {
#endif
static uint cf_hash(byte *c);
#define KW_KEY(n) n->name
#define KW_NEXT(n) n->next
@ -72,37 +60,19 @@ static uint cf_hash(byte *c);
#define KW_FN(k) cf_hash(k)
#define KW_ORDER 8 /* Fixed */
#define SYM_KEY(n) n->name, n->scope->active
#define SYM_NEXT(n) n->next
#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
#define SYM_FN(k,s) cf_hash(k)
#define SYM_ORDER 6 /* Initial */
#define SYM_REHASH sym_rehash
#define SYM_PARAMS /8, *1, 2, 2, 6, 20
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
HASH(struct keyword) kw_hash;
static struct sym_scope *conf_this_scope;
linpool *cfg_mem;
int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
struct include_file_stack *ifs;
static struct include_file_stack *ifs_head;
#define MAX_INCLUDE_DEPTH 8
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
#define YY_NO_UNPUT
#define YY_FATAL_ERROR(msg) cf_error(msg)
#define CTX cfx_get_extra(yyscanner)
#define COR (CTX->order)
#define CST (CTX->order->state)
#define YY_INPUT(buf,result,max) result = COR->cf_read_hook(COR, buf, max);
#define YY_FATAL_ERROR(...) cf_error(CTX, __VA_ARGS__)
static void cf_include(char *arg, int alen);
static int check_eof(void);
#define cf_lval (* (cfx_get_lval(yyscanner)))
static void cf_include(char *arg, int alen, yyscan_t yyscanner);
static int check_eof(yyscan_t yyscanner);
%}
@ -111,6 +81,9 @@ static int check_eof(void);
%option nounput
%option noreject
%option reentrant bison-bridge
%option extra-type="struct cf_context *"
%x COMMENT CCOMM CLI
ALPHA [a-zA-Z_]
@ -124,8 +97,8 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
{include} {
char *start, *end;
if (!ifs->depth)
cf_error("Include not allowed in CLI");
if (!COR->cf_include)
YY_FATAL_ERROR("Include not allowed in CLI");
start = strchr(yytext, '"');
start++;
@ -134,9 +107,9 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
*end = 0;
if (start == end)
cf_error("Include with empty argument");
YY_FATAL_ERROR("Include with empty argument");
cf_include(start, end-start);
cf_include(start, end-start, yyscanner);
}
{DIGIT}+:{DIGIT}+ {
@ -147,7 +120,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
errno = 0;
l = strtoul(yytext, &e, 10);
if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
cf_error("ASN out of range");
YY_FATAL_ERROR("ASN out of range");
if (l >> 16)
{
@ -165,7 +138,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
errno = 0;
l = strtoul(e+1, &e, 10);
if (e && *e || (errno == ERANGE) || (l >> len2))
cf_error("Number out of range");
YY_FATAL_ERROR("Number out of range");
cf_lval.i64 |= l;
return VPN_RD;
@ -192,13 +165,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
errno = 0;
l = strtoul(yytext+2, &e, 10);
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
cf_error("ASN out of range");
YY_FATAL_ERROR("ASN out of range");
cf_lval.i64 |= ((u64) l) << len2;
errno = 0;
l = strtoul(e+1, &e, 10);
if (e && *e || (errno == ERANGE) || (l >> len2))
cf_error("Number out of range");
YY_FATAL_ERROR("Number out of range");
cf_lval.i64 |= l;
return VPN_RD;
@ -214,13 +187,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
e = strchr(yytext, ':');
*e++ = '\0';
if (!ip4_pton(yytext, &ip4))
cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext);
YY_FATAL_ERROR("Invalid IPv4 address %s in Route Distinguisher", yytext);
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
errno = 0;
l = strtoul(e, &e, 10);
if (e && *e || (errno == ERANGE) || (l >> 16))
cf_error("Number out of range");
YY_FATAL_ERROR("Number out of range");
cf_lval.i64 |= l;
return VPN_RD;
@ -228,13 +201,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
if (!ip4_pton(yytext, &cf_lval.ip4))
cf_error("Invalid IPv4 address %s", yytext);
YY_FATAL_ERROR("Invalid IPv4 address %s", yytext);
return IP4;
}
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
if (!ip6_pton(yytext, &cf_lval.ip6))
cf_error("Invalid IPv6 address %s", yytext);
YY_FATAL_ERROR("Invalid IPv6 address %s", yytext);
return IP6;
}
@ -244,7 +217,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
errno = 0;
l = strtoul(yytext+2, &e, 16);
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
cf_error("Number out of range");
YY_FATAL_ERROR("Number out of range");
cf_lval.i = l;
return NUM;
}
@ -255,7 +228,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
errno = 0;
l = strtoul(yytext, &e, 10);
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
cf_error("Number out of range");
YY_FATAL_ERROR("Number out of range");
cf_lval.i = l;
return NUM;
}
@ -283,7 +256,7 @@ else: {
}
}
cf_lval.s = cf_get_symbol(yytext);
cf_lval.s = cf_get_symbol(CTX, yytext);
return SYM;
}
@ -302,36 +275,36 @@ else: {
["][^"\n]*["] {
yytext[yyleng-1] = 0;
cf_lval.t = cfg_strdup(yytext+1);
cf_lval.t = cf_strdup(CTX, yytext+1);
yytext[yyleng-1] = '"';
return TEXT;
}
["][^"\n]*\n cf_error("Unterminated string");
["][^"\n]*\n YY_FATAL_ERROR("Unterminated string");
<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;
@ -346,7 +319,7 @@ else: {
%%
static uint
uint
cf_hash(byte *c)
{
uint h = 13 << 24;
@ -356,283 +329,53 @@ cf_hash(byte *c)
return h;
}
/*
* IFS stack - it contains structures needed for recursive processing
* of include in config files. On the top of the stack is a structure
* for currently processed file. Other structures are either for
* active files interrupted because of include directive (these have
* fd and flex buffer) or for inactive files scheduled to be processed
* later (when parent requested including of several files by wildcard
* match - these do not have fd and flex buffer yet).
*
* FIXME: Most of these ifs and include functions are really sysdep/unix.
*/
static struct include_file_stack *
push_ifs(struct include_file_stack *old)
{
struct include_file_stack *ret;
ret = cfg_allocz(sizeof(struct include_file_stack));
ret->lino = 1;
ret->prev = old;
return ret;
}
static struct include_file_stack *
pop_ifs(struct include_file_stack *old)
{
yy_delete_buffer(old->buffer);
close(old->fd);
return old->prev;
}
static void
enter_ifs(struct include_file_stack *new)
cf_init_state(struct cf_context *ctx, struct conf_state *cs)
{
if (!new->buffer)
{
new->fd = open(new->file_name, O_RDONLY);
if (new->fd < 0)
{
ifs = ifs->up;
cf_error("Unable to open included file %s: %m", new->file_name);
}
new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE);
}
yy_switch_to_buffer(new->buffer);
cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
}
struct conf_state *
cf_new_state(struct cf_context *ctx, const char *name)
{
struct conf_state *cs = cfg_alloc(sizeof(struct conf_state));
*cs = (struct conf_state) {
.name = cfg_strdup(name),
.lino = 1,
};
cf_init_state(ctx, cs);
return cs;
}
/**
* cf_lex_unwind - unwind lexer state during error
*
* cf_lex_unwind() frees the internal state on IFS stack when the lexical
* analyzer is terminated by cf_error().
*/
void
cf_lex_unwind(void)
cf_free_state(struct cf_context *ctx, struct conf_state *cs)
{
struct include_file_stack *n;
for (n = ifs; n != ifs_head; n = n->prev)
{
/* Memory is freed automatically */
if (n->buffer)
yy_delete_buffer(n->buffer);
if (n->fd)
close(n->fd);
}
ifs = ifs_head;
yy_delete_buffer(cs->buffer, ctx->yyscanner);
/* The state structure is allocated from linpool, will be auto-freed. */
}
static void
cf_include(char *arg, int alen)
cf_include(char *arg, int alen, yyscan_t yyscanner)
{
struct include_file_stack *base_ifs = ifs;
int new_depth, rv, i;
char *patt;
glob_t g = {};
new_depth = ifs->depth + 1;
if (new_depth > MAX_INCLUDE_DEPTH)
cf_error("Max include depth reached");
/* expand arg to properly handle relative filenames */
if (*arg != '/')
{
int dlen = strlen(ifs->file_name);
char *dir = alloca(dlen + 1);
patt = alloca(dlen + alen + 2);
memcpy(dir, ifs->file_name, dlen + 1);
sprintf(patt, "%s/%s", dirname(dir), arg);
}
else
patt = arg;
/* Skip globbing if there are no wildcards, mainly to get proper
response when the included config file is missing */
if (!strpbrk(arg, "?*["))
{
ifs = push_ifs(ifs);
ifs->file_name = cfg_strdup(patt);
ifs->depth = new_depth;
ifs->up = base_ifs;
enter_ifs(ifs);
return;
}
/* Expand the pattern */
rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g);
if (rv == GLOB_ABORTED)
cf_error("Unable to match pattern %s: %m", patt);
if ((rv != 0) || (g.gl_pathc <= 0))
return;
/*
* Now we put all found files to ifs stack in reverse order, they
* will be activated and processed in order as ifs stack is popped
* by pop_ifs() and enter_ifs() in check_eof().
*/
for(i = g.gl_pathc - 1; i >= 0; i--)
{
char *fname = g.gl_pathv[i];
struct stat fs;
if (stat(fname, &fs) < 0)
{
globfree(&g);
cf_error("Unable to stat included file %s: %m", fname);
}
if (fs.st_mode & S_IFDIR)
continue;
/* Prepare new stack item */
ifs = push_ifs(ifs);
ifs->file_name = cfg_strdup(fname);
ifs->depth = new_depth;
ifs->up = base_ifs;
}
globfree(&g);
enter_ifs(ifs);
COR->cf_include(COR, arg, alen);
yy_switch_to_buffer(CST->buffer, yyscanner);
}
static int
check_eof(void)
check_eof(yyscan_t yyscanner)
{
if (ifs == ifs_head)
{
/* EOF in main config file */
ifs->lino = 1; /* Why this? */
return 1;
}
if (!COR->cf_outclude)
return 1;
ifs = pop_ifs(ifs);
enter_ifs(ifs);
if (COR->cf_outclude(COR))
return 1;
yy_switch_to_buffer(CST->buffer, yyscanner);
return 0;
}
static struct symbol *
cf_new_symbol(byte *c)
{
struct symbol *s;
uint l = strlen(c);
if (l > SYM_MAX_LEN)
cf_error("Symbol too long");
s = cfg_alloc(sizeof(struct symbol) + l);
s->scope = conf_this_scope;
s->class = SYM_VOID;
s->def = NULL;
s->aux = 0;
strcpy(s->name, c);
if (!new_config->sym_hash.data)
HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
return s;
}
/**
* cf_find_symbol - find a symbol by name
* @cfg: specificed config
* @c: symbol name
*
* This functions searches the symbol table in the config @cfg for a symbol of
* given name. First it examines the current scope, then the second recent one
* and so on until it either finds the symbol and returns a pointer to its
* &symbol structure or reaches the end of the scope chain and returns %NULL to
* signify no match.
*/
struct symbol *
cf_find_symbol(struct config *cfg, byte *c)
{
struct symbol *s;
if (cfg->sym_hash.data &&
(s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
return s;
if (cfg->fallback &&
cfg->fallback->sym_hash.data &&
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
return s;
return NULL;
}
/**
* cf_get_symbol - get a symbol by name
* @c: symbol name
*
* This functions searches the symbol table of the currently parsed config
* (@new_config) for a symbol of given name. It returns either the already
* existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no
* existing symbol is found.
*/
struct symbol *
cf_get_symbol(byte *c)
{
return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
}
struct symbol *
cf_default_name(char *template, int *counter)
{
char buf[SYM_MAX_LEN];
struct symbol *s;
char *perc = strchr(template, '%');
for(;;)
{
bsprintf(buf, template, ++(*counter));
s = cf_get_symbol(buf);
if (s->class == SYM_VOID)
return s;
if (!perc)
break;
}
cf_error("Unable to generate default name");
}
/**
* cf_define_symbol - define meaning of a symbol
* @sym: symbol to be defined
* @type: symbol class to assign
* @def: class dependent data
*
* Defines new meaning of a symbol. If the symbol is an undefined
* one (%SYM_VOID), it's just re-defined to the new type. If it's defined
* in different scope, a new symbol in current scope is created and the
* meaning is assigned to it. If it's already defined in the current scope,
* an error is reported via cf_error().
*
* Result: Pointer to the newly defined symbol. If we are in the top-level
* scope, it's the same @sym as passed to the function.
*/
struct symbol *
cf_define_symbol(struct symbol *sym, int type, void *def)
{
if (sym->class)
{
if (sym->scope == conf_this_scope)
cf_error("Symbol already defined");
sym = cf_new_symbol(sym->name);
}
sym->class = type;
sym->def = def;
return sym;
}
static void
cf_lex_init_kh(void)
void
cf_init_kh(void)
{
HASH_INIT(kw_hash, &root_pool, KW_ORDER);
@ -642,108 +385,46 @@ cf_lex_init_kh(void)
}
/**
* cf_lex_init - initialize the lexer
* cf_new_context - initialize the lexer
* @is_cli: true if we're going to parse CLI command, false for configuration
* @c: configuration structure
*
* cf_lex_init() initializes the lexical analyzer and prepares it for
* cf_new_context() initializes the lexical analyzer and prepares it for
* parsing of a new input.
*/
void
cf_lex_init(int is_cli, struct config *c)
struct cf_context *
cf_new_context(int is_cli, struct conf_order *order)
{
if (!kw_hash.data)
cf_lex_init_kh();
struct cf_context *ctx = order->ctx = lp_allocz(order->new_config->mem, sizeof(struct cf_context));
*ctx = (struct cf_context) {
.new_config = order->new_config,
.cfg_mem = order->new_config->mem,
.order = order,
};
ifs_head = ifs = push_ifs(NULL);
if (!is_cli)
{
ifs->file_name = c->file_name;
ifs->fd = c->file_fd;
ifs->depth = 1;
}
cfx_lex_init_extra(ctx, &(ctx->yyscanner));
struct yyguts_t *yyg = ctx->yyscanner;
yyrestart(NULL);
ifs->buffer = YY_CURRENT_BUFFER;
cf_init_state(ctx, order->state);
yy_switch_to_buffer(order->state->buffer, yyg);
if (is_cli)
BEGIN(CLI);
else
BEGIN(INITIAL);
conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
conf_this_scope->active = 1;
ctx->sym_scope = cfg_allocz(sizeof(struct sym_scope));
ctx->sym_scope->active = 1;
return ctx;
}
/**
* cf_push_scope - enter new scope
* @sym: symbol representing scope name
*
* If we want to enter a new scope to process declarations inside
* a nested block, we can just call cf_push_scope() to push a new
* scope onto the scope stack which will cause all new symbols to be
* defined in this scope and all existing symbols to be sought for
* in all scopes stored on the stack.
*/
void
cf_push_scope(struct symbol *sym)
cf_free_context(struct cf_context *ctx)
{
struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
s->next = conf_this_scope;
conf_this_scope = s;
s->active = 1;
s->name = sym;
cfx_lex_destroy(ctx->yyscanner);
}
/**
* cf_pop_scope - leave a scope
*
* cf_pop_scope() pops the topmost scope from the scope stack,
* leaving all its symbols in the symbol table, but making them
* invisible to the rest of the config.
*/
void
cf_pop_scope(void)
{
conf_this_scope->active = 0;
conf_this_scope = conf_this_scope->next;
ASSERT(conf_this_scope);
}
/**
* cf_symbol_class_name - get name of a symbol class
* @sym: symbol
*
* This function returns a string representing the class
* of the given symbol.
*/
char *
cf_symbol_class_name(struct symbol *sym)
{
if (cf_symbol_is_constant(sym))
return "constant";
switch (sym->class)
{
case SYM_VOID:
return "undefined";
case SYM_PROTO:
return "protocol";
case SYM_TEMPLATE:
return "protocol template";
case SYM_FUNCTION:
return "function";
case SYM_FILTER:
return "filter";
case SYM_TABLE:
return "routing table";
default:
return "unknown type";
}
}
/**
* DOC: Parser
*

View File

@ -54,11 +54,10 @@
#include "lib/event.h"
#include "lib/timer.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "filter/filter.h"
static jmp_buf conf_jmpbuf;
struct config *config, *new_config;
static struct config *old_config; /* Old configuration */
@ -85,23 +84,17 @@ int undo_available; /* Undo was not requested from last reconfiguration */
* pool and a linear memory pool to it and makes it available for
* further use. Returns a pointer to the structure.
*/
struct config *
config_alloc(const char *name)
static struct config *
config_alloc(struct pool *pp, struct linpool *lp)
{
pool *p = rp_new(&root_pool, "Config");
linpool *l = lp_new_default(p);
pool *p = rp_new(pp ?: &root_pool, "Config");
linpool *l = lp ?: lp_new_default(p);
struct config *c = lp_allocz(l, sizeof(struct config));
/* Duplication of name string in local linear pool */
uint nlen = strlen(name) + 1;
char *ndup = lp_allocu(l, nlen);
memcpy(ndup, name, nlen);
init_list(&c->tests);
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
c->pool = p;
c->mem = l;
c->file_name = ndup;
c->load_time = current_time();
c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
c->tf_base = c->tf_log = TM_ISO_LONG_MS;
@ -110,77 +103,73 @@ config_alloc(const char *name)
return c;
}
/**
* config_parse - parse a configuration
* @c: configuration
*
* config_parse() reads input by calling a hook function pointed to
* by @cf_read_hook and parses it according to the configuration
* grammar. It also calls all the preconfig and postconfig hooks
* before, resp. after parsing.
*
* Result: 1 if the config has been parsed successfully, 0 if any
* error has occurred (such as anybody calling cf_error()) and
* the @err_msg field has been set to the error message.
*/
int
config_parse(struct config *c)
config_parse(struct conf_order *order)
{
int done = 0;
DBG("Parsing configuration file `%s'\n", c->file_name);
new_config = c;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
goto cleanup;
DBG("Parsing configuration named `%s'\n", order->state->name);
cf_lex_init(0, c);
sysdep_preconfig(c);
protos_preconfig(c);
rt_preconfig(c);
cf_parse();
if (!order->new_config)
order->new_config = config_alloc(order->pool, order->lp);
if (EMPTY_LIST(c->protos))
cf_error("No protocol is specified in the config file");
struct cf_context *ctx = cf_new_context(0, order);
int ret;
/*
if (!c->router_id)
cf_error("Router ID must be configured manually");
*/
if (setjmp(ctx->jmpbuf))
{
if (order->cf_outclude)
while (! order->cf_outclude(order))
;
done = 1;
ret = 0;
config_free(ctx->new_config);
order->new_config = NULL;
goto cleanup;
}
sysdep_preconfig(ctx);
protos_preconfig(ctx->new_config);
rt_preconfig(ctx);
cfx_parse(ctx, ctx->yyscanner);
if (EMPTY_LIST((ctx->new_config)->protos))
cf_error(ctx, "No protocol is specified in the config file");
ret = 1;
cleanup:
new_config = NULL;
cfg_mem = NULL;
return done;
cf_free_context(ctx);
order->ctx = NULL;
return ret;
}
/**
* cli_parse - parse a CLI command
* @c: temporary config structure
*
* cli_parse() is similar to config_parse(), but instead of a configuration,
* it parses a CLI command. See the CLI module for more information.
*/
int
cli_parse(struct config *c)
cli_parse(struct conf_order *order)
{
int done = 0;
c->fallback = config;
new_config = c;
cfg_mem = c->mem;
if (setjmp(conf_jmpbuf))
goto cleanup;
DBG("Parsing command line\n");
cf_lex_init(1, c);
cf_parse();
done = 1;
struct config cc = {};
cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config");
cc.mem = order->lp ?: lp_new_default(cc.pool);
cleanup:
c->fallback = NULL;
new_config = NULL;
cfg_mem = NULL;
return done;
order->new_config = &cc;
struct cf_context *ctx = cf_new_context(1, order);
int ok = 0;
if (setjmp(ctx->jmpbuf))
goto done;
cfx_parse(ctx, ctx->yyscanner);
ok = 1;
done:
cf_free_context(ctx);
config_free(&cc);
order->new_config = NULL;
order->ctx = NULL;
return ok;
}
/**
@ -465,6 +454,8 @@ config_init(void)
config_timer = tm_new(&root_pool);
config_timer->hook = config_timeout;
cf_init_kh();
}
/**
@ -501,22 +492,43 @@ order_shutdown(void)
* error in the configuration.
*/
void
cf_error(const char *msg, ...)
cf_error(struct cf_context *ctx, const char *msg, ...)
{
char buf[1024];
va_list args;
va_start(args, msg);
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
strcpy(buf, "<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
* @c: string to copy
@ -527,7 +539,7 @@ cf_error(const char *msg, ...)
* and we want to preserve it for further use.
*/
char *
cfg_strdup(const char *c)
cf_strdup(struct cf_context *ctx, const char *c)
{
int l = strlen(c) + 1;
char *z = cfg_allocu(l);
@ -537,7 +549,7 @@ cfg_strdup(const char *c)
void
cfg_copy_list(list *dest, list *src, unsigned node_size)
cf_copy_list(struct cf_context *ctx, list *dest, list *src, unsigned node_size)
{
node *dn, *sn;

View File

@ -10,6 +10,7 @@
#define _BIRD_CONF_H_
#include "sysdep/config.h"
#include "nest/cli.h"
#include "lib/ip.h"
#include "lib/hash.h"
#include "lib/resource.h"
@ -45,11 +46,6 @@ struct config {
u32 latency_limit; /* Events with longer duration are logged (us) */
u32 watchdog_warning; /* I/O loop watchdog limit for warning (us) */
u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */
char *err_msg; /* Parser error message */
int err_lino; /* Line containing error */
char *err_file_name; /* File name containing error */
char *file_name; /* Name of main configuration file */
int file_fd; /* File descriptor of main configuration file */
HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */
struct config *fallback; /* Link to regular config for CLI parsing */
int obstacle_count; /* Number of items blocking freeing of this config */
@ -57,19 +53,61 @@ struct config {
btime load_time; /* When we've got this configuration */
};
struct conf_state {
void *buffer; /* Internal lexer state */
const char *name; /* Current file name */
uint lino; /* Current line */
};
struct conf_order {
struct config *new_config; /* Store the allocated config here */
struct cf_context *ctx; /* Internal config context, do not set */
struct conf_state *state;
struct pool *pool; /* If set, use this resource pool */
struct linpool *lp; /* If set, use this linpool */
int (*cf_read_hook)(struct conf_order *order, byte *buf, uint max);
void (*cf_include)(struct conf_order *order, char *name, uint len);
int (*cf_outclude)(struct conf_order *order);
void (*cf_error)(struct conf_order *order, const char *msg, va_list args);
};
/* Please don't use these variables in protocols. Use proto_config->global instead. */
extern struct config *config; /* Currently active configuration */
extern struct config *new_config; /* Configuration being parsed */
struct config *config_alloc(const char *name);
int config_parse(struct config *);
int cli_parse(struct config *);
/**
* Parse configuration
*
* Arguments:
* @order provides callbacks to read config files
*
* Return value:
* 1 on success; order->new_config is then set to the parsed config
* 0 on fail; order->new_config is undefined
**/
int config_parse(struct conf_order *order);
/**
* Parse CLI command
*
* Arguments:
* @order provides callbacks to read command line
*
* Return value:
* 1 on success
* 0 on fail
*
* Parsed config is never kept, order->new_config should be zero after return.
**/
int cli_parse(struct conf_order *order);
/** Callback for returning error from parser hooks */
void cf_error(struct cf_context *, const char *msg, ...) NORET;
void config_free(struct config *);
int config_commit(struct config *, int type, uint timeout);
int config_confirm(void);
int config_undo(void);
void config_init(void);
void cf_error(const char *msg, ...) NORET;
void config_add_obstacle(struct config *);
void config_del_obstacle(struct config *);
void order_shutdown(void);
@ -87,21 +125,16 @@ void order_shutdown(void);
#define CONF_SHUTDOWN -1
#define CONF_NOTHING -2
/* Pools */
extern linpool *cfg_mem;
#define cfg_alloc(size) lp_alloc(cfg_mem, size)
#define cfg_allocu(size) lp_allocu(cfg_mem, size)
#define cfg_allocz(size) lp_allocz(cfg_mem, size)
char *cfg_strdup(const char *c);
void cfg_copy_list(list *dest, list *src, unsigned node_size);
void *cf_alloc(struct cf_context *ctx, unsigned size);
void *cf_allocu(struct cf_context *ctx, unsigned size);
void *cf_allocz(struct cf_context *ctx, unsigned size);
void cf_copy_list(struct cf_context *ctx, list *dest, list *src, unsigned node_size);
char *cf_strdup(struct cf_context *ctx, const char *c);
/* Lexer */
extern int (*cf_read_hook)(byte *buf, uint max, int fd);
struct symbol {
struct symbol *next;
struct sym_scope *scope;
@ -134,45 +167,16 @@ struct sym_scope {
#define SYM_TYPE(s) (((struct f_val *) (s)->def)->type)
#define SYM_VAL(s) (((struct f_val *) (s)->def)->val)
struct include_file_stack {
void *buffer; /* Internal lexer state */
char *file_name; /* File name */
int fd; /* File descriptor */
int lino; /* Current line num */
int depth; /* Include depth, 0 = cannot include */
struct include_file_stack *prev; /* Previous record in stack */
struct include_file_stack *up; /* Parent (who included this file) */
};
extern struct include_file_stack *ifs;
int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);
struct symbol *cf_find_symbol(struct config *cfg, byte *c);
struct symbol *cf_get_symbol(byte *c);
struct symbol *cf_default_name(char *template, int *counter);
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
void cf_push_scope(struct symbol *);
void cf_pop_scope(void);
char *cf_symbol_class_name(struct symbol *sym);
static inline int cf_symbol_is_constant(struct symbol *sym)
{ return (sym->class & 0xff00) == SYM_CONSTANT; }
/* Parser */
extern char *cf_text;
int cf_parse(void);
/* Sysdep hooks */
void sysdep_preconfig(struct config *);
void sysdep_preconfig(struct cf_context *ctx);
int sysdep_commit(struct config *, struct config *);
void sysdep_shutdown_done(void);

View File

@ -12,6 +12,7 @@ CF_HDR
#include "nest/bird.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "lib/timer.h"
@ -24,17 +25,32 @@ CF_HDR
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
CF_CTX
void *yyscanner;
struct sym_scope *sym_scope;
struct config *new_config;
jmp_buf jmpbuf;
linpool *cfg_mem;
struct conf_order *order;
CF_DEFINES
static void
check_u16(uint val)
#define BFD_CHECK(use) do { if (use) cf_error(ctx, "BFD not available"); } while (0)
static inline void
check_u16(struct cf_context *ctx, uint val)
{
if (val > 0xFFFF)
cf_error("Value %u out of range (0-65535)", val);
cf_error(ctx, "Value %u out of range (0-65535)", val);
}
CF_DECLS
%define api.pure full
%parse-param {struct cf_context *ctx}
%param {void *yyscanner}
%union {
uint i;
u32 i32;
@ -123,17 +139,17 @@ conf: definition ;
definition:
DEFINE SYM '=' term ';' {
struct f_val *val = cfg_alloc(sizeof(struct f_val));
*val = f_eval($4, cfg_mem);
if (val->type == T_RETURN) cf_error("Runtime error");
cf_define_symbol($2, SYM_CONSTANT | val->type, val);
*val = f_eval($4, ctx->cfg_mem);
if (val->type == T_RETURN) cf_error(ctx, "Runtime error");
cf_define_symbol(ctx, $2, SYM_CONSTANT | val->type, val);
}
;
expr:
NUM
| '(' term ')' { $$ = f_eval_int($2); }
| '(' term ')' { $$ = f_eval_int($2, ctx); }
| SYM {
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error(ctx, "Number expected");
$$ = SYM_VAL($1).i; }
;
@ -162,7 +178,7 @@ ipa:
IP4 { $$ = ipa_from_ip4($1); }
| IP6 { $$ = ipa_from_ip6($1); }
| SYM {
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error(ctx, "IP address expected");
$$ = SYM_VAL($1).ip;
}
;
@ -177,7 +193,7 @@ ipa_scope:
pxlen4:
'/' NUM {
if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error(ctx, "Invalid prefix length %u", $2);
$$ = $2;
}
;
@ -188,37 +204,37 @@ net_ip4_: IP4 pxlen4
net_addr_ip4 *n = (void *) &($$);
if (!net_validate_ip4(n))
cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
cf_error(ctx, "Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
};
net_ip6_: IP6 '/' NUM
{
if ($3 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $3);
cf_error(ctx, "Invalid prefix length %u", $3);
net_fill_ip6(&($$), $1, $3);
net_addr_ip6 *n = (void *) &($$);
if (!net_validate_ip6(n))
cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
cf_error(ctx, "Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
};
net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
{
if ($3 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $3);
cf_error(ctx, "Invalid prefix length %u", $3);
if ($7 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $7);
cf_error(ctx, "Invalid prefix length %u", $7);
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr($$, $1, $3, $5, $7);
net_addr_ip6_sadr *n = (void *) $$;
if (!net_validate_ip6_sadr(n))
cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
cf_error(ctx, "Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
@ -241,7 +257,7 @@ net_roa4_: net_ip4_ MAX NUM AS NUM
$$ = cfg_alloc(sizeof(net_addr_roa4));
net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
cf_error("Invalid max prefix length %u", $3);
cf_error(ctx, "Invalid max prefix length %u", $3);
};
net_roa6_: net_ip6_ MAX NUM AS NUM
@ -249,7 +265,7 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
$$ = cfg_alloc(sizeof(net_addr_roa6));
net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid max prefix length %u", $3);
cf_error(ctx, "Invalid max prefix length %u", $3);
};
net_mpls_: MPLS NUM
@ -278,7 +294,7 @@ net_ip6:
net_ip6_
| SYM {
if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
cf_error("IPv6 network expected");
cf_error(ctx, "IPv6 network expected");
$$ = * SYM_VAL($1).net;
}
;
@ -287,7 +303,7 @@ net_ip:
net_ip_
| SYM {
if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
cf_error("IP network expected");
cf_error(ctx, "IP network expected");
$$ = * SYM_VAL($1).net;
}
;
@ -296,7 +312,7 @@ net_any:
net_
| SYM {
if ($1->class != (SYM_CONSTANT | T_NET))
cf_error("Network expected");
cf_error(ctx, "Network expected");
$$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
}
;
@ -312,7 +328,7 @@ net_or_ipa:
else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
$$ = * SYM_VAL($1).net;
else
cf_error("IP address or network expected");
cf_error(ctx, "IP address or network expected");
}
;
@ -327,7 +343,7 @@ label_stack:
label_stack_start
| label_stack '/' NUM {
if ($1->len >= MPLS_MAX_LABEL_STACK)
cf_error("Too many labels in stack");
cf_error(ctx, "Too many labels in stack");
$1->stack[$1->len++] = $3;
$$ = $1;
}
@ -337,14 +353,14 @@ time:
TEXT {
$$ = tm_parse_time($1);
if (!$$)
cf_error("Invalid date/time");
cf_error(ctx, "Invalid date/time");
}
;
text:
TEXT
| SYM {
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error(ctx, "String expected");
$$ = SYM_VAL($1).s;
}
;

View File

@ -14,11 +14,10 @@ CF_HDR
#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
@ -61,10 +60,10 @@ flow_num_type_:
| DSCP { $$ = FLOW_TYPE_DSCP; }
;
flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); };
flow_flag_type: TCP FLAGS { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); };
flow_frag_type: FRAGMENT { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); };
flow_label_type: LABEL { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); };
flow_num_type: flow_num_type_{ flow_builder_set_type(ctx->this_flow, $1); };
flow_flag_type: TCP FLAGS { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_TCP_FLAGS); };
flow_frag_type: FRAGMENT { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_FRAGMENT); };
flow_label_type: LABEL { flow_builder_set_type(ctx->this_flow, FLOW_TYPE_LABEL); };
flow_srcdst:
DST { $$ = FLOW_TYPE_DST_PREFIX; }
@ -73,12 +72,12 @@ flow_srcdst:
flow_num_opts:
flow_num_op expr {
flow_check_cf_value_length(this_flow, $2);
flow_builder_add_op_val(this_flow, $1, $2);
flow_check_cf_value_length(ctx->this_flow, $2);
flow_builder_add_op_val(ctx->this_flow, $1, $2);
}
| flow_num_opts flow_logic_op flow_num_op expr {
flow_check_cf_value_length(this_flow, $4);
flow_builder_add_op_val(this_flow, $2 | $3, $4);
flow_check_cf_value_length(ctx->this_flow, $4);
flow_builder_add_op_val(ctx->this_flow, $2 | $3, $4);
}
| flow_num_opt_ext
| flow_num_opts OR flow_num_opt_ext
@ -86,14 +85,14 @@ flow_num_opts:
flow_num_opt_ext_expr:
expr {
flow_check_cf_value_length(this_flow, $1);
flow_builder_add_op_val(this_flow, FLOW_OP_EQ, $1);
flow_check_cf_value_length(ctx->this_flow, $1);
flow_builder_add_op_val(ctx->this_flow, FLOW_OP_EQ, $1);
}
| expr DDOT expr {
flow_check_cf_value_length(this_flow, $1);
flow_check_cf_value_length(this_flow, $3);
flow_builder_add_op_val(this_flow, FLOW_OP_GEQ, $1);
flow_builder_add_op_val(this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3);
flow_check_cf_value_length(ctx->this_flow, $1);
flow_check_cf_value_length(ctx->this_flow, $3);
flow_builder_add_op_val(ctx->this_flow, FLOW_OP_GEQ, $1);
flow_builder_add_op_val(ctx->this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3);
}
;
@ -104,16 +103,16 @@ flow_num_opt_ext:
flow_bmk_opts:
flow_neg expr '/' expr {
flow_check_cf_bmk_values(this_flow, $1, $2, $4);
flow_builder_add_val_mask(this_flow, $1, $2, $4);
flow_check_cf_bmk_values(ctx->this_flow, $1, $2, $4);
flow_builder_add_val_mask(ctx->this_flow, $1, $2, $4);
}
| flow_bmk_opts flow_logic_op flow_neg expr '/' expr {
flow_check_cf_bmk_values(this_flow, $3, $4, $6);
flow_builder_add_val_mask(this_flow, $2 | $3, $4, $6);
flow_check_cf_bmk_values(ctx->this_flow, $3, $4, $6);
flow_builder_add_val_mask(ctx->this_flow, $2 | $3, $4, $6);
}
| flow_bmk_opts ',' flow_neg expr '/' expr {
flow_check_cf_bmk_values(this_flow, $3, $4, $6);
flow_builder_add_val_mask(this_flow, 0x40 | $3, $4, $6); /* AND */
flow_check_cf_bmk_values(ctx->this_flow, $3, $4, $6);
flow_builder_add_val_mask(ctx->this_flow, 0x40 | $3, $4, $6); /* AND */
}
;
@ -131,20 +130,20 @@ flow_frag_val:
flow_frag_opts:
flow_neg flow_frag_val {
flow_builder_add_val_mask(this_flow, 0, ($1 ? 0 : $2), $2);
flow_builder_add_val_mask(ctx->this_flow, 0, ($1 ? 0 : $2), $2);
}
| flow_frag_opts flow_logic_op flow_neg flow_frag_val {
flow_builder_add_val_mask(this_flow, $2, ($3 ? 0 : $4), $4);
flow_builder_add_val_mask(ctx->this_flow, $2, ($3 ? 0 : $4), $4);
}
| flow_frag_opts ',' flow_neg flow_frag_val {
flow_builder_add_val_mask(this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */
flow_builder_add_val_mask(ctx->this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */
}
;
flow4_item:
flow_srcdst net_ip {
flow_builder_set_type(this_flow, $1);
flow_builder4_add_pfx(this_flow, (net_addr_ip4 *) &($2));
flow_builder_set_type(ctx->this_flow, $1);
flow_builder4_add_pfx(ctx->this_flow, (net_addr_ip4 *) &($2));
}
| flow_num_type flow_num_opts
| flow_flag_type flow_bmk_opts
@ -153,14 +152,14 @@ flow4_item:
flow6_item:
flow_srcdst net_ip6 {
flow_builder_set_type(this_flow, $1);
flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), 0);
flow_builder_set_type(ctx->this_flow, $1);
flow_builder6_add_pfx(ctx->this_flow, (net_addr_ip6 *) &($2), 0);
}
| flow_srcdst net_ip6 OFFSET NUM {
if ($4 > $2.pxlen)
cf_error("Prefix offset is higher than prefix length");
flow_builder_set_type(this_flow, $1);
flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), $4);
cf_error(ctx, "Prefix offset is higher than prefix length");
flow_builder_set_type(ctx->this_flow, $1);
flow_builder6_add_pfx(ctx->this_flow, (net_addr_ip6 *) &($2), $4);
}
| flow_num_type flow_num_opts
| flow_flag_type flow_bmk_opts
@ -180,25 +179,25 @@ flow6_opts:
flow_builder_init:
{
if (this_flow == NULL)
this_flow = flow_builder_init(&root_pool);
if (ctx->this_flow == NULL)
ctx->this_flow = flow_builder_init(ctx);
else
flow_builder_clear(this_flow);
flow_builder_clear(ctx->this_flow);
};
flow_builder_set_ipv4: { this_flow->ipv6 = 0; };
flow_builder_set_ipv6: { this_flow->ipv6 = 1; };
flow_builder_set_ipv4: { ctx->this_flow->ipv6 = 0; };
flow_builder_set_ipv6: { ctx->this_flow->ipv6 = 1; };
net_flow4_: FLOW4 '{' flow_builder_init flow_builder_set_ipv4 flow4_opts '}'
{
$$ = (net_addr *) flow_builder4_finalize(this_flow, cfg_mem);
flow4_validate_cf((net_addr_flow4 *) $$);
$$ = (net_addr *) flow_builder4_finalize(ctx->this_flow, ctx->cfg_mem);
flow4_validate_cf(ctx->this_flow, (net_addr_flow4 *) $$);
};
net_flow6_: FLOW6 '{' flow_builder_init flow_builder_set_ipv6 flow6_opts '}'
{
$$ = (net_addr *) flow_builder6_finalize(this_flow, cfg_mem);
flow6_validate_cf((net_addr_flow6 *) $$);
$$ = (net_addr *) flow_builder6_finalize(ctx->this_flow, ctx->cfg_mem);
flow6_validate_cf(ctx->this_flow, (net_addr_flow6 *) $$);
};
net_flow_: net_flow4_ | net_flow6_ ;

33
conf/gen_context.m4 Normal file
View File

@ -0,0 +1,33 @@
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([[,]])

View File

@ -12,6 +12,7 @@ m4_define(DNL, `m4_dnl')
# Diversions used:
# 1 keywords
# 2 context
# Simple iterator
m4_define(CF_itera, `m4_ifelse($#, 1, [[CF_iter($1)]], [[CF_iter($1)[[]]CF_itera(m4_shift($@))]])')
@ -19,6 +20,7 @@ m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)')
# We include all the headers
m4_define(CF_HDR, `m4_divert(0)')
m4_define(CF_CTX, `m4_divert(2)')
m4_define(CF_DECLS, `m4_divert(-1)')
m4_define(CF_DEFINES, `m4_divert(-1)')

View File

@ -9,9 +9,12 @@ m4_divert(-1)m4_dnl
# Diversions used:
# 1 includes
# 2 types etc.
# 3 rules
# 4 C code
# 2 context structure
# 3 inline C code and macros
# 4 parser declarations
# 5 grammar rules
# 6 C code
# Common aliases
m4_define(DNL, `m4_dnl')
@ -19,10 +22,11 @@ m4_define(DNL, `m4_dnl')
# Define macros for defining sections
m4_define(CF_ZONE, `m4_divert($1)/* $2 from m4___file__ */')
m4_define(CF_HDR, `CF_ZONE(1, Headers)')
m4_define(CF_DEFINES, `CF_ZONE(1, Defines)')
m4_define(CF_DECLS, `CF_ZONE(2, Declarations)')
m4_define(CF_GRAMMAR, `CF_ZONE(3, Grammar)')
m4_define(CF_CODE, `CF_ZONE(4, C Code)')
m4_define(CF_CTX, `CF_ZONE(2, Context)')
m4_define(CF_DEFINES, `CF_ZONE(3, Defines)')
m4_define(CF_DECLS, `CF_ZONE(4, Bison Declarations)')
m4_define(CF_GRAMMAR, `CF_ZONE(5, Grammar)')
m4_define(CF_CODE, `CF_ZONE(6, C Code)')
m4_define(CF_END, `m4_divert(-1)')
# Simple iterator
@ -36,8 +40,8 @@ m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@
# CLI commands
m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL
m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
m4_divert(3)cli_cmd: CF_cmd
m4_divert(4)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
m4_divert(5)cli_cmd: CF_cmd
CF_cmd: $1 $2 END')
m4_define(CF_CLI_CMD, `')
m4_define(CF_CLI_HELP, `')
@ -50,15 +54,17 @@ m4_m4wrap(`
m4_divert(0)DNL
%{
m4_undivert(1)DNL
m4_undivert(3)DNL
%}
m4_undivert(2)DNL
%%
m4_undivert(3)DNL
%%
m4_undivert(4)DNL
%%
m4_undivert(5)DNL
%%
m4_undivert(6)DNL
')
# As we are processing C source, we must access all M4 primitives via

61
conf/parser.h Normal file
View File

@ -0,0 +1,61 @@
/*
* 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

208
conf/symbols.c Normal file
View File

@ -0,0 +1,208 @@
/*
* 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;
}

View File

@ -2,6 +2,7 @@
* 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.
*
@ -10,6 +11,8 @@
CF_HDR
#include "filter/f-util.h"
CF_DEFINES
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
@ -43,9 +46,9 @@ f_valid_set_type(int type)
}
static inline struct f_tree *
f_new_item(struct f_val from, struct f_val to)
f_new_item(struct cf_context *ctx, struct f_val from, struct f_val to)
{
struct f_tree *t = f_new_tree();
struct f_tree *t = f_new_tree(ctx);
t->right = t;
t->from = from;
t->to = to;
@ -63,17 +66,17 @@ f_merge_items(struct f_tree *a, struct f_tree *b)
}
static inline struct f_tree *
f_new_pair_item(int fa, int ta, int fb, int tb)
f_new_pair_item(struct cf_context *ctx, int fa, int ta, int fb, int tb)
{
check_u16(fa);
check_u16(ta);
check_u16(fb);
check_u16(tb);
check_u16(ctx, fa);
check_u16(ctx, ta);
check_u16(ctx, fb);
check_u16(ctx, tb);
if ((ta < fa) || (tb < fb))
cf_error( "From value cannot be higher that To value in pair sets");
cf_error(ctx, "From value cannot be higher that To value in pair sets");
struct f_tree *t = f_new_tree();
struct f_tree *t = f_new_tree(ctx);
t->right = t;
t->from.type = t->to.type = T_PAIR;
t->from.val.i = pair(fa, fb);
@ -82,21 +85,21 @@ f_new_pair_item(int fa, int ta, int fb, int tb)
}
static inline struct f_tree *
f_new_pair_set(int fa, int ta, int fb, int tb)
f_new_pair_set(struct cf_context *ctx, int fa, int ta, int fb, int tb)
{
check_u16(fa);
check_u16(ta);
check_u16(fb);
check_u16(tb);
check_u16(ctx, fa);
check_u16(ctx, ta);
check_u16(ctx, fb);
check_u16(ctx, tb);
if ((ta < fa) || (tb < fb))
cf_error( "From value cannot be higher that To value in pair sets");
cf_error(ctx, "From value cannot be higher that To value in pair sets");
struct f_tree *lst = NULL;
int i;
for (i = fa; i <= ta; i++)
lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
lst = f_merge_items(lst, f_new_pair_item(ctx, i, i, fb, tb));
return lst;
}
@ -106,16 +109,16 @@ f_new_pair_set(int fa, int ta, int fb, int tb)
#define LC_ALL 0xFFFFFFFF
static struct f_tree *
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
f_new_ec_item(struct cf_context *ctx, u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
{
u64 fm, to;
if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
check_u16(vf);
check_u16(ctx, vf);
if (vt == EC_ALL)
vt = 0xFFFF;
else
check_u16(vt);
check_u16(ctx, vt);
}
if (kind == EC_GENERIC) {
@ -135,7 +138,7 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
to = ec_as4(kind, key, vt);
}
struct f_tree *t = f_new_tree();
struct f_tree *t = f_new_tree(ctx);
t->right = t;
t->from.type = t->to.type = T_EC;
t->from.val.ec = fm;
@ -144,9 +147,9 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
}
static struct f_tree *
f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
f_new_lc_item(struct cf_context *ctx, u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
{
struct f_tree *t = f_new_tree();
struct f_tree *t = f_new_tree(ctx);
t->right = t;
t->from.type = t->to.type = T_LC;
t->from.val.lc = (lcomm) {f1, f2, f3};
@ -155,9 +158,9 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
}
static inline struct f_inst *
f_generate_empty(struct f_dynamic_attr dyn)
f_generate_empty(struct cf_context *ctx, struct f_dynamic_attr dyn)
{
struct f_inst *e = f_new_inst(FI_EMPTY);
struct f_inst *e = f_new_inst(ctx, FI_EMPTY);
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
@ -173,33 +176,33 @@ f_generate_empty(struct f_dynamic_attr dyn)
e->aux = T_LCLIST;
break;
default:
cf_error("Can't empty that attribute");
cf_error(ctx, "Can't empty that attribute");
}
struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
struct f_inst *s = f_new_inst_da(ctx, FI_EA_SET, dyn);
s->a1.p = e;
return s;
}
static inline struct f_inst *
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
f_generate_dpair(struct cf_context *ctx, struct f_inst *t1, struct f_inst *t2)
{
struct f_inst *rv;
if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT))
cf_error( "Can't operate with value of non-integer type in pair constructor");
cf_error(ctx, "Can't operate with value of non-integer type in pair constructor");
check_u16(t1->a2.i);
check_u16(t2->a2.i);
check_u16(ctx, t1->a2.i);
check_u16(ctx, t2->a2.i);
rv = f_new_inst(FI_CONSTANT);
rv = f_new_inst(ctx, FI_CONSTANT);
rv->aux = T_PAIR;
rv->a2.i = pair(t1->a2.i, t2->a2.i);
}
else {
rv = f_new_inst(FI_PAIR_CONSTRUCT);
rv = f_new_inst(ctx, FI_PAIR_CONSTRUCT);
rv->a1.p = t1;
rv->a2.p = t2;
}
@ -208,7 +211,7 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
}
static inline struct f_inst *
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
f_generate_ec(struct cf_context *ctx, u16 kind, struct f_inst *tk, struct f_inst *tv)
{
struct f_inst *rv;
int c1 = 0, c2 = 0, ipv4_used = 0;
@ -224,7 +227,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
ipv4_used = 1; key = tk->a2.i;
}
else
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
cf_error(ctx, "Can't operate with key of non-integer/IPv4 type in EC constructor");
}
/* IP->Quad implicit conversion */
@ -242,12 +245,12 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
ipv4_used = 1; key = ipa_to_u32(val->val.ip);
}
else
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
cf_error(ctx, "Can't operate with key of non-integer/IPv4 type in EC constructor");
}
if (tv->fi_code == FI_CONSTANT) {
if (tv->aux != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor");
cf_error(ctx, "Can't operate with value of non-integer type in EC constructor");
c2 = 1;
val2 = tv->a2.i;
}
@ -259,25 +262,25 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
ec = ec_generic(key, val2);
}
else if (ipv4_used) {
check_u16(val2);
check_u16(ctx, val2);
ec = ec_ip4(kind, key, val2);
}
else if (key < 0x10000) {
ec = ec_as2(kind, key, val2);
}
else {
check_u16(val2);
check_u16(ctx, val2);
ec = ec_as4(kind, key, val2);
}
NEW_F_VAL;
rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT);
rv->a1.p = val;
val->type = T_EC;
val->val.ec = ec;
}
else {
rv = f_new_inst(FI_EC_CONSTRUCT);
rv = f_new_inst(ctx, FI_EC_CONSTRUCT);
rv->aux = kind;
rv->a1.p = tk;
rv->a2.p = tv;
@ -287,15 +290,15 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
}
static inline struct f_inst *
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
f_generate_lc(struct cf_context *ctx, struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{
struct f_inst *rv;
if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
cf_error(ctx, "LC - Can't operate with value of non-integer type in tuple constructor");
rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT);
NEW_F_VAL;
rv->a1.p = val;
@ -304,7 +307,7 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
}
else
{
rv = f_new_inst(FI_LC_CONSTRUCT);
rv = f_new_inst(ctx, FI_LC_CONSTRUCT);
rv->a1.p = t1;
rv->a2.p = t2;
rv->a3.p = t3;
@ -314,11 +317,11 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
}
static inline struct f_inst *
f_generate_path_mask(struct f_path_mask *t)
f_generate_path_mask(struct cf_context *ctx, struct f_path_mask *t)
{
for (struct f_path_mask *tt = t; tt; tt = tt->next) {
if (tt->kind == PM_ASN_EXPR) {
struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
struct f_inst *mrv = f_new_inst(ctx, FI_PATHMASK_CONSTRUCT);
mrv->a1.p = t;
return mrv;
}
@ -328,7 +331,7 @@ f_generate_path_mask(struct f_path_mask *t)
val->type = T_PATH_MASK;
val->val.path_mask = t;
struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
struct f_inst *rv = f_new_inst(ctx, FI_CONSTANT_INDIRECT);
rv->a1.p = val;
return rv;
@ -340,7 +343,7 @@ f_generate_path_mask(struct f_path_mask *t)
* and return a copy of string
*/
char *
assert_copy_expr(const char *start, size_t len)
assert_copy_expr(struct cf_context *ctx, const char *start, size_t len)
{
/* XXX: Allocates maybe a little more memory than we really finally need */
char *str = cfg_alloc(len + 1);
@ -380,15 +383,15 @@ assert_copy_expr(const char *start, size_t len)
* @end: pointer to the last char of test expression
*/
static struct f_inst *
assert_done(struct f_inst *expr, const char *start, const char *end)
assert_done(struct cf_context *ctx, struct f_inst *expr, const char *start, const char *end)
{
struct f_inst *i;
i = f_new_inst(FI_ASSERT);
i = f_new_inst(ctx, FI_ASSERT);
i->a1.p = expr;
if (end >= start)
{
i->a2.p = assert_copy_expr(start, end - start + 1);
i->a2.p = assert_copy_expr(ctx, start, end - start + 1);
}
else
{
@ -440,32 +443,32 @@ CF_GRAMMAR
conf: filter_def ;
filter_def:
FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
FILTER SYM { $2 = cf_define_symbol(ctx, $2, SYM_FILTER, NULL); cf_push_scope(ctx, $2); }
filter_body {
$2->def = $4;
$4->name = $2->name;
DBG( "We have new filter defined (%s)\n", $2->name );
cf_pop_scope();
cf_pop_scope(ctx);
}
;
conf: filter_eval ;
filter_eval:
EVAL term { f_eval_int($2); }
EVAL term { f_eval_int($2, ctx); }
;
conf: bt_test_suite ;
bt_test_suite:
BT_TEST_SUITE '(' SYM ',' text ')' {
if (!($3->class & SYM_FUNCTION))
cf_error("Function expected");
cf_error(ctx, "Function expected");
struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
t->fn = $3->def;
t->fn_name = $3->name;
t->dsc = $5;
add_tail(&new_config->tests, &t->n);
add_tail(&ctx->new_config->tests, &t->n);
}
;
@ -501,7 +504,7 @@ type:
break;
default:
cf_error( "You can't create sets of this type." );
cf_error(ctx, "You can't create sets of this type." );
}
}
;
@ -510,7 +513,7 @@ one_decl:
type SYM {
struct f_val * val = cfg_alloc(sizeof(struct f_val));
val->type = T_VOID;
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
$2 = cf_define_symbol(ctx, $2, SYM_VARIABLE | $1, val);
DBG( "New variable %s type %x\n", $2->name, $1 );
$2->aux2 = NULL;
$$=$2;
@ -544,7 +547,7 @@ filter_body:
filter:
SYM {
if ($1->class != SYM_FILTER) cf_error("No such filter.");
if ($1->class != SYM_FILTER) cf_error(ctx, "No such filter.");
$$ = $1->def;
}
| filter_body
@ -555,13 +558,13 @@ where_filter:
/* Construct 'IF term THEN ACCEPT; REJECT;' */
struct filter *f = cfg_alloc(sizeof(struct filter));
struct f_inst *i, *acc, *rej;
acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
acc = f_new_inst(ctx, FI_PRINT_AND_DIE); /* ACCEPT */
acc->a1.p = NULL;
acc->a2.i = F_ACCEPT;
rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
rej = f_new_inst(ctx, FI_PRINT_AND_DIE); /* REJECT */
rej->a1.p = NULL;
rej->a2.i = F_REJECT;
i = f_new_inst(FI_CONDITION); /* IF */
i = f_new_inst(ctx, FI_CONDITION); /* IF */
i->a1.p = $2;
i->a2.p = acc;
i->next = rej;
@ -580,7 +583,7 @@ function_body:
decls '{' cmds '}' {
if ($1) {
/* Prepend instruction to clear local variables */
$$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
$$ = f_new_inst(ctx, FI_CLEAR_LOCAL_VARS);
$$->a1.p = $1;
$$->next = $3;
} else
@ -591,13 +594,13 @@ function_body:
conf: function_def ;
function_def:
FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
cf_push_scope($2);
$2 = cf_define_symbol(ctx, $2, SYM_FUNCTION, NULL);
cf_push_scope(ctx, $2);
} function_params function_body {
$2->def = $5;
$2->aux2 = $4;
DBG("Hmm, we've got one function here - %s\n", $2->name);
cf_pop_scope();
cf_pop_scope(ctx);
}
;
@ -645,38 +648,38 @@ set_atom:
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
$$ = f_eval($2, cfg_mem);
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
$$ = f_eval($2, ctx->cfg_mem);
if (!f_valid_set_type($$.type)) cf_error(ctx, "Set-incompatible type");
}
| SYM {
if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
if (!cf_symbol_is_constant($1)) cf_error(ctx, "%s: constant expected", $1->name);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error(ctx, "%s: set-incompatible type", $1->name);
$$ = *(struct f_val *)($1->def);
}
;
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2, ctx); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
cnum:
term { $$ = f_eval_int($1); }
term { $$ = f_eval_int($1, ctx); }
pair_item:
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
| '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
| '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
| '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
| '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
| '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
| '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
| '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
| '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
'(' cnum ',' cnum ')' { $$ = f_new_pair_item(ctx, $2, $2, $4, $4); }
| '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item(ctx, $2, $2, $4, $6); }
| '(' cnum ',' '*' ')' { $$ = f_new_pair_item(ctx, $2, $2, 0, CC_ALL); }
| '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set(ctx, $2, $4, $6, $6); }
| '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(ctx, $2, $4, $6, $8); }
| '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item(ctx, $2, $4, 0, CC_ALL); }
| '(' '*' ',' cnum ')' { $$ = f_new_pair_set(ctx, 0, CC_ALL, $4, $4); }
| '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(ctx, 0, CC_ALL, $4, $6); }
| '(' '*' ',' '*' ')' { $$ = f_new_pair_item(ctx, 0, CC_ALL, 0, CC_ALL); }
| '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
{ $$ = f_new_pair_item($2, $8, $4, $10); }
{ $$ = f_new_pair_item(ctx, $2, $8, $4, $10); }
;
ec_kind:
@ -687,37 +690,37 @@ ec_kind:
;
ec_item:
'(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
| '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
| '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
'(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, $6, $6); }
| '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, $6, $8); }
| '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item(ctx, $2, 0, $4, 0, EC_ALL); }
;
lc_item:
'(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
| '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
| '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
| '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
| '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
| '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
| '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
'(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, $6, $6); }
| '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, $6, $8); }
| '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $4, 0, LC_ALL); }
| '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, $4, $6, 0, LC_ALL); }
| '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $2, 0, LC_ALL, 0, LC_ALL); }
| '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, $2, $4, 0, LC_ALL, 0, LC_ALL); }
| '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(ctx, 0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
| '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
{ $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
{ $$ = f_new_lc_item(ctx, $2, $10, $4, $12, $6, $14); }
;
set_item:
pair_item
| ec_item
| lc_item
| set_atom { $$ = f_new_item($1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
| set_atom { $$ = f_new_item(ctx, $1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item(ctx, $1, $3); }
;
switch_item:
pair_item
| ec_item
| lc_item
| switch_atom { $$ = f_new_item($1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
| switch_atom { $$ = f_new_item(ctx, $1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item(ctx, $1, $3); }
;
set_items:
@ -737,12 +740,12 @@ fprefix:
| net_ip_ '{' NUM ',' NUM '}' {
$$.net = $1; $$.lo = $3; $$.hi = $5;
if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
cf_error(ctx, "Invalid prefix pattern range: {%u, %u}", $3, $5);
}
;
fprefix_set:
fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
fprefix { $$ = f_new_trie(ctx->cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
| fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
;
@ -755,7 +758,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
$$ = f_merge_items($1, $2);
}
| switch_body ELSECOL cmds {
struct f_tree *t = f_new_tree();
struct f_tree *t = f_new_tree(ctx);
t->from.type = t->to.type = T_VOID;
t->right = t;
t->data = $3;
@ -763,7 +766,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
}
;
/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
/* CONST '(' expr ')' { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
bgp_path_expr:
symbol { $$ = $1; }
@ -784,23 +787,23 @@ bgp_path_tail:
;
constant:
NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
| net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
NUM { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| VPN_RD { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
| net_ { NEW_F_VAL; $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(ctx, FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
;
constructor:
'(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
| '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
| '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
| bgp_path { $$ = f_generate_path_mask($1); }
'(' term ',' term ')' { $$ = f_generate_dpair(ctx, $2, $4); }
| '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec(ctx, $2, $4, $6); }
| '(' term ',' term ',' term ')' { $$ = f_generate_lc(ctx, $2, $4, $6); }
| bgp_path { $$ = f_generate_path_mask(ctx, $1); }
;
@ -812,15 +815,15 @@ function_call:
struct symbol *sym;
struct f_inst *inst = $3;
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
cf_error(ctx, "You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(FI_CALL);
$$ = f_new_inst(ctx, FI_CALL);
$$->a1.p = inst;
$$->a2.p = $1->def;
sym = $1->aux2;
while (sym || inst) {
if (!sym || !inst)
cf_error("Wrong number of arguments for function %s.", $1->name);
cf_error(ctx, "Wrong number of arguments for function %s.", $1->name);
DBG( "You should pass parameter called %s\n", sym->name);
inst->a1.p = sym;
sym = sym->aux2;
@ -832,9 +835,9 @@ function_call:
symbol:
SYM {
switch ($1->class & 0xff00) {
case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
default: cf_error("%s: variable expected.", $1->name);
case SYM_CONSTANT: $$ = f_new_inst(ctx, FI_CONSTANT_INDIRECT); break;
case SYM_VARIABLE: $$ = f_new_inst(ctx, FI_VARIABLE); break;
default: cf_error(ctx, "%s: variable expected.", $1->name);
}
$$->a1.p = $1->def;
@ -855,45 +858,45 @@ static_attr:
term:
'(' term ')' { $$ = $2; }
| term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
| term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
| term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
| term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
| term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
| term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
| term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
| term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
| term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
| term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
| term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
| term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
| term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
| '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
| term '+' term { $$ = f_new_inst(ctx, FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
| term '-' term { $$ = f_new_inst(ctx, FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
| term '*' term { $$ = f_new_inst(ctx, FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
| term '/' term { $$ = f_new_inst(ctx, FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
| term AND term { $$ = f_new_inst(ctx, FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
| term OR term { $$ = f_new_inst(ctx, FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(ctx, FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
| term NEQ term { $$ = f_new_inst(ctx, FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
| term '<' term { $$ = f_new_inst(ctx, FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
| term LEQ term { $$ = f_new_inst(ctx, FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
| term '>' term { $$ = f_new_inst(ctx, FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
| term GEQ term { $$ = f_new_inst(ctx, FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
| term '~' term { $$ = f_new_inst(ctx, FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
| term NMA term { $$ = f_new_inst(ctx, FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
| '!' term { $$ = f_new_inst(ctx, FI_NOT); $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(ctx, FI_DEFINED); $$->a1.p = $3; }
| symbol { $$ = $1; }
| constant { $$ = $1; }
| constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
| PREFERENCE { $$ = f_new_inst(ctx, FI_PREF_GET); }
| rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
| rtadot static_attr { $$ = f_new_inst_sa(ctx, FI_RTA_GET, $2); }
| rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
| rtadot dynamic_attr { $$ = f_new_inst_da(ctx, FI_EA_GET, $2); }
| term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; }
| term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
| term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
| term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; }
| term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; }
| term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
| term '.' IS_V4 { $$ = f_new_inst(ctx, FI_IS_V4); $$->a1.p = $1; }
| term '.' TYPE { $$ = f_new_inst(ctx, FI_TYPE); $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(ctx, FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' RD { $$ = f_new_inst(ctx, FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
| term '.' LEN { $$ = f_new_inst(ctx, FI_LENGTH); $$->a1.p = $1; }
| term '.' MAXLEN { $$ = f_new_inst(ctx, FI_ROA_MAXLEN); $$->a1.p = $1; }
| term '.' ASN { $$ = f_new_inst(ctx, FI_ROA_ASN); $$->a1.p = $1; }
| term '.' SRC { $$ = f_new_inst(ctx, FI_SADR_SRC); $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(ctx, FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(ctx, FI_AS_PATH_FIRST); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(ctx, FI_AS_PATH_LAST); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(ctx, FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
/* Communities */
/* This causes one shift/reduce conflict
@ -903,19 +906,19 @@ term:
| rtadot dynamic_attr '.' RESET{ }
*/
| '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| '+' EMPTY '+' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(ctx, FI_EMPTY); $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(ctx, FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check(ctx, $3, NULL, NULL); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check(ctx, $3, $5, $7); }
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; }
| FORMAT '(' term ')' { $$ = f_new_inst(ctx, FI_FORMAT); $$->a1.p = $3; }
/* | term '.' LEN { $$->code = P('P','l'); } */
@ -924,15 +927,15 @@ term:
struct symbol *sym;
struct f_inst *inst = $3;
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
cf_error(ctx, "You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(FI_CALL);
$$ = f_new_inst(ctx, FI_CALL);
$$->a1.p = inst;
$$->a2.p = $1->def;
sym = $1->aux2;
while (sym || inst) {
if (!sym || !inst)
cf_error("Wrong number of arguments for function %s.", $1->name);
cf_error(ctx, "Wrong number of arguments for function %s.", $1->name);
DBG( "You should pass parameter called %s\n", sym->name);
inst->a1.p = sym;
sym = sym->aux2;
@ -951,7 +954,7 @@ break_command:
;
print_one:
term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
term { $$ = f_new_inst(ctx, FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
;
print_list: /* EMPTY */ { $$ = NULL; }
@ -965,13 +968,13 @@ print_list: /* EMPTY */ { $$ = NULL; }
;
var_listn: term {
$$ = f_new_inst(FI_SET);
$$ = f_new_inst(ctx, FI_SET);
$$->a1.p = NULL;
$$->a2.p = $1;
$$->next = NULL;
}
| term ',' var_listn {
$$ = f_new_inst(FI_SET);
$$ = f_new_inst(ctx, FI_SET);
$$->a1.p = NULL;
$$->a2.p = $1;
$$->next = $3;
@ -984,70 +987,75 @@ var_list: /* EMPTY */ { $$ = NULL; }
cmd:
IF term THEN block {
$$ = f_new_inst(FI_CONDITION);
$$ = f_new_inst(ctx, FI_CONDITION);
$$->a1.p = $2;
$$->a2.p = $4;
}
| IF term THEN block ELSE block {
struct f_inst *i = f_new_inst(FI_CONDITION);
struct f_inst *i = f_new_inst(ctx, FI_CONDITION);
i->a1.p = $2;
i->a2.p = $4;
$$ = f_new_inst(FI_CONDITION);
$$ = f_new_inst(ctx, FI_CONDITION);
$$->a1.p = i;
$$->a2.p = $6;
}
| SYM '=' term ';' {
DBG( "Ook, we'll set value\n" );
if (($1->class & ~T_MASK) != SYM_VARIABLE)
cf_error( "You may set only variables." );
$$ = f_new_inst(FI_SET);
cf_error(ctx, "You may set only variables." );
$$ = f_new_inst(ctx, FI_SET);
$$->a1.p = $1;
$$->a2.p = $3;
}
| RETURN term ';' {
DBG( "Ook, we'll return the value\n" );
$$ = f_new_inst(FI_RETURN);
$$ = f_new_inst(ctx, FI_RETURN);
$$->a1.p = $2;
}
| rtadot dynamic_attr '=' term ';' {
$$ = f_new_inst_da(FI_EA_SET, $2);
$$ = f_new_inst_da(ctx, FI_EA_SET, $2);
$$->a1.p = $4;
}
| rtadot static_attr '=' term ';' {
$$ = f_new_inst_sa(FI_RTA_SET, $2);
$$ = f_new_inst_sa(ctx, FI_RTA_SET, $2);
if (!$$->a1.i)
cf_error( "This static attribute is read-only.");
cf_error(ctx, "This static attribute is read-only.");
$$->a1.p = $4;
}
| PREFERENCE '=' term ';' {
$$ = f_new_inst(FI_PREF_SET);
$$ = f_new_inst(ctx, FI_PREF_SET);
$$->a1.p = $3;
}
| UNSET '(' rtadot dynamic_attr ')' ';' {
$$ = f_new_inst_da(FI_EA_SET, $4);
$$ = f_new_inst_da(ctx, FI_EA_SET, $4);
$$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
$$->a1.p = NULL;
}
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
| break_command print_list ';' { $$ = f_new_inst(ctx, FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
| function_call ';' { $$ = $1; }
| CASE term '{' switch_body '}' {
$$ = f_new_inst(FI_SWITCH);
$$ = f_new_inst(ctx, FI_SWITCH);
$$->a1.p = $2;
$$->a2.p = build_tree( $4 );
}
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty(ctx, $2); }
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_PATH_PREPEND, 'x', $2, $6 ); }
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex(ctx, FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
;
/*
TODO: BT_ASSERT shall be done in completely different way.
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done(ctx, $4, $3 + 1, $5 - 1); }
;
get_cf_position:
{
$$ = cf_text;
};
*/
CF_END

View File

@ -9,33 +9,35 @@
#include "nest/bird.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "filter/filter.h"
#include "filter/f-util.h"
#define P(a,b) ((a<<8) | b)
struct f_inst *
f_new_inst(enum f_instruction_code fi_code)
f_new_inst(struct cf_context *ctx, enum f_instruction_code fi_code)
{
struct f_inst * ret;
ret = cfg_allocz(sizeof(struct f_inst));
ret->fi_code = fi_code;
ret->lineno = ifs->lino;
ret->lineno = ctx->order->state->lino;
return ret;
}
struct f_inst *
f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
f_new_inst_da(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_dynamic_attr da)
{
struct f_inst *ret = f_new_inst(fi_code);
struct f_inst *ret = f_new_inst(ctx, fi_code);
ret->aux = (da.f_type << 8) | da.type;
ret->a2.i = da.ea_code;
return ret;
}
struct f_inst *
f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
f_new_inst_sa(struct cf_context *ctx, enum f_instruction_code fi_code, struct f_static_attr sa)
{
struct f_inst *ret = f_new_inst(fi_code);
struct f_inst *ret = f_new_inst(ctx, fi_code);
ret->aux = sa.f_type;
ret->a2.i = sa.sa_code;
ret->a1.i = sa.readonly;
@ -46,11 +48,11 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
* Generate set_dynamic( operation( get_dynamic(), argument ) )
*/
struct f_inst *
f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
f_generate_complex(struct cf_context *ctx, int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
{
struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
*oper = f_new_inst(operation),
*get_dyn = f_new_inst_da(FI_EA_GET, da);
struct f_inst *set_dyn = f_new_inst_da(ctx, FI_EA_SET, da),
*oper = f_new_inst(ctx, operation),
*get_dyn = f_new_inst_da(ctx, FI_EA_GET, da);
oper->aux = operation_aux;
oper->a1.p = get_dyn;
@ -61,17 +63,17 @@ f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, s
}
struct f_inst *
f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
f_generate_roa_check(struct cf_context *ctx, struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
{
struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
ret->i.fi_code = FI_ROA_CHECK;
ret->i.lineno = ifs->lino;
ret->i.lineno = ctx->order->state->lino;
ret->i.arg1 = prefix;
ret->i.arg2 = asn;
/* prefix == NULL <-> asn == NULL */
if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
cf_error("%s is not a ROA table", table->name);
cf_error(ctx, "%s is not a ROA table", table->name);
ret->rtc = table;
return &ret->i;

26
filter/f-util.h Normal file
View File

@ -0,0 +1,26 @@
/*
* 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

View File

@ -46,7 +46,9 @@
#include "nest/iface.h"
#include "nest/attrs.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "filter/filter.h"
#include "filter/f-util.h"
#define CMP_ERROR 999
@ -1824,13 +1826,13 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool)
}
uint
f_eval_int(struct f_inst *expr)
f_eval_int(struct f_inst *expr, struct cf_context *ctx)
{
/* Called independently in parse-time to eval expressions */
struct f_val res = f_eval(expr, cfg_mem);
struct f_val res = f_eval(expr, ctx->cfg_mem);
if (res.type != T_INT)
cf_error("Integer expression expected");
cf_error(ctx, "Integer expression expected");
return res.val.i;
}

View File

@ -149,17 +149,6 @@ struct filter {
struct f_inst *root;
};
struct f_inst *f_new_inst(enum f_instruction_code fi_code);
struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
struct f_tree *f_new_tree(void);
struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
struct f_tree *build_tree(struct f_tree *);
struct f_tree *find_tree(struct f_tree *t, struct f_val val);
@ -178,7 +167,6 @@ struct rte;
int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
uint f_eval_int(struct f_inst *expr);
char *filter_name(struct filter *filter);
int filter_same(struct filter *new, struct filter *old);

View File

@ -9,6 +9,7 @@
#include "lib/alloca.h"
#include "nest/bird.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "filter/filter.h"
/**
@ -100,7 +101,7 @@ build_tree(struct f_tree *from)
}
struct f_tree *
f_new_tree(void)
f_new_tree(struct cf_context *ctx)
{
struct f_tree * ret;
ret = cfg_alloc(sizeof(struct f_tree));

View File

@ -34,6 +34,7 @@
#include "nest/bird.h"
#include "lib/flowspec.h"
#include "conf/conf.h"
#include "conf/parser.h"
static const char* flow4_type_str[] = {
@ -331,16 +332,16 @@ flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
flow_check_cf_value_length(fb, mask);
if (neg && !(val == 0 || val == mask))
cf_error("For negation, value must be zero or bitmask");
cf_error(fb->ctx, "For negation, value must be zero or bitmask");
if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000))
cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask);
cf_error(fb->ctx, "Invalid mask 0x%x, must not exceed 0xfff", mask);
if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01))
cf_error("Invalid mask 0x%x, bit 0 must be 0", mask);
cf_error(fb->ctx, "Invalid mask 0x%x, bit 0 must be 0", mask);
if (val & ~mask)
cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
cf_error(fb->ctx, "Value 0x%x outside bitmask 0x%x", val, mask);
}
/**
@ -359,13 +360,13 @@ flow_check_cf_value_length(struct flow_builder *fb, u32 val)
u8 max = flow_max_value_length(t, fb->ipv6);
if (t == FLOW_TYPE_DSCP && val > 0x3f)
cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
cf_error(fb->ctx, "%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
if (max == 1 && (val > 0xff))
cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val);
cf_error(fb->ctx, "%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val);
if (max == 2 && (val > 0xffff))
cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
cf_error(fb->ctx, "%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
}
static enum flow_validated_state
@ -538,12 +539,12 @@ flow6_validate(const byte *nlri, uint len)
* with a textual description of reason to failing of validation.
*/
void
flow4_validate_cf(net_addr_flow4 *f)
flow4_validate_cf(struct flow_builder *fb, net_addr_flow4 *f)
{
enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data));
if (r != FLOW_ST_VALID)
cf_error("Invalid flow route: %s", flow_validated_state_str(r));
cf_error(fb->ctx, "Invalid flow route: %s", flow_validated_state_str(r));
}
/**
@ -554,12 +555,12 @@ flow4_validate_cf(net_addr_flow4 *f)
* with a textual description of reason to failing of validation.
*/
void
flow6_validate_cf(net_addr_flow6 *f)
flow6_validate_cf(struct flow_builder *fb, net_addr_flow6 *f)
{
enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data));
if (r != FLOW_ST_VALID)
cf_error("Invalid flow route: %s", flow_validated_state_str(r));
cf_error(fb->ctx, "Invalid flow route: %s", flow_validated_state_str(r));
}
@ -574,10 +575,10 @@ flow6_validate_cf(net_addr_flow6 *f)
* This function prepares flowspec builder instance using memory pool @pool.
*/
struct flow_builder *
flow_builder_init(pool *pool)
flow_builder_init(struct cf_context *ctx)
{
struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder));
BUFFER_INIT(fb->data, pool, 4);
struct flow_builder *fb = mb_allocz(ctx->new_config->pool, sizeof(struct flow_builder));
BUFFER_INIT(fb->data, ctx->new_config->pool, 4);
return fb;
}

View File

@ -92,6 +92,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end);
/* A data structure for keep a state of flow builder */
struct flow_builder {
BUFFER_(byte) data;
struct cf_context *ctx;
enum flow_type this_type;
enum flow_type last_type;
u16 last_op_offset; /* Position of last operator in data.data */
@ -102,7 +103,7 @@ struct flow_builder {
} parts[FLOW_TYPE_MAX]; /* Indexing all components */
};
struct flow_builder *flow_builder_init(pool *pool);
struct flow_builder *flow_builder_init(struct cf_context *ctx);
void flow_builder_clear(struct flow_builder *fb);
void flow_builder_set_type(struct flow_builder *fb, enum flow_type p);
int flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4);
@ -138,8 +139,8 @@ enum flow_validated_state flow4_validate(const byte *nlri, uint len);
enum flow_validated_state flow6_validate(const byte *nlri, uint len);
void flow_check_cf_value_length(struct flow_builder *fb, u32 expr);
void flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask);
void flow4_validate_cf(net_addr_flow4 *f);
void flow6_validate_cf(net_addr_flow6 *f);
void flow4_validate_cf(struct flow_builder *fb, net_addr_flow4 *f);
void flow6_validate_cf(struct flow_builder *fb, net_addr_flow6 *f);
/*

View File

@ -42,14 +42,10 @@ struct bfd_request {
struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data);
static inline void cf_check_bfd(int use UNUSED) { }
#else
static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; }
static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); }
#endif /* CONFIG_BFD */

View File

@ -98,28 +98,9 @@ cli_alloc_out(cli *c, int size)
return o->wpos - size;
}
/**
* cli_printf - send reply to a CLI connection
* @c: CLI connection
* @code: numeric code of the reply, negative for continuation lines
* @msg: a printf()-like formatting string.
*
* This function send a single line of reply to a given CLI connection.
* In works in all aspects like bsprintf() except that it automatically
* prepends the reply line prefix.
*
* Please note that if the connection can be already busy sending some
* data in which case cli_printf() stores the output to a temporary buffer,
* so please avoid sending a large batch of replies without waiting
* for the buffers to be flushed.
*
* If you want to write to the current CLI output, you can use the cli_msg()
* macro instead.
*/
void
cli_printf(cli *c, int code, char *msg, ...)
static void
cli_vprintf(cli *c, int code, const char *msg, va_list args)
{
va_list args;
byte buf[CLI_LINE_SIZE];
int cd = code;
int errcode;
@ -146,9 +127,7 @@ cli_printf(cli *c, int code, char *msg, ...)
}
c->last_reply = cd;
va_start(args, msg);
cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args);
va_end(args);
if (cnt < 0)
{
cli_printf(c, errcode, "<line overflow>");
@ -159,6 +138,35 @@ cli_printf(cli *c, int code, char *msg, ...)
memcpy(cli_alloc_out(c, size), buf, size);
}
/**
* cli_printf - send reply to a CLI connection
* @c: CLI connection
* @code: numeric code of the reply, negative for continuation lines
* @msg: a printf()-like formatting string.
*
* This function send a single line of reply to a given CLI connection.
* In works in all aspects like bsprintf() except that it automatically
* prepends the reply line prefix.
*
* Please note that if the connection can be already busy sending some
* data in which case cli_printf() stores the output to a temporary buffer,
* so please avoid sending a large batch of replies without waiting
* for the buffers to be flushed.
*
* If you want to write to the current CLI output, you can use the cli_msg()
* macro instead.
*
* If you want to pass a va_list, use cli_vprintf().
*/
void
cli_printf(cli *c, int code, char *msg, ...)
{
va_list args;
va_start(args, msg);
cli_vprintf(c, code, msg, args);
va_end(args);
}
static void
cli_copy_message(cli *c)
{
@ -229,50 +237,79 @@ cli_written(cli *c)
}
static byte *cli_rh_pos;
static uint cli_rh_len;
static int cli_rh_trick_flag;
struct cli *this_cli;
struct cli_conf_order {
struct conf_order co;
struct cli *cli;
const char *pos;
uint len;
int lexer_hack;
};
static int
cli_cmd_read_hook(byte *buf, uint max, UNUSED int fd)
cli_cmd_read_hook(struct conf_order *co, byte *buf, uint max)
{
if (!cli_rh_trick_flag)
struct cli_conf_order *cco = (struct cli_conf_order *) co;
if (cco->lexer_hack)
{
cli_rh_trick_flag = 1;
buf[0] = '!';
/* Lexer needs at least one character to be read
* to transition between states. Feeding a dummy
* character which is dropped to make Flex produce
* a dummy "CLIENT" token */
cco->lexer_hack = 0;
buf[0] = '"';
return 1;
}
if (max > cli_rh_len)
max = cli_rh_len;
memcpy(buf, cli_rh_pos, max);
cli_rh_pos += max;
cli_rh_len -= max;
if (max > cco->len)
max = cco->len;
memcpy(buf, cco->pos, cco->len);
cco->pos += max;
cco->len -= max;
return max;
}
static void
cli_cmd_error(struct conf_order *co, const char *msg, va_list args)
{
struct cli_conf_order *cco = (struct cli_conf_order *) co;
cli_vprintf(cco->cli, 9001, msg, args);
}
static void
cli_command(struct cli *c)
{
struct config f;
int res;
struct conf_state state = {
.name = "",
.lino = 1
};
struct cli_conf_order o = {
.co = {
.ctx = NULL,
.state = &state,
.cf_read_hook = cli_cmd_read_hook,
.cf_include = NULL,
.cf_outclude = NULL,
.cf_error = cli_cmd_error,
.lp = c->parser_pool,
.pool = c->pool,
},
.lexer_hack = 1,
.pos = c->rx_buf,
.len = strlen(c->rx_buf),
.cli = c,
};
if (config->cli_debug > 1)
log(L_TRACE "CLI: %s", c->rx_buf);
bzero(&f, sizeof(f));
f.mem = c->parser_pool;
f.pool = rp_new(c->pool, "Config");
cf_read_hook = cli_cmd_read_hook;
cli_rh_pos = c->rx_buf;
cli_rh_len = strlen(c->rx_buf);
cli_rh_trick_flag = 0;
this_cli = c;
lp_flush(c->parser_pool);
res = cli_parse(&f);
if (!res)
cli_printf(c, 9001, f.err_msg);
config_free(&f);
this_cli = c;
cli_parse(&(o.co));
}
static void
@ -316,8 +353,8 @@ cli_new(void *priv)
c->event->hook = cli_event;
c->event->data = c;
c->cont = cli_hello;
c->parser_pool = lp_new_default(c->pool);
c->show_pool = lp_new_default(c->pool);
c->parser_pool = lp_new_default(c->pool);
c->rx_buf = mb_alloc(c->pool, CLI_RX_BUF_SIZE);
ev_schedule(c->event);
return c;

View File

@ -6,6 +6,9 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _NEST_CMDS_H_
#define _NEST_CMDS_H_
struct sym_show_data {
int type; /* Symbols type to show */
struct symbol *sym;
@ -17,3 +20,5 @@ void cmd_show_status(void);
void cmd_show_symbols(struct sym_show_data *sym);
void cmd_show_memory(void);
void cmd_eval(struct f_inst *expr);
#endif

View File

@ -15,52 +15,53 @@ CF_HDR
#include "lib/lists.h"
#include "lib/mac.h"
CF_CTX
struct proto_config *this_proto;
struct channel_config *this_channel;
struct iface_patt *this_ipatt;
struct iface_patt_node *this_ipn;
list *this_p_list;
struct password_item *this_p_item;
int password_id;
CF_DEFINES
static struct proto_config *this_proto;
static struct channel_config *this_channel;
static struct iface_patt *this_ipatt;
static struct iface_patt_node *this_ipn;
/* static struct roa_table_config *this_roa_table; */
static list *this_p_list;
static struct password_item *this_p_item;
static int password_id;
static void
iface_patt_check(void)
iface_patt_check(struct cf_context *ctx)
{
struct iface_patt_node *pn;
WALK_LIST(pn, this_ipatt->ipn_list)
WALK_LIST(pn, ctx->this_ipatt->ipn_list)
if (!pn->pattern || pn->prefix.type)
cf_error("Interface name/mask expected, not IP prefix");
cf_error(ctx, "Interface name/mask expected, not IP prefix");
}
static inline void
reset_passwords(void)
reset_passwords(struct cf_context *ctx)
{
this_p_list = NULL;
ctx->this_p_list = NULL;
}
static inline list *
get_passwords(void)
get_passwords(struct cf_context *ctx)
{
list *rv = this_p_list;
this_p_list = NULL;
list *rv = ctx->this_p_list;
ctx->this_p_list = NULL;
return rv;
}
static void
proto_postconfig(void)
proto_postconfig(struct cf_context *ctx)
{
CALL(this_proto->protocol->postconfig, this_proto);
this_channel = NULL;
this_proto = NULL;
CALL(ctx->this_proto->protocol->postconfig, ctx, ctx->this_proto);
ctx->this_channel = NULL;
ctx->this_proto = NULL;
}
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
#define DIRECT_CFG ((struct rt_dev_config *) ctx->this_proto)
CF_DECLS
@ -106,13 +107,13 @@ CF_GRAMMAR
conf: rtrid ;
rtrid:
ROUTER ID idval ';' { new_config->router_id = $3; }
| ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; }
ROUTER ID idval ';' { ctx->new_config->router_id = $3; }
| ROUTER ID FROM iface_patt ';' { ctx->new_config->router_id_from = ctx->this_ipatt; }
;
idval:
NUM { $$ = $1; }
| '(' term ')' { $$ = f_eval_int($2); }
| '(' term ')' { $$ = f_eval_int($2, ctx); }
| IP4 { $$ = ip4_to_u32($1); }
| SYM {
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
@ -120,13 +121,13 @@ idval:
else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
$$ = ipa_to_u32(SYM_VAL($1).ip);
else
cf_error("Number or IPv4 address constant expected");
cf_error(ctx, "Number or IPv4 address constant expected");
}
;
conf: gr_opts ;
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
gr_opts: GRACEFUL RESTART WAIT expr ';' { ctx->new_config->gr_wait = $4; } ;
/* Network types (for tables, channels) */
@ -158,7 +159,7 @@ table_sorted:
table: net_type TABLE SYM table_sorted {
struct rtable_config *cf;
cf = rt_new_table($3, $1);
cf = rt_new_table(ctx, $3, $1);
cf->sorted = $4;
}
;
@ -166,7 +167,7 @@ table: net_type TABLE SYM table_sorted {
/* Definition of protocols */
conf: proto { proto_postconfig(); } ;
conf: proto { proto_postconfig(ctx); } ;
proto_start:
PROTOCOL { $$ = SYM_PROTO; }
@ -175,62 +176,62 @@ proto_start:
proto_name:
/* EMPTY */ {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
s->class = this_proto->class;
s->def = this_proto;
this_proto->name = s->name;
struct symbol *s = cf_default_name(ctx, ctx->this_proto->protocol->template, &ctx->this_proto->protocol->name_counter);
s->class = ctx->this_proto->class;
s->def = ctx->this_proto;
ctx->this_proto->name = s->name;
}
| SYM {
cf_define_symbol($1, this_proto->class, this_proto);
this_proto->name = $1->name;
cf_define_symbol(ctx, $1, ctx->this_proto->class, ctx->this_proto);
ctx->this_proto->name = $1->name;
}
| FROM SYM {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
s->class = this_proto->class;
s->def = this_proto;
this_proto->name = s->name;
struct symbol *s = cf_default_name(ctx, ctx->this_proto->protocol->template, &ctx->this_proto->protocol->name_counter);
s->class = ctx->this_proto->class;
s->def = ctx->this_proto;
ctx->this_proto->name = s->name;
if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
proto_copy_config(this_proto, $2->def);
if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error(ctx, "Template or protocol name expected");
proto_copy_config(ctx, ctx->this_proto, $2->def);
}
| SYM FROM SYM {
cf_define_symbol($1, this_proto->class, this_proto);
this_proto->name = $1->name;
cf_define_symbol(ctx, $1, ctx->this_proto->class, ctx->this_proto);
ctx->this_proto->name = $1->name;
if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
proto_copy_config(this_proto, $3->def);
if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error(ctx, "Template or protocol name expected");
proto_copy_config(ctx, ctx->this_proto, $3->def);
}
;
proto_item:
/* EMPTY */
| DISABLED bool { this_proto->disabled = $2; }
| DEBUG debug_mask { this_proto->debug = $2; }
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; }
| VRF text { this_proto->vrf = if_get_by_name($2); }
| DISABLED bool { ctx->this_proto->disabled = $2; }
| DEBUG debug_mask { ctx->this_proto->debug = $2; }
| MRTDUMP mrtdump_mask { ctx->this_proto->mrtdump = $2; }
| ROUTER ID idval { ctx->this_proto->router_id = $3; }
| DESCRIPTION text { ctx->this_proto->dsc = $2; }
| VRF text { ctx->this_proto->vrf = if_get_by_name($2); }
;
channel_start: net_type
{
$$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
$$ = ctx->this_channel = channel_config_get(ctx, NULL, net_label[$1], $1, ctx->this_proto);
};
channel_item:
TABLE rtable {
if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
cf_error("Incompatible table type");
this_channel->table = $2;
if (ctx->this_channel->net_type && ($2->addr_type != ctx->this_channel->net_type))
cf_error(ctx, "Incompatible table type");
ctx->this_channel->table = $2;
}
| IMPORT imexport { this_channel->in_filter = $2; }
| EXPORT imexport { this_channel->out_filter = $2; }
| RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
| IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
| IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
| IMPORT imexport { ctx->this_channel->in_filter = $2; }
| EXPORT imexport { ctx->this_channel->out_filter = $2; }
| RECEIVE LIMIT limit_spec { ctx->this_channel->rx_limit = $3; }
| IMPORT LIMIT limit_spec { ctx->this_channel->in_limit = $3; }
| EXPORT LIMIT limit_spec { ctx->this_channel->out_limit = $3; }
| PREFERENCE expr { ctx->this_channel->preference = $2; check_u16(ctx, $2); }
| IMPORT KEEP FILTERED bool { ctx->this_channel->in_keep_filtered = $4; }
;
channel_opts:
@ -245,10 +246,10 @@ channel_opt_list:
channel_end:
{
if (!this_channel->table)
cf_error("Routing table not specified");
if (!ctx->this_channel->table)
cf_error(ctx, "Routing table not specified");
this_channel = NULL;
ctx->this_channel = NULL;
};
proto_channel: channel_start channel_opt_list channel_end;
@ -256,7 +257,7 @@ proto_channel: channel_start channel_opt_list channel_end;
rtable:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table expected");
if ($1->class != SYM_TABLE) cf_error(ctx, "Table expected");
$$ = $1->def;
}
;
@ -285,8 +286,8 @@ limit_spec:
conf: debug_default ;
debug_default:
DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
DEBUG PROTOCOLS debug_mask { ctx->new_config->proto_default_debug = $3; }
| DEBUG COMMANDS expr { ctx->new_config->cli_debug = $3; }
;
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
@ -294,10 +295,10 @@ debug_default:
conf: timeformat_base ;
timeformat_which:
ROUTE { $$ = &new_config->tf_route; }
| PROTOCOL { $$ = &new_config->tf_proto; }
| BASE { $$ = &new_config->tf_base; }
| LOG { $$ = &new_config->tf_log; }
ROUTE { $$ = &ctx->new_config->tf_route; }
| PROTOCOL { $$ = &ctx->new_config->tf_proto; }
| BASE { $$ = &ctx->new_config->tf_base; }
| LOG { $$ = &ctx->new_config->tf_log; }
;
timeformat_spec:
@ -321,19 +322,19 @@ timeformat_base:
iface_patt_node_init:
/* EMPTY */ {
struct iface_patt_node *ipn = cfg_allocz(sizeof(struct iface_patt_node));
add_tail(&this_ipatt->ipn_list, NODE ipn);
this_ipn = ipn;
add_tail(&ctx->this_ipatt->ipn_list, NODE ipn);
ctx->this_ipn = ipn;
}
;
iface_patt_node_body:
TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ }
| opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; }
TEXT { ctx->this_ipn->pattern = $1; /* ctx->this_ipn->prefix stays zero */ }
| opttext net_or_ipa { ctx->this_ipn->pattern = $1; ctx->this_ipn->prefix = $2; }
;
iface_negate:
{ this_ipn->positive = 1; }
| '-' { this_ipn->positive = 0; }
{ ctx->this_ipn->positive = 1; }
| '-' { ctx->this_ipn->positive = 0; }
;
iface_patt_node:
@ -347,12 +348,12 @@ iface_patt_list:
;
/* For name/mask-only iface patterns */
iface_patt_list_nopx: iface_patt_list { iface_patt_check(); }
iface_patt_list_nopx: iface_patt_list { iface_patt_check(ctx); }
iface_patt_init: {
/* Generic this_ipatt init */
this_ipatt = cfg_allocz(sizeof(struct iface_patt));
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct iface_patt));
init_list(&ctx->this_ipatt->ipn_list);
}
;
@ -361,8 +362,8 @@ iface_patt:
;
tos:
CLASS expr { $$ = $2 & 0xfc; if ($2 > 255) cf_error("TX class must be in range 0-255"); }
| DSCP expr { $$ = ($2 & 0x3f) << 2; if ($2 > 63) cf_error("TX DSCP must be in range 0-63"); }
CLASS expr { $$ = $2 & 0xfc; if ($2 > 255) cf_error(ctx, "TX class must be in range 0-255"); }
| DSCP expr { $$ = ($2 & 0x3f) << 2; if ($2 > 63) cf_error(ctx, "TX DSCP must be in range 0-63"); }
;
/* Direct device route protocol */
@ -370,7 +371,7 @@ tos:
proto: dev_proto '}' ;
dev_proto_start: proto_start DIRECT {
this_proto = proto_config_new(&proto_device, $1);
ctx->this_proto = proto_config_new(ctx, &proto_device, $1);
init_list(&DIRECT_CFG->iface_list);
}
;
@ -385,9 +386,9 @@ dev_proto:
dev_iface_init:
/* EMPTY */ {
this_ipatt = cfg_allocz(sizeof(struct iface_patt));
add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct iface_patt));
add_tail(&DIRECT_CFG->iface_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
}
;
@ -454,34 +455,37 @@ password_item:
password_item_begin:
PASSWORD text {
if (!this_p_list) {
this_p_list = cfg_alloc(sizeof(list));
init_list(this_p_list);
password_id = 1;
if (!ctx->this_p_list) {
ctx->this_p_list = cfg_alloc(sizeof(list));
init_list(ctx->this_p_list);
ctx->password_id = 1;
}
this_p_item = cfg_alloc(sizeof (struct password_item));
this_p_item->password = $2;
this_p_item->length = strlen($2);
this_p_item->genfrom = 0;
this_p_item->gento = TIME_INFINITY;
this_p_item->accfrom = 0;
this_p_item->accto = TIME_INFINITY;
this_p_item->id = password_id++;
this_p_item->alg = ALG_UNDEFINED;
add_tail(this_p_list, &this_p_item->n);
struct password_item *pi = cfg_alloc(sizeof (struct password_item));
*pi = (struct password_item) {
.password = $2,
.length = strlen($2),
.genfrom = 0,
.gento = TIME_INFINITY,
.accfrom = 0,
.accto = TIME_INFINITY,
.id = ctx->password_id++,
.alg = ALG_UNDEFINED,
};
ctx->this_p_item = pi;
add_tail(ctx->this_p_list, &pi->n);
}
;
password_item_params:
/* empty */ { }
| GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
| GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
| ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
| ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
| FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
| TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
| ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
| ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
| GENERATE FROM time ';' password_item_params { ctx->this_p_item->genfrom = $3; }
| GENERATE TO time ';' password_item_params { ctx->this_p_item->gento = $3; }
| ACCEPT FROM time ';' password_item_params { ctx->this_p_item->accfrom = $3; }
| ACCEPT TO time ';' password_item_params { ctx->this_p_item->accto = $3; }
| FROM time ';' password_item_params { ctx->this_p_item->genfrom = ctx->this_p_item->accfrom = $2; }
| TO time ';' password_item_params { ctx->this_p_item->gento = ctx->this_p_item->accto = $2; }
| ID expr ';' password_item_params { ctx->this_p_item->id = $2; if ($2 <= 0) cf_error(ctx, "Password ID has to be greated than zero."); }
| ALGORITHM password_algorithm ';' password_item_params { ctx->this_p_item->alg = $2; }
;
password_algorithm:
@ -532,21 +536,22 @@ r_args:
$$ = cfg_allocz(sizeof(struct rt_show_data));
init_list(&($$->tables));
$$->filter = FILTER_ACCEPT;
$$->ctx = ctx;
}
| r_args net_any {
$$ = $1;
if ($$->addr) cf_error("Only one prefix expected");
if ($$->addr) cf_error(ctx, "Only one prefix expected");
$$->addr = $2;
}
| r_args FOR r_args_for {
$$ = $1;
if ($$->addr) cf_error("Only one prefix expected");
if ($$->addr) cf_error(ctx, "Only one prefix expected");
$$->show_for = 1;
$$->addr = $3;
}
| r_args TABLE SYM {
$$ = $1;
if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name);
if ($3->class != SYM_TABLE) cf_error(ctx, "%s is not a table", $3->name);
rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
@ -559,12 +564,12 @@ r_args:
}
| r_args FILTER filter {
$$ = $1;
if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
if ($$->filter != FILTER_ACCEPT) cf_error(ctx, "Filter specified twice");
$$->filter = $3;
}
| r_args where_filter {
$$ = $1;
if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
if ($$->filter != FILTER_ACCEPT) cf_error(ctx, "Filter specified twice");
$$->filter = $2;
}
| r_args ALL {
@ -582,8 +587,8 @@ r_args:
| r_args export_mode SYM {
struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
if ($$->export_mode) cf_error(ctx, "Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name);
$$->export_mode = $2;
$$->export_protocol = c->proto;
$$->running_on_config = c->proto->cf->global;
@ -592,19 +597,19 @@ r_args:
| r_args export_mode SYM '.' r_args_channel {
struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
if ($$->export_mode) cf_error(ctx, "Export specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name);
$$->export_mode = $2;
$$->export_channel = proto_find_channel_by_name(c->proto, $5);
if (!$$->export_channel) cf_error("Export channel not found");
if (!$$->export_channel) cf_error(ctx, "Export channel not found");
$$->running_on_config = c->proto->cf->global;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL SYM {
struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1;
if ($$->show_protocol) cf_error("Protocol specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
if ($$->show_protocol) cf_error(ctx, "Protocol specified twice");
if ($3->class != SYM_PROTO || !c->proto) cf_error(ctx, "%s is not a protocol", $3->name);
$$->show_protocol = c->proto;
$$->running_on_config = c->proto->cf->global;
$$->tables_defined_by = RSD_TDB_INDIRECT;
@ -648,7 +653,7 @@ r_args_for:
else if (($1->class == (SYM_CONSTANT | T_NET)) && net_type_match(SYM_VAL($1).net, NB_IP | NB_VPN))
$$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
else
cf_error("IP address or network expected");
cf_error(ctx, "IP address or network expected");
}
;
@ -741,7 +746,7 @@ echo_mask:
echo_size:
/* empty */ { $$ = 4096; }
| NUM {
if ($1 < 256 || $1 > 65536) cf_error("Invalid log buffer size");
if ($1 < 256 || $1 > 65536) cf_error(ctx, "Invalid log buffer size");
$$ = $1;
}
;

View File

@ -16,6 +16,7 @@
#include "lib/timer.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "nest/route.h"
#include "nest/iface.h"
#include "nest/cli.h"
@ -457,7 +458,7 @@ const struct channel_class channel_basic = {
};
void *
channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
channel_config_new(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{
struct channel_config *cf = NULL;
struct rtable_config *tab = NULL;
@ -465,12 +466,12 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
if (net_type)
{
if (!net_val_match(net_type, proto->protocol->channel_mask))
cf_error("Unsupported channel type");
cf_error(ctx, "Unsupported channel type");
if (proto->net_type && (net_type != proto->net_type))
cf_error("Different channel type");
cf_error(ctx, "Different channel type");
tab = new_config->def_tables[net_type];
tab = ctx->new_config->def_tables[net_type];
}
if (!cc)
@ -493,7 +494,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
}
void *
channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
channel_config_get(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{
struct channel_config *cf;
@ -503,17 +504,17 @@ channel_config_get(const struct channel_class *cc, const char *name, uint net_ty
{
/* Allow to redefine channel only if inherited from template */
if (cf->parent == proto)
cf_error("Multiple %s channels", name);
cf_error(ctx, "Multiple %s channels", name);
cf->parent = proto;
return cf;
}
return channel_config_new(cc, name, net_type, proto);
return channel_config_new(ctx, cc, name, net_type, proto);
}
struct channel_config *
channel_copy_config(struct channel_config *src, struct proto_config *proto)
channel_copy_config(struct cf_context *ctx, struct channel_config *src, struct proto_config *proto)
{
struct channel_config *dst = cfg_alloc(src->channel->config_size);
@ -741,19 +742,19 @@ proto_start(struct proto *p)
* initialized during protos_commit()).
*/
void *
proto_config_new(struct protocol *pr, int class)
proto_config_new(struct cf_context *ctx, struct protocol *pr, int class)
{
struct proto_config *cf = cfg_allocz(pr->config_size);
if (class == SYM_PROTO)
add_tail(&new_config->protos, &cf->n);
add_tail(&ctx->new_config->protos, &cf->n);
cf->global = new_config;
cf->global = ctx->new_config;
cf->protocol = pr;
cf->name = pr->name;
cf->class = class;
cf->debug = new_config->proto_default_debug;
cf->mrtdump = new_config->proto_default_mrtdump;
cf->debug = ctx->new_config->proto_default_debug;
cf->mrtdump = ctx->new_config->proto_default_mrtdump;
init_list(&cf->channels);
@ -773,7 +774,7 @@ proto_config_new(struct protocol *pr, int class)
* copy_config() protocol hook is used to copy protocol-specific data.
*/
void
proto_copy_config(struct proto_config *dest, struct proto_config *src)
proto_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src)
{
struct channel_config *cc;
node old_node;
@ -781,10 +782,10 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src)
char *old_name;
if (dest->protocol != src->protocol)
cf_error("Can't copy configuration from a different protocol type");
cf_error(ctx, "Can't copy configuration from a different protocol type");
if (dest->protocol->copy_config == NULL)
cf_error("Inheriting configuration for %s is not supported", src->protocol->name);
cf_error(ctx, "Inheriting configuration for %s is not supported", src->protocol->name);
DBG("Copying configuration from %s to %s\n", src->name, dest->name);
@ -805,10 +806,10 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src)
init_list(&dest->channels);
WALK_LIST(cc, src->channels)
channel_copy_config(cc, dest);
channel_copy_config(ctx, cc, dest);
/* FIXME: allow for undefined copy_config */
dest->protocol->copy_config(dest, src);
dest->protocol->copy_config(ctx, dest, src);
}
/**
@ -1870,18 +1871,18 @@ proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, in
}
struct proto *
proto_get_named(struct symbol *sym, struct protocol *pr)
proto_get_named(struct cf_context *ctx, struct symbol *sym, struct protocol *pr)
{
struct proto *p, *q;
if (sym)
{
if (sym->class != SYM_PROTO)
cf_error("%s: Not a protocol", sym->name);
cf_error(ctx, "%s: Not a protocol", sym->name);
p = ((struct proto_config *) sym->def)->proto;
if (!p || p->proto != pr)
cf_error("%s: Not a %s protocol", sym->name, pr->name);
cf_error(ctx, "%s: Not a %s protocol", sym->name, pr->name);
}
else
{
@ -1890,11 +1891,11 @@ proto_get_named(struct symbol *sym, struct protocol *pr)
if ((q->proto == pr) && (q->proto_state != PS_DOWN))
{
if (p)
cf_error("There are multiple %s protocols running", pr->name);
cf_error(ctx, "There are multiple %s protocols running", pr->name);
p = q;
}
if (!p)
cf_error("There is no %s protocol running", pr->name);
cf_error(ctx, "There is no %s protocol running", pr->name);
}
return p;

View File

@ -68,7 +68,7 @@ struct protocol {
uint config_size; /* Size of protocol config data structure */
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
void (*postconfig)(struct proto_config *); /* After configuring each instance */
void (*postconfig)(struct cf_context *ctx, struct proto_config *); /* After configuring each instance */
struct proto * (*init)(struct proto_config *); /* Create new instance */
int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance, returns success */
void (*dump)(struct proto *); /* Debugging dump */
@ -80,7 +80,7 @@ struct protocol {
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
void (*copy_config)(struct cf_context *ctx, struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
};
void protos_build(void);
@ -257,8 +257,8 @@ struct proto_spec {
void *proto_new(struct proto_config *);
void *proto_config_new(struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void *proto_config_new(struct cf_context *ctx, struct protocol *, int class);
void proto_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src);
void proto_set_message(struct proto *p, char *msg, int len);
void graceful_restart_recovery(void);
@ -281,7 +281,7 @@ void proto_cmd_debug(struct proto *, uintptr_t, int);
void proto_cmd_mrtdump(struct proto *, uintptr_t, int);
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg);
struct proto *proto_get_named(struct symbol *, struct protocol *);
struct proto *proto_get_named(struct cf_context *ctx, struct symbol *, struct protocol *);
#define CMD_RELOAD 0
#define CMD_RELOAD_IN 1
@ -611,8 +611,8 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
void channel_request_feeding(struct channel *c);
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_new(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(struct cf_context *ctx, const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);

View File

@ -278,9 +278,10 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RIC_DROP -2 /* Silently dropped by protocol */
struct config;
struct cf_context;
void rt_init(void);
void rt_preconfig(struct config *);
void rt_preconfig(struct cf_context *);
void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *);
void rt_unlock_table(rtable *);
@ -310,7 +311,7 @@ void rt_dump(rtable *);
void rt_dump_all(void);
int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
struct rtable_config *rt_new_table(struct cf_context *ctx, struct symbol *s, uint addr_type);
/* Default limit for ECMP next hops, defined in sysdep code */
extern const int rt_default_ecmp;
@ -324,6 +325,7 @@ struct rt_show_data_rtable {
struct rt_show_data {
net_addr *addr;
list tables;
struct cf_context *ctx; /* Parent parser context */
struct rt_show_data_rtable *tab; /* Iterator over table list */
struct rt_show_data_rtable *last_table; /* Last table in output */
struct fib_iterator fit; /* Iterator over networks in table */
@ -340,6 +342,8 @@ struct rt_show_data {
int net_counter_last, rt_counter_last, show_counter_last;
};
struct cf_context;
void rt_show(struct rt_show_data *);
struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t);

View File

@ -116,7 +116,7 @@ dev_if_notify(struct proto *p, uint c, struct iface *iface)
}
static void
dev_postconfig(struct proto_config *CF)
dev_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct rt_dev_config *cf = (void *) CF;
struct channel_config *ip4, *ip6, *ip6_sadr;
@ -126,7 +126,7 @@ dev_postconfig(struct proto_config *CF)
ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);
if (ip6 && ip6_sadr)
cf_error("Both ipv6 and ipv6-sadr channels");
cf_error(ctx, "Both ipv6 and ipv6-sadr channels");
cf->ip4_channel = ip4;
cf->ip6_channel = ip6 ?: ip6_sadr;
@ -167,7 +167,7 @@ dev_reconfigure(struct proto *P, struct proto_config *CF)
}
static void
dev_copy_config(struct proto_config *dest, struct proto_config *src)
dev_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src)
{
struct rt_dev_config *d = (void *) dest;
struct rt_dev_config *s = (void *) src;
@ -177,7 +177,7 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
* Copy suffices to be is shallow, because new nodes can be added, but
* old nodes cannot be modified (although they contain internal lists).
*/
cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
cf_copy_list(ctx, &d->iface_list, &s->iface_list, sizeof(struct iface_patt));
d->check_link = s->check_link;
}

View File

@ -14,6 +14,7 @@
#include "nest/protocol.h"
#include "nest/cli.h"
#include "nest/iface.h"
#include "conf/parser.h"
#include "filter/filter.h"
static void
@ -275,6 +276,7 @@ done:
struct rt_show_data_rtable *
rt_show_add_table(struct rt_show_data *d, rtable *t)
{
struct cf_context *ctx = d->ctx;
struct rt_show_data_rtable *tab = cfg_allocz(sizeof(struct rt_show_data_rtable));
tab->table = t;
add_tail(&(d->tables), &(tab->n));
@ -344,7 +346,7 @@ rt_show_prepare_tables(struct rt_show_data *d)
if (!tab->export_channel)
{
if (d->tables_defined_by & RSD_TDB_NMN)
cf_error("No export channel for table %s", tab->table->name);
cf_error(d->ctx, "No export channel for table %s", tab->table->name);
rem_node(&(tab->n));
continue;
@ -355,7 +357,7 @@ rt_show_prepare_tables(struct rt_show_data *d)
if (d->addr && (tab->table->addr_type != d->addr->type))
{
if (d->tables_defined_by & RSD_TDB_NMN)
cf_error("Incompatible type of prefix/ip for table %s", tab->table->name);
cf_error(d->ctx, "Incompatible type of prefix/ip for table %s", tab->table->name);
rem_node(&(tab->n));
continue;
@ -364,7 +366,7 @@ rt_show_prepare_tables(struct rt_show_data *d)
/* Ensure there is at least one table */
if (EMPTY_LIST(d->tables))
cf_error("No valid tables");
cf_error(d->ctx, "No valid tables");
}
void
@ -375,7 +377,7 @@ rt_show(struct rt_show_data *d)
/* Filtered routes are neither exported nor have sensible ordering */
if (d->filtered && (d->export_mode || d->primary_only))
cf_error("Incompatible show route options");
cf_error(d->ctx, "Incompatible show route options");
rt_show_prepare_tables(d);

View File

@ -38,6 +38,7 @@
#include "lib/event.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "conf/parser.h"
#include "filter/filter.h"
#include "lib/hash.h"
#include "lib/string.h"
@ -1823,12 +1824,12 @@ again:
}
void
rt_preconfig(struct config *c)
rt_preconfig(struct cf_context *ctx)
{
init_list(&c->tables);
init_list(&ctx->new_config->tables);
rt_new_table(cf_get_symbol("master4"), NET_IP4);
rt_new_table(cf_get_symbol("master6"), NET_IP6);
rt_new_table(ctx, cf_get_symbol(ctx, "master4"), NET_IP4);
rt_new_table(ctx, cf_get_symbol(ctx, "master6"), NET_IP6);
}
@ -2060,27 +2061,27 @@ rt_next_hop_update(rtable *tab)
struct rtable_config *
rt_new_table(struct symbol *s, uint addr_type)
rt_new_table(struct cf_context *ctx, struct symbol *s, uint addr_type)
{
/* Hack that allows to 'redefine' the master table */
if ((s->class == SYM_TABLE) &&
(s->def == new_config->def_tables[addr_type]) &&
(s->def == ctx->new_config->def_tables[addr_type]) &&
((addr_type == NET_IP4) || (addr_type == NET_IP6)))
return s->def;
struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
cf_define_symbol(s, SYM_TABLE, c);
cf_define_symbol(ctx, s, SYM_TABLE, c);
c->name = s->name;
c->addr_type = addr_type;
c->gc_max_ops = 1000;
c->gc_min_time = 5;
add_tail(&new_config->tables, &c->n);
add_tail(&ctx->new_config->tables, &c->n);
/* First table of each type is kept as default */
if (! new_config->def_tables[addr_type])
new_config->def_tables[addr_type] = c;
if (!ctx->new_config->def_tables[addr_type])
ctx->new_config->def_tables[addr_type] = c;
return c;
}

View File

@ -2187,7 +2187,7 @@ babel_rte_same(struct rte *new, struct rte *old)
static void
babel_postconfig(struct proto_config *CF)
babel_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct babel_config *cf = (void *) CF;
struct channel_config *ip4, *ip6, *ip6_sadr;
@ -2197,7 +2197,7 @@ babel_postconfig(struct proto_config *CF)
ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);
if (ip6 && ip6_sadr)
cf_error("Both ipv6 and ipv6-sadr channels");
cf_error(ctx, "Both ipv6 and ipv6-sadr channels");
cf->ip4_channel = ip4;
cf->ip6_channel = ip6 ?: ip6_sadr;

View File

@ -17,8 +17,8 @@ CF_HDR
CF_DEFINES
#define BABEL_CFG ((struct babel_config *) this_proto)
#define BABEL_IFACE ((struct babel_iface_config *) this_ipatt)
#define BABEL_CFG ((struct babel_config *) ctx->this_proto)
#define BABEL_IFACE ((struct babel_iface_config *) ctx->this_ipatt)
CF_DECLS
@ -33,7 +33,7 @@ proto: babel_proto ;
babel_proto_start: proto_start BABEL
{
this_proto = proto_config_new(&proto_babel, $1);
ctx->this_proto = proto_config_new(ctx, &proto_babel, $1);
init_list(&BABEL_CFG->iface_list);
BABEL_CFG->hold_time = 1 S_;
};
@ -56,9 +56,9 @@ babel_proto:
babel_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct babel_iface_config));
add_tail(&BABEL_CFG->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct babel_iface_config));
add_tail(&BABEL_CFG->iface_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
BABEL_IFACE->port = BABEL_PORT;
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
@ -95,20 +95,20 @@ babel_iface_finish:
babel_iface_item:
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid port number"); }
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid rxcost"); }
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error(ctx, "Limit must be in range 1-16"); }
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
| HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($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:
@ -130,16 +130,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BAB
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [<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

View File

@ -1061,7 +1061,7 @@ bfd_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
}
static void
bfd_copy_config(struct proto_config *dest, struct proto_config *src UNUSED)
bfd_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest, struct proto_config *src UNUSED)
{
struct bfd_config *d = (struct bfd_config *) dest;
// struct bfd_config *s = (struct bfd_config *) src;

View File

@ -11,8 +11,12 @@ CF_HDR
CF_DEFINES
#define BFD_CFG ((struct bfd_config *) this_proto)
#define BFD_IFACE ((struct bfd_iface_config *) this_ipatt)
/* BFD is available, override the trap in conf/confbase.Y */
#undef BFD_CHECK
#define BFD_CHECK(x)
#define BFD_CFG ((struct bfd_config *) ctx->this_proto)
#define BFD_IFACE ((struct bfd_iface_config *) ctx->this_ipatt)
#define BFD_NEIGHBOR this_bfd_neighbor
static struct bfd_neighbor *this_bfd_neighbor;
@ -35,12 +39,12 @@ proto: bfd_proto ;
bfd_proto_start: proto_start BFD
{
this_proto = proto_config_new(&proto_bfd, $1);
ctx->this_proto = proto_config_new(ctx, &proto_bfd, $1);
init_list(&BFD_CFG->patt_list);
init_list(&BFD_CFG->neigh_list);
if (bfd_cf)
cf_error("Only one BFD instance allowed");
cf_error(ctx, "Only one BFD instance allowed");
bfd_cf = BFD_CFG;
};
@ -62,21 +66,21 @@ bfd_proto:
bfd_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config));
add_tail(&BFD_CFG->patt_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config));
add_tail(&BFD_CFG->patt_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
BFD_IFACE->min_rx_int = BFD_DEFAULT_MIN_RX_INT;
BFD_IFACE->min_tx_int = BFD_DEFAULT_MIN_TX_INT;
BFD_IFACE->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT;
BFD_IFACE->multiplier = BFD_DEFAULT_MULTIPLIER;
reset_passwords();
reset_passwords(ctx);
};
bfd_iface_finish:
{
BFD_IFACE->passwords = get_passwords();
BFD_IFACE->passwords = get_passwords(ctx);
if (!BFD_IFACE->auth_type != !BFD_IFACE->passwords)
log(L_WARN "Authentication and password options should be used together");
@ -87,7 +91,7 @@ bfd_iface_finish:
WALK_LIST(pass, *BFD_IFACE->passwords)
{
if (pass->alg)
cf_error("Password algorithm option not available in BFD protocol");
cf_error(ctx, "Password algorithm option not available in BFD protocol");
pass->alg = bfd_auth_type_to_hash_alg[BFD_IFACE->auth_type];
}
@ -159,16 +163,16 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop
BFD_NEIGHBOR->multihop = $4;
if ($4 && $2)
cf_error("Neighbor cannot set both interface and multihop");
cf_error(ctx, "Neighbor cannot set both interface and multihop");
if ($4 && ipa_zero($3))
cf_error("Multihop neighbor requires specified local address");
cf_error(ctx, "Multihop neighbor requires specified local address");
};
CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]);
CF_CLI(SHOW BFD SESSIONS, optsym, [<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

View File

@ -1681,7 +1681,7 @@ bgp_find_channel_config(struct bgp_config *cf, u32 afi)
}
struct rtable_config *
bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32 type)
bgp_default_igp_table(struct cf_context *ctx, struct bgp_config *cf, struct bgp_channel_config *cc, u32 type)
{
struct bgp_channel_config *cc2;
struct rtable_config *tab;
@ -1706,12 +1706,12 @@ bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32
if (tab = cf->c.global->def_tables[type])
return tab;
cf_error("Undefined IGP table");
cf_error(ctx, "Undefined IGP table");
}
void
bgp_postconfig(struct proto_config *CF)
bgp_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct bgp_config *cf = (void *) CF;
int internal = (cf->local_as == cf->remote_as);
@ -1736,44 +1736,44 @@ bgp_postconfig(struct proto_config *CF)
if (!cf->local_as)
cf_error("Local AS number must be set");
cf_error(ctx, "Local AS number must be set");
if (ipa_zero(cf->remote_ip))
cf_error("Neighbor must be configured");
cf_error(ctx, "Neighbor must be configured");
if (!cf->remote_as)
cf_error("Remote AS number must be set");
cf_error(ctx, "Remote AS number must be set");
if (ipa_is_link_local(cf->remote_ip) && !cf->iface)
cf_error("Link-local neighbor address requires specified interface");
cf_error(ctx, "Link-local neighbor address requires specified interface");
if (!(cf->capabilities && cf->enable_as4) && (cf->remote_as > 0xFFFF))
cf_error("Neighbor AS number out of range (AS4 not available)");
cf_error(ctx, "Neighbor AS number out of range (AS4 not available)");
if (!internal && cf->rr_client)
cf_error("Only internal neighbor can be RR client");
cf_error(ctx, "Only internal neighbor can be RR client");
if (internal && cf->rs_client)
cf_error("Only external neighbor can be RS client");
cf_error(ctx, "Only external neighbor can be RS client");
if (!cf->confederation && cf->confederation_member)
cf_error("Confederation ID must be set for member sessions");
cf_error(ctx, "Confederation ID must be set for member sessions");
if (cf->multihop && (ipa_is_link_local(cf->local_ip) ||
ipa_is_link_local(cf->remote_ip)))
cf_error("Multihop BGP cannot be used with link-local addresses");
cf_error(ctx, "Multihop BGP cannot be used with link-local addresses");
if (cf->multihop && cf->iface)
cf_error("Multihop BGP cannot be bound to interface");
cf_error(ctx, "Multihop BGP cannot be bound to interface");
if (cf->multihop && cf->check_link)
cf_error("Multihop BGP cannot depend on link state");
cf_error(ctx, "Multihop BGP cannot depend on link state");
if (cf->multihop && cf->bfd && ipa_zero(cf->local_ip))
cf_error("Multihop BGP with BFD requires specified local address");
cf_error(ctx, "Multihop BGP with BFD requires specified local address");
if (!cf->gr_mode && cf->llgr_mode)
cf_error("Long-lived graceful restart requires basic graceful restart");
cf_error(ctx, "Long-lived graceful restart requires basic graceful restart");
struct bgp_channel_config *cc;
@ -1784,14 +1784,14 @@ bgp_postconfig(struct proto_config *CF)
if (interior)
cc->c.in_filter = FILTER_ACCEPT;
else
cf_error("EBGP requires explicit import policy");
cf_error(ctx, "EBGP requires explicit import policy");
/* Handle undefined export filter */
if (cc->c.out_filter == FILTER_UNDEF)
if (interior)
cc->c.out_filter = FILTER_REJECT;
else
cf_error("EBGP requires explicit export policy");
cf_error(ctx, "EBGP requires explicit export policy");
/* Disable after error incompatible with restart limit action */
if ((cc->c.in_limit.action == PLA_RESTART) && cf->disable_after_error)
@ -1819,29 +1819,29 @@ bgp_postconfig(struct proto_config *CF)
if ((cc->gw_mode == GW_RECURSIVE) && !cc->desc->no_igp)
{
if (!cc->igp_table_ip4 && (bgp_cc_is_ipv4(cc) || cc->ext_next_hop))
cc->igp_table_ip4 = bgp_default_igp_table(cf, cc, NET_IP4);
cc->igp_table_ip4 = bgp_default_igp_table(ctx, cf, cc, NET_IP4);
if (!cc->igp_table_ip6 && (bgp_cc_is_ipv6(cc) || cc->ext_next_hop))
cc->igp_table_ip6 = bgp_default_igp_table(cf, cc, NET_IP6);
cc->igp_table_ip6 = bgp_default_igp_table(ctx, cf, cc, NET_IP6);
if (cc->igp_table_ip4 && bgp_cc_is_ipv6(cc) && !cc->ext_next_hop)
cf_error("Mismatched IGP table type");
cf_error(ctx, "Mismatched IGP table type");
if (cc->igp_table_ip6 && bgp_cc_is_ipv4(cc) && !cc->ext_next_hop)
cf_error("Mismatched IGP table type");
cf_error(ctx, "Mismatched IGP table type");
}
if (cf->multihop && (cc->gw_mode == GW_DIRECT))
cf_error("Multihop BGP cannot use direct gateway mode");
cf_error(ctx, "Multihop BGP cannot use direct gateway mode");
if ((cc->gw_mode == GW_RECURSIVE) && cc->c.table->sorted)
cf_error("BGP in recursive mode prohibits sorted table");
cf_error(ctx, "BGP in recursive mode prohibits sorted table");
if (cf->deterministic_med && cc->c.table->sorted)
cf_error("BGP with deterministic MED prohibits sorted table");
cf_error(ctx, "BGP with deterministic MED prohibits sorted table");
if (cc->secondary && !cc->c.table->sorted)
cf_error("BGP with secondary option requires sorted table");
cf_error(ctx, "BGP with secondary option requires sorted table");
}
}
@ -1916,7 +1916,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC)
}
static void
bgp_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
bgp_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
{
/* Just a shallow copy */
}

View File

@ -12,8 +12,8 @@ CF_HDR
CF_DEFINES
#define BGP_CFG ((struct bgp_config *) this_proto)
#define BGP_CC ((struct bgp_channel_config *) this_channel)
#define BGP_CFG ((struct bgp_config *) ctx->this_proto)
#define BGP_CC ((struct bgp_channel_config *) ctx->this_channel)
CF_DECLS
@ -44,7 +44,7 @@ CF_GRAMMAR
proto: bgp_proto '}' ;
bgp_proto_start: proto_start BGP {
this_proto = proto_config_new(&proto_bgp, $1);
ctx->this_proto = proto_config_new(ctx, &proto_bgp, $1);
BGP_CFG->local_port = BGP_PORT;
BGP_CFG->remote_port = BGP_PORT;
BGP_CFG->multihop = -1; /* undefined */
@ -73,13 +73,13 @@ bgp_proto_start: proto_start BGP {
bgp_loc_opts:
/* empty */
| bgp_loc_opts PORT expr { BGP_CFG->local_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); }
| bgp_loc_opts PORT expr { BGP_CFG->local_port = $3; if (($3<1) || ($3>65535)) cf_error(ctx, "Invalid port number"); }
| bgp_loc_opts AS expr { BGP_CFG->local_as = $3; }
;
bgp_nbr_opts:
/* empty */
| bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); }
| bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error(ctx, "Invalid port number"); }
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
;
@ -118,7 +118,7 @@ bgp_proto:
| bgp_proto NEIGHBOR bgp_nbr_opts ';'
| bgp_proto NEIGHBOR ipa ipa_scope bgp_nbr_opts ';' {
if (ipa_nonzero(BGP_CFG->remote_ip))
cf_error("Only one neighbor per BGP instance is allowed");
cf_error(ctx, "Only one neighbor per BGP instance is allowed");
BGP_CFG->remote_ip = $3;
if ($4) BGP_CFG->iface = $4;
}
@ -132,7 +132,7 @@ bgp_proto:
| bgp_proto STARTUP HOLD TIME expr ';' { BGP_CFG->initial_hold_time = $5; }
| bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; }
| bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; }
| bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); }
| bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error(ctx, "Multihop must be in range 1-255"); }
| bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; }
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
| bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; }
@ -142,7 +142,7 @@ bgp_proto:
| bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; }
| bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; }
| bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->local_ip = $4; }
| bgp_proto START DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; log(L_WARN "%s: Start delay time option is deprecated, use connect delay time", this_proto->name); }
| bgp_proto START DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; log(L_WARN "%s: Start delay time option is deprecated, use connect delay time", ctx->this_proto->name); }
| bgp_proto CONNECT DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; }
| bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
| bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; }
@ -169,8 +169,8 @@ bgp_proto:
| bgp_proto LONG LIVED STALE TIME expr ';' { BGP_CFG->llgr_time = $6; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
| bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
| bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
| bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; cf_check_bfd(1); }
| bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; BFD_CHECK($3); }
| bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; BFD_CHECK(1); }
;
bgp_afi:
@ -193,9 +193,9 @@ bgp_channel_start: bgp_afi
const struct bgp_af_desc *desc = bgp_get_af_desc($1);
if (!desc)
cf_error("Unknown AFI/SAFI");
cf_error(ctx, "Unknown AFI/SAFI");
this_channel = channel_config_get(&channel_bgp, desc->name, desc->net, this_proto);
ctx->this_channel = channel_config_get(ctx, &channel_bgp, desc->name, desc->net, ctx->this_proto);
/* New channel */
if (!BGP_CC->desc)
@ -231,14 +231,14 @@ bgp_channel_item:
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
| IGP TABLE rtable {
if (BGP_CC->desc->no_igp)
cf_error("IGP table not allowed here");
cf_error(ctx, "IGP table not allowed here");
if ($3->addr_type == NET_IP4)
BGP_CC->igp_table_ip4 = $3;
else if ($3->addr_type == NET_IP6)
BGP_CC->igp_table_ip6 = $3;
else
cf_error("Mismatched IGP table type");
cf_error(ctx, "Mismatched IGP table type");
}
;
@ -254,10 +254,10 @@ bgp_channel_opt_list:
bgp_channel_end:
{
if (!this_channel->table)
cf_error("Routing table not specified");
if (!ctx->this_channel->table)
cf_error(ctx, "Routing table not specified");
this_channel = NULL;
ctx->this_channel = NULL;
};
bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;

View File

@ -10,22 +10,24 @@ CF_HDR
#include "proto/ospf/ospf.h"
CF_CTX
struct ospf_area_config *this_area;
struct nbma_node *this_nbma;
list *this_nets;
struct area_net_config *this_pref;
struct ospf_stubnet_config *this_stubnet;
CF_DEFINES
#define OSPF_CFG ((struct ospf_config *) this_proto)
#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt)
#define OSPF_CFG ((struct ospf_config *) ctx->this_proto)
#define OSPF_PATT ((struct ospf_iface_patt *) ctx->this_ipatt)
static struct ospf_area_config *this_area;
static struct nbma_node *this_nbma;
static list *this_nets;
static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
static inline int ospf_cfg_is_v2(struct cf_context *ctx) { return OSPF_CFG->ospf2; }
static inline int ospf_cfg_is_v3(struct cf_context *ctx) { return ! OSPF_CFG->ospf2; }
static void
ospf_iface_finish(void)
ospf_iface_finish(struct cf_context *ctx)
{
struct ospf_iface_patt *ip = OSPF_PATT;
@ -35,9 +37,9 @@ ospf_iface_finish(void)
if (ip->waitint == 0)
ip->waitint = ip->deadc * ip->helloint;
ip->passwords = get_passwords();
ip->passwords = get_passwords(ctx);
if (ospf_cfg_is_v2() && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
if (ospf_cfg_is_v2(ctx) && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks");
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
@ -49,46 +51,46 @@ ospf_iface_finish(void)
WALK_LIST(pass, *ip->passwords)
{
if (pass->alg && (ip->autype != OSPF_AUTH_CRYPT))
cf_error("Password algorithm option requires cryptographic authentication");
cf_error(ctx, "Password algorithm option requires cryptographic authentication");
/* Set default OSPF crypto algorithms */
if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT))
pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256;
pass->alg = ospf_cfg_is_v2(ctx) ? ALG_MD5 : ALG_HMAC_SHA256;
if (ospf_cfg_is_v3() && ip->autype && (pass->alg < ALG_HMAC))
cf_error("Keyed hash algorithms are not allowed, use HMAC algorithms");
if (ospf_cfg_is_v3(ctx) && ip->autype && (pass->alg < ALG_HMAC))
cf_error(ctx, "Keyed hash algorithms are not allowed, use HMAC algorithms");
}
}
}
static void
ospf_area_finish(void)
ospf_area_finish(struct cf_context *ctx)
{
if ((this_area->areaid == 0) && (this_area->type != OPT_E))
cf_error("Backbone area cannot be stub/NSSA");
if ((ctx->this_area->areaid == 0) && (ctx->this_area->type != OPT_E))
cf_error(ctx, "Backbone area cannot be stub/NSSA");
if (this_area->summary && (this_area->type == OPT_E))
cf_error("Only stub/NSSA areas can use summary propagation");
if (ctx->this_area->summary && (ctx->this_area->type == OPT_E))
cf_error(ctx, "Only stub/NSSA areas can use summary propagation");
if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary))
cf_error("Only NSSA areas with summary propagation can use NSSA default route");
if (ctx->this_area->default_nssa && ((ctx->this_area->type != OPT_N) || ! ctx->this_area->summary))
cf_error(ctx, "Only NSSA areas with summary propagation can use NSSA default route");
if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa)
cf_error("Only NSSA default route can use type 2 metric");
if ((ctx->this_area->default_cost & LSA_EXT3_EBIT) && ! ctx->this_area->default_nssa)
cf_error(ctx, "Only NSSA default route can use type 2 metric");
}
static void
ospf_proto_finish(void)
ospf_proto_finish(struct cf_context *ctx)
{
struct ospf_config *cf = OSPF_CFG;
struct ospf_area_config *ac;
struct ospf_iface_patt *ic;
/* Define default channel */
if (EMPTY_LIST(this_proto->channels))
if (EMPTY_LIST(ctx->this_proto->channels))
{
uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, net_label[net_type], net_type, this_proto);
uint net_type = ctx->this_proto->net_type = ospf_cfg_is_v2(ctx) ? NET_IP4 : NET_IP6;
channel_config_new(ctx, NULL, net_label[net_type], net_type, ctx->this_proto);
}
/* Propagate global instance ID to interfaces */
@ -104,9 +106,9 @@ ospf_proto_finish(void)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
}
if (ospf_cfg_is_v3())
if (ospf_cfg_is_v3(ctx))
{
uint ipv4 = (this_proto->net_type == NET_IP4);
uint ipv4 = (ctx->this_proto->net_type == NET_IP4);
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
/* RFC 5838 - OSPFv3-AF */
@ -121,22 +123,22 @@ ospf_proto_finish(void)
else if (ic->instance_id >= 128)
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
cf_error(ctx, "Instance ID %d invalid for given channel type", ic->instance_id);
}
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
cf_error(ctx, "Vlinks not supported in AFs other than IPv6 unicast");
}
else
{
if (ipv4 || cf->af_mc)
cf_error("Different channel type");
cf_error(ctx, "Different channel type");
}
}
if (EMPTY_LIST(cf->area_list))
cf_error("No configured areas in OSPF");
cf_error(ctx, "No configured areas in OSPF");
int areano = 0;
int backbone = 0;
@ -153,7 +155,7 @@ ospf_proto_finish(void)
cf->abr = areano > 1;
/* Route export or NSSA translation (RFC 3101 3.1) */
cf->asbr = (proto_cf_main_channel(this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr);
cf->asbr = (proto_cf_main_channel(ctx->this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr);
if (cf->abr && !backbone)
{
@ -167,24 +169,24 @@ ospf_proto_finish(void)
}
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
cf_error("Vlinks cannot be used on single area router");
cf_error(ctx, "Vlinks cannot be used on single area router");
if (cf->asbr && (areano == 1) && (this_area->type == 0))
cf_error("ASBR must be in non-stub area");
if (cf->asbr && (areano == 1) && (ctx->this_area->type == 0))
cf_error(ctx, "ASBR must be in non-stub area");
}
static inline void
ospf_check_defcost(int cost)
ospf_check_defcost(struct cf_context *ctx, int cost)
{
if ((cost <= 0) || (cost >= LSINFINITY))
cf_error("Default cost must be in range 1-%u", LSINFINITY-1);
cf_error(ctx, "Default cost must be in range 1-%u", LSINFINITY-1);
}
static inline void
ospf_check_auth(void)
ospf_check_auth(struct cf_context *ctx)
{
if (ospf_cfg_is_v3())
cf_error("Plaintext authentication not supported in OSPFv3");
if (ospf_cfg_is_v3(ctx))
cf_error(ctx, "Plaintext authentication not supported in OSPFv3");
}
@ -207,7 +209,7 @@ CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838)
CF_GRAMMAR
proto: ospf_proto '}' { ospf_proto_finish(); } ;
proto: ospf_proto '}' { ospf_proto_finish(ctx); } ;
ospf_variant:
OSPF { $$ = 1; }
@ -217,8 +219,8 @@ ospf_variant:
ospf_proto_start: proto_start ospf_variant
{
this_proto = proto_config_new(&proto_ospf, $1);
this_proto->net_type = $2 ? NET_IP4 : 0;
ctx->this_proto = proto_config_new(ctx, &proto_ospf, $1);
ctx->this_proto->net_type = $2 ? NET_IP4 : 0;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
@ -242,10 +244,10 @@ ospf_af_mc:
ospf_channel_start: net_type ospf_af_mc
{
/* TODO: change name for multicast channels */
$$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
$$ = ctx->this_channel = channel_config_get(ctx, NULL, net_label[$1], $1, ctx->this_proto);
/* Save the multicast flag */
if (this_channel == proto_cf_main_channel(this_proto))
if (ctx->this_channel == proto_cf_main_channel(ctx->this_proto))
OSPF_CFG->af_mc = $2;
};
@ -253,34 +255,34 @@ ospf_channel: ospf_channel_start channel_opt_list channel_end;
ospf_proto_item:
proto_item
| ospf_channel { this_proto->net_type = $1->net_type; }
| ospf_channel { ctx->this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
| RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3(ctx)) cf_error(ctx, "RFC5838 option requires OSPFv3"); }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error(ctx, "Tick must be greater than zero"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error(ctx, "Instance ID must be in range 0-255"); }
| ospf_area
;
ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2;
this_area->default_cost = OSPF_DEFAULT_STUB_COST;
this_area->type = OPT_E;
this_area->transint = OSPF_DEFAULT_TRANSINT;
ctx->this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE ctx->this_area);
ctx->this_area->areaid = $2;
ctx->this_area->default_cost = OSPF_DEFAULT_STUB_COST;
ctx->this_area->type = OPT_E;
ctx->this_area->transint = OSPF_DEFAULT_TRANSINT;
init_list(&this_area->patt_list);
init_list(&this_area->net_list);
init_list(&this_area->enet_list);
init_list(&this_area->stubnet_list);
init_list(&ctx->this_area->patt_list);
init_list(&ctx->this_area->net_list);
init_list(&ctx->this_area->enet_list);
init_list(&ctx->this_area->stubnet_list);
}
;
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(ctx); }
;
ospf_area_opts:
@ -289,17 +291,17 @@ ospf_area_opts:
;
ospf_area_item:
STUB bool { this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ }
| NSSA { this_area->type = OPT_N; }
| SUMMARY bool { this_area->summary = $2; }
| DEFAULT NSSA bool { this_area->default_nssa = $3; }
| DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); }
| STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| TRANSLATOR bool { this_area->translator = $2; }
| TRANSLATOR STABILITY expr { this_area->transint = $3; }
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
| EXTERNAL { this_nets = &this_area->enet_list; } '{' pref_list '}'
STUB bool { ctx->this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ }
| NSSA { ctx->this_area->type = OPT_N; }
| SUMMARY bool { ctx->this_area->summary = $2; }
| DEFAULT NSSA bool { ctx->this_area->default_nssa = $3; }
| DEFAULT COST expr { ctx->this_area->default_cost = $3; ospf_check_defcost(ctx, $3); }
| DEFAULT COST2 expr { ctx->this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost(ctx, $3); }
| STUB COST expr { ctx->this_area->default_cost = $3; ospf_check_defcost(ctx, $3); }
| TRANSLATOR bool { ctx->this_area->translator = $2; }
| TRANSLATOR STABILITY expr { ctx->this_area->transint = $3; }
| NETWORKS { ctx->this_nets = &ctx->this_area->net_list; } '{' pref_list '}'
| EXTERNAL { ctx->this_nets = &ctx->this_area->enet_list; } '{' pref_list '}'
| STUBNET ospf_stubnet
| INTERFACE ospf_iface
| ospf_vlink
@ -312,10 +314,10 @@ ospf_stubnet:
ospf_stubnet_start:
net_ip {
this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config));
add_tail(&this_area->stubnet_list, NODE this_stubnet);
this_stubnet->prefix = $1;
this_stubnet->cost = COST_D;
ctx->this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config));
add_tail(&ctx->this_area->stubnet_list, NODE ctx->this_stubnet);
ctx->this_stubnet->prefix = $1;
ctx->this_stubnet->cost = COST_D;
}
;
@ -325,14 +327,14 @@ ospf_stubnet_opts:
;
ospf_stubnet_item:
HIDDEN bool { this_stubnet->hidden = $2; }
| SUMMARY bool { this_stubnet->summary = $2; }
| COST expr { this_stubnet->cost = $2; }
HIDDEN bool { ctx->this_stubnet->hidden = $2; }
| SUMMARY bool { ctx->this_stubnet->summary = $2; }
| COST expr { ctx->this_stubnet->cost = $2; }
;
ospf_vlink:
ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
| ospf_vlink_start ospf_instance_id { ospf_iface_finish(); }
ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(ctx); }
| ospf_vlink_start ospf_instance_id { ospf_iface_finish(ctx); }
;
ospf_vlink_opts:
@ -341,25 +343,25 @@ ospf_vlink_opts:
;
ospf_vlink_item:
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Hello interval must be in range 1-65535"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error(ctx, "Retransmit int must be greater than one"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error(ctx, "Transmit delay must be in range 1-65535"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error(ctx, "Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error(ctx, "Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error(ctx, "Dead count must be greater than one"); }
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(ctx); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; }
| password_list
;
ospf_vlink_start: VIRTUAL LINK idval
{
if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
OSPF_PATT->voa = this_area->areaid;
if (ctx->this_area->areaid == 0) cf_error(ctx, "Virtual link cannot be in backbone");
ctx->this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&OSPF_CFG->vlink_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
OSPF_PATT->voa = ctx->this_area->areaid;
OSPF_PATT->vid = $3;
OSPF_PATT->helloint = HELLOINT_D;
OSPF_PATT->rxmtint = RXMTINT_D;
@ -367,18 +369,18 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_VLINK;
init_list(&OSPF_PATT->nbma_list);
reset_passwords();
reset_passwords(ctx);
}
;
ospf_iface_item:
COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); }
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Cost must be in range 1-65535"); }
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error(ctx, "Hello interval must be in range 1-65535"); }
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error(ctx, "Poll int must be greater than zero"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error(ctx, "Retransmit int must be greater than one"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error(ctx, "Wait interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error(ctx, "Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error(ctx, "Dead count must be greater than one"); }
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
| TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
| TYPE NONBROADCAST { OSPF_PATT->type = OSPF_IT_NBMA ; }
@ -387,28 +389,28 @@ ospf_iface_item:
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error("Priority must be in range 0-255"); }
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2(ctx)) cf_error(ctx, "Real broadcast option requires OSPFv2"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2(ctx)) cf_error(ctx, "PtP netmask option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error(ctx, "Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error(ctx, "Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; }
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); }
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error(ctx, "ECMP weight must be in range 1-256"); }
| LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3(ctx)) cf_error(ctx, "Link LSA suppression option requires OSPFv3"); }
| NEIGHBORS '{' nbma_list '}'
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(ctx); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; }
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error(ctx, "Buffer size must be in range 256-65535"); }
| TX tos { OSPF_PATT->tx_tos = $2; }
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
| TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); }
| TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error(ctx, "TX length must be in range 256-65535"); }
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
| BFD bool { OSPF_PATT->bfd = $2; BFD_CHECK($2); }
| password_list
;
@ -421,16 +423,16 @@ pref_item: pref_base pref_opt ';' ;
pref_base: net_ip
{
this_pref = cfg_allocz(sizeof(struct area_net_config));
add_tail(this_nets, NODE this_pref);
this_pref->prefix = $1;
ctx->this_pref = cfg_allocz(sizeof(struct area_net_config));
add_tail(ctx->this_nets, NODE ctx->this_pref);
ctx->this_pref->prefix = $1;
}
;
pref_opt:
/* empty */
| HIDDEN { this_pref->hidden = 1; }
| TAG expr { this_pref->tag = $2; }
| HIDDEN { ctx->this_pref->hidden = 1; }
| TAG expr { ctx->this_pref->tag = $2; }
;
nbma_list:
@ -445,18 +447,18 @@ nbma_eligible:
nbma_item: ipa nbma_eligible ';'
{
this_nbma = cfg_allocz(sizeof(struct nbma_node));
add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
this_nbma->ip=$1;
this_nbma->eligible=$2;
ctx->this_nbma = cfg_allocz(sizeof(struct nbma_node));
add_tail(&OSPF_PATT->nbma_list, NODE ctx->this_nbma);
ctx->this_nbma->ip=$1;
ctx->this_nbma->eligible=$2;
}
;
ospf_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&this_area->patt_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&ctx->this_area->patt_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
OSPF_PATT->cost = COST_D;
OSPF_PATT->helloint = HELLOINT_D;
OSPF_PATT->pollint = POLLINT_D;
@ -470,17 +472,17 @@ ospf_iface_start:
OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
OSPF_PATT->tx_priority = sk_priority_control;
reset_passwords();
reset_passwords(ctx);
}
;
ospf_instance_id:
/* empty */
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error(ctx, "Instance ID must be in range 0-255"); }
;
ospf_iface_patt_list:
iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id
iface_patt_list { if (ospf_cfg_is_v3(ctx)) iface_patt_check(ctx); } ospf_instance_id
;
ospf_iface_opts:
@ -494,7 +496,7 @@ ospf_iface_opt_list:
;
ospf_iface:
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(ctx); }
;
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ;
@ -504,29 +506,29 @@ dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUA
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optsym, [<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]])
@ -535,6 +537,7 @@ CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [ls
lsadb_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct lsadb_show_data));
$$->ctx = ctx;
}
| lsadb_args GLOBAL { $$ = $1; $$->scope = LSA_SCOPE_AS; }
| lsadb_args AREA idval { $$ = $1; $$->scope = LSA_SCOPE_AREA; $$->area = $3; }

View File

@ -1374,7 +1374,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
void
ospf_sh_lsadb(struct lsadb_show_data *ld)
{
struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->ctx, ld->name, &proto_ospf);
uint num = p->gr->hash_entries;
uint i, j;
int last_dscope = -1;

View File

@ -854,6 +854,7 @@ struct ospf_lsreq_header
#define SH_ROUTER_SELF 0xffffffff
struct lsadb_show_data {
struct cf_context *ctx; /* Config context */
struct symbol *name; /* Protocol to request data from */
u16 type; /* LSA Type, 0 -> all */
u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */

View File

@ -12,7 +12,7 @@ CF_HDR
CF_DEFINES
#define PIPE_CFG ((struct pipe_config *) this_proto)
#define PIPE_CFG ((struct pipe_config *) ctx->this_proto)
CF_DECLS
@ -20,19 +20,19 @@ CF_KEYWORDS(PIPE, PEER, TABLE)
CF_GRAMMAR
proto: pipe_proto '}' { this_channel = NULL; } ;
proto: pipe_proto '}' { ctx->this_channel = NULL; } ;
pipe_proto_start: proto_start PIPE
{
this_proto = proto_config_new(&proto_pipe, $1);
ctx->this_proto = proto_config_new(ctx, &proto_pipe, $1);
}
proto_name
{
this_channel = proto_cf_main_channel(this_proto);
if (!this_channel) {
this_channel = channel_config_new(NULL, NULL, 0, this_proto);
this_channel->in_filter = FILTER_ACCEPT;
this_channel->out_filter = FILTER_ACCEPT;
ctx->this_channel = proto_cf_main_channel(ctx->this_proto);
if (!ctx->this_channel) {
ctx->this_channel = channel_config_new(ctx, NULL, NULL, 0, ctx->this_proto);
ctx->this_channel->in_filter = FILTER_ACCEPT;
ctx->this_channel->out_filter = FILTER_ACCEPT;
}
};

View File

@ -119,28 +119,28 @@ pipe_reload_routes(struct channel *C)
static void
pipe_postconfig(struct proto_config *CF)
pipe_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct pipe_config *cf = (void *) CF;
struct channel_config *cc = proto_cf_main_channel(CF);
if (!cc->table)
cf_error("Primary routing table not specified");
cf_error(ctx, "Primary routing table not specified");
if (!cf->peer)
cf_error("Secondary routing table not specified");
cf_error(ctx, "Secondary routing table not specified");
if (cc->table == cf->peer)
cf_error("Primary table and peer table must be different");
cf_error(ctx, "Primary table and peer table must be different");
if (cc->table->addr_type != cf->peer->addr_type)
cf_error("Primary table and peer table must have the same type");
cf_error(ctx, "Primary table and peer table must have the same type");
if (cc->rx_limit.action)
cf_error("Pipe protocol does not support receive limits");
cf_error(ctx, "Pipe protocol does not support receive limits");
if (cc->in_keep_filtered)
cf_error("Pipe protocol prohibits keeping filtered routes");
cf_error(ctx, "Pipe protocol prohibits keeping filtered routes");
}
static int
@ -197,7 +197,7 @@ pipe_reconfigure(struct proto *P, struct proto_config *CF)
}
static void
pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
pipe_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
{
/* Just a shallow copy, not many items here */
}

View File

@ -9,20 +9,21 @@ CF_HDR
#include "proto/radv/radv.h"
CF_CTX
struct radv_prefix_config *this_radv_prefix;
struct radv_rdnss_config this_radv_rdnss;
struct radv_dnssl_config this_radv_dnssl;
list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */
u8 radv_mult_val; /* Used by radv_mult for second return value */
CF_DEFINES
#define RADV_CFG ((struct radv_config *) this_proto)
#define RADV_IFACE ((struct radv_iface_config *) this_ipatt)
#define RADV_PREFIX this_radv_prefix
#define RADV_RDNSS (&this_radv_rdnss)
#define RADV_DNSSL (&this_radv_dnssl)
static struct radv_prefix_config *this_radv_prefix;
static struct radv_rdnss_config this_radv_rdnss;
static struct radv_dnssl_config this_radv_dnssl;
static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */
static u8 radv_mult_val; /* Used by radv_mult for second return value */
#define RADV_CFG ((struct radv_config *) ctx->this_proto)
#define RADV_IFACE ((struct radv_iface_config *) ctx->this_ipatt)
#define RADV_PREFIX ctx->this_radv_prefix
#define RADV_RDNSS (&ctx->this_radv_rdnss)
#define RADV_DNSSL (&ctx->this_radv_dnssl)
CF_DECLS
@ -43,7 +44,7 @@ proto: radv_proto ;
radv_proto_start: proto_start RADV
{
this_proto = proto_config_new(&proto_radv, $1);
ctx->this_proto = proto_config_new(ctx, &proto_radv, $1);
init_list(&RADV_CFG->patt_list);
init_list(&RADV_CFG->pref_list);
@ -55,9 +56,9 @@ radv_proto_item:
proto_item
| proto_channel
| INTERFACE radv_iface
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE ctx->this_radv_prefix); }
| RDNSS { init_list(&ctx->radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &ctx->radv_dns_list); }
| DNSSL { init_list(&ctx->radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &ctx->radv_dns_list); }
| TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
;
@ -73,9 +74,9 @@ radv_proto:
radv_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct radv_iface_config));
add_tail(&RADV_CFG->patt_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct radv_iface_config));
add_tail(&RADV_CFG->patt_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
init_list(&RADV_IFACE->pref_list);
init_list(&RADV_IFACE->rdnss_list);
init_list(&RADV_IFACE->dnssl_list);
@ -95,18 +96,18 @@ radv_iface_start:
};
radv_iface_item:
MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
| MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); }
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error(ctx, "Min RA interval must be at least 3"); }
| MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error(ctx, "Max RA interval must be in range 4-1800"); }
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error(ctx, "Min delay must be positive"); }
| MANAGED bool { RADV_IFACE->managed = $2; }
| OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
| LINK MTU expr { RADV_IFACE->link_mtu = $3; }
| REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); }
| REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error(ctx, "Reachable time must be in range 0-3600000"); }
| RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; }
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); }
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error(ctx, "Current hop limit must be in range 0-255"); }
| DEFAULT LIFETIME expr radv_sensitive {
RADV_IFACE->default_lifetime = $3;
if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000");
if ($3 > 9000) cf_error(ctx, "Default lifetime must be in range 0-9000");
if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
}
| ROUTE LIFETIME expr radv_sensitive {
@ -117,9 +118,9 @@ radv_iface_item:
| ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; }
| PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; }
| ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE ctx->this_radv_prefix); }
| RDNSS { init_list(&ctx->radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &ctx->radv_dns_list); }
| DNSSL { init_list(&ctx->radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &ctx->radv_dns_list); }
| RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
| DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
;
@ -150,19 +151,19 @@ radv_iface_finish:
if ((ic->min_ra_int > 3) &&
(ic->min_ra_int > (ic->max_ra_int * 3 / 4)))
cf_error("Min RA interval must be at most 3/4 * Max RA interval");
cf_error(ctx, "Min RA interval must be at most 3/4 * Max RA interval");
if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int))
cf_error("Default lifetime must be either 0 or at least Max RA interval");
cf_error(ctx, "Default lifetime must be either 0 or at least Max RA interval");
if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int))
cf_error("Route lifetime must be either 0 or at least Max RA interval");
cf_error(ctx, "Route lifetime must be either 0 or at least Max RA interval");
if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int))
cf_error("Prefix linger time must be either 0 or at least Max RA interval");
cf_error(ctx, "Prefix linger time must be either 0 or at least Max RA interval");
if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int))
cf_error("Route linger time must be either 0 or at least Max RA interval");
cf_error(ctx, "Route linger time must be either 0 or at least Max RA interval");
RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time);
};
@ -184,7 +185,7 @@ radv_iface:
radv_prefix_start: net_ip6
{
this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config));
ctx->this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config));
RADV_PREFIX->prefix = *(net_addr_ip6 *) &($1);
RADV_PREFIX->onlink = 1;
@ -210,10 +211,10 @@ radv_prefix_item:
radv_prefix_finish:
{
if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime)
cf_error("Preferred lifetime must be at most Valid lifetime");
cf_error(ctx, "Preferred lifetime must be at most Valid lifetime");
if (RADV_PREFIX->valid_lifetime_sensitive > RADV_PREFIX->preferred_lifetime_sensitive)
cf_error("Valid lifetime sensitive requires that Preferred lifetime is sensitive too");
cf_error(ctx, "Valid lifetime sensitive requires that Preferred lifetime is sensitive too");
};
radv_prefix_opts:
@ -234,7 +235,7 @@ radv_prefix:
radv_rdnss_node: ipa
{
struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config));
add_tail(&radv_dns_list, NODE cf);
add_tail(&ctx->radv_dns_list, NODE cf);
cf->server = $1;
cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
@ -248,16 +249,16 @@ radv_rdnss_start:
radv_rdnss_item:
| NS radv_rdnss_node
| LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; }
| LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = ctx->radv_mult_val; }
;
radv_rdnss_finish:
{
if (EMPTY_LIST(radv_dns_list))
cf_error("No nameserver in RDNSS section");
if (EMPTY_LIST(ctx->radv_dns_list))
cf_error(ctx, "No nameserver in RDNSS section");
struct radv_rdnss_config *cf;
WALK_LIST(cf, radv_dns_list)
WALK_LIST(cf, ctx->radv_dns_list)
{
cf->lifetime = RADV_RDNSS->lifetime;
cf->lifetime_mult = RADV_RDNSS->lifetime_mult;
@ -278,13 +279,13 @@ radv_rdnss:
radv_dnssl_node: TEXT
{
struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config));
add_tail(&radv_dns_list, NODE cf);
add_tail(&ctx->radv_dns_list, NODE cf);
cf->domain = $1;
cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
if (radv_process_domain(cf) < 0)
cf_error("Invalid domain dame");
cf_error(ctx, "Invalid domain dame");
};
radv_dnssl_start:
@ -295,16 +296,16 @@ radv_dnssl_start:
radv_dnssl_item:
| DOMAIN radv_dnssl_node
| LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; }
| LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = ctx->radv_mult_val; }
;
radv_dnssl_finish:
{
if (EMPTY_LIST(radv_dns_list))
cf_error("No domain in DNSSL section");
if (EMPTY_LIST(ctx->radv_dns_list))
cf_error(ctx, "No domain in DNSSL section");
struct radv_dnssl_config *cf;
WALK_LIST(cf, radv_dns_list)
WALK_LIST(cf, ctx->radv_dns_list)
{
cf->lifetime = RADV_DNSSL->lifetime;
cf->lifetime_mult = RADV_DNSSL->lifetime_mult;
@ -323,8 +324,8 @@ radv_dnssl:
radv_mult:
expr { $$ = $1; radv_mult_val = 0; }
| MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); }
expr { $$ = $1; ctx->radv_mult_val = 0; }
| MULT expr { $$ = 0; ctx->radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error(ctx, "Multiplier must be in range 1-254"); }
;
radv_sensitive:

View File

@ -563,13 +563,13 @@ radv_check_active(struct radv_proto *p)
}
static void
radv_postconfig(struct proto_config *CF)
radv_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
// struct radv_config *cf = (void *) CF;
/* Define default channel */
if (EMPTY_LIST(CF->channels))
channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF);
channel_config_new(ctx, NULL, net_label[NET_IP6], NET_IP6, CF);
}
static struct proto *
@ -705,7 +705,7 @@ radv_reconfigure(struct proto *P, struct proto_config *CF)
}
static void
radv_copy_config(struct proto_config *dest, struct proto_config *src)
radv_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src)
{
struct radv_config *d = (struct radv_config *) dest;
struct radv_config *s = (struct radv_config *) src;
@ -714,7 +714,7 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src)
init_list(&d->patt_list);
/* We copy pref_list, shallow copy suffices */
cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
cf_copy_list(ctx, &d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
}
static void

View File

@ -16,17 +16,17 @@ CF_HDR
CF_DEFINES
#define RIP_CFG ((struct rip_config *) this_proto)
#define RIP_IFACE ((struct rip_iface_config *) this_ipatt)
#define RIP_CFG ((struct rip_config *) ctx->this_proto)
#define RIP_IFACE ((struct rip_iface_config *) ctx->this_ipatt)
static inline int rip_cfg_is_v2(void) { return RIP_CFG->rip2; }
static inline int rip_cfg_is_ng(void) { return ! RIP_CFG->rip2; }
static inline int rip_cfg_is_v2(struct cf_context *ctx) { return RIP_CFG->rip2; }
static inline int rip_cfg_is_ng(struct cf_context *ctx) { return ! RIP_CFG->rip2; }
static inline void
rip_check_auth(void)
rip_check_auth(struct cf_context *ctx)
{
if (rip_cfg_is_ng())
cf_error("Authentication not supported in RIPng");
if (rip_cfg_is_ng(ctx))
cf_error(ctx, "Authentication not supported in RIPng");
}
@ -51,8 +51,8 @@ rip_variant:
rip_proto_start: proto_start rip_variant
{
this_proto = proto_config_new(&proto_rip, $1);
this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
ctx->this_proto = proto_config_new(ctx, &proto_rip, $1);
ctx->this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
init_list(&RIP_CFG->patt_list);
RIP_CFG->rip2 = $2;
@ -82,21 +82,21 @@ rip_proto:
rip_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct rip_iface_config));
add_tail(&RIP_CFG->patt_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
reset_passwords();
ctx->this_ipatt = cfg_allocz(sizeof(struct rip_iface_config));
add_tail(&RIP_CFG->patt_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
reset_passwords(ctx);
RIP_IFACE->metric = 1;
RIP_IFACE->port = rip_cfg_is_v2() ? RIP_PORT : RIP_NG_PORT;
RIP_IFACE->version = rip_cfg_is_v2() ? RIP_V2 : RIP_V1;
RIP_IFACE->port = rip_cfg_is_v2(ctx) ? RIP_PORT : RIP_NG_PORT;
RIP_IFACE->version = rip_cfg_is_v2(ctx) ? RIP_V2 : RIP_V1;
RIP_IFACE->split_horizon = 1;
RIP_IFACE->poison_reverse = 1;
RIP_IFACE->check_zero = 1;
RIP_IFACE->check_link = 1;
RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1;
RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
RIP_IFACE->ttl_security = rip_cfg_is_v2(ctx) ? 0 : 1;
RIP_IFACE->rx_buffer = rip_cfg_is_v2(ctx) ? RIP_MAX_PKT_LENGTH : 0;
RIP_IFACE->tx_length = rip_cfg_is_v2(ctx) ? RIP_MAX_PKT_LENGTH : 0;
RIP_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
RIP_IFACE->tx_priority = sk_priority_control;
RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME;
@ -108,10 +108,10 @@ rip_iface_finish:
{
/* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */
if (!RIP_IFACE->mode)
RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ?
RIP_IFACE->mode = (rip_cfg_is_v2(ctx) && (RIP_IFACE->version == RIP_V1)) ?
RIP_IM_BROADCAST : RIP_IM_MULTICAST;
RIP_IFACE->passwords = get_passwords();
RIP_IFACE->passwords = get_passwords(ctx);
if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords)
log(L_WARN "Authentication and password options should be used together");
@ -122,7 +122,7 @@ rip_iface_finish:
WALK_LIST(pass, *RIP_IFACE->passwords)
{
if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO))
cf_error("Password algorithm option requires cryptographic authentication");
cf_error(ctx, "Password algorithm option requires cryptographic authentication");
/* Set default crypto algorithm (MD5) */
if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO))
@ -135,34 +135,34 @@ rip_iface_finish:
};
rip_iface_item:
METRIC expr { RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error("Metric must be in range 1-255"); }
METRIC expr { RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error(ctx, "Metric must be in range 1-255"); }
| MODE MULTICAST { RIP_IFACE->mode = RIP_IM_MULTICAST; }
| MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); }
| MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng(ctx)) cf_error(ctx, "Broadcast not supported in RIPng"); }
| PASSIVE bool { RIP_IFACE->passive = $2; }
| ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); }
| PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
| ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2(ctx)) cf_error(ctx, "IP address version mismatch"); }
| PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error(ctx, "Invalid port number"); }
| VERSION expr { RIP_IFACE->version = $2;
if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng");
if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error("Unsupported version");
if (rip_cfg_is_ng(ctx)) cf_error(ctx, "Version not supported in RIPng");
if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error(ctx, "Unsupported version");
}
| VERSION ONLY bool { RIP_IFACE->version_only = $3; }
| SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; }
| POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
| CHECK ZERO bool { RIP_IFACE->check_zero = $3; }
| UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
| UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error(ctx, "Update time must be positive"); }
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error(ctx, "Timeout time must be positive"); }
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error(ctx, "Garbage time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error(ctx, "ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error(ctx, "TX length must be in range 256-65535"); }
| TX tos { RIP_IFACE->tx_tos = $2; }
| TX PRIORITY expr { RIP_IFACE->tx_priority = $3; }
| TTL SECURITY bool { RIP_IFACE->ttl_security = $3; }
| TTL SECURITY TX ONLY { RIP_IFACE->ttl_security = 2; }
| CHECK LINK bool { RIP_IFACE->check_link = $3; }
| BFD bool { RIP_IFACE->bfd = $2; cf_check_bfd($2); }
| AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(); }
| password_list { rip_check_auth(); }
| BFD bool { RIP_IFACE->bfd = $2; BFD_CHECK($2); }
| AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(ctx); }
| password_list { rip_check_auth(ctx); }
;
rip_auth:
@ -192,10 +192,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG)
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
CF_CLI(SHOW RIP INTERFACES, optsym opttext, [<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

View File

@ -1062,13 +1062,13 @@ rip_rte_same(struct rte *new, struct rte *old)
static void
rip_postconfig(struct proto_config *CF)
rip_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
// struct rip_config *cf = (void *) CF;
/* Define default channel */
if (EMPTY_LIST(CF->channels))
channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
channel_config_new(ctx, NULL, net_label[CF->net_type], CF->net_type, CF);
}
static struct proto *

View File

@ -12,21 +12,21 @@ CF_HDR
CF_DEFINES
#define RPKI_CFG ((struct rpki_config *) this_proto)
#define RPKI_CFG ((struct rpki_config *) ctx->this_proto)
#define RPKI_TR_SSH_CFG ((struct rpki_tr_ssh_config *) RPKI_CFG->tr_config.spec)
static void
rpki_check_unused_hostname(void)
rpki_check_unused_hostname(struct cf_context *ctx)
{
if (RPKI_CFG->hostname != NULL)
cf_error("Only one cache server per protocol allowed");
cf_error(ctx, "Only one cache server per protocol allowed");
}
static void
rpki_check_unused_transport(void)
rpki_check_unused_transport(struct cf_context *ctx)
{
if (RPKI_CFG->tr_config.spec != NULL)
cf_error("At the most one transport per protocol allowed");
cf_error(ctx, "At the most one transport per protocol allowed");
}
CF_DECLS
@ -41,13 +41,13 @@ CF_GRAMMAR
proto: rpki_proto ;
rpki_proto_start: proto_start RPKI {
this_proto = proto_config_new(&proto_rpki, $1);
ctx->this_proto = proto_config_new(ctx, &proto_rpki, $1);
RPKI_CFG->retry_interval = RPKI_RETRY_INTERVAL;
RPKI_CFG->refresh_interval = RPKI_REFRESH_INTERVAL;
RPKI_CFG->expire_interval = RPKI_EXPIRE_INTERVAL;
};
rpki_proto: rpki_proto_start proto_name '{' rpki_proto_opts '}' { rpki_check_config(RPKI_CFG); };
rpki_proto: rpki_proto_start proto_name '{' rpki_proto_opts '}' { rpki_check_config(ctx, RPKI_CFG); };
rpki_proto_opts:
/* empty */
@ -63,19 +63,19 @@ rpki_proto_item:
| TRANSPORT rpki_transport
| REFRESH rpki_keep_interval expr {
if (rpki_check_refresh_interval($3))
cf_error(rpki_check_refresh_interval($3));
cf_error(ctx, rpki_check_refresh_interval($3));
RPKI_CFG->refresh_interval = $3;
RPKI_CFG->keep_refresh_interval = $2;
}
| RETRY rpki_keep_interval expr {
if (rpki_check_retry_interval($3))
cf_error(rpki_check_retry_interval($3));
cf_error(ctx, rpki_check_retry_interval($3));
RPKI_CFG->retry_interval = $3;
RPKI_CFG->keep_retry_interval = $2;
}
| EXPIRE rpki_keep_interval expr {
if (rpki_check_expire_interval($3))
cf_error(rpki_check_expire_interval($3));
cf_error(ctx, rpki_check_expire_interval($3));
RPKI_CFG->expire_interval = $3;
RPKI_CFG->keep_expire_interval = $2;
}
@ -86,15 +86,15 @@ rpki_keep_interval:
| KEEP { $$ = 1; }
;
rpki_proto_item_port: PORT expr { check_u16($2); RPKI_CFG->port = $2; };
rpki_proto_item_port: PORT expr { check_u16(ctx, $2); RPKI_CFG->port = $2; };
rpki_cache_addr:
text {
rpki_check_unused_hostname();
rpki_check_unused_hostname(ctx);
RPKI_CFG->hostname = $1;
}
| ipa {
rpki_check_unused_hostname();
rpki_check_unused_hostname(ctx);
RPKI_CFG->ip = $1;
/* Ensure hostname is filled */
char *hostname = cfg_allocz(sizeof(INET6_ADDRSTRLEN + 1));
@ -110,14 +110,14 @@ rpki_transport:
rpki_transport_tcp_init:
{
rpki_check_unused_transport();
rpki_check_unused_transport(ctx);
RPKI_CFG->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_tcp_config));
RPKI_CFG->tr_config.type = RPKI_TR_TCP;
};
rpki_transport_ssh_init:
{
rpki_check_unused_transport();
rpki_check_unused_transport(ctx);
RPKI_CFG->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_ssh_config));
RPKI_CFG->tr_config.type = RPKI_TR_SSH;
};
@ -136,7 +136,7 @@ rpki_transport_ssh_item:
rpki_transport_ssh_check:
{
if (RPKI_TR_SSH_CFG->user == NULL)
cf_error("User must be set");
cf_error(ctx, "User must be set");
};
CF_CODE

View File

@ -866,19 +866,19 @@ rpki_show_proto_info(struct proto *P)
* This function is called at the end of parsing RPKI protocol configuration.
*/
void
rpki_check_config(struct rpki_config *cf)
rpki_check_config(struct cf_context *ctx, struct rpki_config *cf)
{
/* Do not check templates at all */
if (cf->c.class == SYM_TEMPLATE)
return;
if (ipa_zero(cf->ip) && cf->hostname == NULL)
cf_error("IP address or hostname of cache server must be set");
cf_error(ctx, "IP address or hostname of cache server must be set");
/* Set default transport type */
if (cf->tr_config.spec == NULL)
{
cf->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_tcp_config));
cf->tr_config.spec = cf_allocz(ctx, sizeof(struct rpki_tr_tcp_config));
cf->tr_config.type = RPKI_TR_TCP;
}
@ -897,15 +897,15 @@ rpki_check_config(struct rpki_config *cf)
}
static void
rpki_postconfig(struct proto_config *CF)
rpki_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
/* Define default channel */
if (EMPTY_LIST(CF->channels))
channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
channel_config_new(ctx, NULL, net_label[CF->net_type], CF->net_type, CF);
}
static void
rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
rpki_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
{
/* FIXME: Should copy transport */
}

View File

@ -127,7 +127,7 @@ struct rpki_config {
u8 keep_expire_interval:1; /* Do not overwrite expire interval by cache server update */
};
void rpki_check_config(struct rpki_config *cf);
void rpki_check_config(struct cf_context *ctx, struct rpki_config *cf);
/*

View File

@ -10,35 +10,38 @@ CF_HDR
#include "proto/static/static.h"
CF_CTX
struct static_route *this_srt, *this_snh;
struct f_inst **this_srt_last_cmd;
CF_DEFINES
#define STATIC_CFG ((struct static_config *) this_proto)
static struct static_route *this_srt, *this_snh;
static struct f_inst **this_srt_last_cmd;
#define STATIC_CFG ((struct static_config *) ctx->this_proto)
static struct static_route *
static_nexthop_new(void)
static_nexthop_new(struct cf_context *ctx)
{
struct static_route *nh = this_srt;
struct static_route *nh = ctx->this_srt;
if (this_snh)
if (ctx->this_snh)
{
/* Additional next hop */
nh = cfg_allocz(sizeof(struct static_route));
nh->net = this_srt->net;
this_snh->mp_next = nh;
nh->net = ctx->this_srt->net;
ctx->this_snh->mp_next = nh;
}
nh->dest = RTD_UNICAST;
nh->mp_head = this_srt;
nh->mp_head = ctx->this_srt;
return nh;
};
static void
static_route_finish(void)
static_route_finish(struct cf_context *ctx)
{
if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
cf_error("Unexpected or missing nexthop/type");
if (net_type_match(ctx->this_srt->net, NB_DEST) == !ctx->this_srt->dest)
cf_error(ctx, "Unexpected or missing nexthop/type");
}
CF_DECLS
@ -53,14 +56,14 @@ proto: static_proto '}' ;
static_proto_start: proto_start STATIC
{
this_proto = proto_config_new(&proto_static, $1);
ctx->this_proto = proto_config_new(ctx, &proto_static, $1);
init_list(&STATIC_CFG->routes);
};
static_proto:
static_proto_start proto_name '{'
| static_proto proto_item ';'
| static_proto proto_channel ';' { this_proto->net_type = $2->net_type; }
| static_proto proto_channel ';' { ctx->this_proto->net_type = $2->net_type; }
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
| static_proto IGP TABLE rtable ';' {
if ($4->addr_type == NET_IP4)
@ -68,34 +71,34 @@ static_proto:
else if ($4->addr_type == NET_IP6)
STATIC_CFG->igp_table_ip6 = $4;
else
cf_error("Incompatible IGP table type");
cf_error(ctx, "Incompatible IGP table type");
}
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(ctx); }
;
stat_nexthop:
VIA ipa ipa_scope {
this_snh = static_nexthop_new();
this_snh->via = $2;
this_snh->iface = $3;
ctx->this_snh = static_nexthop_new(ctx);
ctx->this_snh->via = $2;
ctx->this_snh->iface = $3;
}
| VIA TEXT {
this_snh = static_nexthop_new();
this_snh->via = IPA_NONE;
this_snh->iface = if_get_by_name($2);
ctx->this_snh = static_nexthop_new(ctx);
ctx->this_snh->via = IPA_NONE;
ctx->this_snh->iface = if_get_by_name($2);
}
| stat_nexthop MPLS label_stack {
this_snh->mls = $3;
ctx->this_snh->mls = $3;
}
| stat_nexthop ONLINK bool {
this_snh->onlink = $3;
ctx->this_snh->onlink = $3;
}
| stat_nexthop WEIGHT expr {
this_snh->weight = $3 - 1;
if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
ctx->this_snh->weight = $3 - 1;
if (($3<1) || ($3>256)) cf_error(ctx, "Weight must be in range 1-256");
}
| stat_nexthop BFD bool {
this_snh->use_bfd = $3; cf_check_bfd($3);
ctx->this_snh->use_bfd = $3; BFD_CHECK($3);
}
;
@ -105,36 +108,36 @@ stat_nexthops:
;
stat_route0: ROUTE net_any {
this_srt = cfg_allocz(sizeof(struct static_route));
add_tail(&STATIC_CFG->routes, &this_srt->n);
this_srt->net = $2;
this_srt_last_cmd = &(this_srt->cmds);
this_srt->mp_next = NULL;
this_snh = NULL;
ctx->this_srt = cfg_allocz(sizeof(struct static_route));
add_tail(&STATIC_CFG->routes, &ctx->this_srt->n);
ctx->this_srt->net = $2;
ctx->this_srt_last_cmd = &(ctx->this_srt->cmds);
ctx->this_srt->mp_next = NULL;
ctx->this_snh = NULL;
}
;
stat_route:
stat_route0 stat_nexthops
| stat_route0 RECURSIVE ipa {
this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3;
ctx->this_srt->dest = RTDX_RECURSIVE;
ctx->this_srt->via = $3;
}
| stat_route0 RECURSIVE ipa MPLS label_stack {
this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3;
this_srt->mls = $5;
ctx->this_srt->dest = RTDX_RECURSIVE;
ctx->this_srt->via = $3;
ctx->this_srt->mls = $5;
}
| stat_route0 { this_srt->dest = RTD_NONE; }
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 UNREACHABLE { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; }
| stat_route0 { ctx->this_srt->dest = RTD_NONE; }
| stat_route0 DROP { ctx->this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { ctx->this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 BLACKHOLE { ctx->this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 UNREACHABLE { ctx->this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { ctx->this_srt->dest = RTD_PROHIBIT; }
;
stat_route_item:
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
cmd { *ctx->this_srt_last_cmd = $1; ctx->this_srt_last_cmd = &($1->next); }
;
stat_route_opts:
@ -149,7 +152,7 @@ stat_route_opt_list:
CF_CLI(SHOW STATIC, optsym, [<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

View File

@ -360,13 +360,13 @@ static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED)
static void
static_postconfig(struct proto_config *CF)
static_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct static_config *cf = (void *) CF;
struct static_route *r;
if (EMPTY_LIST(CF->channels))
cf_error("Channel not specified");
cf_error(ctx, "Channel not specified");
struct channel_config *cc = proto_cf_main_channel(CF);
@ -380,7 +380,7 @@ static_postconfig(struct proto_config *CF)
WALK_LIST(r, cf->routes)
if (r->net && (r->net->type != CF->net_type))
cf_error("Route %N incompatible with channel type", r->net);
cf_error(ctx, "Route %N incompatible with channel type", r->net);
}
static struct proto *
@ -573,7 +573,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
}
static void
static_copy_config(struct proto_config *dest, struct proto_config *src)
static_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src)
{
struct static_config *d = (struct static_config *) dest;
struct static_config *s = (struct static_config *) src;
@ -588,7 +588,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
for (snh = srt; snh; snh = snh->mp_next)
{
dnh = cfg_alloc(sizeof(struct static_route));
dnh = cf_alloc(ctx, sizeof(struct static_route));
memcpy(dnh, snh, sizeof(struct static_route));
if (!drt)

View File

@ -19,9 +19,9 @@ kern_proto: kern_proto kern_sys_item ';' ;
kern_sys_item:
KERNEL TABLE expr {
if ($3 && (krt_max_tables == 1))
cf_error("Multiple kernel routing tables not supported");
cf_error(ctx, "Multiple kernel routing tables not supported");
if ($3 >= krt_max_tables)
cf_error("Kernel table id must be in range 0-%u", krt_max_tables - 1);
cf_error(ctx, "Kernel table id must be in range 0-%u", krt_max_tables - 1);
THIS_KRT->sys.table_id = $3;
}

View File

@ -1,4 +1,4 @@
src := io.c krt.c log.c main.c random.c
src := io.c krt.c log.c main.c random.c conf.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)

423
sysdep/unix/conf.c Normal file
View File

@ -0,0 +1,423 @@
/*
* 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);
}

View File

@ -30,7 +30,7 @@ log_config: LOG log_file log_mask ';' {
struct log_config *c = cfg_allocz(sizeof(struct log_config));
c->fh = $2;
c->mask = $3;
add_tail(&new_config->logfiles, &c->n);
add_tail(&ctx->new_config->logfiles, &c->n);
}
;
@ -41,11 +41,11 @@ syslog_name:
log_file:
text {
FILE *f = tracked_fopen(new_config->pool, $1, "a");
if (!f) cf_error("Unable to open log file `%s': %m", $1);
FILE *f = tracked_fopen(ctx->new_config->pool, $1, "a");
if (!f) cf_error(ctx, "Unable to open log file `%s': %m", $1);
$$ = f;
}
| SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
| SYSLOG syslog_name { $$ = NULL; ctx->new_config->syslog_name = $2; }
| STDERR { $$ = stderr; }
;
@ -75,11 +75,11 @@ log_cat:
conf: mrtdump_base ;
mrtdump_base:
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
MRTDUMP PROTOCOLS mrtdump_mask ';' { ctx->new_config->proto_default_mrtdump = $3; }
| MRTDUMP text ';' {
FILE *f = tracked_fopen(new_config->pool, $2, "a");
if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
new_config->mrtdump_file = fileno(f);
FILE *f = tracked_fopen(ctx->new_config->pool, $2, "a");
if (!f) cf_error(ctx, "Unable to open MRTDump file '%s': %m", $2);
ctx->new_config->mrtdump_file = fileno(f);
}
;
@ -87,10 +87,10 @@ mrtdump_base:
conf: debug_unix ;
debug_unix:
DEBUG LATENCY bool { new_config->latency_debug = $3; }
| DEBUG LATENCY LIMIT expr_us { new_config->latency_limit = $4; }
| WATCHDOG WARNING expr_us { new_config->watchdog_warning = $3; }
| WATCHDOG TIMEOUT expr_us { new_config->watchdog_timeout = ($3 + 999999) TO_S; }
DEBUG LATENCY bool { ctx->new_config->latency_debug = $3; }
| DEBUG LATENCY LIMIT expr_us { ctx->new_config->latency_limit = $4; }
| WATCHDOG WARNING expr_us { ctx->new_config->watchdog_warning = $3; }
| WATCHDOG TIMEOUT expr_us { ctx->new_config->watchdog_timeout = ($3 + 999999) TO_S; }
;

View File

@ -10,14 +10,19 @@ CF_HDR
#include "sysdep/unix/krt.h"
CF_CTX
struct kif_config *kif_cf;
struct krt_config *krt_cf;
CF_DEFINES
#define THIS_KRT ((struct krt_config *) this_proto)
#define THIS_KIF ((struct kif_config *) this_proto)
#define KIF_IFACE ((struct kif_iface_config *) this_ipatt)
#define THIS_KRT ((struct krt_config *) ctx->this_proto)
#define THIS_KIF ((struct kif_config *) ctx->this_proto)
#define KIF_IFACE ((struct kif_iface_config *) ctx->this_ipatt)
static void
kif_set_preferred(ip_addr ip)
kif_set_preferred(struct cf_context *ctx, ip_addr ip)
{
if (ipa_is_ip4(ip))
KIF_IFACE->pref_v4 = ip;
@ -27,6 +32,44 @@ kif_set_preferred(ip_addr ip)
KIF_IFACE->pref_ll = ip;
}
static struct proto_config *
kif_init_config(struct cf_context *ctx, int class)
{
if (ctx->kif_cf)
cf_error(ctx, "Kernel device protocol already defined");
ctx->kif_cf = (struct kif_config *) proto_config_new(ctx, &proto_unix_iface, class);
ctx->kif_cf->scan_time = 60 S_;
init_list(&ctx->kif_cf->iface_list);
kif_sys_init_config(ctx->kif_cf);
return (struct proto_config *) ctx->kif_cf;
}
struct proto_config *
krt_init_config(struct cf_context *ctx, int class)
{
#ifndef CONFIG_MULTIPLE_TABLES
if (ctx->krt_cf)
cf_error(ctx, "Kernel protocol already defined");
#endif
ctx->krt_cf = (struct krt_config *) proto_config_new(ctx, &proto_unix_kernel, class);
ctx->krt_cf->scan_time = 60 S_;
krt_sys_init_config(ctx->krt_cf);
return (struct proto_config *) ctx->krt_cf;
}
#ifdef CONFIG_ALL_TABLES_AT_ONCE
void
krt_check_scan_time(struct cf_context *ctx, struct krt_config *cf)
{
if (ctx->krt_cf->scan_time != cf->scan_time)
cf_error(ctx, "All kernel syncers must use the same table scan interval");
}
#endif
CF_DECLS
CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS)
@ -41,7 +84,7 @@ CF_GRAMMAR
proto: kern_proto '}' ;
kern_proto_start: proto_start KERNEL {
this_proto = krt_init_config($1);
ctx->this_proto = krt_init_config(ctx, $1);
}
;
@ -50,12 +93,12 @@ kern_proto: kern_proto kern_item ';' ;
kern_mp_limit:
/* empty */ { $$ = KRT_DEFAULT_ECMP_LIMIT; }
| LIMIT expr { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error("Merge paths limit must be in range 1-255"); }
| LIMIT expr { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error(ctx, "Merge paths limit must be in range 1-255"); }
;
kern_item:
proto_item
| proto_channel { this_proto->net_type = $1->net_type; }
| proto_channel { ctx->this_proto->net_type = $1->net_type; }
| PERSIST bool { THIS_KRT->persist = $2; }
| SCAN TIME expr {
/* Scan time of 0 means scan on startup only */
@ -65,7 +108,7 @@ kern_item:
THIS_KRT->learn = $2;
#ifndef KRT_ALLOW_LEARN
if ($2)
cf_error("Learning of kernel routes not supported on this platform");
cf_error(ctx, "Learning of kernel routes not supported on this platform");
#endif
}
| GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; }
@ -73,7 +116,7 @@ kern_item:
THIS_KRT->merge_paths = $3 ? $4 : 0;
#ifndef KRT_ALLOW_MERGE_PATHS
if ($3)
cf_error("Path merging not supported on this platform");
cf_error(ctx, "Path merging not supported on this platform");
#endif
}
;
@ -82,7 +125,7 @@ kern_item:
proto: kif_proto '}' ;
kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); }
kif_proto_start: proto_start DEVICE { ctx->this_proto = kif_init_config(ctx, $1); }
;
kif_proto: kif_proto_start proto_name '{' ;
@ -99,13 +142,13 @@ kif_item:
kif_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct kif_iface_config));
add_tail(&THIS_KIF->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
ctx->this_ipatt = cfg_allocz(sizeof(struct kif_iface_config));
add_tail(&THIS_KIF->iface_list, NODE ctx->this_ipatt);
init_list(&ctx->this_ipatt->ipn_list);
}
kif_iface_item:
PREFERRED ipa { kif_set_preferred($2); }
PREFERRED ipa { kif_set_preferred(ctx, $2); }
;
kif_iface_opts:

View File

@ -85,7 +85,6 @@ krt_io_init(void)
*/
struct kif_proto *kif_proto;
static struct kif_config *kif_cf;
static timer *kif_scan_timer;
static btime kif_last_shot;
@ -198,32 +197,17 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
static void
kif_preconfig(struct protocol *P UNUSED, struct config *c)
{
kif_cf = NULL;
kif_sys_preconfig(c);
}
struct proto_config *
kif_init_config(int class)
{
if (kif_cf)
cf_error("Kernel device protocol already defined");
kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
kif_cf->scan_time = 60 S;
init_list(&kif_cf->iface_list);
kif_sys_init_config(kif_cf);
return (struct proto_config *) kif_cf;
}
static void
kif_copy_config(struct proto_config *dest, struct proto_config *src)
kif_copy_config(struct cf_context *ctx, struct proto_config *dest, struct proto_config *src)
{
struct kif_config *d = (struct kif_config *) dest;
struct kif_config *s = (struct kif_config *) src;
/* Copy interface config list */
cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
cf_copy_list(ctx, &d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
/* Fix sysdep parts */
kif_sys_copy_config(d, s);
@ -1039,32 +1023,28 @@ krt_rte_same(rte *a, rte *b)
* Protocol glue
*/
struct krt_config *krt_cf;
static void
krt_preconfig(struct protocol *P UNUSED, struct config *c)
{
krt_cf = NULL;
krt_sys_preconfig(c);
}
static void
krt_postconfig(struct proto_config *CF)
krt_postconfig(struct cf_context *ctx, struct proto_config *CF)
{
struct krt_config *cf = (void *) CF;
if (EMPTY_LIST(CF->channels))
cf_error("Channel not specified");
cf_error(ctx, "Channel not specified");
#ifdef CONFIG_ALL_TABLES_AT_ONCE
if (krt_cf->scan_time != cf->scan_time)
cf_error("All kernel syncers must use the same table scan interval");
krt_check_scan_time(ctx, cf);
#endif
struct channel_config *cc = proto_cf_main_channel(CF);
struct rtable_config *tab = cc->table;
if (tab->krt_attached)
cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
cf_error(ctx, "Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name);
tab->krt_attached = CF;
if (cf->merge_paths)
@ -1172,23 +1152,8 @@ krt_reconfigure(struct proto *p, struct proto_config *CF)
return o->scan_time == n->scan_time && o->learn == n->learn;
}
struct proto_config *
krt_init_config(int class)
{
#ifndef CONFIG_MULTIPLE_TABLES
if (krt_cf)
cf_error("Kernel protocol already defined");
#endif
krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, class);
krt_cf->scan_time = 60 S;
krt_sys_init_config(krt_cf);
return (struct proto_config *) krt_cf;
}
static void
krt_copy_config(struct proto_config *dest, struct proto_config *src)
krt_copy_config(struct cf_context *ctx UNUSED, struct proto_config *dest, struct proto_config *src)
{
struct krt_config *d = (struct krt_config *) dest;
struct krt_config *s = (struct krt_config *) src;

View File

@ -81,11 +81,12 @@ extern pool *krt_pool;
if (pr->p.debug & fl) \
{ log(L_TRACE "%s: " msg, pr->p.name , ## args); } } while(0)
struct proto_config * kif_init_config(int class);
void kif_request_scan(void);
void krt_got_route(struct krt_proto *p, struct rte *e);
void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
void krt_check_scan_time(struct cf_context *ctx, struct krt_config *cf);
/* Values for rte->u.krt_sync.src */
#define KRT_SRC_UNKNOWN -1 /* Nobody knows */
#define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */
@ -121,7 +122,6 @@ extern struct kif_proto *kif_proto;
#define KIF_CF ((struct kif_config *)p->p.cf)
struct kif_iface_config * kif_get_iface_config(struct iface *iface);
struct proto_config * krt_init_config(int class);
/* krt sysdep */

View File

@ -45,9 +45,9 @@
*/
#ifdef DEBUGGING
static int debug_flag = 1;
int debug_flag = 1;
#else
static int debug_flag = 0;
int debug_flag = 0;
#endif
void
@ -90,260 +90,6 @@ drop_gid(gid_t gid)
die("setgid: %m");
}
/*
* Reading the Configuration
*/
#ifdef PATH_IPROUTE_DIR
static inline void
add_num_const(char *name, int val)
{
struct symbol *s = cf_get_symbol(name);
s->class = SYM_CONSTANT | T_INT;
s->def = cfg_allocz(sizeof(struct f_val));
SYM_TYPE(s) = T_INT;
SYM_VAL(s).i = val;
}
/* the code of read_iproute_table() is based on
rtnl_tab_initialize() from iproute2 package */
static void
read_iproute_table(char *file, char *prefix, int max)
{
char buf[512], namebuf[512];
char *name;
int val;
FILE *fp;
strcpy(namebuf, prefix);
name = namebuf + strlen(prefix);
fp = fopen(file, "r");
if (!fp)
return;
while (fgets(buf, sizeof(buf), fp))
{
char *p = buf;
while (*p == ' ' || *p == '\t')
p++;
if (*p == '#' || *p == '\n' || *p == 0)
continue;
if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
sscanf(p, "0x%x %s #", &val, name) != 2 &&
sscanf(p, "%d %s\n", &val, name) != 2 &&
sscanf(p, "%d %s #", &val, name) != 2)
continue;
if (val < 0 || val > max)
continue;
for(p = name; *p; p++)
if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
*p = '_';
add_num_const(namebuf, val);
}
fclose(fp);
}
#endif // PATH_IPROUTE_DIR
static char *config_name = PATH_CONFIG_FILE;
static int
cf_read(byte *dest, uint len, int fd)
{
int l = read(fd, dest, len);
if (l < 0)
cf_error("Read error");
return l;
}
void
sysdep_preconfig(struct config *c)
{
init_list(&c->logfiles);
c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
#ifdef PATH_IPROUTE_DIR
read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
#endif
}
int
sysdep_commit(struct config *new, struct config *old UNUSED)
{
log_switch(debug_flag, &new->logfiles, new->syslog_name);
return 0;
}
static int
unix_read_config(struct config **cp, char *name)
{
struct config *conf = config_alloc(name);
int ret;
*cp = conf;
conf->file_fd = open(name, O_RDONLY);
if (conf->file_fd < 0)
return 0;
cf_read_hook = cf_read;
ret = config_parse(conf);
close(conf->file_fd);
return ret;
}
static struct config *
read_config(void)
{
struct config *conf;
if (!unix_read_config(&conf, config_name))
{
if (conf->err_msg)
die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
else
die("Unable to open configuration file %s: %m", config_name);
}
return conf;
}
void
async_config(void)
{
struct config *conf;
log(L_INFO "Reconfiguration requested by SIGHUP");
if (!unix_read_config(&conf, config_name))
{
if (conf->err_msg)
log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
else
log(L_ERR "Unable to open configuration file %s: %m", config_name);
config_free(conf);
}
else
config_commit(conf, RECONFIG_HARD, 0);
}
static struct config *
cmd_read_config(char *name)
{
struct config *conf;
if (!name)
name = config_name;
cli_msg(-2, "Reading configuration from %s", name);
if (!unix_read_config(&conf, name))
{
if (conf->err_msg)
cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
else
cli_msg(8002, "%s: %m", name);
config_free(conf);
conf = NULL;
}
return conf;
}
void
cmd_check_config(char *name)
{
struct config *conf = cmd_read_config(name);
if (!conf)
return;
cli_msg(20, "Configuration OK");
config_free(conf);
}
static void
cmd_reconfig_msg(int r)
{
switch (r)
{
case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
default: break;
}
}
/* Hack for scheduled undo notification */
cli *cmd_reconfig_stored_cli;
void
cmd_reconfig_undo_notify(void)
{
if (cmd_reconfig_stored_cli)
{
cli *c = cmd_reconfig_stored_cli;
cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
cli_write_trigger(c);
}
}
void
cmd_reconfig(char *name, int type, uint timeout)
{
if (cli_access_restricted())
return;
struct config *conf = cmd_read_config(name);
if (!conf)
return;
int r = config_commit(conf, type, timeout);
if ((r >= 0) && (timeout > 0))
{
cmd_reconfig_stored_cli = this_cli;
cli_msg(-22, "Undo scheduled in %d s", timeout);
}
cmd_reconfig_msg(r);
}
void
cmd_reconfig_confirm(void)
{
if (cli_access_restricted())
return;
int r = config_confirm();
cmd_reconfig_msg(r);
}
void
cmd_reconfig_undo(void)
{
if (cli_access_restricted())
return;
cli_msg(-21, "Undo requested");
int r = config_undo();
cmd_reconfig_msg(r);
}
/*
* Command-Line Interface

View File

@ -105,12 +105,19 @@ int sk_open_unix(struct birdsock *s, char *name);
void *tracked_fopen(struct pool *, char *name, char *mode);
void test_old_bird(char *path);
/* conf.c */
extern char *config_name;
struct config *read_config(void);
/* krt.c bits */
void krt_io_init(void);
/* log.c */
extern int debug_flag;
void main_thread_init(void);
void log_init_debug(char *); /* Initialize debug dump to given file (NULL=stderr, ""=off) */
void log_switch(int debug, list *l, char *); /* Use l=NULL for initial switch */