[RFC PATCH 14/20] adapt infrastructure
Asbjørn Sloth Tønnesen
ast at 2e8.dk
Mon Dec 30 17:56:40 CET 2019
---
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
More information about the Bird-users
mailing list