diff options
Diffstat (limited to 'filter')
-rw-r--r-- | filter/config.Y | 7 | ||||
-rw-r--r-- | filter/f-util.c | 20 | ||||
-rw-r--r-- | filter/filter.c | 100 | ||||
-rw-r--r-- | filter/filter.h | 9 | ||||
-rw-r--r-- | filter/test.conf | 51 |
5 files changed, 163 insertions, 24 deletions
diff --git a/filter/config.Y b/filter/config.Y index 0166d27b..2e8b522e 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -259,6 +259,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, DEFINED, ADD, DELETE, CONTAINS, RESET, PREPEND, FIRST, LAST, MATCH, + ROA_CHECK, EMPTY, FILTER, WHERE, EVAL) @@ -495,7 +496,7 @@ pair_item: /* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */ if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4))) cf_error("syntax error"); - $$ = f_new_pair_item(pair_b($2), pair_b($4), $8, $10); + $$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10); } ; @@ -755,6 +756,9 @@ term: | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } + | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); } + | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } + /* | term '.' LEN { $$->code = P('P','l'); } */ /* function_call is inlined here */ @@ -801,7 +805,6 @@ print_list: /* EMPTY */ { $$ = NULL; } $$ = $1; } else $$ = $3; } - ; var_listn: term { diff --git a/filter/f-util.c b/filter/f-util.c index 9f2eb6b3..5908ac64 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -54,6 +54,24 @@ f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct return set_dyn; } + +struct f_inst * +f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn) +{ + struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check)); + ret->i.code = P('R','C'); + ret->i.lineno = ifs->conf_lino; + ret->i.arg1 = prefix; + ret->i.arg2 = asn; + /* prefix == NULL <-> asn == NULL */ + + if ((sym->class != SYM_ROA) || ! sym->def) + cf_error("%s is not a ROA table", sym->name); + ret->rtc = sym->def; + + return &ret->i; +} + char * filter_name(struct filter *filter) { @@ -61,6 +79,8 @@ filter_name(struct filter *filter) return "ACCEPT"; else if (filter == FILTER_REJECT) return "REJECT"; + else if (!filter->name) + return "(unnamed)"; else return filter->name; } diff --git a/filter/filter.c b/filter/filter.c index d6d338bf..acdcfd2b 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 @@ -245,7 +248,7 @@ val_simple_in_range(struct f_val v1, struct f_val v2) return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len); if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) - return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len) && (v1.val.px.len >= v2.val.px.len); + return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len); return CMP_ERROR; } @@ -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: @@ -1187,6 +1208,38 @@ interpret(struct f_inst *what) break; + case P('R','C'): /* ROA Check */ + if (what->arg1) + { + TWOARGS; + if ((v1.type != T_PREFIX) || (v2.type != T_INT)) + runtime("Invalid argument to roa_check()"); + + as = v2.val.i; + } + else + { + v1.val.px.ip = (*f_rte)->net->n.prefix; + v1.val.px.len = (*f_rte)->net->n.pxlen; + + /* We ignore temporary attributes, probably not a problem here */ + /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */ + eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02)); + + if (!e || e->type != EAF_TYPE_AS_PATH) + runtime("Missing AS_PATH attribute"); + + as_path_get_last(e->u.ptr, &as); + } + + struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc; + if (!rtc->table) + runtime("Missing ROA table"); + + res.type = T_ENUM_ROA; + res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as); + break; + default: bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); } @@ -1311,6 +1364,13 @@ i_same(struct f_inst *f1, struct f_inst *f2) case P('C','a'): TWOARGS; break; case P('a','f'): case P('a','l'): ONEARG; break; + case P('R','C'): + TWOARGS; + /* Does not really make sense - ROA check resuls may change anyway */ + if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, + ((struct f_inst_roa_check *) f2)->rtc->name)) + return 0; + break; default: bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); } diff --git a/filter/filter.h b/filter/filter.h index 2cf4652d..2386fc95 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -32,6 +32,12 @@ struct f_inst { /* Instruction */ #define arg1 a1.p #define arg2 a2.p +/* Not enough fields in f_inst for three args used by roa_check() */ +struct f_inst_roa_check { + struct f_inst i; + struct roa_table_config *rtc; +}; + struct f_prefix { ip_addr ip; int len; @@ -66,6 +72,8 @@ struct f_inst *f_new_inst(void); struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */ struct f_tree *f_new_tree(void); struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument); +struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn); + struct f_tree *build_tree(struct f_tree *); struct f_tree *find_tree(struct f_tree *t, struct f_val val); @@ -141,6 +149,7 @@ int tree_compare(const void *p1, const void *p2); #define T_ENUM_SCOPE 0x32 #define T_ENUM_RTC 0x33 #define T_ENUM_RTD 0x34 +#define T_ENUM_ROA 0x35 /* new enums go here */ #define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */ diff --git a/filter/test.conf b/filter/test.conf index 4f09637c..64e6d91b 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -52,12 +52,40 @@ function fifteen() return 15; } +roa table rl +{ + roa 10.110.0.0/16 max 16 as 1000; + roa 10.120.0.0/16 max 24 as 1000; + roa 10.130.0.0/16 max 24 as 2000; + roa 10.130.128.0/18 max 24 as 3000; +} + +function test_roa() +{ + # cannot be tested in __startup(), sorry + print "Testing ROA"; + print "Should be true: ", roa_check(rl, 10.10.0.0/16, 1000) = ROA_UNKNOWN, + " ", roa_check(rl, 10.0.0.0/8, 1000) = ROA_UNKNOWN, + " ", roa_check(rl, 10.110.0.0/16, 1000) = ROA_VALID, + " ", roa_check(rl, 10.110.0.0/16, 2000) = ROA_INVALID, + " ", roa_check(rl, 10.110.32.0/20, 1000) = ROA_INVALID, + " ", roa_check(rl, 10.120.32.0/20, 1000) = ROA_VALID; + print "Should be true: ", roa_check(rl, 10.120.32.0/20, 2000) = ROA_INVALID, + " ", roa_check(rl, 10.120.32.32/28, 1000) = ROA_INVALID, + " ", roa_check(rl, 10.130.130.0/24, 1000) = ROA_INVALID, + " ", roa_check(rl, 10.130.130.0/24, 2000) = ROA_VALID, + " ", roa_check(rl, 10.130.30.0/24, 3000) = ROA_INVALID, + " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID; +} + function paths() bgpmask pm1; bgpmask pm2; bgppath p2; clist l; +clist l2; eclist el; +eclist el2; { pm1 = / 4 3 2 1 /; pm2 = [= 4 3 2 1 =]; @@ -67,10 +95,10 @@ eclist el; p2 = prepend( p2, 3 ); p2 = prepend( p2, 4 ); print "Testing paths: ", p2; - print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2; + print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2; print "4 = ", p2.len; p2 = prepend( p2, 5 ); - print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2; + print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2; print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /; print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =]; print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4); @@ -108,6 +136,7 @@ eclist el; l = add( l, (3,3) ); l = add( l, (3,4) ); l = add( l, (3,5) ); + l2 = filter( l, [(3,*)] ); l = delete( l, [(3,2..4)] ); print "Community list (1,2) (3,1) (3,5) ", l; l = add( l, (3,2) ); @@ -120,6 +149,14 @@ eclist el; print "Community list (3,1) ", l; l = delete( l, [(*,(onef(5)))] ); print "Community list empty ", l; + l2 = add( l2, (3,6) ); + l = filter( l2, [(3,1..4)] ); + l2 = filter( l2, [(3,3..6)] ); + print "clist A (1..4): ", l; + print "clist B (3..6): ", l2; + print "clist A union B: ", add( l2, l ); + print "clist A isect B: ", filter( l, l2 ); + print "clist A \ B: ", delete( l, l2 ); el = -- empty --; el = add(el, (rt, 10, 20)); @@ -143,6 +180,16 @@ eclist el; print "EC list (rt, 10, 1) (rt, 10, 30): ", el; print "Testing EC list, true: ", (rt, 10, 1) ~ el, " ", el ~ [(rt, 10, ten..40)]; print "Testing EC list, false: ", (rt, 10, 20) ~ el, " ", (ro, 10.20.30.40, 100) ~ el, " ", el ~ [(rt, 10, 35..40)], " ", el ~ [(ro, 10, *)]; + el = add(el, (rt, 10, 40)); + el2 = filter(el, [(rt, 10, 20..40)] ); + el2 = add(el2, (rt, 10, 50)); + print "eclist A (1,30,40): ", el; + print "eclist B (30,40,50): ", el2; + print "eclist A union B: ", add( el2, el ); + print "eclist A isect B: ", filter( el, el2 ); + print "eclist A \ B: ", delete( el, el2 ); + +# test_roa(); } function bla() |