]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Revert "Filter: Dropped the setter instructions in favor of direct result storage."
authorMaria Matejka <mq@ucw.cz>
Wed, 19 Jun 2019 12:09:57 +0000 (14:09 +0200)
committerMaria Matejka <mq@ucw.cz>
Wed, 19 Jun 2019 12:09:57 +0000 (14:09 +0200)
This reverts commit bd91338246c1ba40358243f1bdf5a6dbd3a29f35.

filter/config.Y
filter/data.c
filter/data.h
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/filter.c

index f57575fc84837533a03d6224785e2b714a86030f..3898748cb6e2593ccc2cb0cd63a4c90af5d96e9e 100644 (file)
@@ -21,13 +21,9 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
 static inline u32 pair_a(u32 p) { return p >> 16; }
 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
 
-#define f_generate_complex(fi_code, _da, arg) ({ \
-  struct f_inst *fi = f_new_inst(fi_code, f_new_inst(FI_EA_GET, _da), arg); \
-  fi->result.type = F_LVAL_EA; \
-  fi->result.da = _da; \
-  fi; \
-})
-  
+#define f_generate_complex(fi_code, da, arg) \
+  f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
+
 /*
  * Sets and their items are during parsing handled as lists, linked
  * through left ptr. The first item in a list also contains a pointer
@@ -188,10 +184,7 @@ f_generate_empty(struct f_dynamic_attr dyn)
       cf_error("Can't empty that attribute");
   }
 
-  struct f_inst *fi = f_new_inst(FI_CONSTANT, empty);
-  fi->result.type = F_LVAL_EA;
-  fi->result.da = dyn;
-  return fi;
+  return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
 }
 
 #if 0
@@ -404,34 +397,31 @@ assert_done(struct f_inst *expr, const char *start, const char *end)
 static struct f_inst *
 assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
 {
-  struct f_inst *getter;
+  struct f_inst *setter, *getter, *checker;
   switch (lval->type) {
-    case F_LVAL_STACK:
-      bug("This shall never happen");
-    case F_LVAL_EXCEPTION:
-      bug("This shall never happen");
     case F_LVAL_VARIABLE:
+      setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
       getter = f_new_inst(FI_VAR_GET, lval->sym);
       break;
     case F_LVAL_PREFERENCE:
+      setter = f_new_inst(FI_PREF_SET, expr);
       getter = f_new_inst(FI_PREF_GET);
       break;
     case F_LVAL_SA:
+      setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
       getter = f_new_inst(FI_RTA_GET, lval->sa);
       break;
     case F_LVAL_EA:
+      setter = f_new_inst(FI_EA_SET, expr, lval->da);
       getter = f_new_inst(FI_EA_GET, lval->da);
       break;
+    default:
+      bug("Unknown lval type");
   }
 
-  struct f_inst *checker = f_new_inst(FI_EQ, expr, getter);
-
-  struct f_inst *setter = cfg_alloc(sizeof(struct f_inst));
-  *setter = *expr;
-
+  checker = f_new_inst(FI_EQ, expr, getter);
   setter->next = checker;
-  setter->result = *lval;
-
+  
   return assert_done(setter, start, end);
 }
 
@@ -995,40 +985,29 @@ cmd:
  | CF_SYM_KNOWN '=' term ';' {
      switch ($1->class) {
        case SYM_VARIABLE_RANGE:
-        $3->result.type = F_LVAL_VARIABLE;
-        $3->result.sym = $1;
+        $$ = f_new_inst(FI_VAR_SET, $3, $1);
         break;
        case SYM_ATTRIBUTE:
-        $3->result.type = F_LVAL_EA;
-        $3->result.da = *$1->attribute;
+        $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
         break;
        default:
         cf_error("Can't assign to symbol %s", $1->name);
      }
-     $$ = $3;
    }
  | RETURN term ';' {
      DBG( "Ook, we'll return the value\n" );
-     $2->result.type = F_LVAL_EXCEPTION;
-     $2->result.exception = FE_RETURN;
-     $$ = $2;
+     $$ = f_new_inst(FI_RETURN, $2);
    }
  | dynamic_attr '=' term ';' {
-     $3->result.type = F_LVAL_EA;
-     $3->result.da = $1;
-     $$ = $3;
+     $$ = f_new_inst(FI_EA_SET, $3, $1);
    }
  | static_attr '=' term ';' {
      if ($1.readonly)
        cf_error( "This static attribute is read-only.");
-
-     $3->result.type = F_LVAL_SA;
-     $3->result.sa = $1;
-     $$ = $3;
+     $$ = f_new_inst(FI_RTA_SET, $3, $1);
    }
  | PREFERENCE '=' term ';' {
-     $3->result.type = F_LVAL_PREFERENCE;
-     $$ = $3;
+     $$ = f_new_inst(FI_PREF_SET, $3);
    }
  | UNSET '(' dynamic_attr ')' ';' {
      $$ = f_new_inst(FI_EA_UNSET, $3);
index cb759a5956893e84be9987b3765729e6ffe0ae02..912e2b00aaf0c726085b31f7f1df02ca83f46ee9 100644 (file)
@@ -525,3 +525,4 @@ val_dump(const struct f_val *v) {
   val_format(v, &b);
   return val_dump_buffer;
 }
+
index 3718cea4ee6d10834e05df93e00a5b0299421dfd..6973008ffca924ebda7feec8ee0044cc6c3bdd01 100644 (file)
@@ -107,15 +107,8 @@ struct f_static_attr {
   int readonly:1;                      /* Don't allow writing */
 };
 
