Hello list!

bird filters/functions are very powerful mechanism for managing route announces and redistribution. However, building complicated filters or/and applying filters on peers based on RIPE (or MERIT, or ..) database makes bird.conf grow very fast. Additionally, all this machine-generated stuff needs to be in the beginning since config parser requires filters to be defined _before_ using them. As a result, human re-configuration becomes more complicated. Proposed solution is to add include directive to permit (recursive) include of other files from bird[6].conf. Patch is attached, comments/reviews are welcome.

http link: http://static.ipfw.ru/patches/bird_includes_20110513.diff

--
WBR, Alexander
MELI-RIPE


Index: conf/conf.c
===================================================================
--- conf/conf.c (revision 4873)
+++ conf/conf.c (revision 4875)
@@ -108,7 +108,7 @@
   cfg_mem = c->mem;
   if (setjmp(conf_jmpbuf))
     return 0;
-  cf_lex_init(0);
+  cf_lex_init(c, 0);
   sysdep_preconfig(c);
   protos_preconfig(c);
   rt_preconfig(c);
@@ -138,7 +138,7 @@
   cfg_mem = c->mem;
   if (setjmp(conf_jmpbuf))
     return 0;
-  cf_lex_init(1);
+  cf_lex_init(c, 1);
   cf_parse();
   return 1;
 }
@@ -356,6 +356,7 @@
     strcpy(buf, "<bug: error message too long>");
   new_config->err_msg = cfg_strdup(buf);
   new_config->err_lino = conf_lino;
+  new_config->err_fname = conf_fname;
   longjmp(conf_jmpbuf, 1);
 }
 
Index: conf/cf-lex.l
===================================================================
--- conf/cf-lex.l       (revision 4873)
+++ conf/cf-lex.l       (revision 4875)
@@ -30,6 +30,9 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgen.h>
 
 #define PARSER 1
 
@@ -64,18 +67,36 @@
 static struct sym_scope *conf_this_scope;
 
 int conf_lino;
+char conf_fname[255];
+int conf_fd;
 
+char conf_base[255];
+
 static int cf_hash(byte *c);
 static struct symbol *cf_find_sym(byte *c, unsigned int h0);
 
 linpool *cfg_mem;
 
-int (*cf_read_hook)(byte *buf, unsigned int max);
+int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
 
-#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
-#define YY_NO_UNPUT
+#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, 
STACK(conf_fd));
 #define YY_FATAL_ERROR(msg) cf_error(msg)
 
+#define MAX_INCLUDE_DEPTH      42
+struct include_file_stack {
+       YY_BUFFER_STATE stack; /* Internal lexer state */
+       unsigned int    conf_lino; /* Current file lineno (at include) */
+       char            conf_fname[255]; /* Current file name */
+       int             conf_fd; /* Current file descriptor */
+};
+
+static struct include_file_stack ifs[MAX_INCLUDE_DEPTH];
+static int ifs_ind; /* Current stack depth */
+#define STACK(x)       ifs[ifs_ind].x
+
+static void dispatch_include(void);
+static int check_eof(void);
+
 %}
 
 %option noyywrap
@@ -90,9 +111,12 @@
 XIGIT [0-9a-fA-F]
 ALNUM [a-zA-Z_0-9]
 WHITE [ \t]
+include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
 
 %%
 
