From ba5c0057ed01fb006b7a6fb1bd8c21f0c9ae12be Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 22 May 2010 22:47:24 +0200 Subject: [PATCH] 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)). --- doc/bird.sgml | 16 +++++++--- filter/config.Y | 8 ++++- filter/filter.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ filter/test.conf | 12 ++++---- 4 files changed, 103 insertions(+), 10 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 61ebc7a5..a6fa4df1 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -706,7 +706,8 @@ incompatible with each other (that is to prevent you from shooting in the foot). Filters recognize four types of sets. Sets are similar to strings: you can pass them around but you can't modify them. Literals of type int set look like [ 1, 2, 5..7 ]. As you can see, both simple values and ranges are permitted in - sets. + sets. For pair sets, expressions like ipaddress/pxlen{low,high}. @@ -777,9 +778,16 @@ incompatible with each other (that is to prevent you from shooting in the foot). no literals of this type. There are two special operators on clists: - add( adds pair (or quad) add( adds pair (or quad) delete( deletes pair (or quad) delete( deletes pair (or quad) + can be shortened to if Control structures diff --git a/filter/config.Y b/filter/config.Y index 77236586..0140c0c5 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -243,7 +243,13 @@ set_atom: ; set_item: - set_atom { + '(' NUM ',' '*' ')' { + $$ = f_new_tree(); + $$->from.type = $$->to.type = T_PAIR; + $$->from.val.i = make_pair($2, 0); + $$->to.val.i = make_pair($2, 0xffff); + } + | set_atom { $$ = f_new_tree(); $$->from = $1; $$->to = $1; diff --git a/filter/filter.c b/filter/filter.c index 32306101..5492f80d 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; diff --git a/filter/test.conf b/filter/test.conf index aca049c9..48143960 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -79,10 +79,11 @@ clist l; l = add( l, (1,2) ); l = add( l, (2,3) ); print "Community list (1,2) (2,3) ", l; - print "Should be true: ", (2,3) ~ l; - l = delete( l, (2,3) ); + print "Should be true: ", (2,3) ~ l, " ", l ~ [(1,*)], " ", l ~ [(2,3)]; + l = add( l, (2,5) ); + l = delete( l, [(2,*)] ); print "Community list (1,2) ", l; - print "Should be false: ", (2,3) ~ l; + print "Should be false: ", (2,3) ~ l, " ", l ~ [(2,*)]; } function bla() @@ -196,8 +197,9 @@ string s; ", true: ", RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE], ", false: ", RTS_BGP ~ [RTS_STATIC, RTS_DEVICE]; - ps = [(1,2), (3,4)..(3,8)]; - print "Testing pair set (TTF):", pp ~ ps, " ", (3,5) ~ ps, " ", (3,9) ~ ps; + ps = [(1,2), (3,4)..(4,8), (5,*)]; + print "Testing pair set, true: ", pp ~ ps, " ", (3,5) ~ ps, " ", (4,1) ~ ps, " ", (5,4) ~ ps, " ", (5,65535) ~ ps; + print "Testing pair set, false: ", (3,3) ~ ps, " ", (4,9) ~ ps, " ", (4,65535) ~ ps, " ", (6,0) ~ ps ; qq = 1.2.3.4; print "Testinq quad: 1.2.3.4 = ", qq,