]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter + Config: Fix bugs, tests and split symbols by type
authorMaria Matejka <mq@ucw.cz>
Wed, 30 Jan 2019 13:03:47 +0000 (14:03 +0100)
committerMaria Matejka <mq@ucw.cz>
Wed, 20 Feb 2019 21:30:54 +0000 (22:30 +0100)
16 files changed:
conf/cf-lex.l
conf/conf.h
conf/confbase.Y
filter/config.Y
filter/f-inst.c
filter/filter.h
filter/filter_test.c
filter/test.conf
nest/config.Y
proto/babel/config.Y
proto/bfd/config.Y
proto/ospf/config.Y
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/rip/config.Y
proto/static/config.Y

index 9bbb3660a45efac9b9f4127265972da58aea0da6..5e7c84180e3d03152ad4ff9060634241d91a4887 100644 (file)
@@ -285,7 +285,18 @@ else: {
   }
 
   cf_lval.s = cf_get_symbol(yytext);
-  return SYM;
+  switch (cf_lval.s->class) {
+    case SYM_VOID: return CF_SYM_VOID;
+    case SYM_PROTO: return CF_SYM_PROTO;
+    case SYM_TEMPLATE: return CF_SYM_TEMPLATE;
+    case SYM_FUNCTION: return CF_SYM_FUNCTION;
+    case SYM_FILTER: return CF_SYM_FILTER;
+    case SYM_TABLE: return CF_SYM_TABLE;
+    case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE;
+    case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE;
+    case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT;
+    default: bug("Unknown symbol class %d", cf_lval.s->class);
+  }
 }
 
 <CLI>(.|\n) {
@@ -723,9 +734,6 @@ cf_pop_scope(void)
 char *
 cf_symbol_class_name(struct symbol *sym)
 {
-  if (cf_symbol_is_constant(sym))
-    return "constant";
-
   switch (sym->class)
     {
     case SYM_VOID:
@@ -740,6 +748,12 @@ cf_symbol_class_name(struct symbol *sym)
       return "filter";
     case SYM_TABLE:
       return "routing table";
+    case SYM_ATTRIBUTE:
+      return "custom attribute";
+    case SYM_CONSTANT_RANGE:
+      return "constant";
+    case SYM_VARIABLE_RANGE:
+      return "variable";
     default:
       return "unknown type";
     }
index 6138ccecdb90c6fa9b63aed24463ec304af71193..4e3addb3cb0b8e708452a67a7abb2f63c1deb2be 100644 (file)
@@ -165,10 +165,6 @@ void cf_push_scope(struct symbol *);
 void cf_pop_scope(void);
 char *cf_symbol_class_name(struct symbol *sym);
 
-static inline int cf_symbol_is_constant(struct symbol *sym)
-{ return (sym->class & 0xff00) == SYM_CONSTANT; }
-
-
 /* Parser */
 
 extern char *cf_text;
index 13f6aadeade8b403b222b704c702aab2ad36ae4a..2195e8fcfcfb48cb0094da87826c6776dde87800 100644 (file)
@@ -55,6 +55,7 @@ CF_DECLS
   enum ec_subtype ecs;
   struct f_dynamic_attr fda;
   struct f_static_attr fsa;
+  struct f_lval flv;
   struct filter *f;
   struct f_tree *e;
   struct f_trie *trie;
@@ -81,7 +82,7 @@ CF_DECLS
 %token <ip4> IP4
 %token <ip6> IP6
 %token <i64> VPN_RD
-%token <s> SYM
+%token <s> CF_SYM_VOID CF_SYM_PROTO CF_SYM_TEMPLATE CF_SYM_FUNCTION CF_SYM_FILTER CF_SYM_TABLE CF_SYM_ATTRIBUTE CF_SYM_VARIABLE CF_SYM_CONSTANT
 %token <t> TEXT
 %type <iface> ipa_scope
 
@@ -93,6 +94,7 @@ CF_DECLS
 %type <mls> label_stack_start label_stack
 
 %type <t> text opttext
+%type <s> symbol
 
 %nonassoc PREFIX_DUMMY
 %left AND OR
@@ -125,7 +127,7 @@ conf: ';' ;
 conf: definition ;
 
 definition:
-   DEFINE SYM '=' term ';' {
+   DEFINE CF_SYM_VOID '=' term ';' {
      struct f_val *val = cfg_alloc(sizeof(struct f_val));
      if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
      cf_define_symbol($2, SYM_CONSTANT | val->type, val);
@@ -135,18 +137,29 @@ definition:
 expr:
    NUM
  | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
      $$ = SYM_VAL($1).i; }
  ;
 
-
 expr_us:
    expr S  { $$ = $1 S_; }
  | expr MS { $$ = $1 MS_; }
  | expr US { $$ = $1 US_; }
  ;
 
+symbol:
+   CF_SYM_VOID
+ | CF_SYM_PROTO
+ | CF_SYM_TEMPLATE
+ | CF_SYM_FUNCTION
+ | CF_SYM_FILTER
+ | CF_SYM_TABLE
+ | CF_SYM_ATTRIBUTE
+ | CF_SYM_VARIABLE
+ | CF_SYM_CONSTANT
+ ;
+
 /* Switches */
 
 bool:
@@ -164,7 +177,7 @@ bool:
 ipa:
    IP4 { $$ = ipa_from_ip4($1); }
  | IP6 { $$ = ipa_from_ip6($1); }
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
      $$ = SYM_VAL($1).ip;
    }
@@ -172,7 +185,7 @@ ipa:
 
 ipa_scope:
    /* empty */ { $$ = NULL; }
- | '%' SYM { $$ = if_get_by_name($2->name); }
+ | '%' symbol { $$ = if_get_by_name($2->name); }
  ;
 
 
@@ -279,7 +292,7 @@ net_:
 
 net_ip6:
    net_ip6_
- | SYM {
+ | CF_SYM_CONSTANT {
      if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
        cf_error("IPv6 network expected");
      $$ = * SYM_VAL($1).net;
@@ -288,7 +301,7 @@ net_ip6:
 
 net_ip:
    net_ip_
- | SYM {
+ | CF_SYM_CONSTANT {
      if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
        cf_error("IP network expected");
      $$ = * SYM_VAL($1).net;
@@ -297,7 +310,7 @@ net_ip:
 
 net_any:
    net_
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class != (SYM_CONSTANT | T_NET))
        cf_error("Network expected");
      $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
@@ -309,7 +322,7 @@ net_or_ipa:
  | net_ip6_
  | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
  | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class == (SYM_CONSTANT | T_IP))
        net_fill_ip_host(&($$), SYM_VAL($1).ip);
      else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
@@ -346,7 +359,7 @@ time:
 
 text:
    TEXT
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
      $$ = SYM_VAL($1).s;
    }
index 607f534eb8e1baac755f6c7b5ac1ce9dc983dd4a..1306849fd829967d2783292f6511a3f1d79f00ef 100644 (file)
@@ -17,7 +17,7 @@ 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) \
-  f_new_inst(FI_EA_SET, da, f_new_inst(fi_code, f_new_inst(FI_EA_GET, 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
@@ -179,7 +179,7 @@ f_generate_empty(struct f_dynamic_attr dyn)
       cf_error("Can't empty that attribute");
   }
 
-  return f_new_inst(FI_EA_SET, dyn, f_new_inst(FI_CONSTANT, empty));
+  return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
 }
 
 #if 0
@@ -389,6 +389,37 @@ 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 *setter, *getter, *checker;
+  switch (lval->type) {
+    case F_LVAL_VARIABLE:
+      setter = f_new_inst(FI_SET, expr, lval->sym);
+      getter = f_new_inst(FI_VARIABLE, 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");
+  }
+
+  checker = f_new_inst(FI_EQ, expr, getter);
+  f_inst_next(setter, checker);
+  
+  return assert_done(setter, start, end);
+}
+
 CF_DECLS
 
 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
@@ -407,17 +438,18 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
        EMPTY,
        FILTER, WHERE, EVAL, ATTRIBUTE,
-       BT_ASSERT, BT_TEST_SUITE, FORMAT)
+       BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, FORMAT)
 
 %nonassoc THEN
 %nonassoc ELSE
 
 %type <xc> function_params declsn
 %type <xp> cmds_int function_body
-%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail one_decl decls
+%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls
 %type <fda> dynamic_attr
 %type <fsa> static_attr
 %type <f> filter filter_body where_filter
+%type <flv> lvalue
 %type <i> type
 %type <ecs> ec_kind
 %type <fret> break_command 
@@ -432,7 +464,7 @@ CF_GRAMMAR
 
 conf: filter_def ;
 filter_def:
-   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
+   FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
      filter_body {
      $2->def = $4;
      $4->name = $2->name;
@@ -447,16 +479,13 @@ filter_eval:
  ;
 
 conf: custom_attr ;
-custom_attr: ATTRIBUTE type SYM ';' {
+custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
   cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
 };
 
 conf: bt_test_suite ;
 bt_test_suite:
- BT_TEST_SUITE '(' SYM ',' text ')' {
-  if (!($3->class & SYM_FUNCTION))
-    cf_error("Function expected");
-
+ BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' {
   struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
   t->fn = $3->def;
   t->fn_name = $3->name;
@@ -505,7 +534,7 @@ type:
  ;
 
 one_decl:
-   type SYM {
+   type CF_SYM_VOID {
      struct f_val * val = cfg_alloc(sizeof(struct f_val));
      val->type = T_VOID;
      $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
@@ -545,8 +574,7 @@ filter_body:
  ;
 
 filter:
-   SYM {
-     if ($1->class != SYM_FILTER) cf_error("No such filter.");
+   CF_SYM_FILTER {
      $$ = $1->def;
    }
  | filter_body
@@ -573,7 +601,7 @@ function_body:
 
 conf: function_def ;
 function_def:
-   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
+   FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
      $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
      cf_push_scope($2);
    } function_params function_body {
@@ -647,8 +675,7 @@ set_atom:
      if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
      if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
    }
- | SYM {
-     if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
+ | CF_SYM_CONSTANT {
      if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
      $$ = *(struct f_val *)($1->def);
    }
@@ -764,7 +791,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
  ;
 
 bgp_path_expr:
-   symbol       { $$ = $1; }
+   symbol_value { $$ = $1; }
  | '(' term ')' { $$ = $2; }
  ;
 
@@ -806,31 +833,17 @@ constructor:
  ;
 
 
-rtadot: /* EMPTY, we are not permitted RTA. prefix */
- ;
-
 function_call:
-   SYM '(' var_list ')' {
+   CF_SYM_FUNCTION '(' var_list ')' {
      $$ = f_new_inst(FI_CALL, $1, $3);
    }
  ;
 
-symbol:
-   SYM {
-     switch ($1->class & 0xffff) {
-       case SYM_CONSTANT_RANGE:
-         $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def);
-        break;
-       case SYM_VARIABLE_RANGE:
-         $$ = f_new_inst(FI_VARIABLE, $1);
-        break;
-       case SYM_ATTRIBUTE:
-         $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
-        break;
-       default:
-         cf_error("%s: variable expected.", $1->name);
-     }
-   }
+symbol_value:
+   CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); }
+ | CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); }
+ | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); }
+ ;
 
 static_attr:
    FROM    { $$ = f_new_static_attr(T_IP,         SA_FROM,     0); }
