]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: adding explicit route type
authorMaria Matejka <mq@ucw.cz>
Sun, 29 Oct 2023 18:53:09 +0000 (19:53 +0100)
committerMaria Matejka <mq@ucw.cz>
Mon, 30 Oct 2023 12:10:36 +0000 (13:10 +0100)
This is a split-commit of the neighboring aggregator branch
with a bit improved lvalue handling, to have easier merge into v3.

conf/confbase.Y
filter/config.Y
filter/data.c
filter/data.h
filter/f-inst.c
nest/route.h
nest/rt-attr.c
nest/rt-table.c

index 0364bc6e18855df12365a8d6cec018fcf607e6a4..cdf1f018783f258ec12f7e0ba83ee24c6cf8a35c 100644 (file)
@@ -433,7 +433,7 @@ bytestring_text:
  ;
 
 bytestring_expr:
-   symbol_value
+   lvalue { $$ = f_lval_getter(&$1); }
  | term_bs
  | '(' term ')' { $$ = $2; }
  ;
index dfabddf7bff52443cd011b0b8623f99ab4be76b0..4e1f6359f9f685c1fdbd4abda85c0311542331cb 100644 (file)
@@ -38,15 +38,15 @@ static inline void f_method_call_start(struct f_inst *object)
     cf_error("Too many nested method calls");
 
   struct sym_scope *scope = f_type_method_scope(object->type);
