]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filters: comparison of functions and filters caching
authorMaria Matejka <mq@ucw.cz>
Tue, 26 Feb 2019 15:44:24 +0000 (16:44 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 26 Feb 2019 15:44:24 +0000 (16:44 +0100)
conf/cf-lex.l
conf/conf.c
conf/conf.h
filter/config.Y
filter/f-inst.h
filter/f-util.c
filter/filter.c
filter/filter.h
filter/test-reconf-begin.conf [new file with mode: 0644]
filter/test-reconf-end.conf [new file with mode: 0644]

index 593df9d6652c6d3d26f04eb10807f7561002d58c..4f69993e1a29b222aa57fe4f7b70f0dd9cca9c66 100644 (file)
@@ -561,6 +561,8 @@ cf_new_symbol(const byte *c)
 
   HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
 
+  add_tail(&(new_config->symbols), &(s->n));
+
   return s;
 }
 
@@ -576,7 +578,7 @@ cf_new_symbol(const byte *c)
  * signify no match.
  */
 struct symbol *
-cf_find_symbol(struct config *cfg, const byte *c)
+cf_find_symbol(const struct config *cfg, const byte *c)
 {
   struct symbol *s;
 
index 439aa41d733d9c568c535a93df42632e0811ea17..b0980d7e34fdeeff441e29bd8300933f131a9892 100644 (file)
@@ -98,6 +98,7 @@ config_alloc(const char *name)
   memcpy(ndup, name, nlen);
 
   init_list(&c->tests);
+  init_list(&c->symbols);
   c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
   c->pool = p;
   c->mem = l;
@@ -258,6 +259,8 @@ config_do_commit(struct config *c, int type)
   if (old_config)
     old_config->obstacle_count++;
 
+  DBG("filter_commit\n");
+  filter_commit(c, old_config);
   DBG("sysdep_commit\n");
   int force_restart = sysdep_commit(c, old_config);
   DBG("global_commit\n");
index acb3413ba7fee3bd2919101ab95293dc8764c7b6..f14c0e213204a628ca52643f4c044c1feafd849c 100644 (file)
@@ -24,6 +24,7 @@ struct config {
   list tables;                         /* Configured routing tables (struct rtable_config) */
   list logfiles;                       /* Configured log files (sysdep) */
   list tests;                          /* Configured unit tests (f_bt_test_suite) */
+  list symbols;                                /* Configured symbols in config order */
 
   int mrtdump_file;                    /* Configured MRTDump file (sysdep, fd in unix) */
   char *syslog_name;                   /* Name used for syslog (NULL -> no syslog) */
@@ -103,6 +104,7 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size);
 extern int (*cf_read_hook)(byte *buf, uint max, int fd);
 
 struct symbol {
+  node n;                              /* In list of symbols in config */
   struct symbol *next;
   struct sym_scope *scope;
   int class;                           /* SYM_* */
@@ -167,7 +169,7 @@ 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, const byte *c);
+struct symbol *cf_find_symbol(const struct config *cfg, const byte *c);
 
 struct symbol *cf_get_symbol(const byte *c);
 struct symbol *cf_default_name(char *template, int *counter);
index 5ec226f006c36c65e98f14ed71aac004a88ccc12..a7618987f93fd6f4802060b59c9992262b6dcf03 100644 (file)
@@ -470,7 +470,7 @@ filter_def:
    FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
      filter_body {
      struct filter *f = cfg_alloc(sizeof(struct filter));
-     *f = (struct filter) { .name = $2->name, .root = $4 };
+     *f = (struct filter) { .sym = $2, .root = $4 };
      $2->filter = f;
 
      cf_pop_scope();
index 5b397a5dc21baea3cccfe1284de1630ab9fe333e..4b42c57c0439e903303b2ebcdc155eb11f2c05e9 100644 (file)
@@ -31,12 +31,10 @@ const char *f_instruction_name(enum f_instruction_code fi);
 struct f_inst *f_clear_local_vars(struct f_inst *decls);
 
 /* Filter structures for execution */
-struct f_line;
-
 /* Line of instructions to be unconditionally executed one after another */
 struct f_line {
   uint len;                            /* Line length */
-  u16 args;                            /* Function: Args required  */
+  u8 args;                             /* Function: Args required */
   struct f_line_item items[0];         /* The items themselves */
 };
 
index 85f5d1c408561a10f68269d92250a146d3fd8709..35944b2ca1d3da879116680d08d70a344a3216a5 100644 (file)
@@ -24,10 +24,10 @@ filter_name(const struct filter *filter)
     return "ACCEPT";
   else if (filter == FILTER_REJECT)
     return "REJECT";
-  else if (!filter->name)
+  else if (!filter->sym)
     return "(unnamed)";
   else
-    return filter->name;
+    return filter->sym->name;
 }
 
 void f_inst_next(struct f_inst *first, const struct f_inst *append)
@@ -54,7 +54,7 @@ struct filter *f_new_where(const struct f_inst *where)
   struct f_inst i = {
     .fi_code = FI_CONDITION,
     .lineno = ifs->lino,
-    .size = 3,
+    .size = 3 + where->size,
     .i_FI_CONDITION = {
       .f1 = where,
       .f2 = &acc,
@@ -62,8 +62,7 @@ struct filter *f_new_where(const struct f_inst *where)
     },
   };
 
-  struct filter *f = cfg_alloc(sizeof(struct filter));
-  f->name = NULL;
+  struct filter *f = cfg_allocz(sizeof(struct filter));
   f->root = f_postfixify(&i);
   return f;
 }
