]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Aggregator: polishing of filter API
authorMaria Matejka <mq@ucw.cz>
Fri, 23 Jun 2023 09:28:19 +0000 (11:28 +0200)
committerMaria Matejka <mq@ucw.cz>
Sun, 24 Sep 2023 13:42:09 +0000 (15:42 +0200)
conf/conf.h
filter/config.Y
filter/f-inst.c
filter/filter.c
filter/filter.h
nest/aggregator.c
nest/config.Y
nest/proto.c
nest/route.h
proto/static/static.c

index 486499ad10a87ebbbb8ee68e18a548fec88b7a89..b07b417c2f3137eb3e844171d74e87951cc0428a 100644 (file)
@@ -238,6 +238,9 @@ struct symbol *cf_new_symbol(struct sym_scope *scope, pool *p, struct linpool *l
     sym_->var_ = def_; \
     sym_; })
 
+#define cf_create_symbol(conf_, name_, type_, var_, def_) \
+  cf_define_symbol(conf_, cf_get_symbol(conf_, name_), type_, var_, def_)
+
 void cf_push_scope(struct config *, struct symbol *);
 void cf_pop_scope(struct config *);
 void cf_push_soft_scope(struct config *);
index 1556d74323670be8b3a3f9bb4ded4e68b0a95458..48f2888df4f8c5b78d06282095adfcad57a44f9e 100644 (file)
@@ -339,7 +339,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        ACCEPT, REJECT, ERROR,
        INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC,
        SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
-    ROUTES,
        IF, THEN, ELSE, CASE,
        FOR, DO,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
@@ -917,7 +916,6 @@ term:
  | term_bs
  | function_call
 
- | ROUTES { $$ = f_new_inst(FI_ROUTES_GET); }
  | CF_SYM_KNOWN '.' static_attr {
      cf_assert_symbol($1, SYM_VARIABLE);
      $$ = f_new_inst(FI_RTA_GET, f_new_inst(FI_VAR_GET, $1), $3);
index 23d33064049543f8cf803b2588f4ddd441d37eaa..11c693ef39e3c552153a10427262e84b4527e0b7 100644 (file)
     RESULT_VAL(val);
   }
 
-  INST(FI_ROUTES_GET, 0, 1) {
-    NEVER_CONSTANT;
-    FID_INTERPRET_BODY()
-    RESULT(T_ROUTES_BLOCK, ad, fs->val->val.ad);
-  }
-
   METHOD_R(T_PATH, empty, T_PATH, ad, &null_adata);
   METHOD_R(T_CLIST, empty, T_CLIST, ad, &null_adata);
   METHOD_R(T_ECLIST, empty, T_ECLIST, ad, &null_adata);
 
   INST(FI_ROUTES_BLOCK_FOR_NEXT, 3, 0) {
     NEVER_CONSTANT;
-    ARG(1, T_ROUTE);
+    ARG(1, T_ROUTES_BLOCK);
     if (rte_set_walk(v1.val.ad, &v2.val.i, &v3.val.rte))
       LINE(2,0);
 
index f21574b42d4e251abbe5fbed18fc46918012cce1..422d78051010418775fa2fcfed719826ddb801a5 100644 (file)
@@ -160,18 +160,20 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
  * TWOARGS macro to get both of them evaluated.
  */
 static enum filter_return
-interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
+interpret(struct filter_state *fs, const struct f_line *line, uint argc, const struct f_val *argv, struct f_val *val)
 {
   /* No arguments allowed */
-  ASSERT(line->args == 0);
+  ASSERT_DIE(line->args == argc);
 
   /* Initialize the filter stack */
   struct filter_stack *fstk = fs->stack;
 
-  fstk->vcnt = line->vars;
-  memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars);
+  /* Set the arguments and top-level variables */
+  fstk->vcnt = line->vars + line->args;
+  memcpy(fstk->vstk, argv, sizeof(struct f_val) * line->args);
+  memset(fstk->vstk + line->args, 0, sizeof(struct f_val) * line->vars);
 
-  /* The same as with the value stack. Not resetting the stack for performance reasons. */
+  /* The same as with the value stack. Not resetting the stack completely for performance reasons. */
   fstk->ecnt = 1;
   fstk->estk[0].line = line;
   fstk->estk[0].pos = 0;
@@ -240,30 +242,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
   return F_ERROR;
 }
 
