diff options
Diffstat (limited to 'filter')
-rw-r--r-- | filter/config.Y | 151 | ||||
-rw-r--r-- | filter/filter.c | 175 | ||||
-rw-r--r-- | filter/filter.h | 28 | ||||
-rw-r--r-- | filter/test.conf | 40 | ||||
-rw-r--r-- | filter/tree.c | 9 | ||||
-rw-r--r-- | filter/trie.c | 10 |
6 files changed, 352 insertions, 61 deletions
diff --git a/filter/config.Y b/filter/config.Y index 3eb5b08f..8af444a3 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -36,6 +36,7 @@ f_valid_set_type(int type) case T_ENUM: case T_IP: case T_EC: + case T_LC: return 1; default: @@ -66,6 +67,14 @@ f_merge_items(struct f_tree *a, struct f_tree *b) static inline struct f_tree * f_new_pair_item(int fa, int ta, int fb, int tb) { + check_u16(fa); + check_u16(ta); + check_u16(fb); + check_u16(tb); + + if ((ta < fa) || (tb < fb)) + cf_error( "From value cannot be higher that To value in pair sets"); + struct f_tree *t = f_new_tree(); t->right = t; t->from.type = t->to.type = T_PAIR; @@ -77,22 +86,26 @@ f_new_pair_item(int fa, int ta, int fb, int tb) static inline struct f_tree * f_new_pair_set(int fa, int ta, int fb, int tb) { - struct f_tree *lst = NULL; - int i; + check_u16(fa); + check_u16(ta); + check_u16(fb); + check_u16(tb); - if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF))) - return f_new_pair_item(fa, ta, fb, tb); - if ((ta < fa) || (tb < fb)) cf_error( "From value cannot be higher that To value in pair sets"); + struct f_tree *lst = NULL; + int i; + for (i = fa; i <= ta; i++) lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb)); return lst; } +#define CC_ALL 0xFFFF #define EC_ALL 0xFFFFFFFF +#define LC_ALL 0xFFFFFFFF static struct f_tree * f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) @@ -132,6 +145,17 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) return t; } +static struct f_tree * +f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) +{ + struct f_tree *t = f_new_tree(); + t->right = t; + t->from.type = t->to.type = T_LC; + t->from.val.lc = (lcomm) {f1, f2, f3}; + t->to.val.lc = (lcomm) {t1, t2, t3}; + return t; +} + static inline struct f_inst * f_generate_empty(struct f_inst *dyn) { @@ -148,6 +172,9 @@ f_generate_empty(struct f_inst *dyn) case EAF_TYPE_EC_SET: e->aux = T_ECLIST; break; + case EAF_TYPE_LC_SET: + e->aux = T_LCLIST; + break; default: cf_error("Can't empty that attribute"); } @@ -266,14 +293,44 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) return rv; } +static inline struct f_inst * +f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3) +{ + struct f_inst *rv; + + if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) { + if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) + cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); + + rv = f_new_inst(); + rv->code = 'C'; + + NEW_F_VAL; + rv->a1.p = val; + val->type = T_LC; + val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i }; + } + else + { + rv = cfg_allocz(sizeof(struct f_inst3)); + rv->lineno = ifs->lino; + rv->code = P('m','l'); + rv->a1.p = t1; + rv->a2.p = t2; + INST3(rv).p = t3; + } + + return rv; +} + CF_DECLS CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ACCEPT, REJECT, ERROR, QUITBIRD, - INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, - SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, + INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC, + SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, @@ -291,9 +348,9 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr %type <f> filter filter_body where_filter -%type <i> type break_command pair_expr ec_kind -%type <i32> pair_atom ec_expr -%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body +%type <i> type break_command ec_kind +%type <i32> cnum +%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body %type <trie> fprefix_set %type <v> set_atom switch_atom fipa %type <px> fprefix @@ -326,17 +383,20 @@ type: | PAIR { $$ = T_PAIR; } | QUAD { $$ = T_QUAD; } | EC { $$ = T_EC; } + | LC { $$ = T_LC; } | STRING { $$ = T_STRING; } | BGPMASK { $$ = T_PATH_MASK; } | BGPPATH { $$ = T_PATH; } | CLIST { $$ = T_CLIST; } | ECLIST { $$ = T_ECLIST; } - | type SET { + | LCLIST { $$ = T_LCLIST; } + | type SET { switch ($1) { case T_INT: case T_PAIR: case T_QUAD: case T_EC: + case T_LC: case T_IP: $$ = T_SET; break; @@ -445,7 +505,7 @@ function_def: } function_params function_body { $2->def = $5; $2->aux2 = $4; - DBG("Hmm, we've got one function here - %s\n", $2->name); + DBG("Hmm, we've got one function here - %s\n", $2->name); cf_pop_scope(); } ; @@ -511,30 +571,23 @@ switch_atom: | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } ; -pair_expr: - term { $$ = f_eval_int($1); check_u16($$); } - -pair_atom: - pair_expr { $$ = pair($1, $1); } - | pair_expr DDOT pair_expr { $$ = pair($1, $3); } - | '*' { $$ = 0xFFFF; } - ; +cnum: + term { $$ = f_eval_int($1); } pair_item: - '(' pair_atom ',' pair_atom ')' { - $$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4)); - } - | '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' { - /* 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), $8, pair_b($4), $10); - } + '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } + | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); } + | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); } + | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); } + | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); } + | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); } + | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); } + | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); } + | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); } + | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')' + { $$ = f_new_pair_item($2, $8, $4, $10); } ; -ec_expr: - term { $$ = f_eval_int($1); } - ec_kind: RT { $$ = EC_RT; } | RO { $$ = EC_RO; } @@ -543,14 +596,27 @@ ec_kind: ; ec_item: - '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } - | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } - | '(' ec_kind ',' ec_expr ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } - ; + '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } + | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } + | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } + ; + +lc_item: + '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); } + | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); } + | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); } + | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); } + | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); } + | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); } + | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); } + | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')' + { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } +; set_item: pair_item | ec_item + | lc_item | set_atom { $$ = f_new_item($1, $1); } | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } ; @@ -558,6 +624,7 @@ set_item: switch_item: pair_item | ec_item + | lc_item | switch_atom { $$ = f_new_item($1, $1); } | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } ; @@ -608,7 +675,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } /* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ bgp_path_expr: - symbol { $$ = $1; } + symbol { $$ = $1; } | '(' term ')' { $$ = $2; } ; @@ -648,6 +715,7 @@ constant: constructor: '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } + | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } ; @@ -758,8 +826,9 @@ term: | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } - | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } - | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; } + | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } + | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } | 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'; } @@ -814,7 +883,7 @@ print_list: /* EMPTY */ { $$ = NULL; } } ; -var_listn: term { +var_listn: term { $$ = f_new_inst(); $$->code = 's'; $$->a1.p = NULL; @@ -882,7 +951,7 @@ cmd: $$ = f_new_inst(); $$->code = P('P','S'); $$->a1.p = $3; - } + } | UNSET '(' rtadot dynamic_attr ')' ';' { $$ = $4; $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; diff --git a/filter/filter.c b/filter/filter.c index 3282bd50..09b89401 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -99,6 +99,18 @@ pm_format(struct f_path_mask *p, buffer *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 @@ -138,6 +150,8 @@ val_compare(struct f_val v1, struct f_val v2) return uint_cmp(v1.val.i, v2.val.i); case T_EC: 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: @@ -201,6 +215,7 @@ val_same(struct f_val v1, struct f_val v2) 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); @@ -241,6 +256,10 @@ static inline int eclist_set_type(struct f_tree *set) { return set->from.type == T_EC; } +static inline int +lclist_set_type(struct f_tree *set) +{ return set->from.type == T_LC; } + static int clist_match_set(struct adata *clist, struct f_tree *set) { @@ -286,6 +305,30 @@ eclist_match_set(struct adata *list, struct f_tree *set) return 0; } +static int +lclist_match_set(struct adata *list, 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 struct adata * clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) { @@ -312,7 +355,7 @@ clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos *k++ = v.val.i; } - int nl = (k - tmp) * 4; + uint nl = (k - tmp) * sizeof(u32); if (nl == list->length) return list; @@ -346,7 +389,39 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po } } - int nl = (k - tmp) * 4; + 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 struct adata * +lclist_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); + 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; @@ -381,6 +456,9 @@ val_in_range(struct f_val v1, struct f_val v2) 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); @@ -407,6 +485,9 @@ val_in_range(struct f_val v1, struct f_val v2) 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); @@ -431,12 +512,14 @@ val_format(struct f_val v, buffer *buf) 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_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; } @@ -628,6 +711,7 @@ interpret(struct f_inst *what) runtime("Can't operate with value of non-integer type in EC constructor"); val = v2.val.i; + /* XXXX */ res.type = T_EC; if (what->aux == EC_GENERIC) { @@ -649,6 +733,24 @@ interpret(struct f_inst *what) break; } + case P('m','l'): + { + TWOARGS; + + /* Third argument hack */ + struct f_val v3 = interpret(INST3(what).p); + if (v3.type & T_RETURN) + return v3; + + if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT)) + runtime( "Can't operate with value of non-integer type in LC constructor" ); + + res.type = T_LC; + res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i }; + + break; + } + /* Relational operators */ #define COMPARE(x) \ @@ -883,6 +985,13 @@ interpret(struct f_inst *what) break; } + /* The same special case for lc_set */ + if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) { + res.type = T_LCLIST; + res.val.ad = adata_empty(f_pool, 0); + break; + } + /* Undefined value */ res.type = T_VOID; break; @@ -922,6 +1031,10 @@ interpret(struct f_inst *what) res.type = T_ECLIST; res.val.ad = e->u.ptr; break; + case EAF_TYPE_LC_SET: + res.type = T_LCLIST; + res.val.ad = e->u.ptr; + break; case EAF_TYPE_UNDEF: res.type = T_VOID; break; @@ -1010,6 +1123,11 @@ interpret(struct f_inst *what) runtime( "Setting eclist attribute to non-eclist value" ); l->attrs[0].u.ptr = v1.val.ad; break; + case EAF_TYPE_LC_SET: + if (v1.type != T_LCLIST) + runtime( "Setting lclist attribute to non-lclist value" ); + l->attrs[0].u.ptr = v1.val.ad; + break; case EAF_TYPE_UNDEF: if (v1.type != T_VOID) runtime( "Setting void attribute to non-void value" ); @@ -1051,6 +1169,7 @@ interpret(struct f_inst *what) case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break; case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break; + case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break; default: runtime( "Prefix, path, clist or eclist expected" ); } break; @@ -1240,7 +1359,7 @@ interpret(struct f_inst *what) else if (v2.type == T_ECLIST) arg_set = 2; else if (v2.type != T_EC) - runtime("Can't add/delete non-pair"); + runtime("Can't add/delete non-ec"); res.type = T_ECLIST; switch (what->aux) @@ -1271,8 +1390,50 @@ interpret(struct f_inst *what) bug("unknown Ca operation"); } } + else if (v1.type == T_LCLIST) + { + /* Large community list */ + int arg_set = 0; + + /* v2.val is either LC or LC-set */ + if ((v2.type == T_SET) && lclist_set_type(v2.val.t)) + arg_set = 1; + else if (v2.type == T_LCLIST) + arg_set = 2; + else if (v2.type != T_LC) + runtime("Can't add/delete non-lc"); + + res.type = T_LCLIST; + switch (what->aux) + { + case 'a': + if (arg_set == 1) + runtime("Can't add set"); + else if (!arg_set) + res.val.ad = lc_set_add(f_pool, v1.val.ad, v2.val.lc); + else + res.val.ad = lc_set_union(f_pool, v1.val.ad, v2.val.ad); + break; + + case 'd': + if (!arg_set) + res.val.ad = lc_set_del(f_pool, v1.val.ad, v2.val.lc); + else + res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 0); + break; + + case 'f': + if (!arg_set) + runtime("Can't filter lc"); + res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 1); + break; + + default: + bug("unknown Ca operation"); + } + } else - runtime("Can't add/delete to non-(e)clist"); + runtime("Can't add/delete to non-[e|l]clist"); break; @@ -1370,6 +1531,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) case '~': TWOARGS; break; case P('d','e'): ONEARG; break; + case P('m','l'): + TWOARGS; + if (!i_same(INST3(f1).p, INST3(f2).p)) + return 0; + break; + case 's': ARG(v2, a2.p); { diff --git a/filter/filter.h b/filter/filter.h index af490121..fc11b91e 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -38,6 +38,17 @@ struct f_inst_roa_check { struct rtable_config *rtc; }; +struct f_inst3 { + struct f_inst i; + union { + int i; + void *p; + } a3; +}; + +#define INST3(x) (((struct f_inst3 *) x)->a3) + + struct f_prefix { net_addr net; u8 lo, hi; @@ -48,6 +59,7 @@ struct f_val { union { uint i; u64 ec; + lcomm lc; ip_addr ip; const net_addr *net; char *s; @@ -146,8 +158,10 @@ void val_format(struct f_val v, buffer *buf); #define T_PATH_MASK 0x23 /* mask for BGP path */ #define T_PATH 0x24 /* BGP path */ #define T_CLIST 0x25 /* Community list */ -#define T_ECLIST 0x26 /* Extended community list */ -#define T_EC 0x27 /* Extended community value, u64 */ +#define T_EC 0x26 /* Extended community value, u64 */ +#define T_ECLIST 0x27 /* Extended community list */ +#define T_LC 0x28 /* Large community value, lcomm */ +#define T_LCLIST 0x29 /* Large community list */ #define T_RETURN 0x40 #define T_SET 0x80 @@ -160,10 +174,10 @@ void val_format(struct f_val v, buffer *buf); #define SA_PROTO 4 #define SA_SOURCE 5 #define SA_SCOPE 6 -#define SA_CAST 7 -#define SA_DEST 8 -#define SA_IFNAME 9 -#define SA_IFINDEX 10 +#define SA_CAST 7 +#define SA_DEST 8 +#define SA_IFNAME 9 +#define SA_IFINDEX 10 struct f_tree { @@ -175,7 +189,7 @@ struct f_tree { struct f_trie_node { ip_addr addr, mask, accept; - int plen; + uint plen; struct f_trie_node *c[2]; }; diff --git a/filter/test.conf b/filter/test.conf index a8c3a508..e65b3ebb 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -31,6 +31,11 @@ function 'mkpair-a'(int a) return (1, a); } +function mktrip(int a) +{ + return (a, 2*a, 3*a); +} + function mkpath(int a; int b) { return [= a b 3 2 1 =]; @@ -95,6 +100,8 @@ clist l; clist l2; eclist el; eclist el2; +lclist ll; +lclist ll2; { print "Entering path test..."; pm1 = / 4 3 2 1 /; @@ -160,7 +167,7 @@ eclist el2; print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len; l = add( l, (3,2) ); l = add( l, (4,5) ); - print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l, " len: ", l.len; + print "Community list (1,2) (3,1) (3,5) (3,2) (4,5) ", l, " len: ", l.len; print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)]; print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))]; l = delete( l, [(*,(one+onef(3)))] ); @@ -175,7 +182,7 @@ eclist el2; 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 ); + print "clist A \ B: ", delete( l, l2 ); el = -- empty --; el = add(el, (rt, 10, 20)); @@ -207,7 +214,34 @@ eclist el2; 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 ); + print "eclist A \ B: ", delete( el, el2 ); + + ll = --- empty ---; + ll = add(ll, (ten, 20, 30)); + ll = add(ll, (1000, 2000, 3000)); + ll = add(ll, mktrip(100000)); + print "LC list (10, 20, 30) (1000, 2000, 3000) (100000, 200000, 300000):"; + print ll; + print "LC len: ", el.len; + print "Should be true: ", mktrip(1000) ~ ll, " ", ll ~ [(5,10,15), (10,20,30)], " ", ll ~ [(10,15..25,*)], " ", ll ~ [(ten, *, *)]; + print "Should be false: ", mktrip(100) ~ ll, " ", ll ~ [(5,10,15), (10,21,30)], " ", ll ~ [(10,21..25,*)], " ", ll ~ [(11, *, *)]; + print "LC filtered: ", filter(ll, [(5..15, *, *), (100000, 500..500000, *)]); + + ll = --- empty ---; + ll = add(ll, (10, 10, 10)); + ll = add(ll, (20, 20, 20)); + ll = add(ll, (30, 30, 30)); + + ll2 = --- empty ---; + ll2 = add(ll2, (20, 20, 20)); + ll2 = add(ll2, (30, 30, 30)); + ll2 = add(ll2, (40, 40, 40)); + + print "lclist A (10,20,30): ", ll; + print "lclist B (20,30,40): ", ll2; + print "lclist A union B: ", add(ll, ll2); + print "lclist A isect B: ", filter(ll, ll2); + print "lclist A \ B: ", delete(ll, ll2); # test_roa(); } diff --git a/filter/tree.c b/filter/tree.c index 328c7184..f8379fa8 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -63,7 +63,7 @@ tree_compare(const void *p1, const void *p2) * build_tree * @from: degenerated tree (linked by @tree->left) to be transformed into form suitable for find_tree() * - * Transforms denerated tree into balanced tree. + * Transforms degenerated tree into balanced tree. */ struct f_tree * build_tree(struct f_tree *from) @@ -162,12 +162,15 @@ void tree_format(struct f_tree *t, buffer *buf) { buffer_puts(buf, "["); - + tree_node_format(t, buf); + if (buf->pos == buf->end) + return; + /* Undo last separator */ if (buf->pos[-1] != '[') buf->pos -= 2; - + buffer_puts(buf, "]"); } diff --git a/filter/trie.c b/filter/trie.c index dad87339..adcfcdf3 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -220,7 +220,7 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h) } static int -trie_match_prefix(struct f_trie *t, ip_addr px, int plen) +trie_match_prefix(struct f_trie *t, ip_addr px, uint plen) { ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); @@ -266,7 +266,8 @@ trie_match_prefix(struct f_trie *t, ip_addr px, int plen) int trie_match_net(struct f_trie *t, const net_addr *n) { - int add = 0; + uint add = 0; + switch (n->type) { case NET_IP4: case NET_VPN4: @@ -333,9 +334,12 @@ trie_format(struct f_trie *t, buffer *buf) buffer_puts(buf, "["); if (t->zero) - buffer_print(buf, "%I/%d", IPA_NONE, 0); + buffer_print(buf, "%I/%d, ", IPA_NONE, 0); trie_node_format(t->root, buf); + if (buf->pos == buf->end) + return; + /* Undo last separator */ if (buf->pos[-1] != '[') buf->pos -= 2; |