]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Config: Make the parser and lexer reentrant.
authorMaria Jan Matejka <mq@jmq.cz>
Mon, 13 Aug 2018 09:41:27 +0000 (11:41 +0200)
committerJan Maria Matejka <mq@ucw.cz>
Fri, 14 Sep 2018 12:44:45 +0000 (14:44 +0200)
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

59 files changed:
Makefile.in
conf/Makefile
conf/cf-lex.l
conf/conf.c
conf/conf.h
conf/confbase.Y
conf/flowspec.Y
conf/gen_context.m4 [new file with mode: 0644]
conf/gen_keywords.m4
conf/gen_parser.m4
conf/parser.h [new file with mode: 0644]
conf/symbols.c [new file with mode: 0644]
filter/config.Y
filter/f-util.c
filter/f-util.h [new file with mode: 0644]
filter/filter.c
filter/filter.h
filter/tree.c
lib/flowspec.c
lib/flowspec.h
nest/bfd.h
nest/cli.c
nest/cmds.h
nest/config.Y
nest/proto.c
nest/protocol.h
nest/route.h
nest/rt-dev.c
nest/rt-show.c
nest/rt-table.c
proto/babel/babel.c
proto/babel/config.Y
proto/bfd/bfd.c
proto/bfd/config.Y
proto/bgp/bgp.c
proto/bgp/config.Y
proto/ospf/config.Y
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/pipe/config.Y
proto/pipe/pipe.c
proto/radv/config.Y
proto/radv/radv.c
proto/rip/config.Y
proto/rip/rip.c
proto/rpki/config.Y
proto/rpki/rpki.c
proto/rpki/rpki.h
proto/static/config.Y
proto/static/static.c
sysdep/bsd/krt-sock.Y
sysdep/unix/Makefile
sysdep/unix/conf.c [new file with mode: 0644]
sysdep/unix/config.Y
sysdep/unix/krt.Y
sysdep/unix/krt.c
sysdep/unix/krt.h
sysdep/unix/main.c
sysdep/unix/unix.h

index b755df44b21a32707635d00a9e13cc4a7d69db28..7713bcb1d615688b246854076c9a5cf39455f6d7 100644 (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
 
index 39628bffb76b08257a4dd87c3d119d4676666353..59207d88585f88b52057df8b79a8d71eb459863a 100644 (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
index c3154b363bca4122dcf384e0a0f19bfa7278c12c..1a587dcef52e0490787795109248d85790672744 100644 (file)
 %{
 #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__)
+
+#define cf_lval (* (cfx_get_lval(yyscanner)))
 
-static void cf_include(char *arg, int alen);
-static int check_eof(void);
+static void cf_include(char *arg, int alen, yyscan_t yyscanner);
+static int check_eof(yyscan_t yyscanner);
 
 %}
 
@@ -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)
+static void
+cf_init_state(struct cf_context *ctx, struct conf_state *cs)
 {
- yy_delete_buffer(old->buffer);
- close(old->fd);
- return old->prev;
+  cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
 }
 
-static void
-enter_ifs(struct include_file_stack *new)
+struct conf_state *
+cf_new_state(struct cf_context *ctx, const char *name)
 {
-  if (!new->buffer)
-    {
-      new->fd = open(new->file_name, O_RDONLY);
-      if (new->fd < 0)
-        {
-          ifs = ifs->up;
-         cf_error("Unable to open included file %s: %m", new->file_name);
-        }
-
-      new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE);
-    }
-
-  yy_switch_to_buffer(new->buffer);
+  struct conf_state *cs = cfg_alloc(sizeof(struct conf_state));
+  *cs = (struct conf_state) {
+    .name = cfg_strdup(name),
+    .lino = 1,
+  };
+  cf_init_state(ctx, cs);
+  return cs;
 }
 
-/**
- * cf_lex_unwind - unwind lexer state during error
- *
- * cf_lex_unwind() frees the internal state on IFS stack when the lexical
- * analyzer is terminated by cf_error().
- */
 void
