diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2013-11-23 11:50:34 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2013-11-23 11:50:34 +0100 |
commit | 736e143fa50607fcd88132291e96089b899af979 (patch) | |
tree | c0fcd5fb3174bae8a39b3a32dfe582b2ccb6df17 /filter | |
parent | 094d2bdb79e1ffa0a02761fd651aa0f0b6b0c585 (diff) | |
parent | 2b3d52aa421ae1c31e30107beefd82fddbb42854 (diff) |
Merge branch 'master' into add-path
Conflicts:
filter/filter.c
nest/proto.c
nest/rt-table.c
proto/bgp/bgp.h
proto/bgp/config.Y
Diffstat (limited to 'filter')
-rw-r--r-- | filter/config.Y | 73 | ||||
-rw-r--r-- | filter/filter.c | 510 | ||||
-rw-r--r-- | filter/filter.h | 22 | ||||
-rw-r--r-- | filter/test.conf | 56 | ||||
-rw-r--r-- | filter/tree.c | 39 | ||||
-rw-r--r-- | filter/trie.c | 38 |
6 files changed, 430 insertions, 308 deletions
diff --git a/filter/config.Y b/filter/config.Y index 0eeb2ce1..04acfbab 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -193,7 +193,14 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) else if (tk->code == 'C') { c1 = 1; struct f_val *val = tk->a1.p; - if (val->type == T_IP) { + + if (val->type == T_INT) { + ipv4_used = 0; key = val->val.i; + } + else if (val->type == T_QUAD) { + ipv4_used = 1; key = val->val.i; + } + else if (val->type == T_IP) { ipv4_used = 1; key = ipa_to_u32(val->val.px.ip); } else @@ -254,7 +261,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, IF, THEN, ELSE, CASE, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, - FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE, + FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, + PREFERENCE, LEN, DEFINED, ADD, DELETE, CONTAINS, RESET, @@ -329,8 +337,8 @@ type: one_decl: type SYM { - struct f_val * val = cfg_alloc(sizeof(struct f_val)); - val->type = $1; + struct f_val * val = cfg_alloc(sizeof(struct f_val)); + val->type = T_VOID; $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); DBG( "New variable %s type %x\n", $2->name, $1 ); $2->aux2 = NULL; @@ -661,49 +669,28 @@ function_call: symbol: SYM { $$ = f_new_inst(); - switch ($1->class) { - case SYM_NUMBER: - $$ = f_new_inst(); - $$->code = 'c'; - $$->aux = T_INT; - $$->a2.i = $1->aux; - break; - case SYM_IPA: - { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.px.ip = * (ip_addr *) ($1->def); } - break; - case SYM_VARIABLE | T_BOOL: - case SYM_VARIABLE | T_INT: - case SYM_VARIABLE | T_PAIR: - case SYM_VARIABLE | T_QUAD: - case SYM_VARIABLE | T_EC: - case SYM_VARIABLE | T_STRING: - case SYM_VARIABLE | T_IP: - case SYM_VARIABLE | T_PREFIX: - case SYM_VARIABLE | T_PREFIX_SET: - case SYM_VARIABLE | T_SET: - case SYM_VARIABLE | T_PATH: - case SYM_VARIABLE | T_PATH_MASK: - case SYM_VARIABLE | T_CLIST: - case SYM_VARIABLE | T_ECLIST: - $$->code = 'V'; - $$->a1.p = $1->def; - $$->a2.p = $1->name; - break; - default: - cf_error("%s: variable expected.", $1->name ); + + switch ($1->class & 0xff00) { + case SYM_CONSTANT: $$->code = 'C'; break; + case SYM_VARIABLE: $$->code = 'V'; break; + default: cf_error("%s: variable expected.", $1->name); } + + $$->a1.p = $1->def; + $$->a2.p = $1->name; } static_attr: - FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); $$->a1.i = 1; } - - | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); $$->a1.i = 1; } - | NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ } - | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = 0x12345678; /* T_STRING is also special-cased. */ } - | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); } - | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope); $$->a1.i = 1; } - | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = OFFSETOF(struct rta, cast); } - | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = OFFSETOF(struct rta, dest); $$->a1.i = 1; } + FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; } + | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; } + | NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = SA_NET; } + | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; } + | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; } + | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; } + | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; } + | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; } + | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; } + | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; } ; term: diff --git a/filter/filter.c b/filter/filter.c index 7c883fff..ed8efd54 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -58,79 +58,54 @@ adata_empty(struct linpool *pool, int l) return res; } -static int -pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2) -{ - while (1) { - if ((!m1) || (!m2)) - return !((!m1) && (!m2)); - - /* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */ - if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1; - m1 = m1->next; - m2 = m2->next; - } -} - -u32 f_eval_asn(struct f_inst *expr); - static void -pm_format(struct f_path_mask *p, byte *buf, unsigned int size) +pm_format(struct f_path_mask *p, buffer *buf) { - byte *end = buf + size - 16; + buffer_puts(buf, "[= "); while (p) + { + switch(p->kind) { - if (buf > end) - { - strcpy(buf, " ..."); - return; - } - - switch(p->kind) - { - case PM_ASN: - buf += bsprintf(buf, " %u", p->val); - break; - - case PM_QUESTION: - buf += bsprintf(buf, " ?"); - break; + case PM_ASN: + buffer_print(buf, "%u ", p->val); + break; - case PM_ASTERISK: - buf += bsprintf(buf, " *"); - break; + case PM_QUESTION: + buffer_puts(buf, "? "); + break; - case PM_ASN_EXPR: - buf += bsprintf(buf, " %u", f_eval_asn((struct f_inst *) p->val)); - break; - } + case PM_ASTERISK: + buffer_puts(buf, "* "); + break; - p = p->next; + case PM_ASN_EXPR: + buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val)); + break; } - *buf = 0; + p = p->next; + } + + buffer_puts(buf, "=]"); } -static inline int int_cmp(int i1, int i2) +static inline int +int_cmp(int i1, int i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (i1 > i2) - (i1 < i2); } -static inline int uint_cmp(unsigned int i1, unsigned int i2) +static inline int +uint_cmp(uint i1, uint i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (int)(i1 > i2) - (int)(i1 < i2); } -static inline int u64_cmp(u64 i1, u64 i2) +static inline int +u64_cmp(u64 i1, u64 i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (int)(i1 > i2) - (int)(i1 < i2); } /** @@ -138,23 +113,21 @@ static inline int u64_cmp(u64 i1, u64 i2) * @v1: first value * @v2: second value * - * Compares two values and returns -1, 0, 1 on <, =, > or 999 on error. - * Tree module relies on this giving consistent results so that it can - * build balanced trees. + * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on + * error. Tree module relies on this giving consistent results so + * that it can be used for building balanced trees. */ int val_compare(struct f_val v1, struct f_val v2) { int rc; - if ((v1.type == T_VOID) && (v2.type == T_VOID)) - return 0; - if (v1.type == T_VOID) /* Hack for else */ - return -1; - if (v2.type == T_VOID) - return 1; - if (v1.type != v2.type) { + if (v1.type == T_VOID) /* Hack for else */ + return -1; + if (v2.type == T_VOID) + return 1; + #ifndef IPV6 /* IP->Quad implicit conversion */ if ((v1.type == T_QUAD) && (v2.type == T_IP)) @@ -166,7 +139,10 @@ val_compare(struct f_val v1, struct f_val v2) debug( "Types do not match in val_compare\n" ); return CMP_ERROR; } + switch (v1.type) { + case T_VOID: + return 0; case T_ENUM: case T_INT: case T_BOOL: @@ -181,25 +157,63 @@ val_compare(struct f_val v1, struct f_val v2) case T_PREFIX: if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip)) return rc; - if (v1.val.px.len < v2.val.px.len) - return -1; - if (v1.val.px.len > v2.val.px.len) - return 1; - return 0; - case T_PATH_MASK: - return pm_path_compare(v1.val.path_mask, v2.val.path_mask); + return int_cmp(v1.val.px.len, v2.val.px.len); case T_STRING: return strcmp(v1.val.s, v2.val.s); default: - debug( "Compare of unknown entities: %x\n", v1.type ); return CMP_ERROR; } } -int -tree_compare(const void *p1, const void *p2) +static int +pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2) { - return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); + while (m1 && m2) + { + if ((m1->kind != m2->kind) || (m1->val != m2->val)) + return 0; + + m1 = m1->next; + m2 = m2->next; + } + + return !m1 && !m2; +} + +/** + * val_same - compare two values + * @v1: first value + * @v2: second value + * + * Compares two values and returns 1 if they are same and 0 if not. + * Comparison of values of different types is valid and returns 0. + */ +int +val_same(struct f_val v1, struct f_val v2) +{ + int rc; + + rc = val_compare(v1, v2); + if (rc != CMP_ERROR) + return !rc; + + if (v1.type != v2.type) + return 0; + + switch (v1.type) { + case T_PATH_MASK: + return pm_path_same(v1.val.path_mask, v2.val.path_mask); + case T_PATH: + case T_CLIST: + case T_ECLIST: + return adata_same(v1.val.ad, v2.val.ad); + case T_SET: + return same_tree(v1.val.t, v2.val.t); + case T_PREFIX_SET: + return trie_same(v1.val.ti, v2.val.ti); + default: + bug("Invalid type in val_same(): %x", v1.type); + } } void @@ -220,39 +234,6 @@ fprefix_get_bounds(struct f_prefix *px, int *l, int *h) } } -/* - * val_simple_in_range - check if @v1 ~ @v2 for everything except sets - */ -static int -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 - /* IP->Quad implicit conversion */ - if ((v1.type == T_IP) && (v2.type == T_CLIST)) - return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); -#endif - if ((v1.type == T_EC) && (v2.type == T_ECLIST)) - return ec_set_contains(v2.val.ad, v1.val.ec); - - if ((v1.type == T_STRING) && (v2.type == T_STRING)) - return patmatch(v2.val.s, v1.val.s); - - if ((v1.type == T_IP) && (v2.type == T_PREFIX)) - 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 net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len); - - return CMP_ERROR; -} - static int clist_set_type(struct f_tree *set, struct f_val *v) { @@ -396,103 +377,86 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po * @v1: element * @v2: set * - * Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see - * |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early). + * Checks if @v1 is element (|~| operator) of @v2. */ static int val_in_range(struct f_val v1, struct f_val v2) { - int res; + if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) + return as_path_match(v1.val.ad, v2.val.path_mask); - res = val_simple_in_range(v1, v2); + if ((v1.type == T_INT) && (v2.type == T_PATH)) + return as_path_contains(v2.val.ad, v1.val.i, 1); - if (res != CMP_ERROR) - return res; - - if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET)) - return trie_match_fprefix(v2.val.ti, &v1.val.px); + 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 + /* IP->Quad implicit conversion */ + if ((v1.type == T_IP) && (v2.type == T_CLIST)) + return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); +#endif - if ((v1.type == T_CLIST) && (v2.type == T_SET)) - return clist_match_set(v1.val.ad, v2.val.t); + if ((v1.type == T_EC) && (v2.type == T_ECLIST)) + return ec_set_contains(v2.val.ad, v1.val.ec); - if ((v1.type == T_ECLIST) && (v2.type == T_SET)) - return eclist_match_set(v1.val.ad, v2.val.t); + if ((v1.type == T_STRING) && (v2.type == T_STRING)) + return patmatch(v2.val.s, v1.val.s); - if (v2.type == T_SET) - switch (v1.type) { - case T_ENUM: - case T_INT: - case T_PAIR: - case T_QUAD: - case T_IP: - case T_EC: - { - struct f_tree *n; - n = find_tree(v2.val.t, v1); - if (!n) - return 0; - return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */ - } - } - return CMP_ERROR; -} + if ((v1.type == T_IP) && (v2.type == T_PREFIX)) + return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len); -static void val_print(struct f_val v); + if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) + return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len); -static void -tree_node_print(struct f_tree *t, char **sep) -{ - if (t == NULL) - return; + if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET)) + return trie_match_fprefix(v2.val.ti, &v1.val.px); - tree_node_print(t->left, sep); + if (v2.type != T_SET) + return CMP_ERROR; - logn(*sep); - val_print(t->from); - if (val_compare(t->from, t->to) != 0) - { - logn( ".." ); - val_print(t->to); - } - *sep = ", "; + /* With integrated Quad<->IP implicit conversion */ + if ((v1.type == v2.val.t->from.type) || + ((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP))) + return !!find_tree(v2.val.t, v1); - tree_node_print(t->right, sep); -} + if (v1.type == T_CLIST) + return clist_match_set(v1.val.ad, v2.val.t); -static void -tree_print(struct f_tree *t) -{ - char *sep = ""; - logn( "[" ); - tree_node_print(t, &sep); - logn( "] " ); + if (v1.type == T_ECLIST) + return eclist_match_set(v1.val.ad, v2.val.t); + + if (v1.type == T_PATH) + return as_path_match_set(v1.val.ad, v2.val.t); + + return CMP_ERROR; } /* - * val_print - format filter value + * val_format - format filter value */ -static void -val_print(struct f_val v) +void +val_format(struct f_val v, buffer *buf) { char buf2[1024]; - switch (v.type) { - case T_VOID: logn("(void)"); return; - case T_BOOL: logn(v.val.i ? "TRUE" : "FALSE"); return; - case T_INT: logn("%d", v.val.i); return; - case T_STRING: logn("%s", v.val.s); return; - case T_IP: logn("%I", v.val.px.ip); return; - case T_PREFIX: logn("%I/%d", v.val.px.ip, v.val.px.len); return; - case T_PAIR: logn("(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return; - case T_QUAD: logn("%R", v.val.i); return; - case T_EC: ec_format(buf2, v.val.ec); logn("%s", buf2); return; - case T_PREFIX_SET: trie_print(v.val.ti); return; - case T_SET: tree_print(v.val.t); return; - case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); return; - case T_PATH: as_path_format(v.val.ad, buf2, 1000); logn("(path %s)", buf2); return; - case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); logn("(clist %s)", buf2); return; - case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); logn("(eclist %s)", buf2); return; - case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1000); logn("(pathmask%s)", buf2); return; - default: logn( "[unknown type %x]", v.type ); return; + switch (v.type) + { + case T_VOID: buffer_puts(buf, "(void)"); return; + case T_BOOL: buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return; + case T_INT: buffer_print(buf, "%d", v.val.i); return; + case T_STRING: buffer_print(buf, "%s", v.val.s); return; + case T_IP: buffer_print(buf, "%I", v.val.px.ip); return; + case T_PREFIX: buffer_print(buf, "%I/%d", v.val.px.ip, v.val.px.len); return; + case T_PAIR: buffer_print(buf, "(%d,%d)", 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_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)%d", 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_PATH_MASK: pm_format(v.val.path_mask, buf); return; + default: buffer_print(buf, "[unknown type %x]", v.type); return; } } @@ -500,6 +464,7 @@ static struct rte **f_rte; static struct rta *f_old_rta; static struct ea_list **f_tmp_attrs; static struct linpool *f_pool; +static struct buffer f_buf; static int f_flags; static inline void f_rte_cow(void) @@ -555,6 +520,8 @@ static struct rate_limit rl_runtime_err; #define TWOARGS_C TWOARGS \ if (v1.type != v2.type) \ runtime( "Can't operate with values of incompatible types" ); +#define ACCESS_RTE \ + do { if (!f_rte) runtime("No route to access"); } while (0) /** * interpret @@ -622,9 +589,6 @@ interpret(struct f_inst *what) case T_VOID: runtime( "Can't operate with values of type void" ); case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); res.val.i = v1.val.i / v2.val.i; break; - case T_IP: if (v2.type != T_INT) - runtime( "Incompatible types in / operator" ); - break; default: runtime( "Usage of unknown type" ); } break; @@ -717,8 +681,15 @@ interpret(struct f_inst *what) res.val.i = (x); \ break; - case P('!','='): COMPARE(i!=0); - case P('=','='): COMPARE(i==0); +#define SAME(x) \ + TWOARGS; \ + i = val_same(v1, v2); \ + res.type = T_BOOL; \ + res.val.i = (x); \ + break; + + case P('!','='): SAME(!i); + case P('=','='): SAME(i); case '<': COMPARE(i==-1); case P('<','='): COMPARE(i!=1); @@ -782,7 +753,7 @@ interpret(struct f_inst *what) break; case 'p': ONEARG; - val_print(v1); + val_format(v1, &f_buf); break; case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ ONEARG; @@ -800,7 +771,7 @@ interpret(struct f_inst *what) case P('p',','): ONEARG; if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) - log_commit(*L_INFO); + log_commit(*L_INFO, &f_buf); switch (what->a2.i) { case F_QUITBIRD: @@ -821,62 +792,83 @@ interpret(struct f_inst *what) break; case 'a': /* rta access */ { + ACCESS_RTE; struct rta *rta = (*f_rte)->attrs; res.type = what->aux; - switch(res.type) { - case T_IP: - res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i); - break; - case T_ENUM: - res.val.i = * ((char *) rta + what->a2.i); - break; - case T_STRING: /* Warning: this is a special case for proto attribute */ - res.val.s = rta->src->proto->name; - break; - case T_PREFIX: /* Warning: this works only for prefix of network */ - { - res.val.px.ip = (*f_rte)->net->n.prefix; - res.val.px.len = (*f_rte)->net->n.pxlen; - break; - } + + switch (what->a2.i) + { + case SA_FROM: res.val.px.ip = rta->from; break; + case SA_GW: res.val.px.ip = rta->gw; break; + case SA_NET: res.val.px.ip = (*f_rte)->net->n.prefix; + res.val.px.len = (*f_rte)->net->n.pxlen; break; + case SA_PROTO: res.val.s = rta->src->proto->name; break; + case SA_SOURCE: res.val.i = rta->source; break; + case SA_SCOPE: res.val.i = rta->scope; break; + case SA_CAST: res.val.i = rta->cast; break; + case SA_DEST: res.val.i = rta->dest; break; + case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break; + case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break; + default: - bug( "Invalid type for rta access (%x)", res.type ); + bug("Invalid static attribute access (%x)", res.type); } } break; case P('a','S'): + ACCESS_RTE; ONEARG; if (what->aux != v1.type) runtime( "Attempt to set static attribute to incompatible type" ); + f_rta_cow(); { struct rta *rta = (*f_rte)->attrs; - switch (what->aux) { - case T_IP: - * (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip; + switch (what->a2.i) + { + case SA_FROM: + rta->from = v1.val.px.ip; break; - case T_ENUM_SCOPE: + case SA_GW: + { + ip_addr ip = v1.val.px.ip; + neighbor *n = neigh_find(rta->src->proto, &ip, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_ROUTER; + rta->gw = ip; + rta->iface = n->iface; + rta->nexthops = NULL; + rta->hostentry = NULL; + } + break; + + case SA_SCOPE: rta->scope = v1.val.i; break; - case T_ENUM_RTD: + case SA_DEST: i = v1.val.i; if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + rta->dest = i; rta->gw = IPA_NONE; rta->iface = NULL; rta->nexthops = NULL; + rta->hostentry = NULL; break; default: - bug( "Unknown type in set of static attribute" ); + bug("Invalid static attribute access (%x)", res.type); } } break; case P('e','a'): /* Access to extended attributes */ + ACCESS_RTE; { eattr *e = NULL; if (!(f_flags & FF_FORCE_TMPATTR)) @@ -944,6 +936,7 @@ interpret(struct f_inst *what) } break; case P('e','S'): + ACCESS_RTE; ONEARG; { struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); @@ -956,11 +949,25 @@ interpret(struct f_inst *what) l->attrs[0].type = what->aux | EAF_ORIGINATED; switch (what->aux & EAF_TYPE_MASK) { case EAF_TYPE_INT: - case EAF_TYPE_ROUTER_ID: if (v1.type != T_INT) runtime( "Setting int attribute to non-int value" ); l->attrs[0].u.data = v1.val.i; break; + + case EAF_TYPE_ROUTER_ID: +#ifndef IPV6 + /* IP->Quad implicit conversion */ + if (v1.type == T_IP) { + l->attrs[0].u.data = ipa_to_u32(v1.val.px.ip); + break; + } +#endif + /* T_INT for backward compatibility */ + if ((v1.type != T_QUAD) && (v1.type != T_INT)) + runtime( "Setting quad attribute to non-quad value" ); + l->attrs[0].u.data = v1.val.i; + break; + case EAF_TYPE_OPAQUE: runtime( "Setting opaque attribute is not allowed" ); break; @@ -1007,10 +1014,12 @@ interpret(struct f_inst *what) } break; case 'P': + ACCESS_RTE; res.type = T_INT; res.val.i = (*f_rte)->pref; break; case P('P','S'): + ACCESS_RTE; ONEARG; if (v1.type != T_INT) runtime( "Can't set preference to non-integer" ); @@ -1025,7 +1034,9 @@ interpret(struct f_inst *what) switch(v1.type) { case T_PREFIX: res.val.i = v1.val.px.len; break; case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; - default: runtime( "Prefix or path expected" ); + 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; + default: runtime( "Prefix, path, clist or eclist expected" ); } break; case P('c','p'): /* Convert prefix to ... */ @@ -1124,7 +1135,34 @@ interpret(struct f_inst *what) case P('C','a'): /* (Extended) Community list add or delete */ TWOARGS; - if (v1.type == T_CLIST) + if (v1.type == T_PATH) + { + struct f_tree *set = NULL; + u32 key = 0; + int pos; + + if (v2.type == T_INT) + key = v2.val.i; + else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT)) + set = v2.val.t; + else + runtime("Can't delete non-integer (set)"); + + switch (what->aux) + { + case 'a': runtime("Can't add to path"); + case 'd': pos = 0; break; + case 'f': pos = 1; break; + default: bug("unknown Ca operation"); + } + + if (pos && !set) + runtime("Can't filter integer"); + + res.type = T_PATH; + res.val.ad = as_path_filter(f_pool, v1.val.ad, set, key, pos); + } + else if (v1.type == T_CLIST) { /* Community (or cluster) list */ struct f_val dummy; @@ -1232,6 +1270,7 @@ interpret(struct f_inst *what) } else { + ACCESS_RTE; v1.val.px.ip = (*f_rte)->net->n.prefix; v1.val.px.len = (*f_rte)->net->n.pxlen; @@ -1343,10 +1382,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) A2_SAME; } break; - case 'C': - if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) + + case 'C': + if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) return 0; break; + case 'V': if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) return 0; @@ -1418,6 +1459,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags) { + if (filter == FILTER_ACCEPT) + return F_ACCEPT; + + if (filter == FILTER_REJECT) + return F_REJECT; + int rte_cow = ((*rte)->flags & REF_COW); DBG( "Running filter `%s'...", filter->name ); @@ -1427,7 +1474,8 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc f_pool = tmp_pool; f_flags = flags; - log_reset(); + LOG_BUFFER_INIT(f_buf); + struct f_val res = interpret(filter->root); if (f_old_rta) { @@ -1458,22 +1506,28 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc return res.val.i; } -int -f_eval_int(struct f_inst *expr) +struct f_val +f_eval(struct f_inst *expr, struct linpool *tmp_pool) { - /* Called independently in parse-time to eval expressions */ - struct f_val res; - f_flags = 0; f_tmp_attrs = NULL; f_rte = NULL; - f_pool = cfg_mem; + f_pool = tmp_pool; + + LOG_BUFFER_INIT(f_buf); + + return interpret(expr); +} - log_reset(); - res = interpret(expr); +int +f_eval_int(struct f_inst *expr) +{ + /* Called independently in parse-time to eval expressions */ + struct f_val res = f_eval(expr, cfg_mem); if (res.type != T_INT) cf_error("Integer expression expected"); + return res.val.i; } diff --git a/filter/filter.h b/filter/filter.h index 2386fc95..07a4c9e4 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -78,12 +78,13 @@ struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, s struct f_tree *build_tree(struct f_tree *); struct f_tree *find_tree(struct f_tree *t, struct f_val val); int same_tree(struct f_tree *t1, struct f_tree *t2); +void tree_format(struct f_tree *t, buffer *buf); struct f_trie *f_new_trie(linpool *lp); void trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h); int trie_match_prefix(struct f_trie *t, ip_addr px, int plen); int trie_same(struct f_trie *t1, struct f_trie *t2); -void trie_print(struct f_trie *t); +void trie_format(struct f_trie *t, buffer *buf); void fprefix_get_bounds(struct f_prefix *px, int *l, int *h); @@ -106,6 +107,7 @@ struct ea_list; struct rte; int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags); +struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); int f_eval_int(struct f_inst *expr); u32 f_eval_asn(struct f_inst *expr); @@ -115,7 +117,10 @@ int filter_same(struct filter *new, struct filter *old); int i_same(struct f_inst *f1, struct f_inst *f2); int val_compare(struct f_val v1, struct f_val v2); -int tree_compare(const void *p1, const void *p2); +int val_same(struct f_val v1, struct f_val v2); + +void val_format(struct f_val v, buffer *buf); + #define F_NOP 0 #define F_NONL 1 @@ -169,6 +174,19 @@ int tree_compare(const void *p1, const void *p2); #define T_SET 0x80 #define T_PREFIX_SET 0x81 + +#define SA_FROM 1 +#define SA_GW 2 +#define SA_NET 3 +#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 + + struct f_tree { struct f_tree *left, *right; struct f_val from, to; diff --git a/filter/test.conf b/filter/test.conf index 64e6d91b..ae8a95a6 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -95,16 +95,18 @@ eclist el2; p2 = prepend( p2, 3 ); p2 = prepend( p2, 4 ); print "Testing paths: ", p2; - print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2; + print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20]; print "4 = ", p2.len; p2 = prepend( p2, 5 ); - print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2; + print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, 10..20],; 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); print "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1; print "5 = ", p2.len; - + print "Delete 3: ", delete(p2, 3); + print "Filter 1-3: ", filter(p2, [1..3]); + pm1 = [= 1 2 * 3 4 5 =]; p2 = prepend( + empty +, 5 ); p2 = prepend( p2, 4 ); @@ -113,6 +115,8 @@ eclist el2; p2 = prepend( p2, 2 ); p2 = prepend( p2, 1 ); print "Should be true: ", p2 ~ pm1, " ", p2, " ", pm1; + print "Delete 3: ", delete(p2, 3); + print "Delete 4-5: ", delete(p2, [4..5]); l = - empty -; print "Should be false in this special case: ", l ~ [(*,*)]; @@ -138,10 +142,10 @@ eclist el2; 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; + 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; + print "Community list (1,2) (3,1) (3,2) (3,5) (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)))] ); @@ -164,6 +168,7 @@ eclist el2; el = add(el, (ro, 11.21.31.41.mask(16), 200)); print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):"; print el; + print "EC len: ", el.len; el = delete(el, (rt, 10, 20)); el = delete(el, (rt, 10, 30)); el = add(el, (unknown 2, ten, 1)); @@ -240,6 +245,15 @@ int b; print "Defined: ", a, " ", b, " ", defined(b); } +define is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19]; +define is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2]; +define is3 = [5, 17, 2, 11, 8, 15, 3, 19]; + +define pxs2 = [ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ]; + +define ecs2 = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)]; + + function __startup() int i; bool b; @@ -249,13 +263,11 @@ pair pp; quad qq; ec cc; int set is; -int set is1; -int set is2; -int set is3; pair set ps; ec set ecs; +ip set ips; prefix set pxs; -string s; +string st; { print "1a-a1 = 30: ", '1a-a1'; print "Testing filter language:"; @@ -272,6 +284,12 @@ string s; # if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; } if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok"; is = [ 2, 3, 4, 7..11 ]; + + print "must be true: ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- , + " ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ]; + print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ , + " ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ]; + print " must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ]; print " data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ]; print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a"); @@ -279,11 +297,6 @@ string s; print " must be true: ", defined(1), ",", defined(1.2.3.4), ",", 1 != 2, ",", 1 <= 2; print " data types: must be false: ", 1 ~ [ 2, 3, 4 ], ",", 5 ~ is, ",", 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ], ",", (1,2) > (2,2), ",", (1,1) > (1,1), ",", 1.0.0.0/9 ~ [ 1.0.0.0/8- ], ",", 1.2.0.0/17 ~ [ 1.0.0.0/8{ 15 , 16 } ], ",", true && false; - is1 = [ 1, 5, 8, 11, 15, 17, 19]; - - is1 = [ one, (2+1), (6-one), 8, 11, 15, 17, 19]; - is2 = [(17+2), 17, 15, 11, 8, 5, 3, 2]; - is3 = [5, 17, 2, 11, 8, 15, 3, 19]; print " must be true: ", 1 ~ is1, " ", 3 ~ is1, " ", 5 ~ is1; print " must be true: ", (one+2) ~ is1, " ", 2 ~ is2, " ", 2 ~ is3; @@ -333,13 +346,14 @@ string s; ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)]; print "EC set: ", ecs; + print "EC set: ", ecs2; print "Testing EC set, true: ", (rt, 10, 20) ~ ecs, " ", (ro, 100000, 100) ~ ecs, " ", (ro, 100000, 200) ~ ecs, " ", (rt, 12345, 0) ~ ecs, " ", cc ~ ecs, " ", (rt, 12345, 4000000) ~ ecs; print "Testing EC set, false: ", (ro, 10, 20) ~ ecs, " ", (rt, 10, 21) ~ ecs, " ", (ro, 100000, 99) ~ ecs, " ", (ro, 12345, 10) ~ ecs, " ", (rt, 12346, 0) ~ ecs, " ", (ro, 0.1.134.160, 150) ~ ecs; - s = "Hello"; - print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*"; + st = "Hello"; + print "Testing string: ", st, " true: ", st ~ "Hell*", " false: ", st ~ "ell*"; b = true; print "Testing bool: ", b, ", ", !b; @@ -347,6 +361,12 @@ string s; if ( b = true ) then print "Testing bool comparison b = true: ", b; else { print "*** FAIL: TRUE test failed" ; quitbird; } + ips = [ 1.1.1.0 .. 1.1.1.255, 1.2.2.2]; + print "Testing IP sets: "; + print ips; + print " must be true: ", 1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips; + print " must be false: ", 1.1.0.255 ~ ips, ",", 1.1.2.0 ~ ips, ",", 1.2.2.3 ~ ips, ",", 192.168.1.1 ~ ips; + pxs = [ 1.2.0.0/16, 1.4.0.0/16+]; print "Testing prefix sets: "; print pxs; @@ -354,6 +374,7 @@ string s; print " must be false: ", 1.1.0.0/16 ~ pxs, ",", 1.3.0.0/16 ~ pxs, ",", 1.2.0.0/15 ~ pxs, ",", 1.2.0.0/17 ~ pxs, ",", 1.2.0.0/32 ~ pxs, ",", 1.4.0.0/15 ~ pxs; + test_pxset(pxs2); test_pxset([ 10.0.0.0/16{8,12}, 20.0.0.0/16{24,28} ]); print "What will this do? ", [ 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 5 ]; @@ -372,6 +393,9 @@ string s; print "1.2.3.4 = ", onetwo; + i = 4200000000; + print "4200000000 = ", i, " false: ", i = 4200000000, " ", i > 4100000000, " false: ", i > 4250000000; + test_undef(2); test_undef(3); test_undef(2); diff --git a/filter/tree.c b/filter/tree.c index f6ab75b4..ee9f448a 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h) return n; } +static int +tree_compare(const void *p1, const void *p2) +{ + return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); +} /** * build_tree @@ -132,3 +137,37 @@ same_tree(struct f_tree *t1, struct f_tree *t2) return 0; return 1; } + + +static void +tree_node_format(struct f_tree *t, buffer *buf) +{ + if (t == NULL) + return; + + tree_node_format(t->left, buf); + + val_format(t->from, buf); + if (val_compare(t->from, t->to) != 0) + { + buffer_puts(buf, ".."); + val_format(t->to, buf); + } + buffer_puts(buf, ", "); + + tree_node_format(t->right, buf); +} + +void +tree_format(struct f_tree *t, buffer *buf) +{ + buffer_puts(buf, "["); + + tree_node_format(t, buf); + + /* Undo last separator */ + if (buf->pos[-1] != '[') + buf->pos -= 2; + + buffer_puts(buf, "]"); +} diff --git a/filter/trie.c b/filter/trie.c index 581332c6..217d72c3 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -265,37 +265,37 @@ trie_same(struct f_trie *t1, struct f_trie *t2) } static void -trie_node_print(struct f_trie_node *t, char **sep) +trie_node_format(struct f_trie_node *t, buffer *buf) { if (t == NULL) return; if (ipa_nonzero(t->accept)) - { - logn("%s%I/%d{%I}", *sep, t->addr, t->plen, t->accept); - *sep = ", "; - } + buffer_print(buf, "%I/%d{%I}, ", t->addr, t->plen, t->accept); - trie_node_print(t->c[0], sep); - trie_node_print(t->c[1], sep); + trie_node_format(t->c[0], buf); + trie_node_format(t->c[1], buf); } /** - * trie_print - * @t: trie to be printed + * trie_format + * @t: trie to be formatted + * @buf: destination buffer * - * Prints the trie to the log buffer. + * Prints the trie to the supplied buffer. */ void -trie_print(struct f_trie *t) +trie_format(struct f_trie *t, buffer *buf) { - char *sep = ""; - logn("["); + buffer_puts(buf, "["); + if (t->zero) - { - logn("0.0.0.0/0"); - sep = ", "; - } - trie_node_print(&t->root, &sep); - logn("]"); + buffer_print(buf, "%I/%d", IPA_NONE, 0); + trie_node_format(&t->root, buf); + + /* Undo last separator */ + if (buf->pos[-1] != '[') + buf->pos -= 2; + + buffer_puts(buf, "]"); } |