]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filters: First try (and first step) on simple method-like builtins
authorJan Maria Matejka <mq@ucw.cz>
Tue, 5 Jun 2018 14:10:26 +0000 (16:10 +0200)
committerJan Maria Matejka <mq@ucw.cz>
Tue, 5 Jun 2018 14:44:51 +0000 (16:44 +0200)
Makefile.in
conf/cf-lex.l
conf/confbase.Y
conf/gen_parser.m4
filter/Makefile
filter/config.Y
filter/f-util.c
filter/filter.c
filter/filter.h
filter/gen_methods.m4 [new file with mode: 0644]
filter/methods.Y [new file with mode: 0644]

index 8f6c0c8bf797f5925f7eccaecf05f9782ff84d2a..fcf2a66cbdd0cc2d81430a824621ecf3c0e9c352 100644 (file)
@@ -69,7 +69,7 @@ $(daemon): LIBS += $(DAEMON_LIBS)
 # Include directories
 dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@
 
-conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h)
+conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) $(objdir)/filter/methods.h
 cf-local = $(conf-y-targets): $(s)config.Y
 
 src-o-files = $(patsubst %.c,$(o)%.o,$(src))
index ae0bb5a6008906551a685602d5caa1bfb7356d6b..ca6b855dfdfd82e65afca8f125f8bb1ee2013c46 100644 (file)
@@ -45,6 +45,7 @@
 #include "nest/route.h"
 #include "nest/protocol.h"
 #include "filter/filter.h"
+#include "filter/methods.h"
 #include "conf/conf.h"
 #include "conf/cf-parse.tab.h"
 #include "lib/string.h"
index 72f56f1e9872fec2bc324b8376bf06c5b5202fe2..03543b30548811461fb8a8c7ff2a61f82fad3bdc 100644 (file)
@@ -51,6 +51,7 @@ CF_DECLS
   struct f_inst *x;
   struct f_dynamic_attr fda;
   struct f_static_attr fsa;
+  enum f_method efm;
   struct filter *f;
   struct f_tree *e;
   struct f_trie *trie;
index 00b55023766177f55c86e5c1ade9bdcc3f039027..1c478c908f36b69b9b4ce68dbe431ba50ddf700b 100644 (file)
@@ -39,6 +39,10 @@ m4_define(CF_dyn_rules,)
 m4_define(CF_ADDTO, `m4_define([[CF_rule_$1]],m4_ifdef([[CF_rule_$1]],CF_rule_$1 | ,[[m4_define([[CF_dyn_rules]],CF_dyn_rules[[CF_RULE($1)
 ]])]])$2)DNL')
 
+# Simple filter object methods
+m4_define(CF_OBJM, `m4_divert(2)CF_KEYWORDS($1)
+m4_divert(3)f_object_method_simple: $1 { $$ = FM_$1; };')
+
 # CLI commands
 m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL
 m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
index 6bada8cac6a0d4aa12f8a10ee8019ab3e5475c5d..fbde7dd1cd690f8667c4e5fb204304631278088a 100644 (file)
@@ -6,3 +6,11 @@ $(cf-local)
 tests_src := tree_test.c filter_test.c trie_test.c
 tests_targets := $(tests_targets) $(tests-target-files)
 tests_objs := $(tests_objs) $(src-o-files)
+
+$(conf-y-targets): $(s)methods.Y
+
+$(o)methods.h: | $(s)gen_methods.m4
+$(objdir)/conf/cf-parse.tab.o: $(o)methods.h
+
+$(addprefix $(o), methods.h): $(objdir)/.dir-stamp
+$(call clean, methods.h)
index 182bfa3c021238c3972ab5d9cf9153fb1a6d31b4..25fce5cf89568743f5fb6e55603d818123dfa998 100644 (file)
@@ -10,6 +10,8 @@
 
 CF_HDR
 
+#include "filter/methods.h"
+
 CF_DEFINES
 
 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
@@ -413,7 +415,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        IS_V4, IS_V6,
        LEN, MAXLEN,
        DEFINED,
-       ADD, DELETE, CONTAINS, RESET,
+       ADD, DELETE, CONTAINS,
        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
        EMPTY,
        FILTER, WHERE, EVAL,
@@ -425,6 +427,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
 %type <fda> dynamic_attr
 %type <fsa> static_attr
+%type <efm> f_object_method_simple
 %type <f> filter filter_body where_filter
 %type <i> type break_command ec_kind
 %type <i32> cnum
@@ -889,26 +892,9 @@ term:
 
  | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
 
- | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; }
- | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; }
- | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
- | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
- | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
- | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; }
- | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; }
- | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a1.p = $1; }
+ | term '.' f_object_method_simple { $$ = f_new_inst_method($1, $3); }
+
  | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
- | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
- | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
- | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
-
-/* 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{ }
-*/
 
  | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
  | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
@@ -924,8 +910,6 @@ term:
 
  | FORMAT '(' term ')' {  $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; }
 
-/* | term '.' LEN { $$->code = P('P','l'); } */
-
 /* function_call is inlined here */
  | SYM '(' var_list ')' {
      struct symbol *sym;
index 6170760b0769559c68f182381d57fa562ead1d5a..e652a23403637516ac6be212287403d8051f6d73 100644 (file)
@@ -42,6 +42,16 @@ f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
   return ret;
 }
 
+struct f_inst *
+f_new_inst_method(struct f_inst *target, enum f_method method)
+{
+  struct f_inst *ret = f_new_inst(FI_METHOD);
+  ret->a1.p = target;
+  ret->a2.i = method;
+
+  return ret;
+}
+
 /*
  * Generate set_dynamic( operation( get_dynamic(), argument ) )
  */
index 3fa3d34c5c8136641a69f43929dcf1b358331d5a..4ca86de73d01caff8cd6108d0a153a3cae0a1bd2 100644 (file)
@@ -840,23 +840,101 @@ interpret(struct f_inst *what)
     res.type = T_BOOL;
     res.val.i = (v1.type != T_VOID) && !undef_value(v1);
     break;
