summaryrefslogtreecommitdiffstats
path: root/filter/filter.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-05-22 22:47:24 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2010-05-22 22:47:24 +0200
commitba5c0057ed01fb006b7a6fb1bd8c21f0c9ae12be (patch)
treebcbab1f5404ec81e6d5eef038ce4104a20866368 /filter/filter.c
parent6d04ef8987f6f5483d353d393ef66dae4b887f30 (diff)
downloadbird-ba5c0057ed01fb006b7a6fb1bd8c21f0c9ae12be.tar
bird-ba5c0057ed01fb006b7a6fb1bd8c21f0c9ae12be.zip
Extends pair set syntax, matching and deleting against clist.
Expressions like (123,*) can be used in pair set literals, clists can be matched against pair sets (community ~ pairset) and pair sets can be used to specify items to delete from clists (community.delete(pairset)).
Diffstat (limited to 'filter/filter.c')
-rw-r--r--filter/filter.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/filter/filter.c b/filter/filter.c
index 3230610..5492f80 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -230,6 +230,76 @@ val_simple_in_range(struct f_val v1, struct f_val v2)
return CMP_ERROR;
}
+static int
+clist_set_type(struct f_tree *set, struct f_val *v)
+{
+ switch (set->from.type) {
+ case T_PAIR:
+ v->type = T_PAIR;
+ return 1;
+ case T_QUAD:
+#ifndef IPV6
+ case T_IP:
+#endif
+ v->type = T_QUAD;
+ return 1;
+ break;
+ default:
+ v->type = T_VOID;
+ return 0;
+ }
+}
+
+static int
+clist_match_set(struct adata *clist, 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 struct adata *
+clist_del_matching(struct linpool *pool, struct adata *clist, struct f_tree *set)
+{
+ if (!clist)
+ return NULL;
+
+ struct f_val v;
+ clist_set_type(set, &v);
+
+ u32 tmp[clist->length/4];
+ u32 *l = (u32 *) clist->data;
+ u32 *k = tmp;
+ u32 *end = l + clist->length/4;
+
+ while (l < end) {
+ v.val.i = *l++;
+ if (!find_tree(set, v))
+ *k++ = v.val.i;
+ }
+
+ int nl = (k - tmp) * 4;
+ if (nl == clist->length)
+ return clist;
+
+ struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
+ res->length = nl;
+ memcpy(res->data, tmp, nl);
+ return res;
+}
+
/**
* val_in_range - implement |~| operator
* @v1: element
@@ -251,6 +321,9 @@ val_in_range(struct f_val v1, struct f_val v2)
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
return trie_match_prefix(v2.val.ti, &v1.val.px);
+ if ((v1.type == T_CLIST) && (v2.type == T_SET))
+ return clist_match_set(v1.val.ad, v2.val.t);
+
if (v2.type == T_SET)
switch (v1.type) {
case T_ENUM:
@@ -845,6 +918,7 @@ interpret(struct f_inst *what)
if (v1.type != T_CLIST)
runtime("Can't add/delete to non-clist");
+ struct f_val dummy;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
i = v2.val.i;
#ifndef IPV6
@@ -852,6 +926,8 @@ interpret(struct f_inst *what)
else if (v2.type == T_IP)
i = ipa_to_u32(v2.val.px.ip);
#endif
+ else if ((v2.type == T_SET) && (what->aux == 'd') && clist_set_type(v2.val.t, &dummy))
+ what->aux = 'D';
else
runtime("Can't add/delete non-pair");
@@ -859,6 +935,7 @@ interpret(struct f_inst *what)
switch (what->aux) {
case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, i); break;
case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, i); break;
+ case 'D': res.val.ad = clist_del_matching(f_pool, v1.val.ad, v2.val.t); break;
default: bug("unknown Ca operation");
}
break;