-/* Exception bits */
-enum f_exception {
-  FE_RETURN = 0x1,
-};
-
 /* Filter l-value type */
 enum f_lval_type {
-  F_LVAL_STACK = 0,
-  F_LVAL_EXCEPTION,
   F_LVAL_VARIABLE,
   F_LVAL_PREFERENCE,
   F_LVAL_SA,
@@ -126,7 +119,6 @@ enum f_lval_type {
 struct f_lval {
   enum f_lval_type type;
   union {
-    enum f_exception exception;
     const struct symbol *sym;
     struct f_dynamic_attr da;
     struct f_static_attr sa;
index a1d625f3b85c7c40e3c1058c58da37230c3fd0c5..9934d0bac61206379997beb96f3b9714ab8d2373 100644 (file)
@@ -119,6 +119,8 @@ case INST_NAME(): {
   m4_undivert(105)
 #undef what
 #undef item
+  dest->items[pos].fi_code = what_->fi_code;
+  dest->items[pos].lineno = what_->lineno;
   break;
 }
 m4_undefine([[FID_LINEARIZE_BODY_EXISTS]])
@@ -234,29 +236,9 @@ do { if (whati->fl$1) {
 } } while(0)m4_dnl
 FID_ALL()')
 
-m4_define(RESULT_PTR, `
-FID_INTERPRET_BODY
-  do {
-    enum filter_return fret = f_lval_set(fs, &(what->result), $1);
-    if (fret != F_NOP) return fret;
-  } while (0)m4_dnl
-FID_ALL()')
-
-m4_define(RESULT, `
-FID_INTERPRET_BODY
-  do {
-    struct f_val res_ = { .type = $1, .val.$2 = $3 };
-    RESULT_PTR(&res_);
-  } while (0)m4_dnl
-FID_ALL()')
-
-m4_define(RESULT_VOID, `
-FID_INTERPRET_BODY
-  do {
-    struct f_val res_ = { .type = T_VOID };
-    RESULT_PTR(&res_);
-  } while (0)m4_dnl
-FID_ALL()')
+m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()')
+m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
+m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()')
 
 m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym,
 [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)')
@@ -320,16 +302,6 @@ void f_dump_line(const struct f_line *dest, uint indent)
   for (uint i=0; i<dest->len; i++) {
     const struct f_line_item *item = &dest->items[i];
     debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno);
-
-    switch (item->result.type) {
-      case F_LVAL_STACK: debug("%son stack\n", INDENT); break;
-      case F_LVAL_EXCEPTION: debug("%s=>exception 0x%x\n", INDENT, item->result.exception); break;
-      case F_LVAL_VARIABLE: debug("%s=>%s\n", INDENT, item->result.sym->name); break;
-      case F_LVAL_PREFERENCE: debug("%s=>preference\n", INDENT); break;
-      case F_LVAL_SA: debug("%s=>sa\n", INDENT); break;
-      case F_LVAL_EA: debug("%s=>ea\n", INDENT); break;
-    }
-
     switch (item->fi_code) {
 FID_WR_PUT(7)
       default: bug("Unknown instruction %x in f_dump_line", item->fi_code);
@@ -346,9 +318,6 @@ linearize(struct f_line *dest, const struct f_inst *what_, uint pos)
     switch (what_->fi_code) {
 FID_WR_PUT(8)
     }
-    dest->items[pos].fi_code = what_->fi_code;
-    dest->items[pos].lineno = what_->lineno;
-    dest->items[pos].result = what_->result;
     pos++;
   }
   return pos;
@@ -391,32 +360,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2)
     if (f1_->flags != f2_->flags)
       return 0;
 
-    if (f1_->result.type != f2_->result.type) return 0;
-    switch (f1_->result.type) {
-      case F_LVAL_STACK:
-       break;
-      case F_LVAL_EXCEPTION:
-       if (f1_->result.exception != f2_->result.exception)
-         return 0;
-       break;
-      case F_LVAL_VARIABLE:
-       if (strcmp(f1_->result.sym->name, f2_->result.sym->name))
-         return 0;
-       if (f1_->result.sym->class != f2_->result.sym->class)
-         return 0;
-       break;
-      case F_LVAL_PREFERENCE:
-       break;
-      case F_LVAL_SA:
-       if (f1_->result.sa.sa_code != f2_->result.sa.sa_code)
-         return 0;
-       break;
-      case F_LVAL_EA:
-       if (f1_->result.da.ea_code != f2_->result.da.ea_code)
-         return 0;
-       break;
-    }
-
     switch(f1_->fi_code) {
 FID_WR_PUT(9)
     }
@@ -439,7 +382,6 @@ struct f_inst {
   enum f_instruction_code fi_code;     /* Instruction code */
   int size;                            /* How many instructions are underneath */
   int lineno;                          /* Line number */
-  struct f_lval result;                        /* Destination */
   union {
     FID_WR_PUT(1)
   };
@@ -450,7 +392,6 @@ struct f_line_item {
   enum f_instruction_code fi_code;     /* What to do */
   enum f_instruction_flags flags;      /* Flags, instruction-specific */
   uint lineno;                         /* Where */
-  struct f_lval result;                        /* Destination */
   union {
     FID_WR_PUT(2)
   };
index 3be76d11ecb75d7e7b95e597ba4f84d94200251d..749e072ce868cb3ea099a1019863496cb2ffcd30 100644 (file)
@@ -36,7 +36,7 @@
  *     m4_dnl    ACCESS_RTE;                           this instruction needs route
  *     m4_dnl    ACCESS_EATTRS;                        this instruction needs extended attributes
  *     m4_dnl    RESULT(type, union-field, value);     putting this on value stack
- *     m4_dnl    RESULT_PTR(vptr);                     put what is pointed-to on the value stack
+ *     m4_dnl    RESULT_OK;                            legalize what already is on the value stack
  *     m4_dnl  }
  *
  *     Other code is just copied into the interpreter part.
   INST(FI_ADD, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    RESULT(T_INT, i, v1.val.i + v2.val.i);
+    res.val.i += v2.val.i;
+    RESULT_OK;
   }
   INST(FI_SUBTRACT, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    RESULT(T_INT, i, v1.val.i - v2.val.i);
+    res.val.i -= v2.val.i;
+    RESULT_OK;
   }
   INST(FI_MULTIPLY, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    RESULT(T_INT, i, v1.val.i * v2.val.i);
+    res.val.i *= v2.val.i;
+    RESULT_OK;
   }
   INST(FI_DIVIDE, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
     if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
-    RESULT(T_INT, i, v1.val.i / v2.val.i);
+    res.val.i /= v2.val.i;
+    RESULT_OK;
   }
   INST(FI_AND, 1, 1) {
     ARG(1,T_BOOL);
-    if (v1.val.i)
+    if (res.val.i)
       LINE(2,0);
     else
-      RESULT_PTR(&(v1));
+      RESULT_OK;
   }
   INST(FI_OR, 1, 1) {
     ARG(1,T_BOOL);
-    if (!v1.val.i)
+    if (!res.val.i)
       LINE(2,0);
     else
-      RESULT_PTR(&(v1));
+      RESULT_OK;
   }
   INST(FI_PAIR_CONSTRUCT, 2, 1) {
     ARG(1,T_INT);
 
   INST(FI_VAR_GET, 0, 1) {
     SYMBOL(1);
-    RESULT_PTR(&(fstk->vstk[curline.vbase + sym->offset]));
+    res = fstk->vstk[curline.vbase + sym->offset];
+    RESULT_OK;
   }
 
     /* some constants have value in a[1], some in *a[0].p, strange. */
       debug("%svalue %s\n", INDENT, val_dump(&item->val));
     FID_ALL
 
-    RESULT_PTR(&(whati->val));
+    res = whati->val;
+    RESULT_OK;
   }
   INST(FI_CONSTANT_DEFINED, 0, 1) {
     FID_STRUCT_IN
       debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp));
     FID_ALL
 
-    RESULT_PTR(whati->valp);
+    res = *whati->valp;
+    RESULT_OK;
   }
   INST(FI_PRINT, 1, 0) {
     ARG_ANY(1);
     }
   }
 
+  INST(FI_RTA_SET, 1, 0) {
+    ACCESS_RTE;
+    ARG_ANY(1);
+    STATIC_ATTR;
+    if (sa.f_type != v1.type)
+      runtime( "Attempt to set static attribute to incompatible type" );
+
+    f_rta_cow(fs);
+    {
+      struct rta *rta = (*fs->rte)->attrs;
+
+      switch (sa.sa_code)
+      {
+      case SA_FROM:
+       rta->from = v1.val.ip;
+       break;
+
+      case SA_GW:
+       {
+         ip_addr ip = v1.val.ip;
+         neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
+         if (!n || (n->scope == SCOPE_HOST))
+           runtime( "Invalid gw address" );
+
+         rta->dest = RTD_UNICAST;
+         rta->nh.gw = ip;
+         rta->nh.iface = n->iface;
+         rta->nh.next = NULL;
+         rta->hostentry = NULL;
+       }
+       break;
+
+      case SA_SCOPE:
+       rta->scope = v1.val.i;
+       break;
+
+      case SA_DEST:
+       {
+         int i = v1.val.i;
+         if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
+           runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
+
+         rta->dest = i;
+         rta->nh.gw = IPA_NONE;
+         rta->nh.iface = NULL;
+         rta->nh.next = NULL;
+         rta->hostentry = NULL;
+       }
+       break;
+
+      case SA_IFNAME:
+       {
+         struct iface *ifa = if_find_by_name(v1.val.s);
+         if (!ifa)
+           runtime( "Invalid iface name" );
+
+         rta->dest = RTD_UNICAST;
+         rta->nh.gw = IPA_NONE;
+         rta->nh.iface = ifa;
+         rta->nh.next = NULL;
+         rta->hostentry = NULL;
+       }
+       break;
+
+      default:
+       bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
+      }
+    }
+  }
+
   INST(FI_EA_GET, 0, 1) {      /* Access to extended attributes */
     DYNAMIC_ATTR;
     ACCESS_RTE;
        }
 
        /* Undefined value */
-       RESULT_VOID;
+       res.type = T_VOID;
+       RESULT_OK;
        break;
       }
 
        RESULT(T_LCLIST, ad, e->u.ptr);
        break;
       case EAF_TYPE_UNDEF:
-       RESULT_VOID;
+       res.type = T_VOID;
+       RESULT_OK;
        break;
       default:
        bug("Unknown dynamic attribute type");
     }
   }
 
+  INST(FI_EA_SET, 1, 0) {
+    ACCESS_RTE;
+    ACCESS_EATTRS;
+    ARG_ANY(1);
+    DYNAMIC_ATTR;
+    {
+      struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
+
+      l->next = NULL;
+      l->flags = EALF_SORTED;
+      l->count = 1;
+      l->attrs[0].id = da.ea_code;
+      l->attrs[0].flags = 0;
+      l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
+
+      switch (da.type) {
+      case EAF_TYPE_INT:
+       if (v1.type != da.f_type)
+         runtime( "Setting int attribute to non-int value" );
+       l->attrs[0].u.data = v1.val.i;
+       break;
+
+      case EAF_TYPE_ROUTER_ID:
+       /* IP->Quad implicit conversion */
+       if (val_is_ip4(&v1)) {
+         l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
+         break;
+       }
+       /* T_INT for backward compatibility */
+       if ((v1.type != T_QUAD) && (v1.type != T_INT))
+         runtime( "Setting quad attribute to non-quad value" );
+       l->attrs[0].u.data = v1.val.i;
+       break;
+
+      case EAF_TYPE_OPAQUE:
+       runtime( "Setting opaque attribute is not allowed" );
+       break;
+      case EAF_TYPE_IP_ADDRESS:
+       if (v1.type != T_IP)
+         runtime( "Setting ip attribute to non-ip value" );
+       int len = sizeof(ip_addr);
+       struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
+       ad->length = len;
+       (* (ip_addr *) ad->data) = v1.val.ip;
+       l->attrs[0].u.ptr = ad;
+       break;
+      case EAF_TYPE_AS_PATH:
+       if (v1.type != T_PATH)
+         runtime( "Setting path attribute to non-path value" );
+       l->attrs[0].u.ptr = v1.val.ad;
+       break;
+      case EAF_TYPE_BITFIELD:
+       if (v1.type != T_BOOL)
+         runtime( "Setting bit in bitfield attribute to non-bool value" );
+       {
+         /* First, we have to find the old value */
+         eattr *e = ea_find(*fs->eattrs, da.ea_code);
+         u32 data = e ? e->u.data : 0;
+
+         if (v1.val.i)
+           l->attrs[0].u.data = data | (1u << da.bit);
+         else
+           l->attrs[0].u.data = data & ~(1u << da.bit);
+       }
+       break;
+      case EAF_TYPE_INT_SET:
+       if (v1.type != T_CLIST)
+         runtime( "Setting clist attribute to non-clist value" );
+       l->attrs[0].u.ptr = v1.val.ad;
+       break;
+      case EAF_TYPE_EC_SET:
+       if (v1.type != T_ECLIST)
+         runtime( "Setting eclist attribute to non-eclist value" );
+       l->attrs[0].u.ptr = v1.val.ad;
+       break;
+      case EAF_TYPE_LC_SET:
+       if (v1.type != T_LCLIST)
+         runtime( "Setting lclist attribute to non-lclist value" );
+       l->attrs[0].u.ptr = v1.val.ad;
+       break;
+      default: bug("Unknown type in e,S");
+      }
+
+      f_rta_cow(fs);
+      l->next = *fs->eattrs;
+      *fs->eattrs = l;
+    }
+  }
+
   INST(FI_EA_UNSET, 0, 0) {
     DYNAMIC_ATTR;
     ACCESS_RTE;
     RESULT(T_INT, i, (*fs->rte)->pref);
   }
 
+  INST(FI_PREF_SET, 1, 0) {
+    ACCESS_RTE;
+    ARG(1,T_INT);
+    if (v1.val.i > 0xFFFF)
+      runtime( "Setting preference value out of bounds" );
+    f_rte_cow(fs);
+    (*fs->rte)->pref = v1.val.i;
+  }
+
   INST(FI_LENGTH, 1, 1) {      /* Get length of */
     ARG_ANY(1);
     switch(v1.type) {
     RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
   }
 
+  INST(FI_RETURN, 1, 1) {
+    /* Acquire the return value */
+    ARG_ANY(1);
+    uint retpos = fstk->vcnt;
+
+    /* Drop every sub-block including ourselves */
+    while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
+      ;
+
+    /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
+    if (!fstk->ecnt)
+      if (fstk->vstk[retpos].type == T_BOOL)
+       if (fstk->vstk[retpos].val.i)
+
+         return F_ACCEPT;
+       else
+         return F_REJECT;
+      else
+       runtime("Can't return non-bool from non-function");
+
+    /* Set the value stack position, overwriting the former implicit void */
+    fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
+
+    /* Copy the return value */
+    RESULT_VAL(fstk->vstk[retpos]);
+  }
+
   INST(FI_CALL, 0, 1) {
     SYMBOL;
 
index ca685ded80ab82a96f8c46ca25066cd9f83ec0f0..f0dcec6493c8d632b496e67892d916adb3c58276 100644 (file)
@@ -84,6 +84,7 @@ static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_t
 { return (struct f_dynamic_attr) { .type = type, .bit = bit, .f_type = f_type, .ea_code = code }; }   /* f_type currently unused; will be handy for static type checking */
 static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
 { return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
+struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument);
 struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
 
 /* Hook for call bt_assert() function in configuration */
index 77378178ee5187cc277cbe1a832958caa002f325..ee29522e4994e6c4178873df28e4fd8f1ddb5fb2 100644 (file)
 #include "filter/data.h"
 
 
+/* Exception bits */
+enum f_exception {
+  FE_RETURN = 0x1,
+};
+
+
 struct filter_stack {
   /* Value stack for execution */
 #define F_VAL_STACK_MAX        4096
@@ -145,7 +151,7 @@ f_rta_cow(struct filter_state *fs)
 }
 
 static char *
-val_format_str(struct filter_state *fs, const struct f_val *v) {
+val_format_str(struct filter_state *fs, struct f_val *v) {
   buffer b;
   LOG_BUFFER_INIT(b);
   val_format(v, &b);
@@ -154,233 +160,6 @@ val_format_str(struct filter_state *fs, const struct f_val *v) {
 
 static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
 
-#define runtime(fmt, ...) do { \
-  if (!(fs->flags & FF_SILENT)) \
-    log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, \
-       (fs->stack->estk[fs->stack->ecnt-1].line->items[fs->stack->estk[fs->stack->ecnt-1].pos-1]).lineno, \
-       ##__VA_ARGS__); \
-  return F_ERROR; \
-} while(0)
-
-#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
-#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
-
-static inline enum filter_return
-f_rta_set(struct filter_state *fs, struct f_static_attr sa, const struct f_val *val)
-{
-    ACCESS_RTE;
-    if (sa.f_type != val->type)
-      runtime( "Attempt to set static attribute to incompatible type" );
-
-    f_rta_cow(fs);
-    {
-      struct rta *rta = (*fs->rte)->attrs;
-
-      switch (sa.sa_code)
-      {
-      case SA_FROM:
-       rta->from = val->val.ip;
-       return F_NOP;
-
-      case SA_GW:
-       {
-         ip_addr ip = val->val.ip;
-         neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
-         if (!n || (n->scope == SCOPE_HOST))
-           runtime( "Invalid gw address" );
-
-         rta->dest = RTD_UNICAST;
-         rta->nh.gw = ip;
-         rta->nh.iface = n->iface;
-         rta->nh.next = NULL;
-         rta->hostentry = NULL;
-       }
-       return F_NOP;
-
-      case SA_SCOPE:
-       rta->scope = val->val.i;
-       return F_NOP;
-
-      case SA_DEST:
-       {
-         int i = val->val.i;
-         if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
-           runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
-
-         rta->dest = i;
-         rta->nh.gw = IPA_NONE;
-         rta->nh.iface = NULL;
-         rta->nh.next = NULL;
-         rta->hostentry = NULL;
-       }
-       return F_NOP;
-
-      case SA_IFNAME:
-       {
-         struct iface *ifa = if_find_by_name(val->val.s);
-         if (!ifa)
-           runtime( "Invalid iface name" );
-
-         rta->dest = RTD_UNICAST;
-         rta->nh.gw = IPA_NONE;
-         rta->nh.iface = ifa;
-         rta->nh.next = NULL;
-         rta->hostentry = NULL;
-       }
-       return F_NOP;
-
-      default:
-       bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
-      }
-    }
-}
-
-static inline enum filter_return
-f_ea_set(struct filter_state *fs, struct f_dynamic_attr da, const struct f_val *val)
-{
-    ACCESS_RTE;
-    ACCESS_EATTRS;
-    {
-      struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
-
-      l->next = NULL;
-      l->flags = EALF_SORTED;
-      l->count = 1;
-      l->attrs[0].id = da.ea_code;
-      l->attrs[0].flags = 0;
-      l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH;
-
-      switch (da.type) {
-      case EAF_TYPE_INT:
-       if (val->type != da.f_type)
-         runtime( "Setting int attribute to non-int value" );
-       l->attrs[0].u.data = val->val.i;
-       break;
-
-      case EAF_TYPE_ROUTER_ID:
-       /* IP->Quad implicit conversion */
-       if (val_is_ip4(val)) {
-         l->attrs[0].u.data = ipa_to_u32(val->val.ip);
-         break;
-       }
-       /* T_INT for backward compatibility */
-       if ((val->type != T_QUAD) && (val->type != T_INT))
-         runtime( "Setting quad attribute to non-quad value" );
-       l->attrs[0].u.data = val->val.i;
-       break;
-
-      case EAF_TYPE_OPAQUE:
-       runtime( "Setting opaque attribute is not allowed" );
-       break;
-      case EAF_TYPE_IP_ADDRESS:
-       if (val->type != T_IP)
-         runtime( "Setting ip attribute to non-ip value" );
-       int len = sizeof(ip_addr);
-       struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
-       ad->length = len;
-       (* (ip_addr *) ad->data) = val->val.ip;
-       l->attrs[0].u.ptr = ad;
-       break;
-      case EAF_TYPE_AS_PATH:
-       if (val->type != T_PATH)
-         runtime( "Setting path attribute to non-path value" );
-       l->attrs[0].u.ptr = val->val.ad;
-       break;
-      case EAF_TYPE_BITFIELD:
-       if (val->type != T_BOOL)
-         runtime( "Setting bit in bitfield attribute to non-bool value" );
-       {
-         /* First, we have to find the old value */
-         eattr *e = ea_find(*fs->eattrs, da.ea_code);
-         u32 data = e ? e->u.data : 0;
-
-         if (val->val.i)
-           l->attrs[0].u.data = data | (1u << da.bit);
-         else
-           l->attrs[0].u.data = data & ~(1u << da.bit);
-       }
-       break;
-      case EAF_TYPE_INT_SET:
-       if (val->type != T_CLIST)
-         runtime( "Setting clist attribute to non-clist value" );
-       l->attrs[0].u.ptr = val->val.ad;
-       break;
-      case EAF_TYPE_EC_SET:
-       if (val->type != T_ECLIST)
-         runtime( "Setting eclist attribute to non-eclist value" );
-       l->attrs[0].u.ptr = val->val.ad;
-       break;
-      case EAF_TYPE_LC_SET:
-       if (val->type != T_LCLIST)
-         runtime( "Setting lclist attribute to non-lclist value" );
-       l->attrs[0].u.ptr = val->val.ad;
-       break;
-      default: bug("Unknown type in e,S");
-      }
-
-      f_rta_cow(fs);
-      l->next = *fs->eattrs;
-      *fs->eattrs = l;
-
-      return F_NOP;
-    }
-}
-
-static inline enum filter_return
-f_lval_set(struct filter_state *fs, const struct f_lval *lv, const struct f_val *val)
-{
-  switch (lv->type) {
-    case F_LVAL_STACK:
-      fs->stack->vstk[fs->stack->vcnt] = *val;
-      fs->stack->vcnt++;
-      return F_NOP;
-    case F_LVAL_EXCEPTION:
-      {
-       /* Drop every sub-block including ourselves */
-       while ((fs->stack->ecnt-- > 0) && !(fs->stack->estk[fs->stack->ecnt].emask & lv->exception))
-         ;
-
-       /* Now we are at the catch frame; if no such, try to convert to accept/reject. */
-       if (!fs->stack->ecnt)
-         if (lv->exception == FE_RETURN)
-           if (val->type == T_BOOL)
-             if (val->val.i)
-               return F_ACCEPT;
-             else
-               return F_REJECT;
-           else
-             runtime("Can't return non-bool from non-function");
-         else
-           runtime("Unhandled exception 0x%x: %s", lv->exception, val_format_str(fs, val));
-
-       /* Set the value stack position, overwriting the former implicit void */
-       fs->stack->vcnt = fs->stack->estk[fs->stack->ecnt].ventry;
-
-       /* Copy the return value */
-       fs->stack->vstk[fs->stack->vcnt - 1] = *val;
-       return F_NOP;
-      }
-    case F_LVAL_VARIABLE:
-      fs->stack->vstk[fs->stack->estk[fs->stack->ecnt-1].vbase + lv->sym->offset] = *val;
-      return F_NOP;
-    case F_LVAL_PREFERENCE:
-      ACCESS_RTE;
-      if (val->type != T_INT)
-       runtime("Preference must be integer, got 0x%02x", val->type);
-      if (val->val.i > 0xFFFF)
-       runtime("Preference is at most 65536");
-      f_rte_cow(fs);
-      (*fs->rte)->pref = val->val.i;
-      return F_NOP;
-    case F_LVAL_SA:
-      return f_rta_set(fs, lv->sa, val);
-    case F_LVAL_EA:
-      return f_ea_set(fs, lv->da, val);
-    default:
-      bug("This shall never happen");
-  }    
-}
-
 /**
  * interpret
  * @fs: filter state
@@ -430,6 +209,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
 #define v2 fstk->vstk[fstk->vcnt + 1]
 #define v3 fstk->vstk[fstk->vcnt + 2]
 
+#define runtime(fmt, ...) do { \
+  if (!(fs->flags & FF_SILENT)) \
+    log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
+  return F_ERROR; \
+} while(0)
+
+#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0)
+#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0)
+
 #include "filter/inst-interpret.c"
 #undef res
 #undef v1
@@ -445,16 +233,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
     fstk->vcnt -= curline.line->vars;
     fstk->vcnt -= curline.line->args;
     fstk->ecnt--;
-
-    /* If the caller wants to store the result somewhere, do it. */
-    if (fstk->ecnt) {
-      const struct f_line_item *caller = &(curline.line->items[curline.pos-1]);
-      if (caller->result.type != F_LVAL_STACK) {
-       enum filter_return fret = f_lval_set(fs, &(caller->result), &fstk->vstk[--fstk->vcnt]);
-       if (fret != F_NOP)
-         return fret;
-      }
-    }
   }
 
   if (fstk->vcnt == 0) {