-  case FI_TYPE:
-    ARG_ANY(1); /* There may be more types supporting this operation */
-    switch (v1.type)
+  case FI_METHOD:
+    switch (what->a2.i)
     {
-      case T_NET:
+      case FM_IS_V4:
+       ARG(1, T_IP);
+       res.type = T_BOOL;
+       res.val.i = ipa_is_ip4(v1.val.ip);
+       break;
+      case FM_TYPE:
+       ARG(1, T_NET);
        res.type = T_ENUM_NETTYPE;
        res.val.i = v1.val.net->type;
        break;
-      default:
-       runtime( "Can't determine type of this item" );
+      case FM_IP:      /* Convert prefix to ... */
+       ARG(1, T_NET);
+       res.type = T_IP;
+       res.val.ip = net_prefix(v1.val.net);
+       break;
+      case FM_RD:
+       ARG(1, T_NET);
+       if (!net_is_vpn(v1.val.net))
+         runtime( "VPN address expected" );
+       res.type = T_RD;
+       res.val.ec = net_rd(v1.val.net);
+       break;
+      case FM_LEN:     /* Get length of */
+       ARG_ANY(1);
+       res.type = T_INT;
+       switch(v1.type) {
+         case T_NET:    res.val.i = net_pxlen(v1.val.net); break;
+         case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
+         case T_CLIST:  res.val.i = int_set_get_size(v1.val.ad); break;
+         case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
+         case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
+         default: runtime( "Prefix, path, clist, eclist or lclist expected" );
+       }
+       break;
+      case FM_MAXLEN:  /* Get ROA max prefix length */
+       ARG(1, T_NET);
+       if (!net_is_roa(v1.val.net))
+         runtime( "ROA expected" );
+
+       res.type = T_INT;
+       res.val.i = (v1.val.net->type == NET_ROA4) ?
+         ((net_addr_roa4 *) v1.val.net)->max_pxlen :
+         ((net_addr_roa6 *) v1.val.net)->max_pxlen;
+       break;
+      case FM_ASN:     /* Get ROA ASN */
+       ARG(1, T_NET);
+       if (!net_is_roa(v1.val.net))
+         runtime( "ROA expected" );
+
+       res.type = T_INT;
+       res.val.i = (v1.val.net->type == NET_ROA4) ?
+         ((net_addr_roa4 *) v1.val.net)->asn :
+         ((net_addr_roa6 *) v1.val.net)->asn;
+       break;
+      case FM_SRC:     /* Get SADR src prefix */
+       ARG(1, T_NET);
+       if (!net_is_sadr(v1.val.net))
+         runtime( "SADR expected" );
+
+       {
+         net_addr_ip6_sadr *net = (void *) v1.val.net;
+         net_addr *src = lp_alloc(f_pool, sizeof(net_addr_ip6));
+         net_fill_ip6(src, net->src_prefix, net->src_pxlen);
+
+         res.type = T_NET;
+         res.val.net = src;
+       }
+       break;
+      case FM_FIRST:   /* Get first ASN from AS PATH */
+       ARG(1, T_PATH);
+
+       as = 0;
+       as_path_get_first(v1.val.ad, &as);
+       res.type = T_INT;
+       res.val.i = as;
+       break;
+      case FM_LAST:    /* Get last ASN from AS PATH */
+       ARG(1, T_PATH);
+
+       as = 0;
+       as_path_get_last(v1.val.ad, &as);
+       res.type = T_INT;
+       res.val.i = as;
+       break;
+      case FM_LAST_NONAGGREGATED:      /* Get last ASN from non-aggregated part of AS PATH */
+       ARG(1, T_PATH);
+
+       res.type = T_INT;
+       res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
+       break;
     }
     break;
-  case FI_IS_V4:
-    ARG(1, T_IP);
-    res.type = T_BOOL;
-    res.val.i = ipa_is_ip4(v1.val.ip);
-    break;
 
   /* Set to indirect value, a1 = variable, a2 = value */
   case FI_SET:
@@ -1204,87 +1282,6 @@ interpret(struct f_inst *what)
     f_rte_cow();
     (*f_rte)->pref = v1.val.i;
     break;