-  if (!scope)
+  if (!scope && object->type != T_ROUTE)
     cf_error("No methods defined for type %s", f_type_name(object->type));
 
   FM = (struct f_method_scope) {
     .object = object,
     .main = new_config->current_scope,
     .scope = {
-      .next = NULL,
-      .hash = scope->hash,
+      .next = scope ? global_root_scope : NULL,
+      .hash = scope ? scope->hash : global_root_scope->hash,
       .active = 1,
       .block = 1,
       .readonly = 1,
@@ -244,6 +244,7 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
   return t;
 }
 
+
 /*
  * Remove all new lines and doubled whitespaces
  * and convert all tabulators to spaces
@@ -302,9 +303,10 @@ static struct f_inst *
 f_lval_getter(struct f_lval *lval)
 {
   switch (lval->type) {
+    case F_LVAL_CONSTANT:      return f_new_inst(FI_CONSTANT, *(lval->sym->val));
     case F_LVAL_VARIABLE:      return f_new_inst(FI_VAR_GET, lval->sym);
-    case F_LVAL_SA:            return f_new_inst(FI_RTA_GET, lval->sa);
-    case F_LVAL_EA:            return f_new_inst(FI_EA_GET, lval->da);
+    case F_LVAL_SA:            return f_new_inst(FI_RTA_GET, lval->rte, lval->sa);
+    case F_LVAL_EA:            return f_new_inst(FI_EA_GET, lval->rte, lval->da);
     default:                   bug("Unknown lval type");
   }
 }
@@ -313,8 +315,13 @@ static struct f_inst *
 f_lval_setter(struct f_lval *lval, struct f_inst *expr)
 {
   switch (lval->type) {
+    case F_LVAL_CONSTANT:      cf_error("Constant %s is read-only", lval->sym->name);
     case F_LVAL_VARIABLE:      return f_new_inst(FI_VAR_SET, expr, lval->sym);
-    case F_LVAL_SA:            return f_new_inst(FI_RTA_SET, expr, lval->sa);
+    case F_LVAL_SA:
+      if (lval->sa.readonly)
+       cf_error( "This static attribute is read-only.");
+      return f_new_inst(FI_RTA_SET, expr, lval->sa);
+
     case F_LVAL_EA:            return f_new_inst(FI_EA_SET, expr, lval->da);
     default:                   bug("Unknown lval type");
   }
@@ -357,7 +364,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 %nonassoc ELSE
 
 %type <xp> cmds_int cmd_prep
-%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
+%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
 %type <fda> dynamic_attr
 %type <fsa> static_attr
 %type <f> filter where_filter
@@ -447,6 +454,7 @@ type:
  | CLIST { $$ = T_CLIST; }
  | ECLIST { $$ = T_ECLIST; }
  | LCLIST { $$ = T_LCLIST; }
+ | ROUTE { $$ = T_ROUTE; }
  | type SET {
        switch ($1) {
          case T_INT:
@@ -740,7 +748,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
  ;
 
 bgp_path_expr:
-   symbol_value { $$ = $1; }
+   lvalue { $$ = f_lval_getter(&$1); }
  | '(' term ')' { $$ = $2; }
  ;
 
@@ -822,23 +830,6 @@ function_call:
    }
  ;
 
-symbol_value: symbol_known
-  {
-    switch ($1->class) {
-      case SYM_CONSTANT_RANGE:
-       $$ = f_new_inst(FI_CONSTANT, *($1->val));
-       break;
-      case SYM_VARIABLE_RANGE:
-       $$ = f_new_inst(FI_VAR_GET, $1);
-       break;
-      case SYM_ATTRIBUTE:
-       $$ = f_new_inst(FI_EA_GET, *$1->attribute);
-       break;
-      default:
-       cf_error("Can't get value of symbol %s", $1->name);
-    }
-  }
- ;
 
 static_attr:
    FROM    { $$ = f_new_static_attr(T_IP,         SA_FROM,     0); }
@@ -866,6 +857,16 @@ method_name_cont:
    } '(' var_list ')' {
      $$ = f_dispatch_method($1, FM.object, $4, 1);
    }
+ | static_attr {
+     if (FM.object->type != T_ROUTE)
+       cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type));
+     $$ = f_new_inst(FI_RTA_GET, FM.object, $1);
+   }
+ | dynamic_attr {
+     if (FM.object->type != T_ROUTE)
+       cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type));
+     $$ = f_new_inst(FI_EA_GET, FM.object, $1);
+   }
  ;
 
 term:
@@ -887,13 +888,10 @@ term:
  | '!' term            { $$ = f_new_inst(FI_NOT, $2); }
  | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
 
- | symbol_value   { $$ = $1; }
  | constant { $$ = $1; }
  | constructor { $$ = $1; }
 
- | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
-
- | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
+ | lvalue { $$ = f_lval_getter(&$1); }
 
  | term_dot_method
 
@@ -902,7 +900,7 @@ term:
  | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_ECLIST)); }
  | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_LCLIST)); }
 
-| PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); }
+ | PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); }
  | ADD '(' term ',' term ')' { $$ = f_dispatch_method_x("add", $3->type, $3, $5); }
  | DELETE '(' term ',' term ')' { $$ = f_dispatch_method_x("delete", $3->type, $3, $5); }
  | FILTER '(' term ',' term ')' { $$ = f_dispatch_method_x("filter", $3->type, $3, $5); }
@@ -963,17 +961,8 @@ cmd:
      cf_pop_block_scope(new_config);
      $$ = f_for_cycle($3, $6, $9);
    }
- | symbol_known '=' term ';' {
-     switch ($1->class) {
-       case SYM_VARIABLE_RANGE:
-        $$ = f_new_inst(FI_VAR_SET, $3, $1);
-        break;
-       case SYM_ATTRIBUTE:
-        $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
-        break;
-       default:
-        cf_error("Can't assign to symbol %s", $1->name);
-     }
+ | lvalue '=' term ';' {
+     $$ = f_lval_setter(&$1, $3);
    }
  | RETURN term ';' {
      DBG( "Ook, we'll return the value\n" );
@@ -991,14 +980,6 @@ cmd:
 
      $$ = f_new_inst(FI_RETURN, $2);
    }
- | dynamic_attr '=' term ';' {
-     $$ = f_new_inst(FI_EA_SET, $3, $1);
-   }
- | static_attr '=' term ';' {
-     if ($1.readonly)
-       cf_error( "This static attribute is read-only.");
-     $$ = f_new_inst(FI_RTA_SET, $3, $1);
-   }
  | UNSET '(' dynamic_attr ')' ';' {
      $$ = f_new_inst(FI_EA_UNSET, $3);
    }
@@ -1043,17 +1024,21 @@ lvalue:
    CF_SYM_KNOWN {
      switch ($1->class)
      {
+       case SYM_CONSTANT_RANGE:
+        $$ = (struct f_lval) { .type = F_LVAL_CONSTANT, .sym = $1, };
+        break;
        case SYM_VARIABLE_RANGE:
-        $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
+        $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1, };
          break;
        case SYM_ATTRIBUTE:
-         $$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute) };
+         $$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute), .rte = f_new_inst(FI_CURRENT_ROUTE), };
         break;
        default:
         cf_error("Variable name or custom attribute name required");
      }
    }
- | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
- | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
+ | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; }
+ | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; }
+ ;
 
 CF_END
index 89b75e5654dec620ed0348152ab0329d3dbf59fd..cb52b499c38aa8207f32a59e30238f0d6b5785dc 100644 (file)
@@ -56,6 +56,8 @@ static const char * const f_type_str[] = {
   [T_LC]       = "lc",
   [T_LCLIST]   = "lclist",
   [T_RD]       = "rd",
+
+  [T_ROUTE]    = "route",
 };
 
 const char *
@@ -206,6 +208,7 @@ val_compare(const struct f_val *v1, const struct f_val *v2)
     return net_compare(v1->val.net, v2->val.net);
   case T_STRING:
     return strcmp(v1->val.s, v2->val.s);
+  case T_ROUTE:
   default:
     return F_CMP_ERROR;
   }
@@ -296,6 +299,8 @@ val_same(const struct f_val *v1, const struct f_val *v2)
     return same_tree(v1->val.t, v2->val.t);
   case T_PREFIX_SET:
     return trie_same(v1->val.ti, v2->val.ti);
+  case T_ROUTE:
+    return rte_same(v1->val.rte, v2->val.rte);
   default:
     bug("Invalid type in val_same(): %x", v1->type);
   }
@@ -569,6 +574,21 @@ val_in_range(const struct f_val *v1, const struct f_val *v2)
   return F_CMP_ERROR;
 }
 
+/*
+ * rte_format - format route information
+ */
+static void
+rte_format(const struct rte *rte, buffer *buf)
+{
+  if (rte)
+    buffer_print(buf, "Route [%d] to %N from %s.%s via %s",
+                 rte->src->global_id, rte->net->n.addr,
+                 rte->sender->proto->name, rte->sender->name,
+                 rte->src->proto->name);
+  else
+    buffer_puts(buf, "[No route]");
+}
+
 /*
  * val_format - format filter value
  */
@@ -598,6 +618,7 @@ val_format(const struct f_val *v, buffer *buf)
   case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
   case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
   case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
+  case T_ROUTE: rte_format(v->val.rte, buf); return;
   default:     buffer_print(buf, "[unknown type %x]", v->type); return;
   }
 }