@@ -863,15 +876,15 @@ term:
  | '!' term            { $$ = f_new_inst(FI_NOT, $2); }
  | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
 
- | symbol   { $$ = $1; }
+ | symbol_value   { $$ = $1; }
  | constant { $$ = $1; }
  | constructor { $$ = $1; }
 
  | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
 
- | rtadot static_attr { $$ = f_new_inst(FI_RTA_GET, $2); }
+ | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
 
- | rtadot dynamic_attr { $$ = f_new_inst(FI_EA_GET, $2); }
+ | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
 
  | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
  | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
@@ -888,10 +901,10 @@ term:
 
 /* Communities */
 /* This causes one shift/reduce conflict
- | rtadot dynamic_attr '.' ADD '(' term ')' { }
- | rtadot dynamic_attr '.' DELETE '(' term ')' { }
- | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
- | rtadot dynamic_attr '.' RESET{ }
+ | dynamic_attr '.' ADD '(' term ')' { }
+ | dynamic_attr '.' DELETE '(' term ')' { }
+ | dynamic_attr '.' CONTAINS '(' term ')' { }
+ | dynamic_attr '.' RESET{ }
 */
 
  | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
@@ -956,32 +969,29 @@ cmd:
  | IF term THEN block ELSE block {
      $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
    }