-  case FI_LENGTH:      /* Get length of */
-    ARG_ANY(1);
-    res.type = T_INT;
-    switch(v1.type) {
-    case T_NET:    res.val.i = net_pxlen(v1.val.net); break;
-    case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
-    case T_CLIST:  res.val.i = int_set_get_size(v1.val.ad); break;
-    case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
-    case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
-    default: runtime( "Prefix, path, clist or eclist expected" );
-    }
-    break;
-  case FI_SADR_SRC:    /* Get SADR src prefix */
-    ARG(1, T_NET);
-    if (!net_is_sadr(v1.val.net))
-      runtime( "SADR expected" );
-
-    {
-      net_addr_ip6_sadr *net = (void *) v1.val.net;
-      net_addr *src = lp_alloc(f_pool, sizeof(net_addr_ip6));
-      net_fill_ip6(src, net->src_prefix, net->src_pxlen);
-
-      res.type = T_NET;
-      res.val.net = src;
-    }
-    break;
-  case FI_ROA_MAXLEN:  /* Get ROA max prefix length */
-    ARG(1, T_NET);
-    if (!net_is_roa(v1.val.net))
-      runtime( "ROA expected" );
-
-    res.type = T_INT;
-    res.val.i = (v1.val.net->type == NET_ROA4) ?
-      ((net_addr_roa4 *) v1.val.net)->max_pxlen :
-      ((net_addr_roa6 *) v1.val.net)->max_pxlen;
-    break;
-  case FI_ROA_ASN:     /* Get ROA ASN */
-    ARG(1, T_NET);
-    if (!net_is_roa(v1.val.net))
-      runtime( "ROA expected" );
-
-    res.type = T_INT;
-    res.val.i = (v1.val.net->type == NET_ROA4) ?
-      ((net_addr_roa4 *) v1.val.net)->asn :
-      ((net_addr_roa6 *) v1.val.net)->asn;
-    break;
-  case FI_IP:  /* Convert prefix to ... */
-    ARG(1, T_NET);
-    res.type = T_IP;
-    res.val.ip = net_prefix(v1.val.net);
-    break;
-  case FI_ROUTE_DISTINGUISHER:
-    ARG(1, T_NET);
-    res.type = T_IP;
-    if (!net_is_vpn(v1.val.net))
-      runtime( "VPN address expected" );
-    res.type = T_RD;
-    res.val.ec = net_rd(v1.val.net);
-    break;
-  case FI_AS_PATH_FIRST:       /* Get first ASN from AS PATH */
-    ARG(1, T_PATH);
-
-    as = 0;
-    as_path_get_first(v1.val.ad, &as);
-    res.type = T_INT;
-    res.val.i = as;
-    break;
-  case FI_AS_PATH_LAST:        /* Get last ASN from AS PATH */
-    ARG(1, T_PATH);
-
-    as = 0;
-    as_path_get_last(v1.val.ad, &as);
-    res.type = T_INT;
-    res.val.i = as;
-    break;
-  case FI_AS_PATH_LAST_NAG:    /* Get last ASN from non-aggregated part of AS PATH */
-    ARG(1, T_PATH);
-
-    res.type = T_INT;
-    res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
-    break;
   case FI_RETURN:
     ARG_ANY(1);
     res = v1;
@@ -1619,7 +1616,6 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case FI_NOT_MATCH:
   case FI_MATCH: TWOARGS; break;
   case FI_DEFINED: ONEARG; break;
-  case FI_TYPE: ONEARG; break;
 
   case FI_LC_CONSTRUCT:
     THREEARGS;
@@ -1670,7 +1666,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
     if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
       return 0;
     break;
-  case FI_PRINT: case FI_LENGTH: ONEARG; break;
+  case FI_PRINT: ONEARG; break;
   case FI_CONDITION: THREEARGS; break;
   case FI_NOP: case FI_EMPTY: break;
   case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
@@ -1682,12 +1678,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case FI_EA_SET: ONEARG; A2_SAME; break;
 
   case FI_RETURN: ONEARG; break;
-  case FI_ROA_MAXLEN: ONEARG; break;
-  case FI_ROA_ASN: ONEARG; break;
-  case FI_SADR_SRC: ONEARG; break;
-  case FI_IP: ONEARG; break;
-  case FI_IS_V4: ONEARG; break;
-  case FI_ROUTE_DISTINGUISHER: ONEARG; break;
+  case FI_METHOD: ONEARG; A2_SAME; break;
   case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
              ONEARG;
             if (!i_same(f1->a2.p, f2->a2.p))
@@ -1699,9 +1690,6 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case FI_IP_MASK: TWOARGS; break;
   case FI_PATH_PREPEND: TWOARGS; break;
   case FI_CLIST_ADD_DEL: TWOARGS; break;
-  case FI_AS_PATH_FIRST:
-  case FI_AS_PATH_LAST:
-  case FI_AS_PATH_LAST_NAG: ONEARG; break;
   case FI_ROA_CHECK:
     TWOARGS;
     /* Does not really make sense - ROA check results may change anyway */
index febfdc651cdd408dc78914ab497f2f1352892258..f34d8eadd80297271e09cfba8169bb013443712a 100644 (file)
@@ -14,6 +14,8 @@
 #include "nest/route.h"
 #include "nest/attrs.h"
 
