]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '5951dfbd' into thread-next
authorMaria Matejka <mq@ucw.cz>
Fri, 27 Oct 2023 13:56:06 +0000 (15:56 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 27 Oct 2023 16:06:34 +0000 (18:06 +0200)
1  2 
doc/bird.sgml
filter/config.Y
filter/data.h
filter/f-inst.h
filter/test.conf
sysdep/linux/netlink.Y

diff --cc doc/bird.sgml
Simple merge
diff --cc filter/config.Y
index 671ccb9d86c6e68de350fa8f19bf73e29b0ec005,58c0c16bc1076f3d45e39e4e384a95bce85ffdae..e83c68be8bab7aa8654c29be842bc83045493daa
@@@ -284,27 -293,34 +293,53 @@@ assert_done(struct f_inst *expr, const 
  }
  
  static struct f_inst *
- assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
+ f_lval_getter(struct f_lval *lval)
+ {
+   switch (lval->type) {
+     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_ATTR_BIT:
++      {
++      struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << lval->fab.bit)});
++      return f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, lval->fab.class), c));
++      }
+     default:                  bug("Unknown lval type");
+   }
+ }
+ static struct f_inst *
+ f_lval_setter(struct f_lval *lval, struct f_inst *expr)
  {
-   struct f_inst *setter, *getter, *checker;
    switch (lval->type) {
-     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_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");
+     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_EA:           return f_new_inst(FI_EA_SET, expr, lval->da);
++    case F_LVAL_ATTR_BIT:     return f_new_inst(FI_CONDITION, expr,
++      f_new_inst(FI_EA_SET,
++        f_new_inst(FI_BITOR,
++          f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << lval->fab.bit)}),
++          f_new_inst(FI_EA_GET, lval->fab.class)
++        ),
++        lval->fab.class),
++      f_new_inst(FI_EA_SET,
++        f_new_inst(FI_BITAND,
++          f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << lval->fab.bit)}),
++          f_new_inst(FI_EA_GET, lval->fab.class)
++        ),
++        lval->fab.class)
++      );
+     default:                  bug("Unknown lval type");
    }
+ }
+ static struct f_inst *
+ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
+ {
+   struct f_inst *setter = f_lval_setter(lval, expr),
+               *getter = f_lval_getter(lval);
  
-   checker = f_new_inst(FI_EQ, expr, getter);
+   struct f_inst *checker = f_new_inst(FI_EQ, expr, getter);
    setter->next = checker;
  
    return assert_done(setter, start, end);
@@@ -337,7 -355,8 +372,7 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN
  %nonassoc ELSE
  
  %type <xp> cmds_int cmd_prep
- %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
+ %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail method_cmd method_term
 -%type <fda> dynamic_attr
  %type <fsa> static_attr
  %type <f> filter where_filter
  %type <fl> filter_body function_body
@@@ -831,9 -827,40 +866,38 @@@ static_attr
   | IFNAME  { $$ = f_new_static_attr(T_STRING,     SA_IFNAME,  0); }
   | IFINDEX { $$ = f_new_static_attr(T_INT,        SA_IFINDEX, 1); }
   | WEIGHT  { $$ = f_new_static_attr(T_INT,        SA_WEIGHT,  0); }
 - | PREFERENCE { $$ = f_new_static_attr(T_INT,   SA_PREF,      0); }
   | GW_MPLS { $$ = f_new_static_attr(T_INT,        SA_GW_MPLS, 0); }
 - | ONLINK  { $$ = f_new_static_attr(T_BOOL,       SA_ONLINK,  0); }
   ;
  
 -   EMPTY              { $$ = f_const_empty(FM.object->i_FI_EA_GET.da); }
+ method_term:
+    IS_V4 { $$ = f_new_inst(FI_IS_V4, FM.object); }
+  | TYPE { $$ = f_new_inst(FI_TYPE, FM.object); }
+  | IP { $$ = f_new_inst(FI_IP, FM.object); }
+  | RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, FM.object); }
+  | LEN { $$ = f_new_inst(FI_LENGTH, FM.object); }
+  | MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, FM.object); }
+  | ASN { $$ = f_new_inst(FI_ASN, FM.object); }
+  | SRC { $$ = f_new_inst(FI_NET_SRC, FM.object); }
+  | DST { $$ = f_new_inst(FI_NET_DST, FM.object); }
+  | MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, FM.object, $3); }
+  | FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, FM.object); }
+  | LAST  { $$ = f_new_inst(FI_AS_PATH_LAST, FM.object); }
+  | LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, FM.object); }
+  | DATA { $$ = f_new_inst(FI_PAIR_DATA, FM.object); }
+  | DATA1 { $$ = f_new_inst(FI_LC_DATA1, FM.object); }
+  | DATA2 { $$ = f_new_inst(FI_LC_DATA2, FM.object); }
+  | MIN  { $$ = f_new_inst(FI_MIN, FM.object); }
+  | MAX  { $$ = f_new_inst(FI_MAX, FM.object); }
+  ;
+ method_cmd:
++   EMPTY              { $$ = f_new_inst(FI_CONSTANT, f_get_empty(FM.object->i_FI_EA_GET.da->type)); }
+  | PREPEND '(' term ')'       { $$ = f_new_inst(FI_PATH_PREPEND, FM.object, $3 ); }
+  | ADD '(' term ')'   { $$ = f_new_inst(FI_CLIST_ADD, FM.object, $3 ); }
+  | DELETE '(' term ')'        { $$ = f_new_inst(FI_CLIST_DEL, FM.object, $3 ); }
+  | FILTER '(' term ')'        { $$ = f_new_inst(FI_CLIST_FILTER, FM.object, $3 ); }
+  ;
  term:
     '(' term ')'               { $$ = $2; }
   | term '+' term      { $$ = f_new_inst(FI_ADD, $1, $3); }
  
   | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
  
