]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter data manipulation functions separated to their file
authorMaria Matejka <mq@ucw.cz>
Mon, 11 Feb 2019 16:12:48 +0000 (17:12 +0100)
committerMaria Matejka <mq@ucw.cz>
Wed, 20 Feb 2019 21:30:54 +0000 (22:30 +0100)
filter/Makefile
filter/data.c [new file with mode: 0644]
filter/data.h
filter/f-inst.c
filter/filter.c
filter/filter.h
nest/cmds.c

index 78d39638cc8c62318c2b9e44e8de12dc473db111..df7ff3f918ffcb1352afc97908dbcd14d2539aeb 100644 (file)
@@ -1,4 +1,4 @@
-src := filter.c f-util.c tree.c trie.c inst-gen.c
+src := filter.c data.c f-util.c tree.c trie.c inst-gen.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
diff --git a/filter/data.c b/filter/data.c
new file mode 100644 (file)
index 0000000..b389b8e
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ *     Filters: utility functions
+ *
+ *     (c) 1998 Pavel Machek <pavel@ucw.cz>
+ *     (c) 2019 Maria Matejka <mq@jmq.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ */
+
+#include "nest/bird.h"
+#include "lib/lists.h"
+#include "lib/resource.h"
+#include "lib/socket.h"
+#include "lib/string.h"
+#include "lib/unaligned.h"
+#include "lib/net.h"
+#include "lib/ip.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "nest/attrs.h"
+#include "conf/conf.h"
+#include "filter/filter.h"
+#include "filter/f-inst.h"
+#include "filter/data.h"
+
+const struct f_val f_const_empty_path = {
+  .type = T_PATH,
+  .val.ad = &null_adata,
+}, f_const_empty_clist = {
+  .type = T_CLIST,
+  .val.ad = &null_adata,
+}, f_const_empty_eclist = {
+  .type = T_ECLIST,
+  .val.ad = &null_adata,
+}, f_const_empty_lclist = {
+  .type = T_LCLIST,
+  .val.ad = &null_adata,
+};
+
+static struct adata *
+adata_empty(struct linpool *pool, int l)
+{
+  struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
+  res->length = l;
+  return res;
+}
+
+static void
+pm_format(const struct f_path_mask *p, buffer *buf)
+{
+  buffer_puts(buf, "[= ");
+
+  for (uint i=0; i<p->len; i++)
+  {
+    switch(p->item[i].kind)
+    {
+    case PM_ASN:
+      buffer_print(buf, "%u ", p->item[i].asn);
+      break;
+
+    case PM_QUESTION:
+      buffer_puts(buf, "? ");
+      break;
+
+    case PM_ASTERISK:
+      buffer_puts(buf, "* ");
+      break;
+
+    case PM_ASN_RANGE:
+      buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
+      break;
+
+    case PM_ASN_EXPR:
+      ASSERT(0);
+    }
+
+  }
+
+  buffer_puts(buf, "=]");
+}
+
+static inline int
+lcomm_cmp(lcomm v1, lcomm v2)
+{
+  if (v1.asn != v2.asn)
+    return (v1.asn > v2.asn) ? 1 : -1;
+  if (v1.ldp1 != v2.ldp1)
+    return (v1.ldp1 > v2.ldp1) ? 1 : -1;
+  if (v1.ldp2 != v2.ldp2)
+    return (v1.ldp2 > v2.ldp2) ? 1 : -1;
+  return 0;
+}
+
+/**
+ * val_compare - compare two values
+ * @v1: first value
+ * @v2: second value
+ *
+ * Compares two values and returns -1, 0, 1 on <, =, > or F_CMP_ERROR on
+ * error. Tree module relies on this giving consistent results so
+ * that it can be used for building balanced trees.
+ */
+int
+val_compare(const struct f_val *v1, const struct f_val *v2)
+{
+  if (v1->type != v2->type) {
+    if (v1->type == T_VOID)    /* Hack for else */
+      return -1;
+    if (v2->type == T_VOID)
+      return 1;
+
+    /* IP->Quad implicit conversion */
+    if ((v1->type == T_QUAD) && val_is_ip4(v2))
+      return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
+    if (val_is_ip4(v1) && (v2->type == T_QUAD))
+      return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
+
+    debug( "Types do not match in val_compare\n" );
+    return F_CMP_ERROR;
+  }
+
+  switch (v1->type) {
+  case T_VOID:
+    return 0;
+  case T_ENUM:
+  case T_INT:
+  case T_BOOL:
+  case T_PAIR:
+  case T_QUAD:
+    return uint_cmp(v1->val.i, v2->val.i);
+  case T_EC:
+  case T_RD:
+    return u64_cmp(v1->val.ec, v2->val.ec);
+  case T_LC:
+    return lcomm_cmp(v1->val.lc, v2->val.lc);
+  case T_IP:
+    return ipa_compare(v1->val.ip, v2->val.ip);
+  case T_NET:
+    return net_compare(v1->val.net, v2->val.net);
+  case T_STRING:
+    return strcmp(v1->val.s, v2->val.s);
+  default:
+    return F_CMP_ERROR;
+  }
+}
+
+static int
+pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
+{
+  if (m1->len != m2->len)
+
+  for (uint i=0; i<m1->len; i++)
+  {
+    if (m1->item[i].kind != m2->item[i].kind)
+      return 0;
+
+    switch (m1->item[i].kind) {
+      case PM_ASN:
+       if (m1->item[i].asn != m2->item[i].asn)
+         return 0;
+       break;
+      case PM_ASN_EXPR:
+       if (!f_same(m1->item[i].expr, m2->item[i].expr))
+         return 0;
+       break;
+      case PM_ASN_RANGE:
+       if (m1->item[i].from != m2->item[i].from)
+         return 0;
+       if (m1->item[i].to != m2->item[i].to)
+         return 0;
+       break;
+    }
+  }
+
+  return 1;
+}
+
+/**
+ * val_same - compare two values
+ * @v1: first value
+ * @v2: second value
+ *
+ * Compares two values and returns 1 if they are same and 0 if not.
+ * Comparison of values of different types is valid and returns 0.
+ */
+int
+val_same(const struct f_val *v1, const struct f_val *v2)
+{
+  int rc;
+
+  rc = val_compare(v1, v2);
+  if (rc != F_CMP_ERROR)
+    return !rc;
+
+  if (v1->type != v2->type)
+    return 0;
+
+  switch (v1->type) {
+  case T_PATH_MASK:
+    return pm_same(v1->val.path_mask, v2->val.path_mask);
+  case T_PATH:
+  case T_CLIST:
+  case T_ECLIST:
+  case T_LCLIST:
+    return adata_same(v1->val.ad, v2->val.ad);
+  case T_SET:
+    return same_tree(v1->val.t, v2->val.t);
+  case T_PREFIX_SET:
+    return trie_same(v1->val.ti, v2->val.ti);
+  default:
+    bug("Invalid type in val_same(): %x", v1->type);
+  }
+}
+
+int
+clist_set_type(const struct f_tree *set, struct f_val *v)
+{
+  switch (set->from.type)
+  {
+  case T_PAIR:
+    v->type = T_PAIR;
+    return 1;
+
+  case T_QUAD:
+    v->type = T_QUAD;
+    return 1;
+
+  case T_IP:
+    if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
+    {
+      v->type = T_QUAD;
+      return 1;
+    }
+    /* Fall through */
+  default:
+    v->type = T_VOID;
+    return 0;
+  }
+}
+
+static int
+clist_match_set(const struct adata *clist, const struct f_tree *set)
+{
+  if (!clist)
+    return 0;
+
+  struct f_val v;
+  if (!clist_set_type(set, &v))
+    return F_CMP_ERROR;
+
+  u32 *l = (u32 *) clist->data;
+  u32 *end = l + clist->length/4;
+
+  while (l < end) {
+    v.val.i = *l++;
+    if (find_tree(set, &v))
+      return 1;
+  }
+  return 0;
+}
+
+static int
+eclist_match_set(const struct adata *list, const struct f_tree *set)
+{
+  if (!list)
+    return 0;
+
+  if (!eclist_set_type(set))
+    return F_CMP_ERROR;
+
+  struct f_val v;
+  u32 *l = int_set_get_data(list);
+  int len = int_set_get_size(list);
+  int i;
+
+  v.type = T_EC;
+  for (i = 0; i < len; i += 2) {
+    v.val.ec = ec_get(l, i);
+    if (find_tree(set, &v))
+      return 1;
+  }
+
+  return 0;
+}
+
+static int
+lclist_match_set(const struct adata *list, const struct f_tree *set)
+{
+  if (!list)
+    return 0;
+
+  if (!lclist_set_type(set))
+    return F_CMP_ERROR;
+
+  struct f_val v;
+  u32 *l = int_set_get_data(list);
+  int len = int_set_get_size(list);
+  int i;
+
+  v.type = T_LC;
+  for (i = 0; i < len; i += 3) {
+    v.val.lc = lc_get(l, i);
+    if (find_tree(set, &v))
+      return 1;
+  }
+
+  return 0;
+}
+
+const struct adata *
+clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
+{
+  if (!list)
+    return NULL;
+
+  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+  struct f_val v;
+  if (tree)
+    clist_set_type(set->val.t, &v);
+  else
+    v.type = T_PAIR;
+
+  int len = int_set_get_size(list);
+  u32 *l = int_set_get_data(list);
+  u32 tmp[len];
+  u32 *k = tmp;
+  u32 *end = l + len;
+
+  while (l < end) {
+    v.val.i = *l++;
+    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
+    if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
+      *k++ = v.val.i;
+  }
+
+  uint nl = (k - tmp) * sizeof(u32);
+  if (nl == list->length)
+    return list;
+
+  struct adata *res = adata_empty(pool, nl);
+  memcpy(res->data, tmp, nl);
+  return res;
+}
+
+const struct adata *
+eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
+{
+  if (!list)
+    return NULL;
+
+  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+  struct f_val v;
+
+  int len = int_set_get_size(list);
+  u32 *l = int_set_get_data(list);
+  u32 tmp[len];
+  u32 *k = tmp;
+  int i;
+
+  v.type = T_EC;
+  for (i = 0; i < len; i += 2) {
+    v.val.ec = ec_get(l, i);
+    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
+    if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
+      *k++ = l[i];
+      *k++ = l[i+1];
+    }
+  }
+
+  uint nl = (k - tmp) * sizeof(u32);
+  if (nl == list->length)
+    return list;
+
+  struct adata *res = adata_empty(pool, nl);
+  memcpy(res->data, tmp, nl);
+  return res;
+}
+
+const struct adata *
+lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
+{
+  if (!list)
+    return NULL;
+
+  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
+  struct f_val v;
+
+  int len = int_set_get_size(list);
+  u32 *l = int_set_get_data(list);
+  u32 tmp[len];
+  u32 *k = tmp;
+  int i;
+
+  v.type = T_LC;
+  for (i = 0; i < len; i += 3) {
+    v.val.lc = lc_get(l, i);
+    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
+    if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
+      k = lc_copy(k, l+i);
+  }
+
+  uint nl = (k - tmp) * sizeof(u32);
+  if (nl == list->length)
+    return list;
+
+  struct adata *res = adata_empty(pool, nl);
+  memcpy(res->data, tmp, nl);
+  return res;
+}
+
+/**
+ * val_in_range - implement |~| operator
+ * @v1: element
+ * @v2: set
+ *
+ * Checks if @v1 is element (|~| operator) of @v2.
+ */
+int
+val_in_range(const struct f_val *v1, const struct f_val *v2)
+{
+  if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
+    return as_path_match(v1->val.ad, v2->val.path_mask);
+
+  if ((v1->type == T_INT) && (v2->type == T_PATH))
+    return as_path_contains(v2->val.ad, v1->val.i, 1);
+
+  if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
+    return int_set_contains(v2->val.ad, v1->val.i);
+  /* IP->Quad implicit conversion */
+  if (val_is_ip4(v1) && (v2->type == T_CLIST))
+    return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
+
+  if ((v1->type == T_EC) && (v2->type == T_ECLIST))
+    return ec_set_contains(v2->val.ad, v1->val.ec);
+
+  if ((v1->type == T_LC) && (v2->type == T_LCLIST))
+    return lc_set_contains(v2->val.ad, v1->val.lc);
+
+  if ((v1->type == T_STRING) && (v2->type == T_STRING))
+    return patmatch(v2->val.s, v1->val.s);
+
+  if ((v1->type == T_IP) && (v2->type == T_NET))
+    return ipa_in_netX(v1->val.ip, v2->val.net);
+
+  if ((v1->type == T_NET) && (v2->type == T_NET))
+    return net_in_netX(v1->val.net, v2->val.net);
+
+  if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
+    return trie_match_net(v2->val.ti, v1->val.net);
+
+  if (v2->type != T_SET)
+    return F_CMP_ERROR;
+
+  /* With integrated Quad<->IP implicit conversion */
+  if ((v1->type == v2->val.t->from.type) ||
+      ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
+    return !!find_tree(v2->val.t, v1);
+
+  if (v1->type == T_CLIST)
+    return clist_match_set(v1->val.ad, v2->val.t);
+
+  if (v1->type == T_ECLIST)
+    return eclist_match_set(v1->val.ad, v2->val.t);
+
+  if (v1->type == T_LCLIST)
+    return lclist_match_set(v1->val.ad, v2->val.t);
+
+  if (v1->type == T_PATH)
+    return as_path_match_set(v1->val.ad, v2->val.t);
+
+  return F_CMP_ERROR;
+}
+
+/*
+ * val_format - format filter value
+ */
+void
+val_format(const struct f_val *v, buffer *buf)
+{
+  char buf2[1024];
+  switch (v->type)
+  {
+  case T_VOID: buffer_puts(buf, "(void)"); return;
+  case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
+  case T_INT:  buffer_print(buf, "%u", v->val.i); return;
+  case T_STRING: buffer_print(buf, "%s", v->val.s); return;
+  case T_IP:   buffer_print(buf, "%I", v->val.ip); return;
+  case T_NET:   buffer_print(buf, "%N", v->val.net); return;
+  case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
+  case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
+  case T_EC:   ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
+  case T_LC:   lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
+  case T_RD:   rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
+  case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
+  case T_SET:  tree_format(v->val.t, buf); return;
+  case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
+  case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
+  case T_CLIST:        int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
+  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;
+  default:     buffer_print(buf, "[unknown type %x]", v->type); return;
+  }
+}
+
+static char val_dump_buffer[1024];
+const char *
+val_dump(const struct f_val *v) {
+  static buffer b = {
+    .start = val_dump_buffer,
+    .end = val_dump_buffer + 1024,
+  };
+  b.pos = b.start;
+  val_format(v, &b);
+  return val_dump_buffer;
+}
+
index 58db3e44046fb2bae7c7ba7c3ac1e724b9593ca3..6ef2024f9494f789299476f8953dd2ddd0f6ecee 100644 (file)
@@ -164,6 +164,39 @@ int trie_match_net(const struct f_trie *t, const net_addr *n);
 int trie_same(const struct f_trie *t1, const struct f_trie *t2);
 void trie_format(const struct f_trie *t, buffer *buf);
 
+#define F_CMP_ERROR 999
+
+int val_same(const struct f_val *v1, const struct f_val *v2);
+int val_compare(const struct f_val *v1, const struct f_val *v2);
+void val_format(const struct f_val *v, buffer *buf);
+const char *val_dump(const struct f_val *v);
+
+static inline int val_is_ip4(const struct f_val *v)
+{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
+int val_in_range(const struct f_val *v1, const struct f_val *v2);
+
+int clist_set_type(const struct f_tree *set, struct f_val *v);
+static inline int eclist_set_type(const struct f_tree *set)
+{ return set->from.type == T_EC; }
+static inline int lclist_set_type(const struct f_tree *set)
+{ return set->from.type == T_LC; }
+
+const struct adata *clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
+const struct adata *eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
+const struct adata *lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos);
+
+
+/* Special undef value for paths and clists */
+static inline int
+undef_value(struct f_val v)
+{
+  return ((v.type == T_PATH) || (v.type == T_CLIST) ||
+         (v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
+    (v.val.ad == &null_adata);
+}
+
 extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist;
 
+enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
+
 #endif
index afb895c5eb6b4cea6add6aa45a9a5d357581cf63..96d6108c2d3d277d39aea4a0e50c0ac7d54aa6c7 100644 (file)
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_compare(&v1, &v2);
-    if (i == CMP_ERROR)
+    if (i == F_CMP_ERROR)
       runtime( "Can't compare values of incompatible types" );
     RESULT(T_BOOL, i, (i == -1));
   }
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_compare(&v1, &v2);
-    if (i == CMP_ERROR)
+    if (i == F_CMP_ERROR)
       runtime( "Can't compare values of incompatible types" );
     RESULT(T_BOOL, i, (i != 1));
   }
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_in_range(&v1, &v2);
-    if (i == CMP_ERROR)
+    if (i == F_CMP_ERROR)
       runtime( "~ applied on unknown type pair" );
     RESULT(T_BOOL, i, !!i);
   }
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_in_range(&v1, &v2);
-    if (res.val.i == CMP_ERROR)
+    if (res.val.i == F_CMP_ERROR)
       runtime( "!~ applied on unknown type pair" );
     RESULT(T_BOOL, i, !i);
   }