+#include "filter/methods.h"
+
 /* Filter instruction types */
 
 #define FI__TWOCHAR(a,b)       ((a<<8) | b)
@@ -36,8 +38,6 @@
   F(FI_MATCH,                    0, '~') \
   F(FI_NOT_MATCH,              '!', '~') \
   F(FI_DEFINED,                        'd', 'e') \
-  F(FI_TYPE,                     0, 'T') \
-  F(FI_IS_V4,                  'I', 'i') \
   F(FI_SET,                      0, 's') \
   F(FI_CONSTANT,                 0, 'c') \
   F(FI_VARIABLE,                 0, 'V') \
   F(FI_EA_SET,                 'e', 'S') \
   F(FI_PREF_GET,                 0, 'P') \
   F(FI_PREF_SET,               'P', 'S') \
-  F(FI_LENGTH,                   0, 'L') \
-  F(FI_ROA_MAXLEN,             'R', 'M') \
-  F(FI_ROA_ASN,                        'R', 'A') \
-  F(FI_SADR_SRC,               'n', 's') \
-  F(FI_IP,                     'c', 'p') \
-  F(FI_ROUTE_DISTINGUISHER,    'R', 'D') \
-  F(FI_AS_PATH_FIRST,          'a', 'f') \
-  F(FI_AS_PATH_LAST,           'a', 'l') \
-  F(FI_AS_PATH_LAST_NAG,       'a', 'L') \
+  F(FI_METHOD,                 'o', 'M') \
   F(FI_RETURN,                   0, 'r') \
   F(FI_CALL,                   'c', 'a') \
   F(FI_CLEAR_LOCAL_VARS,       'c', 'V') \
@@ -152,6 +144,7 @@ struct filter {
 struct f_inst *f_new_inst(enum f_instruction_code fi_code);
 struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
 struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
+struct f_inst *f_new_inst_method(struct f_inst *target, enum f_method method);
 static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int 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_static_attr f_new_static_attr(int f_type, int code, int readonly)
diff --git a/filter/gen_methods.m4 b/filter/gen_methods.m4
new file mode 100644 (file)
index 0000000..a6cc512
--- /dev/null
@@ -0,0 +1,33 @@
+m4_divert(-1)m4_dnl
+#
+#      BIRD -- Generator of Object Method List
+#
+#      (c) 2018 Maria Matejka <mq@jmq.cz>
+#
+#      Can be freely distributed and used under the terms of the GNU GPL.
+#
+# Common aliases
+m4_define(DNL, `m4_dnl')
+
+# Diversions used:
+#      1       methods
+
+# We don't need headers
+m4_define(CF_HDR, `m4_divert(-1)')
+
+m4_define(CF_OBJM, `m4_divert(1)FM_$1,
+m4_divert(-1)')
+
+m4_m4wrap(`
+m4_divert(0)
+#ifndef _BIRD_FILTER_METHOD_H_
+#define _BIRD_FILTER_METHOD_H_
+enum f_method {
+m4_undivert(1)
+};
+#endif
+')
+
+# As we are processing C source, we must access all M4 primitives via
+# m4_* and also set different quoting convention: `[[' and ']]'
+m4_changequote([[,]])
diff --git a/filter/methods.Y b/filter/methods.Y
new file mode 100644 (file)
index 0000000..fb50a11
--- /dev/null
@@ -0,0 +1,13 @@
+CF_OBJM(IS_V4)
+CF_OBJM(TYPE)
+CF_OBJM(IP)
+CF_OBJM(RD)
+CF_OBJM(LEN)
+CF_OBJM(MAXLEN)
+CF_OBJM(ASN)
+CF_OBJM(SRC)
+CF_OBJM(FIRST)
+CF_OBJM(LAST)
+CF_OBJM(LAST_NONAGGREGATED)
+CF_OBJM(RESET)
+