- | SYM '=' term ';' {
-     DBG( "Ook, we'll set value\n" );
-     if ($1->class == SYM_ATTRIBUTE) {
-       $$ = f_new_inst(FI_EA_SET, *((struct f_dynamic_attr *) $1->def), $3);
-     } else if (($1->class & ~T_MASK) == SYM_VARIABLE) {
-       $$ = f_new_inst(FI_SET, $3, $1);
-     } else
-       cf_error( "Symbol `%s' is read-only.", $1->name );
+ | CF_SYM_ATTRIBUTE '=' term ';' {
+   $$ = f_new_inst(FI_EA_SET, $3, *((struct f_dynamic_attr *) $1->def));
+   }
+ | CF_SYM_VARIABLE '=' term ';' {
+   $$ = f_new_inst(FI_SET, $3, $1);
    }
  | RETURN term ';' {
      DBG( "Ook, we'll return the value\n" );
      $$ = f_new_inst(FI_RETURN, $2);
    }
- | rtadot dynamic_attr '=' term ';' {
-     $$ = f_new_inst(FI_EA_SET, $2, $4);
+ | dynamic_attr '=' term ';' {
+     $$ = f_new_inst(FI_EA_SET, $3, $1);
    }
- | rtadot static_attr '=' term ';' {
-     if ($2.readonly)
+ | static_attr '=' term ';' {
+     if ($1.readonly)
        cf_error( "This static attribute is read-only.");
-     $$ = f_new_inst(FI_RTA_SET, $2, $4);
+     $$ = f_new_inst(FI_RTA_SET, $3, $1);
    }
  | PREFERENCE '=' term ';' {
      $$ = f_new_inst(FI_PREF_SET, $3);
    }
- | UNSET '(' rtadot dynamic_attr ')' ';' {
-     $$ = f_new_inst(FI_EA_UNSET, $4);
+ | UNSET '(' dynamic_attr ')' ';' {
+     $$ = f_new_inst(FI_EA_UNSET, $3);
    }
  | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
  | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } 
@@ -989,12 +999,13 @@ cmd:
       $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
    }
 
- | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
+ | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
+ | dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
+ | dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
+ | dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
+ | dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
  | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
+ | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
  ;
 
 get_cf_position:
@@ -1002,5 +1013,10 @@ get_cf_position:
   $$ = cf_text;
 };
 
+lvalue:
+   CF_SYM_VARIABLE { $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
+ | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
+ | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
+ | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
 
 CF_END
index ae2b528966e545d441bda134a10e75b774de5518..0dd9f9f69731eb22ea5741dc979c0069dc468524 100644 (file)
     ARG_ANY(1);
     COUNT(2);
 
-    NEW([[]], [[
+    NEW(, [[
        uint len = 0;
        uint dyn = 0;
        for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
   }
 
   INST(FI_RTA_SET, 1, 0) {
-    STATIC_ATTR;
     ACCESS_RTE;
     ARG_ANY(1);
+    STATIC_ATTR;
     if (sa.f_type != v1.type)
       runtime( "Attempt to set static attribute to incompatible type" );
 
   }
 
   INST(FI_EA_SET, 1, 0) {
-    DYNAMIC_ATTR;
     ACCESS_RTE;
     ACCESS_EATTRS;
     ARG_ANY(1);
+    DYNAMIC_ATTR;
     {
       struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
 
     /* Then push the arguments */
     LINE(1,1);
 
-    NEW([[]], [[
+    NEW(, [[
        if (sym->class != SYM_FUNCTION)
          cf_error("You can't call something which is not a function. Really.");
 
   INST(FI_ASSERT, 1, 0) {      /* Birdtest Assert */
     ARG(1, T_BOOL);
     STRING;
-    CALL(bt_assert_hook, res.val.i, what);
+    if (!bt_assert_hook)
+      runtime("No bt_assert hook registered, can't assert");
+
+    bt_assert_hook(res.val.i, what);
   }
index 39f16e93b8b312063842324601e50b1a956482e9..15a24fd4a4f1fbec89d18c592d32a82a38160250 100644 (file)
@@ -128,6 +128,24 @@ enum filter_return {
   F_QUITBIRD,
 };
 
+/* Filter l-value type */
+enum f_lval_type {
+  F_LVAL_VARIABLE,
+  F_LVAL_PREFERENCE,
+  F_LVAL_SA,
+  F_LVAL_EA,
+};
+
+/* Filter l-value */
+struct f_lval {
+  enum f_lval_type type;
+  union {
+    const struct symbol *sym;
+    struct f_dynamic_attr da;
+    struct f_static_attr sa;
+  };
+};
+
 /* Filter instruction declarations */
 #define FI__LIST \
   F(FI_NOP) \
@@ -159,9 +177,9 @@ enum filter_return {
   F(FI_CONDITION, ARG, LINE, LINE) \
   F(FI_PRINT_AND_DIE, ARG, FRET) \
   F(FI_RTA_GET, SA) \
-  F(FI_RTA_SET, SA, ARG) \
+  F(FI_RTA_SET, ARG, SA) \
   F(FI_EA_GET, EA) \
-  F(FI_EA_SET, EA, ARG) \
+  F(FI_EA_SET, ARG, EA) \
   F(FI_EA_UNSET, EA) \
   F(FI_PREF_GET) \
   F(FI_PREF_SET, ARG) \
index e19b0a75a5263e2dd1fbc352647b9890e13c5475..af6b590fdc624294c88063f9d4e43e31849041ca 100644 (file)
 #define BT_CONFIG_FILE "filter/test.conf"
 
 
-static struct config *
-parse_config_file(const void *filename_void)
-{
-  bt_bird_init();
+struct parse_config_file_arg {
+  struct config **cp;
+  const char *filename;
+};
 
-  size_t fn_size = strlen((const char *) filename_void) + 1;
+static int
+parse_config_file(const void *argv)
+{
+  const struct parse_config_file_arg *arg = argv;
+  size_t fn_size = strlen(arg->filename) + 1;
   char *filename = alloca(fn_size);
-  strncpy(filename, filename_void, fn_size);
-
-  struct config *c = bt_config_file_parse(filename);
-  bt_bird_cleanup();
-
-  return c;
+  strncpy(filename, arg->filename, fn_size);
+  
+  *(arg->cp) = bt_config_file_parse(filename);
+  return !!*(arg->cp);
 }
 
 static int
@@ -68,13 +70,18 @@ int
 main(int argc, char *argv[])
 {
   bt_init(argc, argv);
+  bt_bird_init();
+  
+  bt_assert_hook = bt_assert_filter;
 
-  struct config *c = parse_config_file(BT_CONFIG_FILE);
+  struct config *c = NULL;
+  struct parse_config_file_arg pcfa = { .cp = &c, .filename = BT_CONFIG_FILE };
+  bt_test_suite_base(parse_config_file, "conf", (const void *) &pcfa, 0, 0, "parse config file");
+
+  bt_bird_cleanup();
 
   if (c)
   {
-    bt_assert_hook = bt_assert_filter;
-
     struct f_bt_test_suite *t;
     WALK_LIST(t, c->tests)
       bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
index 39b349cc463ae2febbcc308405fdc59a551c9b80..e6b6ca4ec043a5a66f2e530513386c029d6949ed 100644 (file)
@@ -1336,7 +1336,7 @@ bt_test_suite(t_mixed_prefix, "Testing mixed net types");
 
 filter vpn_filter
 {
-       bt_assert(format(net) = "0:1:2 10.1.10.0/24");
+       bt_assert(format(net) = "1:2 10.1.10.0/24");
        bt_assert(net.type = NET_VPN4);
        bt_assert(net.type != NET_IP4);
        bt_assert(net.type != NET_IP6);
@@ -1347,6 +1347,15 @@ filter vpn_filter
          NET_IP6: print "IPV6";
        }
 
+# aoiufahkejtrhaweifdsbhydkfj,ysdnm
+
+       bt_check_assign(from, 10.20.30.40);
+       bt_check_assign(gw, 55.55.55.44);
+
+       bgp_community.add((3,5));
+       bgp_ext_community.add((ro, 135, 999));
+       bgp_large_community.add((6464156, 89646354, 8675643));
+
        accept;
 }
 
index 51fb0bd75e391a0cc954e2c52d1a90c6ae8dbec4..fb75c593989aabdcf7c5d9dd709cadf138e7b3a1 100644 (file)
@@ -88,7 +88,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
 %type <i32> idval
 %type <f> imexport
 %type <r> rtable
-%type <s> optsym
+%type <s> optproto sym_proto_or_template
 %type <ra> r_args
 %type <sd> sym_args
 %type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm
@@ -114,7 +114,7 @@ idval:
    NUM { $$ = $1; }
  | '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
  | IP4 { $$ = ip4_to_u32($1); }
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
        $$ = SYM_VAL($1).i;
      else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
@@ -156,7 +156,7 @@ table_sorted:
  | SORTED { $$ = 1; }
  ;
 
-table: net_type TABLE SYM table_sorted {
+table: net_type TABLE CF_SYM_VOID table_sorted {
    struct rtable_config *cf;
    cf = rt_new_table($3, $1);
    cf->sorted = $4;
@@ -173,6 +173,8 @@ proto_start:
  | TEMPLATE { $$ = SYM_TEMPLATE; }
  ;
 
+sym_proto_or_template: CF_SYM_PROTO | CF_SYM_TEMPLATE ;
+
 proto_name:
    /* EMPTY */ {
      struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
@@ -180,11 +182,11 @@ proto_name:
      s->def = this_proto;
      this_proto->name = s->name;
      }
- | SYM {
+ | CF_SYM_VOID {
      cf_define_symbol($1, this_proto->class, this_proto);
      this_proto->name = $1->name;
    }
- | FROM SYM {
+ | FROM sym_proto_or_template {
      struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
      s->class = this_proto->class;
      s->def = this_proto;
@@ -193,7 +195,7 @@ proto_name:
      if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
      proto_copy_config(this_proto, $2->def);
    }
- | SYM FROM SYM {
+ | CF_SYM_VOID FROM sym_proto_or_template {
      cf_define_symbol($1, this_proto->class, this_proto);
      this_proto->name = $1->name;
 
@@ -254,12 +256,7 @@ channel_end:
 proto_channel: channel_start channel_opt_list channel_end;
 
 
-rtable:
-   SYM {
-     if ($1->class != SYM_TABLE) cf_error("Table expected");
-     $$ = $1->def;
-   }
- ;
+rtable: CF_SYM_TABLE { $$ = $1->def; } ;
 
 imexport:
    FILTER filter { $$ = $2; }
@@ -512,8 +509,8 @@ CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing
 CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
 { proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
 
-optsym:
-   SYM
+optproto:
+   CF_SYM_PROTO
  | /* empty */ { $$ = NULL; }
  ;
 
@@ -545,9 +542,8 @@ r_args:
      $$->show_for = 1;
      $$->addr = $3;
    }
- | r_args TABLE SYM {
+ | r_args TABLE CF_SYM_TABLE {
      $$ = $1;
-     if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name);
      rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
      $$->tables_defined_by = RSD_TDB_DIRECT;
    }
@@ -558,10 +554,10 @@ r_args:
        rt_show_add_table($$, t->table);
      $$->tables_defined_by = RSD_TDB_ALL;
    }
- | r_args IMPORT TABLE SYM '.' r_args_channel {
+ | r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel {
      $$ = $1;
      struct proto_config *cf = (void *) $4->def;
-     if ($4->class != SYM_PROTO || !cf->proto) cf_error("%s is not a protocol", $4->name);
+     if (!cf->proto) cf_error("%s is not a protocol", $4->name);
      struct channel *c = proto_find_channel_by_name(cf->proto, $6);
      if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
      if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
@@ -590,30 +586,30 @@ r_args:
      $$ = $1;
      $$->filtered = 1;
    }
- | r_args export_mode SYM {
+ | r_args export_mode CF_SYM_PROTO {
      struct proto_config *c = (struct proto_config *) $3->def;
      $$ = $1;
      if ($$->export_mode) cf_error("Export specified twice");
-     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
+     if (!c->proto) cf_error("%s is not a protocol", $3->name);
      $$->export_mode = $2;
      $$->export_protocol = c->proto;
      $$->tables_defined_by = RSD_TDB_INDIRECT;
    }
- | r_args export_mode SYM '.' r_args_channel {
+ | r_args export_mode CF_SYM_PROTO '.' r_args_channel {
      struct proto_config *c = (struct proto_config *) $3->def;
      $$ = $1;
      if ($$->export_mode) cf_error("Export specified twice");
-     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
+     if (!c->proto) cf_error("%s is not a protocol", $3->name);
      $$->export_mode = $2;
      $$->export_channel = proto_find_channel_by_name(c->proto, $5);
      if (!$$->export_channel) cf_error("Export channel not found");
      $$->tables_defined_by = RSD_TDB_INDIRECT;
    }
- | r_args PROTOCOL SYM {
+ | r_args PROTOCOL CF_SYM_PROTO {
      struct proto_config *c = (struct proto_config *) $3->def;
      $$ = $1;
      if ($$->show_protocol) cf_error("Protocol specified twice");
-     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
+     if (!c->proto) cf_error("%s is not a protocol", $3->name);
      $$->show_protocol = c->proto;
      $$->tables_defined_by = RSD_TDB_INDIRECT;
    }
@@ -647,7 +643,7 @@ r_args_for:
     $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
     net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
   }
- | SYM {
+ | CF_SYM_CONSTANT {
      if ($1->class == (SYM_CONSTANT | T_IP))
      {
        $$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
@@ -709,7 +705,7 @@ sym_args:
  | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
  | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
  | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
- | sym_args SYM { $$ = $1; $$->sym = $2; }
+ | sym_args symbol { $$ = $1; $$->sym = $2; }
  ;
 
 
@@ -779,13 +775,13 @@ CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
 { this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
 
 proto_patt:
-   SYM  { $$.ptr = $1; $$.patt = 0; }
+   CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; }
  | ALL  { $$.ptr = NULL; $$.patt = 1; }
  | TEXT { $$.ptr = $1; $$.patt = 1; }
  ;
 
 proto_patt2:
-   SYM  { $$.ptr = $1; $$.patt = 0; }
+   CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; }
  |      { $$.ptr = NULL; $$.patt = 1; }
  | TEXT { $$.ptr = $1; $$.patt = 1; }
  ;
index b93a423ba719cc01d7e75d87933dbd80bc7875f7..7817532322c70c111b866a44f4b967bcb04232a4 100644 (file)
@@ -129,16 +129,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_
 
 CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
 
-CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
+CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
 { babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
 
-CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
+CF_CLI(SHOW BABEL NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
 { babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
 
-CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
+CF_CLI(SHOW BABEL ENTRIES, optproto opttext, [<name>], [[Show information about Babel prefix entries]])
 { babel_show_entries(proto_get_named($4, &proto_babel)); };
 
-CF_CLI(SHOW BABEL ROUTES, optsym opttext, [<name>], [[Show information about Babel route entries]])
+CF_CLI(SHOW BABEL ROUTES, optproto opttext, [<name>], [[Show information about Babel route entries]])
 { babel_show_routes(proto_get_named($4, &proto_babel)); };
 
 CF_CODE
index 3f5714fdb8be6acdd2eba34c8698c1b39349c2cf..41228e5133ce7f1a5e1e4de672ef0b108c021c40 100644 (file)
@@ -134,7 +134,7 @@ bfd_multihop:
 
 bfd_neigh_iface:
    /* empty */ { $$ = NULL; }
- | '%' SYM { $$ = if_get_by_name($2->name); }
+ | '%' symbol { $$ = if_get_by_name($2->name); }
  | DEV text { $$ = if_get_by_name($2); }
  ;
 
@@ -167,7 +167,7 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop
 
 
 CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]);
-CF_CLI(SHOW BFD SESSIONS, optsym, [<name>], [[Show information about BFD sessions]])
+CF_CLI(SHOW BFD SESSIONS, optproto, [<name>], [[Show information about BFD sessions]])
 { bfd_show_sessions(proto_get_named($4, &proto_bfd)); };
 
 CF_CODE
index 9669b7086ef011778c568df52e7ee75bcc253852..38b09deb8a7d5fae4b93bfe2268e27e1f2364db4 100644 (file)
@@ -504,29 +504,29 @@ dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF
 dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
 
 CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
-CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]])
+CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
 { ospf_sh(proto_get_named($3, &proto_ospf)); };
 
-CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
+CF_CLI(SHOW OSPF NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
 { ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
 
-CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
+CF_CLI(SHOW OSPF INTERFACE, optproto opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
 { ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
 
 CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
 
-CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[Show information about reachable OSPF network topology]])
+CF_CLI(SHOW OSPF TOPOLOGY, optproto opttext, [<name>], [[Show information about reachable OSPF network topology]])
 { ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
 
-CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [<name>], [[Show information about all OSPF network topology]])
+CF_CLI(SHOW OSPF TOPOLOGY ALL, optproto opttext, [<name>], [[Show information about all OSPF network topology]])
 { ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
 
 CF_CLI_HELP(SHOW OSPF STATE, [all] [<name>], [[Show information about OSPF network state]])
 
-CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about reachable OSPF network state]])
+CF_CLI(SHOW OSPF STATE, optproto opttext, [<name>], [[Show information about reachable OSPF network state]])
 { ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
 
-CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [<name>], [[Show information about all OSPF network state]])
+CF_CLI(SHOW OSPF STATE ALL, optproto opttext, [<name>], [[Show information about all OSPF network state]])
 { ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
 
 CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]);
@@ -544,7 +544,7 @@ lsadb_args:
  | lsadb_args LSID idval { $$ = $1; $$->lsid = $3; }
  | lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; }
  | lsadb_args ROUTER idval { $$ = $1; $$->router = $3; }
- | lsadb_args SYM { $$ = $1; $$->name = $2; }
+ | lsadb_args CF_SYM_PROTO { $$ = $1; $$->proto = (struct ospf_proto *) proto_get_named($2, &proto_ospf); }
  ;
 
 CF_CODE
index ef2a0df43bb5261781ddf0e363fb60c2bb7ef78d..816f33aa9540544913b873621fc5bc22e37ba6e8 100644 (file)
@@ -1402,7 +1402,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
 void
 ospf_sh_lsadb(struct lsadb_show_data *ld)
 {
-  struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
+  struct ospf_proto *p = ld->proto;
   uint num = p->gr->hash_entries;
   uint i, j;
   int last_dscope = -1;
index 7fac47c8e4b908c36da29248fd3f8ea20ef333c6..82ae4df44773db4d5d135aa65147647ed1a940f1 100644 (file)
@@ -900,7 +900,7 @@ struct ospf_lsreq_header
 #define SH_ROUTER_SELF 0xffffffff
 
 struct lsadb_show_data {
-  struct symbol *name; /* Protocol to request data from */
+  struct ospf_proto *proto;    /* Protocol to request data from */
   u16 type;            /* LSA Type, 0 -> all */
   u16 scope;           /* Scope, 0 -> all, hack to handle link scope as 1 */
   u32 area;            /* Specified for area scope */
index 265912b2d492b4073ff438e8becfbe9efbbc1917..4ab793d19c74542a1b87e64d7c3b46fbe98ffd2b 100644 (file)
@@ -191,10 +191,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_T
 
 CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
 
-CF_CLI(SHOW RIP INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
+CF_CLI(SHOW RIP INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
 { rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
 
-CF_CLI(SHOW RIP NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
+CF_CLI(SHOW RIP NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
 { rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
 
 
index 527046eee62b2d25ff2522b079ea948660d8f5fd..0e53c9784393fa45123039a55837768e299f25ca 100644 (file)
@@ -157,7 +157,7 @@ stat_route_opt_list:
  ;
 
 
-CF_CLI(SHOW STATIC, optsym, [<name>], [[Show details of static protocol]])
+CF_CLI(SHOW STATIC, optproto, [<name>], [[Show details of static protocol]])
 { static_show(proto_get_named($3, &proto_static)); } ;
 
 CF_CODE