From f249d0b84c840242a084966999a1d228c603b431 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 26 Feb 2019 16:44:24 +0100 Subject: [PATCH] Filters: comparison of functions and filters caching --- conf/cf-lex.l | 4 ++- conf/conf.c | 3 +++ conf/conf.h | 4 ++- filter/config.Y | 2 +- filter/f-inst.h | 4 +-- filter/f-util.c | 9 +++---- filter/filter.c | 46 +++++++++++++++++++++++++++++++++-- filter/filter.h | 4 ++- filter/test-reconf-begin.conf | 23 ++++++++++++++++++ filter/test-reconf-end.conf | 23 ++++++++++++++++++ 10 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 filter/test-reconf-begin.conf create mode 100644 filter/test-reconf-end.conf 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; +}