]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filters: Also sender protocol and channel name available mq-deref
authorMaria Matejka <mq@jmq.cz>
Thu, 9 Apr 2020 20:12:21 +0000 (22:12 +0200)
committerMaria Matejka <mq@jmq.cz>
Thu, 9 Apr 2020 20:19:06 +0000 (22:19 +0200)
Introducing the object member dereference framework.

filter/Makefile
filter/config.Y
filter/data.h
filter/decl.m4
filter/deref.c [new file with mode: 0644]
filter/f-inst.c

index c20625346e9660fff33fe079aa1505bee87e1720..14e8374bdbbde31c3f86e887226a76420f166ab3 100644 (file)
@@ -1,4 +1,4 @@
-src := filter.c data.c f-util.c tree.c trie.c inst-gen.c
+src := filter.c data.c deref.c f-util.c tree.c trie.c inst-gen.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
index 160f36ed8bf1e19d2dd3ed1026047ac3c2fa07a4..0256dcf6f21ac2f47d76d374cf02775ecb25643e 100644 (file)
@@ -431,7 +431,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
        IF, THEN, ELSE, CASE,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
-       FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
+       FROM, GW, NET, MASK, PROTO, AUTHOR, SENDER, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
        PREFERENCE,
        ROA_CHECK, ASN, SRC, DST,
        IS_V4, IS_V6,
@@ -902,6 +902,8 @@ static_attr:
  | GW      { $$ = f_new_static_attr(T_IP,         SA_GW,       0); }
  | NET     { $$ = f_new_static_attr(T_NET,       SA_NET,       1); }
  | PROTO   { $$ = f_new_static_attr(T_STRING,     SA_PROTO,    1); }
+ | SENDER  { $$ = f_new_static_attr(T_CHANNEL,   SA_SENDER,    1); }
+ | AUTHOR  { $$ = f_new_static_attr(T_PROTO,     SA_AUTHOR,    1); }
  | SOURCE  { $$ = f_new_static_attr(T_ENUM_RTS,   SA_SOURCE,   1); }
  | SCOPE   { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE,    0); }
  | DEST    { $$ = f_new_static_attr(T_ENUM_RTD,   SA_DEST,     0); }
@@ -938,19 +940,24 @@ term:
 
  | 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); }
- | 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_ROA_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 '.' token {
+    switch ($3.value) {
+      case IS_V4: $$ = f_new_inst(FI_IS_V4, $1); break;
+      case TYPE: $$ = f_new_inst(FI_TYPE, $1); break;
+      case IP: $$ = f_new_inst(FI_IP, $1); break;
+      case RD: $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); break;
+      case LEN: $$ = f_new_inst(FI_LENGTH, $1); break;
+      case MAXLEN: $$ = f_new_inst(FI_ROA_MAXLEN, $1); break;
+      case ASN: $$ = f_new_inst(FI_ROA_ASN, $1); break;
+      case SRC: $$ = f_new_inst(FI_NET_SRC, $1); break;
+      case DST: $$ = f_new_inst(FI_NET_DST, $1); break;
+      case FIRST: $$ = f_new_inst(FI_AS_PATH_FIRST, $1); break;
+      case LAST: $$ = f_new_inst(FI_AS_PATH_LAST, $1); break;
+      case LAST_NONAGGREGATED: $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); break;
+      default: $$ = f_new_inst(FI_DEREF, $1, f_get_deref($1->type, &$3)); break;
+    }
+ }
 
 /* Communities */
 /* This causes one shift/reduce conflict
index 4ebce73b6556280473c795ff5acc3c9932a6ceb1..aab3dd424dcb9d1d43044d674afde43a60b5207c 100644 (file)
@@ -61,6 +61,9 @@ enum f_type {
 
   T_SET = 0x80,
   T_PREFIX_SET = 0x81,
+
+  T_PROTO = 0xa0,      /* Protocol instance */
+  T_CHANNEL = 0xa1,    /* Channel */
 } PACKED;
 
 /* Filter value; size of this affects filter memory consumption */
@@ -78,6 +81,8 @@ struct f_val {
     const struct adata *ad;
     const struct f_path_mask *path_mask;
     struct f_path_mask_item pmi;
+    struct proto *proto;
+    struct channel *channel;
   } val;
 };
 
@@ -94,6 +99,8 @@ enum f_sa_code {
   SA_GW,
   SA_NET,
   SA_PROTO,
+  SA_SENDER,
+  SA_AUTHOR,
   SA_SOURCE,
   SA_SCOPE,
   SA_DEST,
@@ -126,6 +133,16 @@ struct f_lval {
   };
 };
 
