--- filter/adapt.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ filter/decl.m4 | 33 +++++++++++++++ filter/f-inst.c | 24 ++++++++++- filter/filter.h | 11 +++++ 4 files changed, 173 insertions(+), 2 deletions(-)
diff --git a/filter/adapt.c b/filter/adapt.c index 13c090da..76367521 100644 --- a/filter/adapt.c +++ b/filter/adapt.c @@ -41,3 +41,110 @@ filter_validate_function(struct symbol *sym) if (f_has_typed_symbols(sym->function)) sym->flags |= SYM_FLAG_DO_ADAPT; } + +struct f_tree * +filter_tree_adapt(struct f_tree *t, const struct f_context ctx) +{ + if (!filter_tree_has_typed_symbols(t)) + return t; + + struct f_tree *rt = cfg_allocz(sizeof(struct f_tree)); + memcpy(rt, t, sizeof(struct f_tree)); + + if (filter_tree_has_typed_symbols(t->left)) + rt->left = filter_tree_adapt(t->left, ctx); + + if (filter_tree_has_typed_symbols(t->right)) + rt->right = filter_tree_adapt(t->right, ctx); + + if (t->data && f_has_typed_symbols(t->data)) + rt->data = filter_adapt_line(t->data, ctx); + + return rt; +} + +struct symbol * +filter_adapt_function(struct symbol *sym, const struct f_context ctx) +{ + const struct f_line *line; + struct symbol *tsym = cf_find_typed_symbol(adapt_config, sym->name, ctx.net_type); + if (tsym) { + if (tsym->flags & SYM_FLAG_DO_ADAPT) { + line = tsym->function; + } else { + return tsym; + } + } else if (sym->flags & SYM_FLAG_IS_TYPED && !(sym->flags & SYM_FLAG_DO_ADAPT)) { + cf_error("function %s is not defined for %s", sym->name, net_label[ctx.net_type]); + } else if (new_config) { + tsym = cf_define_typed_symbol(sym, SYM_FUNCTION, function, NULL, ctx.net_type); + line = sym->function; + } else { + tsym = cfg_allocz(sizeof(struct symbol)); + tsym->class = SYM_FUNCTION; + tsym->scope = sym->scope; + tsym->net_type = ctx.net_type; + line = sym->function; + } + tsym->function = filter_adapt_line(line, ctx); + tsym->flags &= ~SYM_FLAG_DO_ADAPT; + return tsym; +} + +const struct filter * +filter_adapt(const struct filter *filter, const struct f_context ctx) +{ + if (is_pseudo_filter(filter)) + return filter; + + const struct f_line *line = filter->root; + struct symbol *sym = filter->sym; + struct symbol *tsym; + + if (line && !f_has_typed_symbols(line)) + return filter; + + if (sym) { + tsym = cf_find_typed_symbol(adapt_config, sym->name, ctx.net_type); + if (tsym) { + line = tsym->filter->root; + if (!f_has_typed_symbols(line)) + return tsym->filter; + sym = tsym; + } else if (sym->flags & SYM_FLAG_IS_TYPED && !(sym->flags & SYM_FLAG_DO_ADAPT)) { + cf_error("filter %s is not defined for %s", sym->name, net_label[ctx.net_type]); + } else { + sym->flags |= SYM_FLAG_DO_ADAPT; + } + } + + struct filter *f = cfg_allocz(sizeof(struct filter)); + f->root = filter_adapt_line(line, ctx); + + if (f_has_typed_symbols(f->root)) + cf_error("failed to adapt the filter properly"); + + if (sym) { + if (tsym) + tsym->filter = f; + else if (new_config) + f->sym = cf_define_typed_symbol(sym, SYM_FILTER, filter, + f, ctx.net_type); + } + + return f; +} + +void +filters_adapt(const struct filter *(*filters)[NET_MAX], const struct filter *f, const u32 mask, const struct config *cfg) +{ + for (int net_type=1; net_type<NET_MAX; net_type++) { + if (net_val_match(net_type, mask)) { + struct f_context f_ctx = { + .net_type = net_type, + .cfg = cfg, + }; + (*filters)[net_type] = filter_adapt(f, f_ctx); + } + } +} diff --git a/filter/decl.m4 b/filter/decl.m4 index 23024d35..81b07bbe 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -41,6 +41,7 @@ m4_divert(-1)m4_dnl # 107 struct f_line_item content # 108 interpreter body # 109 f_has_typed_symbls +# 110 filter_adapt_line # # Here are macros to allow you to _divert to the right directions. m4_define(FID_STRUCT_IN, `m4_divert(101)') @@ -52,6 +53,7 @@ m4_define(FID_SAME_BODY, `m4_divert(106)') m4_define(FID_LINE_IN, `m4_divert(107)') m4_define(FID_INTERPRET_BODY, `m4_divert(108)') m4_define(FID_HAS_TYPED_BODY, `m4_divert(109)') +m4_define(FID_ADAPT_BODY, `m4_divert(110)') # Sometimes you want slightly different code versions in different # outputs. @@ -210,6 +212,9 @@ FID_SAME_BODY()m4_dnl if (!f_same(f1->fl$1, f2->fl$1)) return 0; FID_HAS_TYPED_BODY()m4_dnl if (f_has_typed_symbols(item->fl$1)) return 1; +FID_ADAPT_BODY()m4_dnl +if (f_has_typed_symbols(item->fl$1)) + item->fl$1 = filter_adapt_line(item->fl$1, ctx); FID_INTERPRET_EXEC()m4_dnl do { if (whati->fl$1) { LINEX_(whati->fl$1); @@ -265,6 +270,7 @@ m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access # 8 linearize # 9 same (filter comparator) # 10 f_has_typed_symbols +# 11 filter_adapt_line # 1 union in struct f_inst # 3 constructors + interpreter # @@ -286,6 +292,7 @@ m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') m4_define(FID_SAME, `FID_ZONE(9, Comparison)') m4_define(FID_HAS_TYPED, `FID_ZONE(10, Has typed symbol)') +m4_define(FID_ADAPT, `FID_ZONE(11, Adapt filter line)') # This macro does all the code wrapping. See inline comments. m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ @@ -380,6 +387,13 @@ m4_undivert(109)m4_dnl #undef item break; +FID_ADAPT()m4_dnl This code checks if a f_line used typed symbols +case INST_NAME(): +#define item (&(fl_item->i_]]INST_NAME()[[)) +m4_undivert(110)m4_dnl +#undef item +break; + m4_divert(-1)FID_FLUSH(101,200)m4_dnl And finally this flushes all the unused diversions ]])') @@ -605,6 +619,25 @@ FID_WR_PUT(10) return 0; } +/* adapt f_line to a specific context */ +struct f_line * +filter_adapt_line(const struct f_line *in, const struct f_context ctx) +{ + size_t sz = sizeof(struct f_line) + sizeof(struct f_line_item)*in->len; + struct f_line *out = cfg_allocz(sz); + memcpy(out, in, sz); + for (uint i=0; i<out->len; i++) { + struct f_line_item *fl_item = &out->items[i]; + struct symbol *sym; + struct symbol *tsym; + + switch (fl_item->fi_code) { +FID_WR_PUT(11) + } + } + return out; +} + #if defined(__GNUC__) && __GNUC__ >= 6 #pragma GCC diagnostic pop #endif diff --git a/filter/f-inst.c b/filter/f-inst.c index 46354aa2..7e4043d3 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -27,13 +27,18 @@ * stack; e.g. the + operation just takes two arguments from the value * stack and puts the result on there. * - * 3 Interpret + * 3 Adaptation + * The filter is adapted to the context in which it's being attached. + * In this step we make sure that all symbols involved is typed + * appropriately. + * + * 4 Interpret * The given line is put on a custom execution stack. If needed (FI_CALL, * FI_SWITCH, FI_AND, FI_OR, FI_CONDITION, ...), another line is put on top * of the stack; when that line finishes, the execution continues on the * older lines on the stack where it stopped before. * - * 4 Same + * 5 Same * On config reload, the filters have to be compared whether channel * reload is needed or not. The comparison is done by comparing the * struct f_line's recursively. @@ -445,6 +450,15 @@ FID_HAS_TYPED_BODY() return 1; + FID_ADAPT_BODY() + sym = item->sym; + tsym = cf_find_typed_symbol(adapt_config, sym->name, ctx.net_type); + if (!tsym) + cf_error("constant %s is not defined for %s", sym->name, net_label[ctx.net_type]); + fl_item->fi_code = FI_CONSTANT; + #define new_item (&(fl_item->i_FI_CONSTANT)) + new_item->val = *(tsym->val); + #undef new_item FID_INTERPRET_BODY() runtime("FI_TYPED_CONSTANT can't be interpreted", sym); } @@ -940,6 +954,9 @@ FID_HAS_TYPED_BODY() if (item->sym->flags & SYM_FLAGS_TYPED) return 1; + FID_ADAPT_BODY() + if (item->sym->flags & SYM_FLAGS_TYPED) + item->sym = filter_adapt_function(item->sym, ctx); FID_INTERPRET_BODY() /* Push the body on stack */ @@ -971,6 +988,9 @@ FID_HAS_TYPED_BODY() if (filter_tree_has_typed_symbols(item->tree)) return 1; + FID_ADAPT_BODY() + if (filter_tree_has_typed_symbols(item->tree)) + item->tree = filter_tree_adapt(item->tree, ctx); FID_INTERPRET_BODY() const struct f_tree *t = find_tree(tree, &v1); diff --git a/filter/filter.h b/filter/filter.h index 33c452e8..fcd12a3d 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -51,6 +51,11 @@ struct filter { const struct f_line *root; }; +struct f_context { + const u8 net_type; + const struct config *cfg; +}; + struct rte; enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); @@ -66,6 +71,12 @@ int f_same(const struct f_line *f1, const struct f_line *f2); int f_has_typed_symbols(const struct f_line *line); int filter_tree_has_typed_symbols(const struct f_tree *t); void filter_validate_function(struct symbol *sym); +const struct filter *filter_adapt(const struct filter *filter, const struct f_context ctx); +void filters_adapt(const struct filter *(*filters)[NET_MAX], const struct filter *f, const u32 mask, const struct config *cfg); +struct f_tree *filter_tree_adapt(struct f_tree *t, const struct f_context ctx); +struct symbol *filter_adapt_function(struct symbol *sym, const struct f_context ctx); +struct f_line *filter_adapt_line(const struct f_line *in, const struct f_context ctx); +#define adapt_config (ctx.cfg ? ctx.cfg : new_config) void filter_commit(struct config *new, struct config *old); -- 2.24.0