[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