+{include} { dispatch_include(); }
+
 {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
 #ifdef IPV6
   if (ipv4_pton_u32(yytext, &cf_lval.i32))
@@ -184,7 +208,7 @@
 
 ["][^"\n]*\n   cf_error("Unterminated string");
 
-<INITIAL,COMMENT><<EOF>>       return END;
+<INITIAL,COMMENT><<EOF>>       { if (check_eof()) return END; }
 
 {WHITE}+
 
@@ -220,7 +244,67 @@
 
 %%
 
+/* Open included file with properly swapped buffers */
+static void
+dispatch_include(void)
+{
+       char *fname, *p = NULL, full_name[255];
+       int fd;
+
+       if ((fname = strchr(yytext, '"')) != NULL) {
+               if ((p = strchr(++fname, '"')) != NULL)
+                       *p = '\0';
+
+               if (*fname == '/')
+                       snprintf(full_name, sizeof(full_name), "%s", fname);
+               else
+                       snprintf(full_name, sizeof(full_name), "%s/%s", 
conf_base, fname);
+
+               if (ifs_ind >= MAX_INCLUDE_DEPTH)
+                       cf_error("Max include depth (%d) reached on file %s", 
MAX_INCLUDE_DEPTH, fname);
+
+               if ((fd = open(full_name, O_RDONLY)) == -1)
+                       cf_error("Error opening included file %s", full_name);
+
+               /* Save current stack */
+               STACK(conf_lino) = conf_lino;
+               STACK(stack) = YY_CURRENT_BUFFER;
+               /* Prepare new stack */
+               ifs_ind++;
+               STACK(conf_lino) = 1;
+               strcpy(STACK(conf_fname), fname); /* XXX: strlcpy should be 
here */
+               STACK(conf_fd) = fd;
+               /* Export to global variables */
+               conf_lino = STACK(conf_lino);
+               conf_fd = STACK(conf_fd);
+               strcpy(conf_fname, STACK(conf_fname));
+
+               yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+       }
+}
+
 static int
+check_eof(void)
+{
+       if (ifs_ind > 0)
+               close(STACK(conf_fd));
+       if (--ifs_ind < 0) {
+               /* EOF in main config file */
+               ifs_ind = 0;
+               conf_lino = 1;
+               return 1;
+       }
+
+       /* switch buffer */
+       conf_lino = STACK(conf_lino);
+       conf_fd = STACK(conf_fd);
+       strcpy(conf_fname, STACK(conf_fname));
+       yy_delete_buffer(YY_CURRENT_BUFFER);
+       yy_switch_to_buffer(STACK(stack));
+       return 0;
+}
+
+static int
 cf_hash(byte *c)
 {
   unsigned int h = 13;
@@ -363,11 +447,28 @@
  * parsing of a new input.
  */
 void
-cf_lex_init(int is_cli)
+cf_lex_init(struct config *c, int is_cli)
 {
   if (!kw_hash_inited)
     cf_lex_init_kh();
   conf_lino = 1;
+  /* Zero stack */
+  memset(ifs, 0, sizeof(ifs));
+  memset(conf_base, 0, sizeof(conf_base));
+  ifs_ind = 0;
+  if (!is_cli) {
+    /* Fill in level 0 */
+    STACK(conf_lino) = 1;
+    STACK(conf_fd) = c->file_fd;
+    strcpy(STACK(conf_fname), c->file_name);
+    /* Save config directory path */
+    strcpy(conf_base, dirname(STACK(conf_fname)));
+  }
+  /* Export to global variables */
+  conf_lino = STACK(conf_lino);
+  conf_fd = STACK(conf_fd);
+  strcpy(conf_fname, STACK(conf_fname));
+
   yyrestart(NULL);
   if (is_cli)
     BEGIN(CLI);
Index: conf/conf.h
===================================================================
--- conf/conf.h (revision 4873)
+++ conf/conf.h (revision 4875)
@@ -38,7 +38,9 @@
   int cli_debug;                       /* Tracing of CLI connections and 
commands */
   char *err_msg;                       /* Parser error message */
   int err_lino;                                /* Line containing error */
+  char *err_fname;                     /* File name containing error */
   char *file_name;                     /* Name of configuration file */
+  int file_fd;                         /* Config file descriptor */
   struct symbol **sym_hash;            /* Lexer: symbol hash table */
   struct symbol **sym_fallback;                /* Lexer: fallback symbol hash 
table */
   int obstacle_count;                  /* Number of items blocking freeing of 
this config */
@@ -83,7 +85,7 @@
 
 /* Lexer */
 
-extern int (*cf_read_hook)(byte *buf, unsigned int max);
+extern int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
 
 struct symbol {
   struct symbol *next;
@@ -107,9 +109,10 @@
 #define SYM_VARIABLE 0x100     /* 0x100-0x1ff are variable types */
 
 extern int conf_lino;
+extern char conf_fname[255];
 
 int cf_lex(void);
-void cf_lex_init(int is_cli);
+void cf_lex_init(struct config *c, int is_cli);
 struct symbol *cf_find_symbol(byte *c);
 struct symbol *cf_default_name(char *template, int *counter);
 struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
Index: doc/bird.conf.example
===================================================================
--- doc/bird.conf.example       (revision 4873)
+++ doc/bird.conf.example       (revision 4875)
@@ -22,6 +22,9 @@
 #      else reject;
 #}
 
+# Write more filters in included config file(s):
+#include "filters.conf";
+
 #filter sink { reject; }
 #filter okay { accept; }
 
Index: sysdep/unix/main.c
===================================================================
--- sysdep/unix/main.c  (revision 4873)
+++ sysdep/unix/main.c  (revision 4875)
@@ -122,13 +122,12 @@
 #endif // PATH_IPROUTE_DIR
 
 
-static int conf_fd;
 static char *config_name = PATH_CONFIG;
 
 static int
-cf_read(byte *dest, unsigned int len)
+cf_read(byte *dest, unsigned int len, int fd)
 {
-  int l = read(conf_fd, dest, len);
+  int l = read(fd, dest, len);
   if (l < 0)
     cf_error("Read error");
   return l;
@@ -158,15 +157,15 @@
 unix_read_config(struct config **cp, char *name)
 {
   struct config *conf = config_alloc(name);
-  int ret;
+  int ret, fd;
 
   *cp = conf;
-  conf_fd = open(name, O_RDONLY);
-  if (conf_fd < 0)
+  if ((fd = open(name, O_RDONLY)) == -1)
     return 0;
+  conf->file_fd = fd;
   cf_read_hook = cf_read;
   ret = config_parse(conf);
-  close(conf_fd);
+  close(fd);
   return ret;
 }
 
@@ -178,7 +177,7 @@
   if (!unix_read_config(&conf, config_name))
     {
       if (conf->err_msg)
-       die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
+       die("%s, line %d: %s", conf->err_fname, conf->err_lino, conf->err_msg);
       else
        die("Unable to open configuration file %s: %m", config_name);
     }

Reply via email to