index ee5d542628ff41efe277c3b00e297bb3dfe4a6fa..3be7343c9346a322505e0e65b43be23c36c1d810 100644 (file)
@@ -293,7 +293,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
 
   if (fret < F_ACCEPT) {
     if (!(fs.flags & FF_SILENT))
-      log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
+      log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter_name(filter));
     return F_ERROR;
   }
   DBG( "done (%u)\n", res.val.i );
@@ -378,5 +378,47 @@ filter_same(const struct filter *new, const struct filter *old)
   if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
       new == FILTER_ACCEPT || new == FILTER_REJECT)
     return 0;
-  return f_same(new->root, old->root);
+
+  if ((!old->sym) && (!new->sym))
+    return f_same(new->root, old->root);
+
+  if ((!old->sym) || (!new->sym))
+    return 0;
+
+  if (strcmp(old->sym->name, new->sym->name))
+    return 0;
+
+  return new->sym->flags & SYM_FLAG_SAME;
+}
+
+/**
+ * filter_commit - do filter comparisons on all the named functions and filters
+ */
+void
+filter_commit(const struct config *new, const struct config *old)
+{
+  if (!old)
+    return;
+
+  struct symbol *sym, *osym;
+  WALK_LIST(sym, new->symbols)
+    switch (sym->class) {
+      case SYM_FUNCTION:
+       if ((osym = cf_find_symbol(old, sym->name)) &&
+           (osym->class == SYM_FUNCTION) &&
+           f_same(sym->function, osym->function))
+         sym->flags |= SYM_FLAG_SAME;
+       else
+         sym->flags &= ~SYM_FLAG_SAME;
+       break;
+
+      case SYM_FILTER:
+       if ((osym = cf_find_symbol(old, sym->name)) &&
+           (osym->class == SYM_FILTER) &&
+           f_same(sym->filter->root, osym->filter->root))
+         sym->flags |= SYM_FLAG_SAME;
+       else
+         sym->flags &= ~SYM_FLAG_SAME;
+       break;
+    }
 }
index 26faeaa333a28d662de2fea681e5f1f1fa4debe4..d919cc74a7a7a7bcb31b200879619ced97129447 100644 (file)
@@ -47,7 +47,7 @@ struct f_val;
 /* The filter encapsulating structure to be pointed-to from outside */
 struct f_line;
 struct filter {
-  char *name;
+  struct symbol *sym;
   const struct f_line *root;
 };
 
@@ -62,6 +62,8 @@ const char *filter_name(const struct filter *filter);
 int filter_same(const struct filter *new, const struct filter *old);
 int f_same(const struct f_line *f1, const struct f_line *f2);
 
+void filter_commit(const struct config *new, const struct config *old);
+
 #define FILTER_ACCEPT NULL
 #define FILTER_REJECT ((void *) 1)
 #define FILTER_UNDEF  ((void *) 2)     /* Used in BGP */
diff --git a/filter/test-reconf-begin.conf b/filter/test-reconf-begin.conf
new file mode 100644 (file)
index 0000000..aeed007
--- /dev/null
@@ -0,0 +1,23 @@
+router id 1.1.1.1;
+protocol device {}
+
+function a() {
+  return true;
+}
+
+function b() {
+  return a();
+}
+
+function c() {
+  return b();
+}
+
+filter d {
+  if c() then accept; else reject;
+}
+
+protocol static {
+  ipv4 { import filter d; };
+  route 10.0.0.0/24 unreachable;
+}
diff --git a/filter/test-reconf-end.conf b/filter/test-reconf-end.conf
new file mode 100644 (file)
index 0000000..1916482
--- /dev/null
@@ -0,0 +1,23 @@
+router id 1.1.1.1;
+protocol device {}
+
+function a() {
+  return false;
+}
+
+function b() {
+  return a();
+}
+
+function c() {
+  return b();
+}
+
+filter d {
+  if c() then accept; else reject;
+}
+
+protocol static {
+  ipv4 { import filter d; };
+  route 10.0.0.0/24 unreachable;
+}