-/**
- * Evaluation for attributes comparison
- */
-enum filter_return
-f_aggr_eval_line(const struct f_line *line, struct rte **rte, struct linpool *pool, struct f_val *pres)
-{
-  /* Initialize the filter state */
-  filter_state = (struct filter_state) {
-    .stack = &filter_stack,
-    .rte = rte,
-    .pool = pool,
-  };
-
-  LOG_BUFFER_INIT(filter_state.buf);
-
-  /* Run the interpreter itself */
-  enum filter_return fret = interpret(&filter_state, line, pres);
-
-  if (filter_state.old_rta)
-    log("Warning: route changed during filter evaluation");
-
-  return fret;
-}
-
 /**
  * f_run - run a filter for a route
  * @filter: filter to run
@@ -297,11 +275,11 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
   if (filter == FILTER_REJECT)
     return F_REJECT;
 
-  return f_run_val(filter, rte, tmp_pool, NULL, flags);
+  return f_run_args(filter, rte, tmp_pool, 0, NULL, flags);
 }
 
 enum filter_return
-f_run_val(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, const struct f_val *val, int flags)
+f_run_args(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, int flags)
 {
   int rte_cow = ((*rte)->flags & REF_COW);
   DBG( "Running filter `%s'...", filter->name );
@@ -311,14 +289,13 @@ f_run_val(const struct filter *filter, struct rte **rte, struct linpool *tmp_poo
     .stack = &filter_stack,
     .rte = rte,
     .pool = tmp_pool,
-    .val = val,
     .flags = flags,
   };
 
   LOG_BUFFER_INIT(filter_state.buf);
 
   /* Run the interpreter itself */
