summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2019-02-26 16:44:24 +0100
committerMaria Matejka <mq@ucw.cz>2019-02-26 16:44:24 +0100
commitf249d0b84c840242a084966999a1d228c603b431 (patch)
tree7e366d772a68306b20c8c71e34febc747d9a8fe5
parent0d12aa48363802e751d3b9a4afd6eb090592d7a3 (diff)
Filters: comparison of functions and filters caching
-rw-r--r--conf/cf-lex.l4
-rw-r--r--conf/conf.c3
-rw-r--r--conf/conf.h4
-rw-r--r--filter/config.Y2
-rw-r--r--filter/f-inst.h4
-rw-r--r--filter/f-util.c9
-rw-r--r--filter/filter.c46
-rw-r--r--filter/filter.h4
-rw-r--r--filter/test-reconf-begin.conf23
-rw-r--r--filter/test-reconf-end.conf23
10 files changed, 108 insertions, 14 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 593df9d6..4f69993e 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -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;
diff --git a/conf/conf.c b/conf/conf.c
index 439aa41d..b0980d7e 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -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");
diff --git a/conf/conf.h b/conf/conf.h
index acb3413b..f14c0e21 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -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);
diff --git a/filter/config.Y b/filter/config.Y
index 5ec226f0..a7618987 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -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();
diff --git a/filter/f-inst.h b/filter/f-inst.h
index 5b397a5d..4b42c57c 100644
--- a/filter/f-inst.h
+++ b/filter/f-inst.h
@@ -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 */
};
diff --git a/filter/f-util.c b/filter/f-util.c
index 85f5d1c4..35944b2c 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -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;
}
diff --git a/filter/filter.c b/filter/filter.c
index ee5d5426..3be7343c 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -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;
+ }
}
diff --git a/filter/filter.h b/filter/filter.h
index 26faeaa3..d919cc74 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -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
index 00000000..aeed007f
--- /dev/null
+++ b/filter/test-reconf-begin.conf
@@ -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
index 00000000..19164825
--- /dev/null
+++ b/filter/test-reconf-end.conf
@@ -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;
+}