-cf_lex_unwind(void)
+cf_free_state(struct cf_context *ctx, struct conf_state *cs)
 {
-  struct include_file_stack *n;
-
-  for (n = ifs; n != ifs_head; n = n->prev)
-    {
-      /* Memory is freed automatically */
-      if (n->buffer)
-       yy_delete_buffer(n->buffer);
-      if (n->fd)
-        close(n->fd);
-    }
-
-  ifs = ifs_head;
+  yy_delete_buffer(cs->buffer, ctx->yyscanner);
+  /* The state structure is allocated from linpool, will be auto-freed. */
 }
 
 static void
-cf_include(char *arg, int alen)
+cf_include(char *arg, int alen, yyscan_t yyscanner)
 {
-  struct include_file_stack *base_ifs = ifs;
-  int new_depth, rv, i;
-  char *patt;
-  glob_t g = {};
-
-  new_depth = ifs->depth + 1;
-  if (new_depth > MAX_INCLUDE_DEPTH)
-    cf_error("Max include depth reached");
-
-  /* expand arg to properly handle relative filenames */
-  if (*arg != '/')
-    {
-      int dlen = strlen(ifs->file_name);
-      char *dir = alloca(dlen + 1);
-      patt = alloca(dlen + alen + 2);
-      memcpy(dir, ifs->file_name, dlen + 1);
-      sprintf(patt, "%s/%s", dirname(dir), arg);
-    }
-  else
-    patt = arg;
-
-  /* Skip globbing if there are no wildcards, mainly to get proper
-     response when the included config file is missing */
-  if (!strpbrk(arg, "?*["))
-    {
-      ifs = push_ifs(ifs);
-      ifs->file_name = cfg_strdup(patt);
-      ifs->depth = new_depth;
-      ifs->up = base_ifs;
-      enter_ifs(ifs);
-      return;
-    }
-
-  /* Expand the pattern */
-  rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g);
-  if (rv == GLOB_ABORTED)
-    cf_error("Unable to match pattern %s: %m", patt);
-  if ((rv != 0) || (g.gl_pathc <= 0))
-    return;
-
-  /*
-   * Now we put all found files to ifs stack in reverse order, they
-   * will be activated and processed in order as ifs stack is popped
-   * by pop_ifs() and enter_ifs() in check_eof().
-   */
-  for(i = g.gl_pathc - 1; i >= 0; i--)
-    {
-      char *fname = g.gl_pathv[i];
-      struct stat fs;
-
-      if (stat(fname, &fs) < 0)
-       {
-         globfree(&g);
-         cf_error("Unable to stat included file %s: %m", fname);
-       }
-
-      if (fs.st_mode & S_IFDIR)
-        continue;
-
-      /* Prepare new stack item */
-      ifs = push_ifs(ifs);
-      ifs->file_name = cfg_strdup(fname);
-      ifs->depth = new_depth;
-      ifs->up = base_ifs;
-    }
-
-  globfree(&g);
-  enter_ifs(ifs);
+  COR->cf_include(COR, arg, alen);
+  yy_switch_to_buffer(CST->buffer, yyscanner);
 }
 
 static int