index 3430455a55c5387bebfad646b29fbdb15ed30453..620a80bf7dbfa91d89fa051db5a3c3daebf08e37 100644 (file)
@@ -62,6 +62,7 @@ enum f_type {
   T_PATH_MASK_ITEM = 0x2b,     /* Path mask item for path mask constructors */
   T_BYTESTRING = 0x2c,
 
+  T_ROUTE = 0x78,
   T_SET = 0x80,
   T_PREFIX_SET = 0x81,
 } PACKED;
@@ -90,6 +91,10 @@ struct f_val {
     const struct adata *ad;
     const struct f_path_mask *path_mask;
     struct f_path_mask_item pmi;
+    struct {
+      rte *rte;
+      ea_list *eattrs;
+    };
   } val;
 };
 
@@ -127,6 +132,7 @@ struct f_static_attr {
 
 /* Filter l-value type */
 enum f_lval_type {
+  F_LVAL_CONSTANT,
   F_LVAL_VARIABLE,
   F_LVAL_PREFERENCE,
   F_LVAL_SA,
@@ -136,6 +142,7 @@ enum f_lval_type {
 /* Filter l-value */
 struct f_lval {
   enum f_lval_type type;
+  struct f_inst *rte;
   union {
     struct symbol *sym;
     struct f_dynamic_attr da;
index a7bec81ed758331419f594f565b60deb9c8c86ae..76ec272de2a5e88c1bd05b8d2e2abf2c86827caf 100644 (file)
     }
   }
 
-  INST(FI_RTA_GET, 0, 1) {
+  INST(FI_CURRENT_ROUTE, 0, 1) {
+    NEVER_CONSTANT;
+    ACCESS_EATTRS;
+    RESULT_TYPE(T_ROUTE);
+    RESULT_VAL([[(struct f_val) { .type = T_ROUTE, .val.rte = *fs->rte, .val.eattrs = *fs->eattrs, }]]);
+  }
+
+  INST(FI_RTA_GET, 1, 1) {
     {
-      STATIC_ATTR;
       ACCESS_RTE;
-      struct rta *rta = (*fs->rte)->attrs;
+      ARG(1, T_ROUTE);
+      STATIC_ATTR;
+
+      struct rta *rta = v1.val.rte->attrs;
 
       switch (sa.sa_code)
       {
     }
   }
 
-  INST(FI_EA_GET, 0, 1) {      /* Access to extended attributes */
-    DYNAMIC_ATTR;
+  INST(FI_EA_GET, 1, 1) {      /* Access to extended attributes */
     ACCESS_RTE;
     ACCESS_EATTRS;
+    ARG(1, T_ROUTE);
+    DYNAMIC_ATTR;
     RESULT_TYPE(da.f_type);
     {
-      eattr *e = ea_find(*fs->eattrs, da.ea_code);
+      struct ea_list *eal = v1.val.eattrs;
+      eattr *e = ea_find(eal, da.ea_code);
 
       if (!e) {
        RESULT_VAL(val_empty(da.f_type));
index 7aec711794179dac68c89e89618ca0690e5ac24a..42da5b198096f51a1e8ad0e7c5fcafc0816d6361 100644 (file)
@@ -326,6 +326,8 @@ void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
 void rt_modify_stale(rtable *t, struct channel *c);
 void rt_schedule_prune(rtable *t);
+int rte_same(rte *, rte *);
+int rta_same(struct rta *, struct rta *);
 void rte_dump(rte *);
 void rte_free(rte *);
 rte *rte_do_cow(rte *);
index d793c72e1ef8473e7f78ef75807af5697abc63fa..69ef454241d9fdd0c93b36070776ebc56f28081a 100644 (file)
@@ -1126,7 +1126,7 @@ rta_hash(rta *a)
   return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
 }
 
-static inline int
+int
 rta_same(rta *x, rta *y)
 {
   return (x->source == y->source &&
index 742e2f05b38b865284abc08afd7ed41089cf401d..206fc6ef398cda68aca5a831f6582855622fe295 100644 (file)
@@ -1206,12 +1206,15 @@ rte_free_quick(rte *e)
   sl_free(e);
 }
 
-static int
+int
 rte_same(rte *x, rte *y)
 {
   /* rte.flags / rte.pflags are not checked, as they are internal to rtable */
   return
-    x->attrs == y->attrs &&
+    (
+     (x->attrs == y->attrs) ||
+     ((!x->attrs->cached || !y->attrs->cached) && rta_same(x->attrs, y->attrs))
+    ) &&
     x->src == y->src &&
     rte_is_filtered(x) == rte_is_filtered(y);
 }