-  enum filter_return fret = interpret(&filter_state, filter->root, NULL);
+  enum filter_return fret = interpret(&filter_state, filter->root, argc, argv, NULL);
 
   if (filter_state.old_rta) {
     /*
@@ -370,8 +347,9 @@ f_run_val(const struct filter *filter, struct rte **rte, struct linpool *tmp_poo
  */
 
 enum filter_return
-f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
+f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, struct f_val *pres)
 {
+  struct rte *old_rte = *rte;
   filter_state = (struct filter_state) {
     .stack = &filter_stack,
     .rte = rte,
@@ -380,10 +358,17 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool
 
   LOG_BUFFER_INIT(filter_state.buf);
 
-  ASSERT(!((*rte)->flags & REF_COW));
-  ASSERT(!rta_is_cached((*rte)->attrs));
+  enum filter_return fret = interpret(&filter_state, expr, argc, argv, pres);
 
-  return interpret(&filter_state, expr, NULL);
+  if (filter_state.old_rta || (old_rte != *rte))
+  {
+    ASSERT_DIE(rta_is_cached(filter_state.old_rta) && !rta_is_cached((*rte)->attrs));
+    log(L_WARN "Attempted to change a read-only route, reverting");
+    (*rte)->attrs = filter_state.old_rta;
+    *rte = old_rte;
+  }
+
+  return fret;
 }
 
 /*
@@ -402,7 +387,7 @@ f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
 
   LOG_BUFFER_INIT(filter_state.buf);
 
-  enum filter_return fret = interpret(&filter_state, expr, pres);
+  enum filter_return fret = interpret(&filter_state, expr, 0, NULL, pres);
   return fret;
 }
 
index d9216fa4d03d9f064ae673a3931f35c3d848981e..18ff0874f56f35ddb9175d31263959ad56199cfa 100644 (file)
@@ -51,10 +51,9 @@ struct filter {
 
 struct rte;
 
-enum filter_return f_aggr_eval_line(const struct f_line *line, struct rte **rte, struct linpool *pool, struct f_val *pres);
 enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
-enum filter_return f_run_val(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, const struct f_val *val, int flags);
-enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
+enum filter_return f_run_args(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, int flags);
+enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool, uint argc, const struct f_val *argv, struct f_val *pres);
 enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
 
 struct f_val cf_eval(const struct f_inst *inst, int type);
index dfaae1dda526472ad96eddcf4385db3326de8840..4e374cc02230db06efc5e6cfd35df8dbdcfcc365 100644 (file)
@@ -320,12 +320,13 @@ create_merged_rte(struct channel *c, struct network *net, const struct rte_val_l
   for (int i = 0; i < length; i++)
     rb->routes[i] = (struct rte *)rte_val[i]->rte;
 
+  /* merge filter needs one argument called "routes" */
   struct f_val val = {
     .type = T_ROUTES_BLOCK,
     .val.ad = &rb->ad,
   };
 
-  f_run_val(ail->merge_filter, &new, rte_update_pool, &val, 0);
+  f_eval_rte(ail->merge_filter, &new, rte_update_pool, 1, &val, 0);
 }
 
 /*
@@ -617,7 +618,7 @@ rt_notify_aggregated(struct channel *c, struct network *net, struct rte *new_cha
         case AGGR_ITEM_TERM: {
           const struct f_line *line = ail->items[val_idx].line;
           struct rte *rt1 = rt0;
-          enum filter_return fret = f_aggr_eval_line(line, &rt1, rte_update_pool, &rte_val->values[val_idx]);
+          enum filter_return fret = f_eval_rte(line, &rt1, rte_update_pool, 0, NULL, &rte_val->values[val_idx]);
 
           if (rt1 != rt0)
           {
index f86c62ccee73a2dc16e518e786440a8d24fddcbc..d3eea8802b50454844e6e777b61b040353ae9f0e 100644 (file)
@@ -141,6 +141,7 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
 
 %type <i32> idval
 %type <f> imexport
+%type <fl> merge_filter
 %type <r> rtable
 %type <s> optproto
 %type <ra> r_args
@@ -344,8 +345,18 @@ aggr_item:
     }
   ;
 
+merge_filter: MERGE BY {
+  cf_push_block_scope(new_config);
+  cf_create_symbol(new_config, "routes", SYM_VARIABLE | T_ROUTES_BLOCK, offset, f_new_var(sym_->scope));
+} function_body {
+  cf_pop_block_scope(new_config);
+  $4->args++;
+  $$ = $4;
+  }
+ ;
+
 aggr_definition:
-    AGGREGATE ON aggr_list MERGE BY filter {
+    AGGREGATE ON aggr_list merge_filter {
       _Bool net_present = 0;
       int count = 0;
 
@@ -375,7 +386,7 @@ aggr_definition:
      }
 
      linear->count = pos;
-     linear->merge_filter = $6;
+     linear->merge_filter = $4;
 
      int node = 1;
 
index f6a2b8618b46153e7735c064c9c8a77996403446..93c2378dae3383c8c418ec59c875b02524964daa 100644 (file)
@@ -881,7 +881,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
   if (cf->ra_mode == RA_AGGREGATED)
   {
     export_changed |= !aggr_item_linearized_same(cf->ai_aggr, c->ai_aggr);
-    export_changed |= !filter_same(cf->ai_aggr->merge_filter, c->ai_aggr->merge_filter);
+    export_changed |= !f_same(cf->ai_aggr->merge_filter, c->ai_aggr->merge_filter);
     c->ai_aggr = cf->ai_aggr;
   }
 
index 9169a64c5a4f6aa9c81fe277c3207ec7fbb5dd74..e13de8c70f9da6ff3f23a95926658bbcb840019b 100644 (file)
@@ -785,7 +785,7 @@ struct aggr_item {
 
 struct aggr_item_linearized {
   int count;
-  const struct filter *merge_filter;
+  const struct f_line *merge_filter;
   struct aggr_item_internal items[];
 };
 
index bb93305ed2fcc89d2d5ac8be316522be28b9d516..cf7a476843aca4d409863e54a42206e9f3a8405d 100644 (file)
@@ -113,7 +113,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
     net_copy(e->net->n.addr, r->net);
 
     /* Evaluate the filter */
-    f_eval_rte(r->cmds, &e, static_lp);
+    f_eval_rte(r->cmds, &e, static_lp, 0, NULL, NULL);
 
     /* Remove the temporary node */
     e->net = NULL;