index 0cb56fe4e2f7b2918aa8918e06581451d414e4ed..0bcf983625ef54bf5075ffd53dee0ff2d601ed2e 100644 (file)
@@ -50,8 +50,6 @@
 #include "filter/f-inst.h"
 #include "filter/data.h"
 
-#define CMP_ERROR 999
-
 /* Internal filter state, to be allocated on stack when executing filters */
 struct filter_state {
   struct rte **rte;
@@ -133,507 +131,6 @@ f_instruction_name(enum f_instruction_code fi)
     bug("Got unknown instruction code: %d", fi);
 }
 
-/* Special undef value for paths and clists */
-static inline int
-undef_value(struct f_val v)
-{
-  return ((v.type == T_PATH) || (v.type == T_CLIST) ||
-         (v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
-    (v.val.ad == &null_adata);
-}
-
-const struct f_val f_const_empty_path = {
-  .type = T_PATH,
-  .val.ad = &null_adata,
-}, f_const_empty_clist = {
-  .type = T_CLIST,
-  .val.ad = &null_adata,
-}, f_const_empty_eclist = {
-  .type = T_ECLIST,
-  .val.ad = &null_adata,
-}, f_const_empty_lclist = {
-  .type = T_LCLIST,
-  .val.ad = &null_adata,
-};
-
-static struct adata *
-adata_empty(struct linpool *pool, int l)
-{
-  struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
-  res->length = l;
-  return res;
-}
-
-static void
-pm_format(const struct f_path_mask *p, buffer *buf)
-{
-  buffer_puts(buf, "[= ");
-
-  for (uint i=0; i<p->len; i++)
-  {
-    switch(p->item[i].kind)
-    {
-    case PM_ASN:
-      buffer_print(buf, "%u ", p->item[i].asn);
-      break;
-
-    case PM_QUESTION:
-      buffer_puts(buf, "? ");
-      break;
-
-    case PM_ASTERISK:
-      buffer_puts(buf, "* ");
-      break;
-
-    case PM_ASN_RANGE:
-      buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
-      break;
-
-    case PM_ASN_EXPR:
-      ASSERT(0);
-    }
-
-  }
-
-  buffer_puts(buf, "=]");
-}
-
-static inline int val_is_ip4(const struct f_val *v)
-{ return (v->type == T_IP) && ipa_is_ip4(v->val.ip); }
-
-static inline int
-lcomm_cmp(lcomm v1, lcomm v2)
-{
-  if (v1.asn != v2.asn)
-    return (v1.asn > v2.asn) ? 1 : -1;
-  if (v1.ldp1 != v2.ldp1)
-    return (v1.ldp1 > v2.ldp1) ? 1 : -1;
-  if (v1.ldp2 != v2.ldp2)
-    return (v1.ldp2 > v2.ldp2) ? 1 : -1;
-  return 0;
-}
-
-/**
- * val_compare - compare two values
- * @v1: first value
- * @v2: second value
- *
- * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
- * error. Tree module relies on this giving consistent results so
- * that it can be used for building balanced trees.
- */
-int
-val_compare(const struct f_val *v1, const struct f_val *v2)
-{
-  if (v1->type != v2->type) {
-    if (v1->type == T_VOID)    /* Hack for else */
-      return -1;
-    if (v2->type == T_VOID)
-      return 1;
-
-    /* IP->Quad implicit conversion */
-    if ((v1->type == T_QUAD) && val_is_ip4(v2))
-      return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
-    if (val_is_ip4(v1) && (v2->type == T_QUAD))
-      return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
-
-    debug( "Types do not match in val_compare\n" );
-    return CMP_ERROR;
-  }
-
-  switch (v1->type) {
-  case T_VOID:
-    return 0;
-  case T_ENUM:
-  case T_INT:
-  case T_BOOL:
-  case T_PAIR:
-  case T_QUAD:
-    return uint_cmp(v1->val.i, v2->val.i);
-  case T_EC:
-  case T_RD:
-    return u64_cmp(v1->val.ec, v2->val.ec);
-  case T_LC:
-    return lcomm_cmp(v1->val.lc, v2->val.lc);
-  case T_IP:
-    return ipa_compare(v1->val.ip, v2->val.ip);
-  case T_NET:
-    return net_compare(v1->val.net, v2->val.net);
-  case T_STRING:
-    return strcmp(v1->val.s, v2->val.s);
-  default:
-    return CMP_ERROR;
-  }
-}
-
-static int
-pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
-{
-  if (m1->len != m2->len)
-
-  for (uint i=0; i<m1->len; i++)
-  {
-    if (m1->item[i].kind != m2->item[i].kind)
-      return 0;
-
-    switch (m1->item[i].kind) {
-      case PM_ASN:
-       if (m1->item[i].asn != m2->item[i].asn)
-         return 0;
-       break;
-      case PM_ASN_EXPR:
-       if (!f_same(m1->item[i].expr, m2->item[i].expr))
-         return 0;
-       break;
-      case PM_ASN_RANGE:
-       if (m1->item[i].from != m2->item[i].from)
-         return 0;
-       if (m1->item[i].to != m2->item[i].to)
-         return 0;
-       break;
-    }
-  }
-
-  return 1;
-}
-
-/**
- * val_same - compare two values
- * @v1: first value
- * @v2: second value
- *
- * Compares two values and returns 1 if they are same and 0 if not.
- * Comparison of values of different types is valid and returns 0.
- */
-int
-val_same(const struct f_val *v1, const struct f_val *v2)
-{
-  int rc;
-
-  rc = val_compare(v1, v2);
-  if (rc != CMP_ERROR)
-    return !rc;
-
-  if (v1->type != v2->type)
-    return 0;
-
-  switch (v1->type) {
-  case T_PATH_MASK:
-    return pm_same(v1->val.path_mask, v2->val.path_mask);
-  case T_PATH:
-  case T_CLIST:
-  case T_ECLIST:
-  case T_LCLIST:
-    return adata_same(v1->val.ad, v2->val.ad);
-  case T_SET:
-    return same_tree(v1->val.t, v2->val.t);
-  case T_PREFIX_SET:
-    return trie_same(v1->val.ti, v2->val.ti);
-  default:
-    bug("Invalid type in val_same(): %x", v1->type);
-  }
-}
-
-static int
-clist_set_type(const struct f_tree *set, struct f_val *v)
-{
-  switch (set->from.type)
-  {
-  case T_PAIR:
-    v->type = T_PAIR;
-    return 1;
-
-  case T_QUAD:
-    v->type = T_QUAD;
-    return 1;
-
-  case T_IP:
-    if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
-    {
-      v->type = T_QUAD;
-      return 1;
-    }
-    /* Fall through */
-  default:
-    v->type = T_VOID;
-    return 0;
-  }
-}
-
-static inline int
-eclist_set_type(const struct f_tree *set)
-{ return set->from.type == T_EC; }
-
-static inline int
-lclist_set_type(const struct f_tree *set)
-{ return set->from.type == T_LC; }
-
-static int
-clist_match_set(const struct adata *clist, const struct f_tree *set)
-{
-  if (!clist)
-    return 0;
-
-  struct f_val v;
-  if (!clist_set_type(set, &v))
-    return CMP_ERROR;
-
-  u32 *l = (u32 *) clist->data;
-  u32 *end = l + clist->length/4;
-
-  while (l < end) {
-    v.val.i = *l++;
-    if (find_tree(set, &v))
-      return 1;
-  }
-  return 0;
-}
-
-static int
-eclist_match_set(const struct adata *list, const struct f_tree *set)
-{
-  if (!list)
-    return 0;
-
-  if (!eclist_set_type(set))
-    return CMP_ERROR;
-
-  struct f_val v;
-  u32 *l = int_set_get_data(list);
-  int len = int_set_get_size(list);
-  int i;
-
-  v.type = T_EC;
-  for (i = 0; i < len; i += 2) {
-    v.val.ec = ec_get(l, i);
-    if (find_tree(set, &v))
-      return 1;
-  }
-
-  return 0;
-}
-
-static int
-lclist_match_set(const struct adata *list, const struct f_tree *set)
-{
-  if (!list)
-    return 0;
-
-  if (!lclist_set_type(set))
-    return CMP_ERROR;
-
-  struct f_val v;
-  u32 *l = int_set_get_data(list);
-  int len = int_set_get_size(list);
-  int i;
-
-  v.type = T_LC;
-  for (i = 0; i < len; i += 3) {
-    v.val.lc = lc_get(l, i);
-    if (find_tree(set, &v))
-      return 1;
-  }
-
-  return 0;
-}
-
-static const struct adata *
-clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
-{
-  if (!list)
-    return NULL;
-
-  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
-  struct f_val v;
-  if (tree)
-    clist_set_type(set->val.t, &v);
-  else
-    v.type = T_PAIR;
-
-  int len = int_set_get_size(list);
-  u32 *l = int_set_get_data(list);
-  u32 tmp[len];
-  u32 *k = tmp;
-  u32 *end = l + len;
-
-  while (l < end) {
-    v.val.i = *l++;
-    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
-    if ((tree ? !!find_tree(set->val.t, &v) : int_set_contains(set->val.ad, v.val.i)) == pos)
-      *k++ = v.val.i;
-  }
-
-  uint nl = (k - tmp) * sizeof(u32);
-  if (nl == list->length)
-    return list;
-
-  struct adata *res = adata_empty(pool, nl);
-  memcpy(res->data, tmp, nl);
-  return res;
-}
-
-static const struct adata *
-eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
-{
-  if (!list)
-    return NULL;
-
-  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
-  struct f_val v;
-
-  int len = int_set_get_size(list);
-  u32 *l = int_set_get_data(list);
-  u32 tmp[len];
-  u32 *k = tmp;
-  int i;
-
-  v.type = T_EC;
-  for (i = 0; i < len; i += 2) {
-    v.val.ec = ec_get(l, i);
-    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
-    if ((tree ? !!find_tree(set->val.t, &v) : ec_set_contains(set->val.ad, v.val.ec)) == pos) {
-      *k++ = l[i];
-      *k++ = l[i+1];
-    }
-  }
-
-  uint nl = (k - tmp) * sizeof(u32);
-  if (nl == list->length)
-    return list;
-
-  struct adata *res = adata_empty(pool, nl);
-  memcpy(res->data, tmp, nl);
-  return res;
-}
-
-static const struct adata *
-lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos)
-{
-  if (!list)
-    return NULL;
-
-  int tree = (set->type == T_SET);     /* 1 -> set is T_SET, 0 -> set is T_CLIST */
-  struct f_val v;
-
-  int len = int_set_get_size(list);
-  u32 *l = int_set_get_data(list);
-  u32 tmp[len];
-  u32 *k = tmp;
-  int i;
-
-  v.type = T_LC;
-  for (i = 0; i < len; i += 3) {
-    v.val.lc = lc_get(l, i);
-    /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
-    if ((tree ? !!find_tree(set->val.t, &v) : lc_set_contains(set->val.ad, v.val.lc)) == pos)
-      k = lc_copy(k, l+i);
-  }
-
-  uint nl = (k - tmp) * sizeof(u32);
-  if (nl == list->length)
-    return list;
-
-  struct adata *res = adata_empty(pool, nl);
-  memcpy(res->data, tmp, nl);
-  return res;
-}
-
-/**
- * val_in_range - implement |~| operator
- * @v1: element
- * @v2: set
- *
- * Checks if @v1 is element (|~| operator) of @v2.
- */
-static int
-val_in_range(const struct f_val *v1, const struct f_val *v2)
-{
-  if ((v1->type == T_PATH) && (v2->type == T_PATH_MASK))
-    return as_path_match(v1->val.ad, v2->val.path_mask);
-
-  if ((v1->type == T_INT) && (v2->type == T_PATH))
-    return as_path_contains(v2->val.ad, v1->val.i, 1);
-
-  if (((v1->type == T_PAIR) || (v1->type == T_QUAD)) && (v2->type == T_CLIST))
-    return int_set_contains(v2->val.ad, v1->val.i);
-  /* IP->Quad implicit conversion */
-  if (val_is_ip4(v1) && (v2->type == T_CLIST))
-    return int_set_contains(v2->val.ad, ipa_to_u32(v1->val.ip));
-
-  if ((v1->type == T_EC) && (v2->type == T_ECLIST))
-    return ec_set_contains(v2->val.ad, v1->val.ec);
-
-  if ((v1->type == T_LC) && (v2->type == T_LCLIST))
-    return lc_set_contains(v2->val.ad, v1->val.lc);
-
-  if ((v1->type == T_STRING) && (v2->type == T_STRING))
-    return patmatch(v2->val.s, v1->val.s);
-
-  if ((v1->type == T_IP) && (v2->type == T_NET))
-    return ipa_in_netX(v1->val.ip, v2->val.net);
-
-  if ((v1->type == T_NET) && (v2->type == T_NET))
-    return net_in_netX(v1->val.net, v2->val.net);
-
-  if ((v1->type == T_NET) && (v2->type == T_PREFIX_SET))
-    return trie_match_net(v2->val.ti, v1->val.net);
-
-  if (v2->type != T_SET)
-    return CMP_ERROR;
-
-  /* With integrated Quad<->IP implicit conversion */
-  if ((v1->type == v2->val.t->from.type) ||
-      ((v1->type == T_QUAD) && val_is_ip4(&(v2->val.t->from)) && val_is_ip4(&(v2->val.t->to))))
-    return !!find_tree(v2->val.t, v1);
-
-  if (v1->type == T_CLIST)
-    return clist_match_set(v1->val.ad, v2->val.t);
-
-  if (v1->type == T_ECLIST)
-    return eclist_match_set(v1->val.ad, v2->val.t);
-
-  if (v1->type == T_LCLIST)
-    return lclist_match_set(v1->val.ad, v2->val.t);
-
-  if (v1->type == T_PATH)
-    return as_path_match_set(v1->val.ad, v2->val.t);
-
-  return CMP_ERROR;
-}
-
-/*
- * val_format - format filter value
- */
-void
-val_format(const struct f_val *v, buffer *buf)
-{
-  char buf2[1024];
-  switch (v->type)
-  {
-  case T_VOID: buffer_puts(buf, "(void)"); return;
-  case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
-  case T_INT:  buffer_print(buf, "%u", v->val.i); return;
-  case T_STRING: buffer_print(buf, "%s", v->val.s); return;
-  case T_IP:   buffer_print(buf, "%I", v->val.ip); return;
-  case T_NET:   buffer_print(buf, "%N", v->val.net); return;
-  case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
-  case T_QUAD: buffer_print(buf, "%R", v->val.i); return;
-  case T_EC:   ec_format(buf2, v->val.ec); buffer_print(buf, "%s", buf2); return;
-  case T_LC:   lc_format(buf2, v->val.lc); buffer_print(buf, "%s", buf2); return;
-  case T_RD:   rd_format(v->val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
-  case T_PREFIX_SET: trie_format(v->val.ti, buf); return;
-  case T_SET:  tree_format(v->val.t, buf); return;
-  case T_ENUM: buffer_print(buf, "(enum %x)%u", v->type, v->val.i); return;
-  case T_PATH: as_path_format(v->val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
-  case T_CLIST:        int_set_format(v->val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
-  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;
-  default:     buffer_print(buf, "[unknown type %x]", v->type); return;
-  }
-}
-
-
 static inline void f_cache_eattrs(struct filter_state *fs)
 {
   fs->eattrs = &((*fs->rte)->attrs->eattrs);
@@ -687,19 +184,6 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
 #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
 static const char f_dump_line_indent_str[] = "                                ";
 
-static char val_dump_buffer[1024];
-
-static const char *
-val_dump(const struct f_val *v) {
-  static buffer b = {
-    .start = val_dump_buffer,
-    .end = val_dump_buffer + 1024,
-  };
-  b.pos = b.start;
-  val_format(v, &b);
-  return val_dump_buffer;
-}
-
 static void f_dump_line(const struct f_line *dest, int indent);
 
 static void
@@ -891,122 +375,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2)
   return 1;
 }
 
-#if 0
-  case FI_ADD: /* fall through */
-  case FI_SUBTRACT:
-  case FI_MULTIPLY:
-  case FI_DIVIDE:
-  case FI_OR:
-  case FI_AND:
-  case FI_PAIR_CONSTRUCT:
-  case FI_EC_CONSTRUCT:
-  case FI_NEQ:
-  case FI_EQ:
-  case FI_LT:
-  case FI_LTE: TWOARGS; break;
-
-  case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a[0].p, f2->a[0].p)) return 0; break;
-
-  case FI_NOT: ONEARG; break;
-  case FI_NOT_MATCH:
-  case FI_MATCH: TWOARGS; break;
-  case FI_DEFINED: ONEARG; break;
-  case FI_TYPE: ONEARG; break;
-
-  case FI_LC_CONSTRUCT:
-    THREEARGS;
-    break;
-
-  case FI_SET:
-    ARG(2);
-    {
-      struct symbol *s1, *s2;
-      s1 = f1->a[0].p;
-      s2 = f2->a[0].p;
-      if (strcmp(s1->name, s2->name))
-       return 0;
-      if (s1->class != s2->class)
-       return 0;
-    }
-    break;
-
-  case FI_CONSTANT:
-    switch (f1->aux) {
-
-    case T_PREFIX_SET:
-      if (!trie_same(f1->a[1].p, f2->a[1].p))
-       return 0;
-      break;
-
-    case T_SET:
-      if (!same_tree(f1->a[1].p, f2->a[1].p))
-       return 0;
-      break;
-
-    case T_STRING:
-      if (strcmp(f1->a[1].p, f2->a[1].p))
-       return 0;
-      break;
-
-    default:
-      A2_SAME;
-    }
-    break;
-
-  case FI_CONSTANT_INDIRECT:
-    if (!val_same(* (struct f_val *) f1->a[0].p, * (struct f_val *) f2->a[0].p))
-      return 0;
-    break;
-
-  case FI_VARIABLE:
-    if (strcmp((char *) f1->a[1].p, (char *) f2->a[1].p))
-      return 0;
-    break;
-  case FI_PRINT: case FI_LENGTH: ONEARG; break;
-  case FI_CONDITION: THREEARGS; break;
-  case FI_NOP: case FI_EMPTY: break;
-  case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
-  case FI_PREF_GET:
-  case FI_RTA_GET: A2_SAME; break;
-  case FI_EA_GET: A2_SAME; break;
-  case FI_PREF_SET:
-  case FI_RTA_SET:
-  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_CALL: /* Call rewriting trickery to avoid exponential behaviour */
-             ONEARG;
-            if (!i_same(f1->a[1].p, f2->a[1].p))
-              return 0;
-            f2->a[1].p = f1->a[1].p;
-            break;
-  case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
-  case FI_SWITCH: ONEARG; if (!same_tree(f1->a[1].p, f2->a[1].p)) return 0; break;
-  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;
-    /* FIXME: ROA check results may change anyway */
-    if (strcmp(f1->a[2].rtc->name,
-              f2->a[2].rtc->name))
-      return 0;
-    break;
-  case FI_FORMAT: ONEARG; break;
-  case FI_ASSERT: ONEARG; break;
-  default:
-    bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
-#endif
-
 /**
  * f_run - run a filter for a route
  * @filter: filter to run
@@ -1133,6 +501,16 @@ f_eval_int(const struct f_line *expr)
   return val.val.i;
 }
 
+enum filter_return
+f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf)
+{
+  struct f_val val;
+  enum filter_return fret = f_eval(expr, tmp_pool, &val);
+  if (fret > F_RETURN)
+    val_format(&val, buf);
+  return fret;
+}
+
 /**
  * filter_same - compare two filters
  * @new: first filter to be compared
index 9b3886fb49740ec8bf3df35345e23b68932289e1..9f1a8e50df316f9dfd9ad4c2aaa0a77a7c89fe19 100644 (file)
@@ -40,17 +40,13 @@ struct rte;
 
 enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
 enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
-enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres);
 uint f_eval_int(const struct f_line *expr);
+enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
 
 char *filter_name(struct filter *filter);
 int filter_same(struct filter *new, struct filter *old);
 int f_same(const struct f_line *f1, const struct f_line *f2);
 
-int val_compare(const struct f_val *v1, const struct f_val *v2);
-
-void val_format(const struct f_val *v, buffer *buf);
-
 #define FILTER_ACCEPT NULL
 #define FILTER_REJECT ((void *) 1)
 #define FILTER_UNDEF  ((void *) 2)     /* Used in BGP */
index 2b83033fb1d400acb8e4ea37037802177c9695f8..da4015cfba0d85d5ce3a21b85cff15e205a4d68a 100644 (file)
@@ -15,7 +15,6 @@
 #include "lib/string.h"
 #include "lib/resource.h"
 #include "filter/filter.h"
-#include "filter/data.h"
 
 extern int shutting_down;
 extern int configuring;
@@ -98,16 +97,14 @@ cmd_show_memory(void)
 void
 cmd_eval(const struct f_line *expr)
 {
-  /* TODO: Return directly the string from eval */
-  struct f_val v;
-  if (f_eval(expr, this_cli->parser_pool, &v) > F_RETURN)
+  buffer buf;
+  LOG_BUFFER_INIT(buf);
+
+  if (f_eval_buf(expr, this_cli->parser_pool, &buf) > F_RETURN)
     {
       cli_msg(8008, "runtime error");
       return;
     }
 
-  buffer buf;
-  LOG_BUFFER_INIT(buf);
-  val_format(&v, &buf);
   cli_msg(23, "%s", buf.start);
 }