-  | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
-  | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
-  | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
-  | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
-  | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
-  | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
-  | term '.' ASN { $$ = f_new_inst(FI_ASN, $1); }
-  | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
-  | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
-  | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
-  | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
-  | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
-  | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
-  | term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
-  | term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
-  | term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
-  | term '.' MIN  { $$ = f_new_inst(FI_MIN, $1); }
-  | term '.' MAX  { $$ = f_new_inst(FI_MAX, $1); }
 - | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
--
- /* Communities */
- /* This causes one shift/reduce conflict
-  | dynamic_attr '.' ADD '(' term ')' { }
-  | dynamic_attr '.' DELETE '(' term ')' { }
-  | dynamic_attr '.' CONTAINS '(' term ')' { }
-  | dynamic_attr '.' RESET{ }
- */
+  | term '.' {
+      f_push_method_scope($1);
+    } method_term {
+      f_pop_method_scope();
+      $$ = $4;
+    }
  
 - | '+' EMPTY '+' { $$ = f_const_empty_path; }
 - | '-' EMPTY '-' { $$ = f_const_empty_clist; }
 - | '-' '-' EMPTY '-' '-' { $$ = f_const_empty_eclist; }
 - | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_const_empty_lclist; }
 + | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_PATH)); }
 + | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); }
 + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_ECLIST)); }
 + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_LCLIST)); }
   | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
   | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
   | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