-check_eof(void)
-{
-  if (ifs == ifs_head)
-    {
-      /* EOF in main config file */
-      ifs->lino = 1; /* Why this? */
-      return 1;
-    }
-
-  ifs = pop_ifs(ifs);
-  enter_ifs(ifs);
-  return 0;
-}
-
-static struct symbol *
-cf_new_symbol(byte *c)
-{
-  struct symbol *s;
-
-  uint l = strlen(c);
-  if (l > SYM_MAX_LEN)
-    cf_error("Symbol too long");
-
-  s = cfg_alloc(sizeof(struct symbol) + l);
-  s->scope = conf_this_scope;
-  s->class = SYM_VOID;
-  s->def = NULL;
-  s->aux = 0;
-  strcpy(s->name, c);
-
-  if (!new_config->sym_hash.data)
-    HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
-
-  HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
-
-  return s;
-}
-
-/**
- * cf_find_symbol - find a symbol by name
- * @cfg: specificed config
- * @c: symbol name
- *
- * This functions searches the symbol table in the config @cfg for a symbol of
- * given name. First it examines the current scope, then the second recent one
- * and so on until it either finds the symbol and returns a pointer to its
- * &symbol structure or reaches the end of the scope chain and returns %NULL to
- * signify no match.
- */
-struct symbol *
-cf_find_symbol(struct config *cfg, byte *c)
-{
-  struct symbol *s;
-
-  if (cfg->sym_hash.data &&
-      (s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
-    return s;
-
-  if (cfg->fallback &&
-      cfg->fallback->sym_hash.data &&
-      (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
-    return s;
-
-  return NULL;
-}
-
-/**
- * cf_get_symbol - get a symbol by name
- * @c: symbol name
- *
- * This functions searches the symbol table of the currently parsed config
- * (@new_config) for a symbol of given name. It returns either the already
- * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no
- * existing symbol is found.
- */
-struct symbol *
-cf_get_symbol(byte *c)
+check_eof(yyscan_t yyscanner)
 {
-  return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
-}
+  if (!COR->cf_outclude)
+    return 1;
 
-struct symbol *
-cf_default_name(char *template, int *counter)
-{
-  char buf[SYM_MAX_LEN];
-  struct symbol *s;
-  char *perc = strchr(template, '%');
-
-  for(;;)
-    {
-      bsprintf(buf, template, ++(*counter));
-      s = cf_get_symbol(buf);
-      if (s->class == SYM_VOID)
-       return s;
-      if (!perc)
-       break;
-    }
-  cf_error("Unable to generate default name");
-}
+  if (COR->cf_outclude(COR))
+    return 1;
 
-/**
- * cf_define_symbol - define meaning of a symbol
- * @sym: symbol to be defined
- * @type: symbol class to assign
- * @def: class dependent data
- *
- * Defines new meaning of a symbol. If the symbol is an undefined
- * one (%SYM_VOID), it's just re-defined to the new type. If it's defined
- * in different scope, a new symbol in current scope is created and the
- * meaning is assigned to it. If it's already defined in the current scope,
- * an error is reported via cf_error().
- *
- * Result: Pointer to the newly defined symbol. If we are in the top-level
- * scope, it's the same @sym as passed to the function.
- */
-struct symbol *
-cf_define_symbol(struct symbol *sym, int type, void *def)
-{
-  if (sym->class)
-    {
-      if (sym->scope == conf_this_scope)
-       cf_error("Symbol already defined");
-      sym = cf_new_symbol(sym->name);
-    }
-  sym->class = type;
-  sym->def = def;
-  return sym;
+  yy_switch_to_buffer(CST->buffer, yyscanner);
+  return 0;
 }
 
-static void
-cf_lex_init_kh(void)
+void
+cf_init_kh(void)
 {
   HASH_INIT(kw_hash, &root_pool, KW_ORDER);
 
@@ -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;
-}
-
-/**
- * cf_push_scope - enter new scope
- * @sym: symbol representing scope name
- *
- * If we want to enter a new scope to process declarations inside
- * a nested block, we can just call cf_push_scope() to push a new
- * scope onto the scope stack which will cause all new symbols to be
- * defined in this scope and all existing symbols to be sought for
- * in all scopes stored on the stack.
- */
-void
-cf_push_scope(struct symbol *sym)
-{
-  struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
+  ctx->sym_scope = cfg_allocz(sizeof(struct sym_scope));
+  ctx->sym_scope->active = 1;
 
-  s->next = conf_this_scope;
-  conf_this_scope = s;
-  s->active = 1;
-  s->name = sym;
+  return ctx;
 }
 
-/**
- * cf_pop_scope - leave a scope
- *
- * cf_pop_scope() pops the topmost scope from the scope stack,
- * leaving all its symbols in the symbol table, but making them
- * invisible to the rest of the config.
- */
 void
-cf_pop_scope(void)
+cf_free_context(struct cf_context *ctx)
 {
-  conf_this_scope->active = 0;
-  conf_this_scope = conf_this_scope->next;
-  ASSERT(conf_this_scope);
+  cfx_lex_destroy(ctx->yyscanner);
 }
 
-/**
- * cf_symbol_class_name - get name of a symbol class
- * @sym: symbol
- *
- * This function returns a string representing the class
- * of the given symbol.
- */
-char *
-cf_symbol_class_name(struct symbol *sym)
-{
-  if (cf_symbol_is_constant(sym))
-    return "constant";
-
-  switch (sym->class)
-    {
-    case SYM_VOID:
-      return "undefined";
-    case SYM_PROTO:
-      return "protocol";
-    case SYM_TEMPLATE:
-      return "protocol template";
-    case SYM_FUNCTION:
-      return "function";
-    case SYM_FILTER:
-      return "filter";
-    case SYM_TABLE:
-      return "routing table";
-    default:
-      return "unknown type";
-    }
-}
-
-
 /**
  * DOC: Parser
  *
index 885e2e7e0ebf2b17ed85494d76239875cd729c0c..05b740f5e824cb30c4ad232900c3dbf2e155ae30 100644 (file)
 #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);
+
+  if (!order->new_config)
+    order->new_config = config_alloc(order->pool, order->lp);
 
-  cf_lex_init(0, c);
-  sysdep_preconfig(c);
-  protos_preconfig(c);
-  rt_preconfig(c);
-  cf_parse();
+  struct cf_context *ctx = cf_new_context(0, order);
+  int ret;
 
-  if (EMPTY_LIST(c->protos))
-    cf_error("No protocol is specified in the config file");
+  if (setjmp(ctx->jmpbuf))
+    {
+      if (order->cf_outclude)
+       while (! order->cf_outclude(order))
+         ;
 
-  /*
-  if (!c->router_id)
-    cf_error("Router ID must be configured manually");
-  */
+      ret = 0;
 
-  done = 1;
+      config_free(ctx->new_config);
+      order->new_config = NULL;
+
+      goto cleanup;
+    }
+
+  sysdep_preconfig(ctx);
+  protos_preconfig(ctx->new_config);
+  rt_preconfig(ctx);
+  cfx_parse(ctx, ctx->yyscanner);
+
+  if (EMPTY_LIST((ctx->new_config)->protos))
+    cf_error(ctx, "No protocol is specified in the config file");
+
+  ret = 1;
 
 cleanup:
-  new_config = NULL;
-  cfg_mem = NULL;
-  return done;
+  cf_free_context(ctx);
+  order->ctx = NULL;
+  return ret;
 }
 
-/**
- * cli_parse - parse a CLI command
- * @c: temporary config structure
- *
- * cli_parse() is similar to config_parse(), but instead of a configuration,
- * it parses a CLI command. See the CLI module for more information.
- */
 int
-cli_parse(struct config *c)
+cli_parse(struct conf_order *order)
 {
-  int done = 0;
-  c->fallback = config;
-  new_config = c;
-  cfg_mem = c->mem;
-  if (setjmp(conf_jmpbuf))
-    goto cleanup;
+  DBG("Parsing command line\n");
 
-  cf_lex_init(1, c);
-  cf_parse();
-  done = 1;
+  struct config cc = {};
+  cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config");
+  cc.mem = order->lp ?: lp_new_default(cc.pool);
 
-cleanup:
-  c->fallback = NULL;
-  new_config = NULL;
-  cfg_mem = NULL;
-  return done;
+  order->new_config = &cc;
+
+  struct cf_context *ctx = cf_new_context(1, order);
+
+  int ok = 0;
+  if (setjmp(ctx->jmpbuf))
+    goto done;
+
+  cfx_parse(ctx, ctx->yyscanner);
+  ok = 1;
+
+done:
+  cf_free_context(ctx);
+  config_free(&cc);
+  order->new_config = NULL;
+  order->ctx = NULL;
+  return ok;
 }
 
 /**
@@ -465,6 +454,8 @@ config_init(void)
 
   config_timer = tm_new(&root_pool);
   config_timer->hook = config_timeout;
+
+  cf_init_kh();
 }
 
 /**
@@ -501,21 +492,42 @@ 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
@@ -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;
 
index f174d352d22a62c490d13ca665ddc96acc84615d..bbdb70ac13a15099d746627be96d8476cd06d2e8 100644 (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);
 
index 8fd72e5ecb87d94c8acf828f88f2ae0a2da0b761..d9bcbad5664b490e261ec29201823817070fdbe1 100644 (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;
    }
  ;
index 4d25976374e5dc3fc3a5a8795c8252d739e371a6..700ac38c9b103cf8d7c89ff71b4d51fd37ded186 100644 (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_ ;
diff --git a/conf/gen_context.m4 b/conf/gen_context.m4
new file mode 100644 (file)
index 0000000..79640cc
--- /dev/null
@@ -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([[,]])
+
index cf3fb58ecb37bb6137a0e89d869294172e40ecbd..0598e5cd97248496858af965053019c8339b6ef1 100644 (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)')
 
index af43d96f0c9b132ae31e136025f518050a257ba1..7625ce256ab18c79bfadf4b7e7924e77170f1a98 100644 (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(4)DNL
 
 %%
-m4_undivert(3)DNL
+m4_undivert(5)DNL
 
 %%
-m4_undivert(4)DNL
+m4_undivert(6)DNL
 ')
 
 # As we are processing C source, we must access all M4 primitives via
diff --git a/conf/parser.h b/conf/parser.h
new file mode 100644 (file)
index 0000000..36cd234
--- /dev/null
@@ -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
diff --git a/conf/symbols.c b/conf/symbols.c
new file mode 100644 (file)
index 0000000..ca66573
--- /dev/null
@@ -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;
+}
index bbb8a6405e0374b08fbdc1604dc4a7511161cdda..59ba42f9be50d7ef8ff78593e5a6f0884b3a1558 100644 (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
index 6170760b0769559c68f182381d57fa562ead1d5a..4b335571a71084ea091c3cadfc60f5711448202d 100644 (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;
diff --git a/filter/f-util.h b/filter/f-util.h
new file mode 100644 (file)
index 0000000..8c0f088
--- /dev/null
@@ -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
index 0a2c26b8b2b0a3ef033b02f30aba71554a0e5d53..ec360e259a9e14f567c531b4fb5f4c6d8d5d2092 100644 (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;
 }
index febfdc651cdd408dc78914ab497f2f1352892258..99ffe8d8d584e03fb064acf3bbd6bf8fe75b8aa5 100644 (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);
index f8379fa8b55c39957c9dd768f15f189ea30912cd..8e44a75891c65b5a97645773555277f08d4405ff 100644 (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));
index 87ce02063f1a201f75ff13c19241185fc7bd801b..2b5495882b30120a71fc0b07afa5ca6654154a53 100644 (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;
 }
 
index fa90c70d07c17a1660222b45f85d2b9b2e839e58..1ba2584f406d2f4a7ec61a61c4d637c76f34aab3 100644 (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);
 
 
 /*
index 04d6c00176631adb4cad23fff0e3ac98c70371f2..f11daa351df6bd8f73709076c60789431f3e3fac 100644 (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 */
 
 
index c421cc7e7c7e14b090a64927387b018b6a0067e7..9d0e4f30340da3911726423d7f9cd11b4a64ea8f 100644 (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;
index 4cf8fb1b8b03469fca0eb18cd46e1b09ac6e855f..3904da0fa34bb403e8d400e9c918942ffb5f9673 100644 (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
index 88f74b965a7ba6eb1a1e0d69869deb45445e5448..4721d4c8937648e2a64e3888ce5bf87690f99490 100644 (file)
@@ -15,52 +15,53 @@ CF_HDR
 #include "lib/lists.h"
 #include "lib/mac.h"
 
-CF_DEFINES
+CF_CTX
+
+struct proto_config *this_proto;
+struct channel_config *this_channel;
+struct iface_patt *this_ipatt;
+struct iface_patt_node *this_ipn;
+list *this_p_list;
+struct password_item *this_p_item;
+int password_id;
 
-static struct proto_config *this_proto;
-static struct channel_config *this_channel;
-static struct iface_patt *this_ipatt;
-static struct iface_patt_node *this_ipn;
-/* static struct roa_table_config *this_roa_table; */
-static list *this_p_list;
-static struct password_item *this_p_item;
-static int password_id;
+CF_DEFINES
 
 static void
-iface_patt_check(void)
+iface_patt_check(struct cf_context *ctx)
 {
   struct iface_patt_node *pn;
 
-  WALK_LIST(pn, this_ipatt->ipn_list)
+  WALK_LIST(pn, ctx->this_ipatt->ipn_list)
     if (!pn->pattern || pn->prefix.type)
-      cf_error("Interface name/mask expected, not IP prefix");
+      cf_error(ctx, "Interface name/mask expected, not IP prefix");
 }
 
 
 static inline void
-reset_passwords(void)
+reset_passwords(struct cf_context *ctx)
 {
-  this_p_list = NULL;
+  ctx->this_p_list = NULL;
 }
 
 static inline list *
-get_passwords(void)
+get_passwords(struct cf_context *ctx)
 {
-  list *rv = this_p_list;
-  this_p_list = NULL;
+  list *rv = ctx->this_p_list;
+  ctx->this_p_list = NULL;
   return rv;
 }
 
 static void
-proto_postconfig(void)
+proto_postconfig(struct cf_context *ctx)
 {
-  CALL(this_proto->protocol->postconfig, this_proto);
-  this_channel = NULL;
-  this_proto = NULL;
+  CALL(ctx->this_proto->protocol->postconfig, ctx, ctx->this_proto);
+  ctx->this_channel = NULL;
+  ctx->this_proto = NULL;
 }
 
 
-#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
+#define DIRECT_CFG ((struct rt_dev_config *) ctx->this_proto)
 
 CF_DECLS
 
@@ -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;
    }
  ;
index 8a8221a807388c267b4da57371bebb62b352fcbd..176c7066c0bcfe05fb60e026ce8d3f9b3439ddd7 100644 (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;
index 343ce52327133e7145f5b88359aed43ed4b1e17f..1071a364c7ca7622277d2c1ebbde836bed2bb13d 100644 (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);
 
 
index 2ec1dc7fa3158465930058bc134fb7ac49e20ac6..335a130e9140061b460fd62d73cb3e7a9896b1a2 100644 (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);
 
index 61f025cea8a28a974e9542dc579db83934f5184e..8b7b1fa29901d10de0861c94db3b0bacfadc562f 100644 (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;
 }
index 90165c57d2d14f9216e6cc676f8c6104a2a44bfc..2eeab6d3ffa479b64e892e4009324ce0fc88b82e 100644 (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);
 
index 036b34c4794765126708e20d3948003106d49b11..bde18c538ad531f746693bf734047b9cc279b733 100644 (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;
 }
index afa482bb9254d48e1a1bd549999bd1893bb32576..59fb58f25259de1d53ce5671b0f47618476d84b9 100644 (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;
index 3af79fd64285a8ce3bf5be6a9b5a7edd421fecc5..e21b424dc530beb70a516494634e4333e58702cd 100644 (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
 
index fdcd72255b85c61410bda30c2e345fd871d57f39..17b85f6f206b97faad486f449d67c93e8984bd95 100644 (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;
index 3f5714fdb8be6acdd2eba34c8698c1b39349c2cf..cf2e43c98c8b4a0d5e2a693bbf639a8959268946 100644 (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
 
index 6dea88c89be873d16e80cf5f1d7c7e4ed9e90291..7f94879140aecc9469b336d2df706bfe56c39b06 100644 (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 */
 }
index 120b1e88a9d4e7cfe102a904f864bf174a177fd0..53f8ff0e62c8635e0143543b82d7e88d52f4bb99 100644 (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;
index b89584e124a4659a0503a06c4f3ee1b12ac40c26..a065ba8d45a47ba79e88065cb2f2be9b69284603 100644 (file)
@@ -10,22 +10,24 @@ CF_HDR
 
 #include "proto/ospf/ospf.h"
 
-CF_DEFINES
+CF_CTX
+
+struct ospf_area_config *this_area;
+struct nbma_node *this_nbma;
+list *this_nets;
+struct area_net_config *this_pref;
+struct ospf_stubnet_config *this_stubnet;
 
-#define OSPF_CFG ((struct ospf_config *) this_proto)
-#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt)
+CF_DEFINES
 
-static struct ospf_area_config *this_area;
-static struct nbma_node *this_nbma;
-static list *this_nets;
-static struct area_net_config *this_pref;
-static struct ospf_stubnet_config *this_stubnet;
+#define OSPF_CFG ((struct ospf_config *) ctx->this_proto)
+#define OSPF_PATT ((struct ospf_iface_patt *) ctx->this_ipatt)
 
-static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
-static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
+static inline int ospf_cfg_is_v2(struct cf_context *ctx) { return OSPF_CFG->ospf2; }
+static inline int ospf_cfg_is_v3(struct cf_context *ctx) { return ! OSPF_CFG->ospf2; }
 
 static void
-ospf_iface_finish(void)
+ospf_iface_finish(struct cf_context *ctx)
 {
   struct ospf_iface_patt *ip = OSPF_PATT;
 
@@ -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;
-
-  init_list(&this_area->patt_list);
-  init_list(&this_area->net_list);
-  init_list(&this_area->enet_list);
-  init_list(&this_area->stubnet_list);
+  ctx->this_area = cfg_allocz(sizeof(struct ospf_area_config));
+  add_tail(&OSPF_CFG->area_list, NODE ctx->this_area);
+  ctx->this_area->areaid = $2;
+  ctx->this_area->default_cost = OSPF_DEFAULT_STUB_COST;
+  ctx->this_area->type = OPT_E;
+  ctx->this_area->transint = OSPF_DEFAULT_TRANSINT;
+
+  init_list(&ctx->this_area->patt_list);
+  init_list(&ctx->this_area->net_list);
+  init_list(&ctx->this_area->enet_list);
+  init_list(&ctx->this_area->stubnet_list);
  }
  ;
 
-ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
+ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(ctx); }
  ;
 
 ospf_area_opts:
@@ -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; }
index 150f519f5ba54b28e7468d5c70ce3e42354b75c1..7ec3fdc5ac1063973a992c1b374b42a845d6c63b 100644 (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;
index ff55621a467ad032764d4c4220275571fa1fa563..d89ed68c9d72b07b207bb2a84030b083147bafa7 100644 (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 */
index 18e1d0fca5de430aaddce1eb79cd67c85d6d5b7c..84fa7a0018818fbb2750ff6ca3514c7595bed08d 100644 (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;
   }
 };
 
index 82ccf38a38bf55941ecc66dd45c49c126a170e31..8cf09e751137fe2e4388e940347afc12fab8274a 100644 (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 */
 }
index 53715f776c31df1ec3f62e7d6a25c3363c081551..727c8dac413d5525f9e44f1aade99959e0b95606 100644 (file)
@@ -9,20 +9,21 @@ CF_HDR
 
 #include "proto/radv/radv.h"
 
-CF_DEFINES
+CF_CTX
 
-#define RADV_CFG ((struct radv_config *) this_proto)
-#define RADV_IFACE ((struct radv_iface_config *) this_ipatt)
-#define RADV_PREFIX this_radv_prefix
-#define RADV_RDNSS (&this_radv_rdnss)
-#define RADV_DNSSL (&this_radv_dnssl)
+struct radv_prefix_config *this_radv_prefix;
+struct radv_rdnss_config this_radv_rdnss;
+struct radv_dnssl_config this_radv_dnssl;
+list radv_dns_list;    /* Used by radv_rdnss and radv_dnssl */
+u8 radv_mult_val;      /* Used by radv_mult for second return value */
 
-static struct radv_prefix_config *this_radv_prefix;
-static struct radv_rdnss_config this_radv_rdnss;
-static struct radv_dnssl_config this_radv_dnssl;
-static list radv_dns_list;     /* Used by radv_rdnss and radv_dnssl */
-static u8 radv_mult_val;       /* Used by radv_mult for second return value */
+CF_DEFINES
 
+#define RADV_CFG ((struct radv_config *) ctx->this_proto)
+#define RADV_IFACE ((struct radv_iface_config *) ctx->this_ipatt)
+#define RADV_PREFIX ctx->this_radv_prefix
+#define RADV_RDNSS (&ctx->this_radv_rdnss)
+#define RADV_DNSSL (&ctx->this_radv_dnssl)
 
 CF_DECLS
 
@@ -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:
index 389f598c6f78f49a9733fb79c3f5022e176d5591..ed70501b8f9d8ad1ca6c831643b67658dfdeb7b4 100644 (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
index 172299d0dfb562a8c9f723e1832de5d3acce487c..71dfedd7a69e52cc525aa94cdbce500b1ba78478 100644 (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
index 2838d425b1793b36bf61f821ea79b6536919d808..af2244771767e8757cabfe4f0c0b03e62173ae87 100644 (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 *
index a88a29a1c00435a36543ff4346a0e50211e075e9..00df2f1d0923d64d623371944c84364219014f4f 100644 (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
index 36097dc515fa7ac295c2fec40dbeea23fecc5caf..347eecbff773e60c81713fed300a42564efa1b3e 100644 (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 */
 }
index 8972b33a50d8958045b675f2b67cd8b5e03cbea6..bb694f90eb3c8268029307381333044d1511b46b 100644 (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);
 
 
 /*
index d7a029613536f04d1c859f55b19fc93996d229a1..067ac0d11ef36f000e060d9b554ab145ecc38169 100644 (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
 
index 40096c16227645ae5efea98fa6275be7644a9438..7af90342e870009c01ad53297eacf8ad986a66f6 100644 (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)
index 8581bd43b232ada9a8de76da078d5a7ce7f47762..9d0a3d8f467a787709efbe1c1ccdc0250371ea2a 100644 (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;
    }
index f592399c1ba85c8cbda5b4c899301bfddd025942..b74cfc47a72a5ba34c259f53100f79c729fd8c23 100644 (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)
diff --git a/sysdep/unix/conf.c b/sysdep/unix/conf.c
new file mode 100644 (file)
index 0000000..571909b
--- /dev/null
@@ -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);
+}
+
index 1bffa322ae98405c9c4b8718fd0ef544e1cc80c8..084f315b9b33d3f22cacf3b41fc82e04b05c29ad 100644 (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; }
  ;
 
 
index 95b54d65dae1454bc09fcbbdd7d4bfff3677cd43..c4015370d14453f664c16f730e3187760c6a3b43 100644 (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:
index a79df54eac9913275bb05198facef48f07d029c9..a68ebc0644dd7d52046a0698c94d2d435b249004 100644 (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;
index 6ace2a869c26c362ed1cae970304ce819ba2c896..c7310db01cc1703887215b55fbb68e16f30bf176 100644 (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 */
index ea1476e7ad91f5ed9cd1175e8e02885498d02a49..3b8fc3cc637638a43c9e5e1994041139fb54d4e5 100644 (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
index cb12fad844bb65da77b3d95960e982e0452ca817..6e28cc24f9efcaf9d0cf26639ba23e29d32ad127 100644 (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 */