]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Recursive filter iteration code
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 7 Feb 2021 18:21:42 +0000 (19:21 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 7 Feb 2021 18:21:42 +0000 (19:21 +0100)
Add macros for recursive filter iteration that allows to examine
all instructions reachable from a filter.

filter/data.h
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/tree.c
lib/buffer.h
nest/proto.c

index a0ec3819b4a27e6d8a271feeea63eb2a5d8bc958..61cdb43e27296c232a09ef152d4286e576a943e8 100644 (file)
@@ -175,6 +175,7 @@ struct f_tree *build_tree(struct f_tree *);
 const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
 int same_tree(const struct f_tree *t0, const struct f_tree *t2);
 void tree_format(const struct f_tree *t, buffer *buf);
+void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data);
 
 struct f_trie *f_new_trie(linpool *lp, uint data_size);
 void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
index 14b9329c95b478d7b88f36afbecbbd29ffd0b750..5242c04c67db1149576a4bb83dc415384f7c621d 100644 (file)
@@ -40,6 +40,7 @@ m4_divert(-1)m4_dnl
 #      106     comparator body
 #      107     struct f_line_item content
 #      108     interpreter body
+#      109     iterator body
 #
 #      Here are macros to allow you to _divert to the right directions.
 m4_define(FID_STRUCT_IN, `m4_divert(101)')
@@ -50,6 +51,7 @@ m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
 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_ITERATE_BODY, `m4_divert(109)')
 
 #      Sometimes you want slightly different code versions in different
 #      outputs.
@@ -211,6 +213,8 @@ FID_LINEARIZE_BODY()m4_dnl
 item->fl$1 = f_linearize(whati->f$1);
 FID_SAME_BODY()m4_dnl
 if (!f_same(f1->fl$1, f2->fl$1)) return 0;
+FID_ITERATE_BODY()m4_dnl
+if (whati->fl$1) BUFFER_PUSH(fit->lines) = whati->fl$1;
 FID_INTERPRET_EXEC()m4_dnl
 do { if (whati->fl$1) {
   LINEX_(whati->fl$1);
@@ -265,6 +269,7 @@ m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access
 #      7       dump line item callers
 #      8       linearize
 #      9       same (filter comparator)
+#      10      iterate
 #      1       union in struct f_inst
 #      3       constructors + interpreter
 #
@@ -285,6 +290,7 @@ m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
 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_ITERATE, `FID_ZONE(10, Iteration)')
 
 #      This macro does all the code wrapping. See inline comments.
 m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
@@ -372,6 +378,13 @@ m4_undivert(106)m4_dnl
 #undef f2
 break;
 
+FID_ITERATE()m4_dnl                    The iterator
+case INST_NAME():
+#define whati (&(what->i_]]INST_NAME()[[))
+m4_undivert(109)m4_dnl
+#undef whati
+break;
+
 m4_divert(-1)FID_FLUSH(101,200)m4_dnl  And finally this flushes all the unused diversions
 ]])')
 
@@ -582,6 +595,27 @@ FID_WR_PUT(9)
   return 1;
 }
 
+
+/* Part of FI_SWITCH filter iterator */
+static void
+f_add_tree_lines(const struct f_tree *t, void *fit_)
+{
+  struct filter_iterator * fit = fit_;
+
+  if (t->data)
+    BUFFER_PUSH(fit->lines) = t->data;
+}
+
+/* Filter line iterator */
+void
+f_add_lines(const struct f_line_item *what, struct filter_iterator *fit)
+{
+  switch(what->fi_code) {
+FID_WR_PUT(10)
+  }
+}
+
+
 #if defined(__GNUC__) && __GNUC__ >= 6
 #pragma GCC diagnostic pop
 #endif
index b6bc81f7bd15e704518464734a2de848960173ea..5cae31ba153d05193ef3cad0a84232795871c200 100644 (file)
  *     m4_dnl  use macros f1 and f2.
  *     m4_dnl  For writing directly here, use FID_SAME_BODY.
  *
+ *     m4_dnl          f_add_lines(...)
+ *     m4_dnl          {
+ *     m4_dnl            switch (what_->fi_code) {
+ *     m4_dnl              case FI_EXAMPLE:
+ *     m4_dnl  (109)         [[ put it here ]]
+ *     m4_dnl                break;
+ *     m4_dnl            }
+ *     m4_dnl          }
+ *     m4_dnl  This code adds new filter lines reachable from the instruction
+ *     m4_dnl  to the filter iterator line buffer. This is for instructions
+ *     m4_dnl  that changes conrol flow, like FI_CONDITION or FI_CALL, most
+ *     m4_dnl  instructions do not need to update it. It is used in generic
+ *     m4_dnl  filter iteration code (FILTER_ITERATE*). For accessing your
+ *     m4_dnl  custom instruction data, use macros f1 and f2. For writing
+ *     m4_dnl  directly here, use FID_ITERATE_BODY.
+ *
  *     m4_dnl          interpret(...)
  *     m4_dnl          {
  *     m4_dnl            switch (what->fi_code) {
     FID_SAME_BODY()
       if (!(f1->sym->flags & SYM_FLAG_SAME))
        return 0;
+
+    FID_ITERATE_BODY()
+      BUFFER_PUSH(fit->lines) = whati->sym->function;
+
     FID_INTERPRET_BODY()
 
     /* Push the body on stack */
 
     FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
 
+    FID_ITERATE_BODY()
+      tree_walk(whati->tree, f_add_tree_lines, fit);
+
+    FID_INTERPRET_BODY()
     const struct f_tree *t = find_tree(tree, &v1);
     if (!t) {
       v1.type = T_VOID;
index bfa163fcd261249016b775ef6ff744a69d7011fc..df45f88e6ddaf1588d819269e749130615451c5c 100644 (file)
@@ -17,6 +17,7 @@
 #include "conf/conf.h"
 #include "filter/filter.h"
 #include "filter/data.h"
+#include "lib/buffer.h"
 #include "lib/flowspec.h"
 
 /* Flags for instructions */
@@ -50,6 +51,41 @@ static inline struct f_line *f_linearize(const struct f_inst *root)
 
 void f_dump_line(const struct f_line *, uint indent);
 
+
+/* Recursive iteration over filter instructions */
+
+struct filter_iterator {
+  BUFFER_(const struct f_line *) lines;
+};
+
+void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
+
+#define FILTER_ITERATE_INIT(fit, filter, pool)                 \
+  ({                                                           \
+    BUFFER_INIT((fit)->lines, (pool), 32);                     \
+    BUFFER_PUSH((fit)->lines) = (filter)->root;                        \
+  })
+
+#define FILTER_ITERATE(fit, fi) ({                             \
+  const struct f_line *fl_;                                    \
+  while (!BUFFER_EMPTY((fit)->lines))                          \
+  {                                                            \
+    BUFFER_POP((fit)->lines);                                  \
+    fl_ = (fit)->lines.data[(fit)->lines.used];                        \
+    for (uint i_ = 0; i_ < fl_->len; i_++)                     \
+    {                                                          \
+      const struct f_line_item *fi = &fl_->items[i_];          \
+      f_add_lines(fi, (fit));
+
+#define FILTER_ITERATE_END } } })
+
+#define FILTER_ITERATE_CLEANUP(fit)                            \
+  ({                                                           \
+    mb_free((fit)->lines.data);                                        \
+    memset((fit), 0, sizeof(struct filter_iterator));          \
+  })
+
+
 struct filter *f_new_where(struct f_inst *);
 static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
 { return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; }   /* f_type currently unused; will be handy for static type checking */
index 2bbc84bb1ce6706b2c631488e630382c6531edcc..5da86b9d28679dae272831bcfe1e63b45867d015 100644 (file)
@@ -170,3 +170,14 @@ tree_format(const struct f_tree *t, buffer *buf)
 
   buffer_puts(buf, "]");
 }
+
+void
+tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data)
+{
+  if (!t)
+    return;
+
+  tree_walk(t->left, hook, data);
+  hook(t, data);
+  tree_walk(t->right, hook, data);
+}
index cd9bab867851027cb778f61a96136bb7c855f752..fd40baa024c3b7bcb6591cf225e592ea01430647 100644 (file)
@@ -50,6 +50,8 @@
 
 #define BUFFER_FLUSH(v)                ({ (v).used = 0; })
 
+#define BUFFER_EMPTY(v)                ({ (v).used == 0; })
+
 #define BUFFER_WALK(v,n)                                               \
   for (BUFFER_TYPE(v) *_n = (v).data, n; _n < ((v).data + (v).used) && (n = *_n, 1); _n++)
 
index aebb5458d90e647904b5a4a7121a7524c3f8430d..7b359152f080b941ac8dd76a0a79e63956a1b7eb 100644 (file)
@@ -20,6 +20,7 @@
 #include "nest/iface.h"
 #include "nest/cli.h"
 #include "filter/filter.h"
+#include "filter/f-inst.h"
 
 pool *proto_pool;
 list  proto_list;