+/* Member dereference (in filter/deref.c) */
+struct f_deref {
+  struct f_val (*deref)(struct f_val *);
+  const char *name;
+  enum f_type source_type, result_type;
+};
+
+struct keyword;
+const struct f_deref *f_get_deref(enum f_type, const struct keyword *);
+
 /* IP prefix range structure */
 struct f_prefix {
   net_addr net;                /* The matching prefix must match this net */
index efecb9a57e6f9e4468c92826a2c98ab785fb70ca..db8af26223a13ceebc7a59c1499a57d9e92833e3 100644 (file)
@@ -90,7 +90,7 @@ FID_DUMP_BODY()m4_dnl
 debug("%s" $4 "\n", INDENT, $5);
 ]])
 FID_INTERPRET_EXEC()m4_dnl
-const $1 $2 = whati->$2
+$1 const $2 = whati->$2
 FID_INTERPRET_BODY')
 
 #      Instruction arguments are needed only until linearization is done.
diff --git a/filter/deref.c b/filter/deref.c
new file mode 100644 (file)
index 0000000..ad241dd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *     Filters: dereferencing metaobjects
+ *
+ *     (c) 2020 Maria Matejka <mq@jmq.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ */
+
+#define PARSER 1
+
+#include "nest/bird.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+#include "filter/filter.h"
+#include "filter/f-inst.h"
+#include "filter/data.h"
+#include "conf/conf.h"
+#include "conf/cf-parse.tab.h"
+
+static struct f_val deref_proto__name__deref(struct f_val *val)
+{ return (struct f_val) { .type = T_STRING, .val.s = val->val.proto->name }; }
+
+static const struct f_deref deref_proto__name = {
+  .deref = deref_proto__name__deref,
+  .name = "name",
+  .source_type = T_PROTO,
+  .result_type = T_STRING,
+};
+
+static struct f_val deref_channel__name__deref(struct f_val *val)
+{ return (struct f_val) { .type = T_STRING, .val.s = val->val.channel->name }; }
+
+static const struct f_deref deref_channel__name = {
+  .deref = deref_channel__name__deref,
+  .name = "name",
+  .source_type = T_CHANNEL,
+  .result_type = T_STRING,
+};
+
+static struct f_val deref_channel__proto__deref(struct f_val *val)
+{ return (struct f_val) { .type = T_PROTO, .val.proto = val->val.channel->proto }; }
+
+static const struct f_deref deref_channel__proto = {
+  .deref = deref_channel__proto__deref,
+  .name = "proto",
+  .source_type = T_CHANNEL,
+  .result_type = T_PROTO,
+};
+
+const struct f_deref *f_get_deref(enum f_type type, const struct keyword *kw)
+{
+  if (!type)
+    cf_error("Can't dereference an object with unsure type");
+
+#define CX(t, v)  ((u64) (t) | ((v) << (8 * sizeof (enum f_type))))
+  switch (CX(type, kw->value))
+  {
+    case CX(T_PROTO, NAME):
+      return &deref_proto__name;
+    case CX(T_CHANNEL, NAME):
+      return &deref_channel__name;
+    case CX(T_CHANNEL, PROTO):
+      return &deref_channel__proto;
+  }
+
+  cf_error("Can't call (%s).%s: Undefined operation", f_type_name(type), kw->name);
+}
index 4b3c627b57b802e2e6b8ce4e514530b1b2c2be41..bde2d52f9d53beff393099e68f44787db8cf8113 100644 (file)
     RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
   }
 
+  INST(FI_DEREF, 1, 1) {
+    NEVER_CONSTANT;
+    ARG_ANY(1);
+    FID_MEMBER(
+       const struct f_deref *,
+       deref,
+       [[ f1->deref != f2->deref ]],
+       "dereference %s from %s",
+       [[ item->deref->name, f_type_name(item->deref->source_type) ]]
+       );
+
+    RESULT_TYPE(deref->result_type);
+    RESULT_VAL(deref->deref(&v1));
+  }
+
   INST(FI_TYPE, 1, 1) {
     ARG_ANY(1); /* There may be more types supporting this operation */
     switch (v1.type)
       case SA_GW:      RESULT(sa.f_type, ip, rta->nh.gw); break;
       case SA_NET:     RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
       case SA_PROTO:   RESULT(sa.f_type, s, rta->src->proto->name); break;
+      case SA_SENDER:  RESULT(sa.f_type, channel, (*fs->rte)->sender); break;
+      case SA_AUTHOR:  RESULT(sa.f_type, proto, rta->src->proto); break;
       case SA_SOURCE:  RESULT(sa.f_type, i, rta->source); break;
       case SA_SCOPE:   RESULT(sa.f_type, i, rta->scope); break;
       case SA_DEST:    RESULT(sa.f_type, i, rta->dest); break;