@@@ -1033,16 -1038,19 +1078,19 @@@ get_cf_position
  
  lvalue:
     CF_SYM_KNOWN {
-       switch ($1->class) {
-       case SYM_VARIABLE_RANGE:
-         $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
-         break;
-       case SYM_ATTRIBUTE:
-         $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute };
-         break;
-       }
-   }
+      switch ($1->class)
+      {
+        case SYM_VARIABLE_RANGE:
+        $$ = (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 };
+        break;
+        default:
 -       cf_error("Variable name or custom attribute name required");
++       cf_error("Variable name or 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 }; };
 + ;
  
  CF_END
diff --cc filter/data.h
index cecb7bd5e10e930fdb9056ffe09891a984085fd6,f341b8b37f9d30ee979f5aa3590b79f43e5f1c89..462acf6145e796f963242e7fd164a2014c08bb97
@@@ -34,16 -109,17 +34,24 @@@ enum f_sa_code 
  
  /* Static attribute definition (members of struct rta) */
  struct f_static_attr {
 -  enum f_type f_type;         /* Filter type */
 +  btype type;                 /* Data type */
    enum f_sa_code sa_code;     /* Static attribute id */
 -  int readonly:1;                     /* Don't allow writing */
 +  int readonly:1;             /* Don't allow writing */
 +};
 +
++struct f_attr_bit {
++  const struct ea_class *class;
++  uint bit;
+ };
++#define f_new_dynamic_attr_bit(_bit, _name)  ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) })
++
  /* Filter l-value type */
  enum f_lval_type {
    F_LVAL_VARIABLE,
 -  F_LVAL_PREFERENCE,
    F_LVAL_SA,
    F_LVAL_EA,
++  F_LVAL_ATTR_BIT,
  };
  
  /* Filter l-value */
@@@ -51,8 -127,8 +59,9 @@@ struct f_lval 
    enum f_lval_type type;
    union {
      struct symbol *sym;
 -    struct f_dynamic_attr da;
 +    const struct ea_class *da;
      struct f_static_attr sa;
++    struct f_attr_bit fab;
    };
  };
  
diff --cc filter/f-inst.h
index 09a84ba222ce0470d0cc2b2936ee619d0e9dc871,3912df089e324affb8dc2be3d0823a9b7e0a654e..5f4c16f128dc358d4847bc5b9f264e0c1c2fd6d2
@@@ -95,17 -95,13 +95,10 @@@ void f_add_lines(const struct f_line_it
  
  
  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 */
 -static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, 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 = EAF_TYPE_BITFIELD, .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 }; }
 +static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
 +{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
 +struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
  
- struct f_attr_bit {
-   const struct ea_class *class;
-   uint bit;
- };
- #define f_new_dynamic_attr_bit(_bit, _name)  ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) })
  /* Hook for call bt_assert() function in configuration */
  extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
  
index 20d67f43bbec6a1fb41260717c9ee6d1ac17f690,6d786034a0af7f9551ce2307da3cb8016563b383..07bc46a2df04a94e98653f41210089cebfc7ddc6
@@@ -9,109 -9,9 +9,112 @@@ router id 62.168.0.1
  /* We have to setup any protocol */
  protocol device { }
  
+ attribute bgppath mypath;
+ attribute lclist mylclist;
 +/* Setting some custom attributes, enough to force BIRD to reallocate the attribute idmap */
 +attribute int test_ca_int1;
 +attribute int test_ca_int2;
 +attribute int test_ca_int3;
 +attribute int test_ca_int4;
 +attribute int test_ca_int5;
 +attribute int test_ca_int6;
 +attribute int test_ca_int7;
 +attribute int test_ca_int8;
 +attribute int test_ca_int9;
 +attribute int test_ca_int10;
 +
 +attribute ip test_ca_ip1;
 +attribute ip test_ca_ip2;
 +attribute ip test_ca_ip3;
 +attribute ip test_ca_ip4;
 +attribute ip test_ca_ip5;
 +attribute ip test_ca_ip6;
 +attribute ip test_ca_ip7;
 +attribute ip test_ca_ip8;
 +attribute ip test_ca_ip9;
 +attribute ip test_ca_ip10;
 +
 +attribute quad test_ca_quad1;
 +attribute quad test_ca_quad2;
 +attribute quad test_ca_quad3;
 +attribute quad test_ca_quad4;
 +attribute quad test_ca_quad5;
 +attribute quad test_ca_quad6;
 +attribute quad test_ca_quad7;
 +attribute quad test_ca_quad8;
 +attribute quad test_ca_quad9;
 +attribute quad test_ca_quad10;
 +
 +attribute bgppath test_ca_bgppath1;
 +attribute bgppath test_ca_bgppath2;
 +attribute bgppath test_ca_bgppath3;
 +attribute bgppath test_ca_bgppath4;
 +attribute bgppath test_ca_bgppath5;
 +attribute bgppath test_ca_bgppath6;
 +attribute bgppath test_ca_bgppath7;
 +attribute bgppath test_ca_bgppath8;
 +attribute bgppath test_ca_bgppath9;
 +attribute bgppath test_ca_bgppath10;
 +
 +attribute clist test_ca_clist1;
 +attribute clist test_ca_clist2;
 +attribute clist test_ca_clist3;
 +attribute clist test_ca_clist4;
 +attribute clist test_ca_clist5;
 +attribute clist test_ca_clist6;
 +attribute clist test_ca_clist7;
 +attribute clist test_ca_clist8;
 +attribute clist test_ca_clist9;
 +attribute clist test_ca_clist10;
 +
 +attribute eclist test_ca_eclist1;
 +attribute eclist test_ca_eclist2;
 +attribute eclist test_ca_eclist3;
 +attribute eclist test_ca_eclist4;
 +attribute eclist test_ca_eclist5;
 +attribute eclist test_ca_eclist6;
 +attribute eclist test_ca_eclist7;
 +attribute eclist test_ca_eclist8;
 +attribute eclist test_ca_eclist9;
 +attribute eclist test_ca_eclist10;
 +
 +attribute lclist test_ca_lclist1;
 +attribute lclist test_ca_lclist2;
 +attribute lclist test_ca_lclist3;
 +attribute lclist test_ca_lclist4;
 +attribute lclist test_ca_lclist5;
 +attribute lclist test_ca_lclist6;
 +attribute lclist test_ca_lclist7;
 +attribute lclist test_ca_lclist8;
 +attribute lclist test_ca_lclist9;
 +attribute lclist test_ca_lclist10;
 +
 +attribute lclist test_ca_lclist_max1;
 +attribute lclist test_ca_lclist_max2;
 +attribute lclist test_ca_lclist_max3;
 +attribute lclist test_ca_lclist_max4;
 +attribute lclist test_ca_lclist_max5;
 +attribute lclist test_ca_lclist_max6;
 +attribute lclist test_ca_lclist_max7;
 +attribute lclist test_ca_lclist_max8;
 +attribute lclist test_ca_lclist_max9;
 +attribute lclist test_ca_lclist_max10;
 +attribute lclist test_ca_lclist_max11;
 +attribute lclist test_ca_lclist_max12;
 +attribute lclist test_ca_lclist_max13;
 +attribute lclist test_ca_lclist_max14;
 +attribute lclist test_ca_lclist_max15;
 +attribute lclist test_ca_lclist_max16;
 +attribute lclist test_ca_lclist_max17;
 +attribute lclist test_ca_lclist_max18;
 +attribute lclist test_ca_lclist_max19;
 +attribute lclist test_ca_lclist_max20;
 +attribute lclist test_ca_lclist_max21;
 +
 +
 +/* Uncomment this to get an error */
 +#attribute int bgp_path;
  
  /*
   *    Common definitions and functions
index 9b07e9bb76dfc5d1c9ffd8aa7baf5e2e4e200ee0,487ad1d8e10f7dc12a6360de218e6f7e6e515310..7dece46b8ea81ed659a6dd019b89217027c6788d
@@@ -27,42 -28,40 +27,25 @@@ kern_sys_item
   | NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; }
   ;
  
 -dynamic_attr: KRT_PREFSRC     { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ;
 -dynamic_attr: KRT_REALM       { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ;
 -dynamic_attr: KRT_SCOPE       { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ;
 -
 -dynamic_attr: KRT_MTU         { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ;
 -dynamic_attr: KRT_WINDOW      { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ;
 -dynamic_attr: KRT_RTT         { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ;
 -dynamic_attr: KRT_RTTVAR      { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ;
 -dynamic_attr: KRT_SSTRESH     { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ;
 -dynamic_attr: KRT_CWND                { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ;
 -dynamic_attr: KRT_ADVMSS      { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ;
 -dynamic_attr: KRT_REORDERING  { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ;
 -dynamic_attr: KRT_HOPLIMIT    { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ;
 -dynamic_attr: KRT_INITCWND    { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ;
 -dynamic_attr: KRT_RTO_MIN     { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ;
 -dynamic_attr: KRT_INITRWND    { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ;
 -dynamic_attr: KRT_QUICKACK    { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ;
 -
  /* Bits of EA_KRT_LOCK, based on RTAX_* constants */
  
 -dynamic_attr: KRT_LOCK_MTU    { $$ = f_new_dynamic_attr_bit(2, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_RTT    { $$ = f_new_dynamic_attr_bit(4, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_SSTRESH        { $$ = f_new_dynamic_attr_bit(6, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_CWND   { $$ = f_new_dynamic_attr_bit(7, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, T_BOOL, EA_KRT_LOCK); } ;
 -dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, T_BOOL, EA_KRT_LOCK); } ;
 -
 -dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, T_BOOL, EA_KRT_FEATURES); } ;
 -dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(3, T_BOOL, EA_KRT_FEATURES); } ;
 -
 +attr_bit: KRT_LOCK_MTU        { $$ = f_new_dynamic_attr_bit(2, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_WINDOW     { $$ = f_new_dynamic_attr_bit(3, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_RTT        { $$ = f_new_dynamic_attr_bit(4, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_RTTVAR     { $$ = f_new_dynamic_attr_bit(5, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_SSTRESH    { $$ = f_new_dynamic_attr_bit(6, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_CWND       { $$ = f_new_dynamic_attr_bit(7, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_ADVMSS     { $$ = f_new_dynamic_attr_bit(8, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, "krt_lock"); } ;
 +attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
 +
 +/* Bits of EA_KRT_FEATURES */
 +attr_bit: KRT_FEATURE_ECN     { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
 +attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
 +
- /* Getting attribute bits (moved here to not confuse Bison on *BSD) */
- term:
-    attr_bit {
-     struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)});
-     $$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1.class), c));
-   }
-  ;
- /* Setting attribute bits (moved here to not confuse Bison on *BSD) */
- cmd:
-    attr_bit '=' term ';' {
-      $$ = f_new_inst(FI_CONDITION, $3,
-       f_generate_complex_default(FI_BITOR, $1.class,
-             f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)}), 0),
-       f_generate_complex_default(FI_BITAND, $1.class,
-             f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << $1.bit)}), 0)
-      );
-    }
-  ;
++/* Using attribute bits in filters (moved here to not confuse Bison on *BSD) */
++lvalue: attr_bit { $$ = (struct f_lval) { .type = F_LVAL_ATTR_BIT, .fab = $1 }; };
  
  CF_CODE