diff options
Diffstat (limited to 'filter/filter.c')
-rw-r--r-- | filter/filter.c | 59 |
1 files changed, 40 insertions, 19 deletions
diff --git a/filter/filter.c b/filter/filter.c index d6d338bf..a087c50b 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -228,6 +228,9 @@ val_simple_in_range(struct f_val v1, 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_is_member(v2.val.ad, v1.val.i); + if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) return int_set_contains(v2.val.ad, v1.val.i); #ifndef IPV6 @@ -320,28 +323,34 @@ eclist_match_set(struct adata *list, struct f_tree *set) } static struct adata * -clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int pos) +clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) { - if (!clist) + if (!list) return NULL; + int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */ struct f_val v; - clist_set_type(set, &v); + if (tree) + clist_set_type(set.val.t, &v); + else + v.type = T_PAIR; - u32 tmp[clist->length/4]; - u32 *l = (u32 *) clist->data; + int len = int_set_get_size(list); + u32 *l = int_set_get_data(list); + u32 tmp[len]; u32 *k = tmp; - u32 *end = l + clist->length/4; + u32 *end = l + len; while (l < end) { v.val.i = *l++; - if (pos == !!find_tree(set, v)) /* pos && find_tree || !pos && !find_tree */ + /* 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; } int nl = (k - tmp) * 4; - if (nl == clist->length) - return clist; + if (nl == list->length) + return list; struct adata *res = adata_empty(pool, nl); memcpy(res->data, tmp, nl); @@ -349,11 +358,12 @@ clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int } static struct adata * -eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int pos) +eclist_filter(struct linpool *pool, struct adata *list, 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); @@ -365,7 +375,8 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int v.type = T_EC; for (i = 0; i < len; i += 2) { v.val.ec = ec_get(l, i); - if (pos == !!find_tree(set, v)) { /* pos && find_tree || !pos && !find_tree */ + /* 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]; } @@ -1116,6 +1127,8 @@ interpret(struct f_inst *what) #endif else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy)) arg_set = 1; + else if (v2.type == T_CLIST) + arg_set = 2; else runtime("Can't add/delete non-pair"); @@ -1123,22 +1136,25 @@ interpret(struct f_inst *what) switch (what->aux) { case 'a': - if (arg_set) + if (arg_set == 1) runtime("Can't add set"); - res.val.ad = int_set_add(f_pool, v1.val.ad, i); + else if (!arg_set) + res.val.ad = int_set_add(f_pool, v1.val.ad, i); + else + res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) res.val.ad = int_set_del(f_pool, v1.val.ad, i); else - res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0); + res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0); break; case 'f': if (!arg_set) runtime("Can't filter pair"); - res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1); + res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1); break; default: @@ -1153,6 +1169,8 @@ interpret(struct f_inst *what) /* v2.val is either EC or EC-set */ if ((v2.type == T_SET) && eclist_set_type(v2.val.t)) arg_set = 1; + else if (v2.type == T_ECLIST) + arg_set = 2; else if (v2.type != T_EC) runtime("Can't add/delete non-pair"); @@ -1160,22 +1178,25 @@ interpret(struct f_inst *what) switch (what->aux) { case 'a': - if (arg_set) + if (arg_set == 1) runtime("Can't add set"); - res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec); + else if (!arg_set) + res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec); + else + res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad); break; case 'd': if (!arg_set) res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec); else - res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 0); + res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0); break; case 'f': if (!arg_set) runtime("Can't filter ec"); - res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 1); + res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1); break; default: |