From: Jan Maria Matejka Date: Tue, 13 Mar 2018 15:51:04 +0000 (+0100) Subject: Merge branch 'master' into int-new X-Git-Tag: v2.0.2~1^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d1ba927b369c91ddb2143b686ca4c1be53e46e64;p=thirdparty%2Fbird.git Merge branch 'master' into int-new --- d1ba927b369c91ddb2143b686ca4c1be53e46e64 diff --cc conf/confbase.Y index 55615528f,b8deed54e..72f56f1e9 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@@ -47,8 -42,9 +47,10 @@@ CF_DECL struct symbol *s; char *t; struct rtable_config *r; + struct channel_config *cc; struct f_inst *x; + struct f_dynamic_attr fda; + struct f_static_attr fsa; struct filter *f; struct f_tree *e; struct f_trie *trie; diff --cc filter/config.Y index cd5a5b33d,1ef5a3a8b..6b7bedaf3 --- a/filter/config.Y +++ b/filter/config.Y @@@ -232,8 -227,9 +227,8 @@@ f_generate_ec(u16 kind, struct f_inst * cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); } -#ifndef IPV6 /* IP->Quad implicit conversion */ - else if (tk->code == 'C') { + else if (tk->fi_code == FI_CONSTANT_INDIRECT) { c1 = 1; struct f_val *val = tk->a1.p; @@@ -249,8 -245,9 +244,8 @@@ else cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); } -#endif - if (tv->code == 'c') { + if (tv->fi_code == FI_CONSTANT) { if (tv->aux != T_INT) cf_error("Can't operate with value of non-integer type in EC constructor"); c2 = 1; @@@ -323,71 -317,7 +315,70 @@@ f_generate_lc(struct f_inst *t1, struc return rv; } +/* + * Remove all new lines and doubled whitespaces + * and convert all tabulators to spaces + * and return a copy of string + */ +char * +assert_copy_expr(const char *start, size_t len) +{ + /* XXX: Allocates maybe a little more memory than we really finally need */ + char *str = cfg_alloc(len + 1); + + char *dst = str; + const char *src = start - 1; + const char *end = start + len; + while (++src < end) + { + if (*src == '\n') + continue; + + /* Skip doubled whitespaces */ + if (src != start) + { + const char *prev = src - 1; + if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t')) + continue; + } + + if (*src == '\t') + *dst = ' '; + else + *dst = *src; + + dst++; + } + *dst = '\0'; + return str; +} + +/* + * assert_done - create f_instruction of bt_assert + * @expr: expression in bt_assert() + * @start: pointer to first char of test expression + * @end: pointer to the last char of test expression + */ +static struct f_inst * +assert_done(struct f_inst *expr, const char *start, const char *end) +{ + struct f_inst *i; - i = f_new_inst(); - i->code = P('a','s'); ++ i = f_new_inst(FI_ASSERT); + i->a1.p = expr; + + if (end >= start) + { + i->a2.p = assert_copy_expr(start, end - start + 1); + } + else + { + /* this is a break of lexer buffer */ + i->a2.p = "???"; + } + + return i; +} CF_DECLS @@@ -775,18 -691,24 +764,18 @@@ bgp_path_tail | { $$ = NULL; } ; -bgp_path_tail2: - NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } - | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; } - | { $$ = NULL; } - ; - constant: - NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } - | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } - | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; } - | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; } - | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } - | VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } - | net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; } - | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } - | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; } - | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } - | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; } + NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; } + | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; } + | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; } + | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; } - | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; } - | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; } - | RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; } ++ | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; } ++ | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } ++ | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; } + | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } + | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; } + | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } + | bgp_path { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; } ; constructor: @@@ -844,15 -763,16 +830,15 @@@ symbol } static_attr: - 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_NET; $$->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; } - | 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; } + FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); } + | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); } - | NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); } ++ | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); } + | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); } + | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); } + | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); } - | CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); } + | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); } + | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); } + | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); } ; term: @@@ -878,23 -798,18 +864,23 @@@ | constant { $$ = $1; } | constructor { $$ = $1; } - | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; } + | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); } - | rtadot static_attr { $$ = $2; $$->code = 'a'; } + | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); } - | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); } + | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); } - | term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; } - | term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; } - | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } - | term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; } - | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; } - | term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; } - | term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; } - | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } - | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } - | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } - | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; } ++ | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; } ++ | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; } + | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; } ++ | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; } + | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; } ++ | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; } ++ | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; } + | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; } + | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; } + | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; } + | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; } /* Communities */ /* This causes one shift/reduce conflict @@@ -904,21 -819,17 +890,21 @@@ | rtadot dynamic_attr '.' RESET{ } */ - | '+' 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; } - | '-' '-' '-' 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'; } + | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; } + | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; } + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; } + | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; } + | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } + | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } + | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->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); } + | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } + - | FORMAT '(' term ')' { $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; } ++ | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; } + +/* | term '.' LEN { $$->code = P('P','l'); } */ /* function_call is inlined here */ | SYM '(' var_list ')' { @@@ -1050,18 -948,12 +1023,18 @@@ cmd $$->a2.p = build_tree( $4 ); } - | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } - | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } - | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } - | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } - | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } + | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); } + | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); } + | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); } + | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); } + | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } ; +get_cf_position: +{ + $$ = cf_text; +}; + + CF_END diff --cc filter/f-util.c index 52c132231,42b08868b..68aecd738 --- a/filter/f-util.c +++ b/filter/f-util.c @@@ -24,13 -24,22 +24,22 @@@ f_new_inst(enum f_instruction_code fi_c } struct f_inst * - f_new_dynamic_attr(int type, int f_type, int code) + f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da) { - /* FIXME: Remove the f_type parameter? */ - struct f_inst *f = f_new_inst(); - f->aux = (f_type << 8) | type; - f->a2.i = code; - return f; + struct f_inst *ret = f_new_inst(fi_code); - ret->aux = da.type; ++ ret->aux = (da.f_type << 8) | da.type; + ret->a2.i = da.ea_code; + return ret; + } + + struct f_inst * + f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa) + { + struct f_inst *ret = f_new_inst(fi_code); + ret->aux = sa.f_type; + ret->a2.i = sa.sa_code; + ret->a1.i = sa.readonly; + return ret; } /* @@@ -54,11 -60,12 +60,11 @@@ f_generate_complex(int operation, int o return set_dyn; } - struct f_inst * -f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn) +f_generate_roa_check(struct rtable_config *table, 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.fi_code = FI_ROA_CHECK; ret->i.lineno = ifs->lino; ret->i.arg1 = prefix; ret->i.arg2 = asn; diff --cc filter/filter.c index 8cf90b535,85721dbdc..f81f5cfec --- a/filter/filter.c +++ b/filter/filter.c @@@ -48,23 -46,8 +48,21 @@@ #include "conf/conf.h" #include "filter/filter.h" - #define P(a,b) ((a<<8) | b) - #define CMP_ERROR 999 +void (*bt_assert_hook)(int result, struct f_inst *assert); + +static struct adata undef_adata; /* adata of length 0 used for undefined */ + +/* Special undef value for paths and clists */ +static inline int +undef_value(struct f_val v) +{ + return ((v.type == T_PATH) || (v.type == T_CLIST) || + (v.type == T_ECLIST) || (v.type == T_LCLIST)) && + (v.val.ad == &undef_adata); +} + static struct adata * adata_empty(struct linpool *pool, int l) { @@@ -462,10 -471,11 +460,9 @@@ val_in_range(struct f_val v1, struct f_ 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 (val_is_ip4(v1) && (v2.type == T_CLIST)) + return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip)); if ((v1.type == T_EC) && (v2.type == T_ECLIST)) return ec_set_contains(v2.val.ad, v1.val.ec); @@@ -824,29 -825,10 +819,29 @@@ interpret(struct f_inst *what res.val.i = !res.val.i; break; - case P('d','e'): + case FI_DEFINED: ONEARG; res.type = T_BOOL; - res.val.i = (v1.type != T_VOID); + res.val.i = (v1.type != T_VOID) && !undef_value(v1); + break; - case 'T': ++ case FI_TYPE: + ONEARG; + switch (v1.type) + { + case T_NET: + res.type = T_ENUM_NETTYPE; + res.val.i = v1.val.net->type; + break; + default: + runtime( "Can't determine type of this item" ); + } + break; - case P('I','i'): ++ case FI_IS_V4: + ONEARG; + if (v1.type != T_IP) + runtime( "IP version check needs an IP address" ); + res.type = T_BOOL; + res.val.i = ipa_is_ip4(v1.val.ip); break; /* Set to indirect value, a1 = variable, a2 = value */ @@@ -1225,43 -1203,18 +1220,43 @@@ default: runtime( "Prefix, path, clist or eclist expected" ); } break; - case P('R','m'): /* Get ROA max prefix length */ ++ case FI_ROA_MAXLEN: /* Get ROA max prefix length */ + ONEARG; + if (v1.type != T_NET || !net_is_roa(v1.val.net)) + runtime( "ROA expected" ); + + res.type = T_INT; + res.val.i = (v1.val.net->type == NET_ROA4) ? + ((net_addr_roa4 *) v1.val.net)->max_pxlen : + ((net_addr_roa6 *) v1.val.net)->max_pxlen; + break; - case P('R','a'): /* Get ROA ASN */ ++ case FI_ROA_ASN: /* Get ROA ASN */ + ONEARG; + if (v1.type != T_NET || !net_is_roa(v1.val.net)) + runtime( "ROA expected" ); + + res.type = T_INT; + res.val.i = (v1.val.net->type == NET_ROA4) ? + ((net_addr_roa4 *) v1.val.net)->asn : + ((net_addr_roa6 *) v1.val.net)->asn; + break; - case P('c','p'): /* Convert prefix to ... */ + case FI_IP: /* Convert prefix to ... */ ONEARG; - if (v1.type != T_PREFIX) + if (v1.type != T_NET) runtime( "Prefix expected" ); - res.type = what->aux; - switch(res.type) { - /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */ - case T_IP: res.val.px.ip = v1.val.px.ip; break; - default: bug( "Unknown prefix to conversion" ); - } + res.type = T_IP; + res.val.ip = net_prefix(v1.val.net); + break; - case P('R','D'): ++ case FI_ROUTE_DISTINGUISHER: + ONEARG; + if (v1.type != T_NET) + runtime( "Prefix expected" ); + if (!net_is_vpn(v1.val.net)) + runtime( "VPN address expected" ); + res.type = T_RD; + res.val.ec = net_rd(v1.val.net); break; - case P('a','f'): /* Get first ASN from AS PATH */ + case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */ ONEARG; if (v1.type != T_PATH) runtime( "AS path expected" ); @@@ -1330,14 -1283,14 +1325,14 @@@ runtime( "Integer expected"); if (v1.type != T_IP) runtime( "You can mask only IP addresses" ); - { - ip_addr mask = ipa_mkmask(v2.val.i); - res.type = T_IP; - res.val.px.ip = ipa_and(mask, v1.val.px.ip); - } + + res.type = T_IP; + res.val.ip = ipa_is_ip4(v1.val.ip) ? + ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) : + ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))); break; - case 'E': /* Create empty attribute */ + case FI_EMPTY: /* Create empty attribute */ res.type = what->aux; res.val.ad = adata_empty(f_pool, 0); break; @@@ -1543,39 -1498,12 +1537,39 @@@ as_path_get_last(e->u.ptr, &as); } - struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc; - if (!rtc->table) + struct rtable *table = ((struct f_inst_roa_check *) what)->rtc->table; + if (!table) runtime("Missing ROA table"); + if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) + runtime("Table type must be either ROA4 or ROA6"); + res.type = T_ENUM_ROA; - res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as); + + if (table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6)) + res.val.i = ROA_UNKNOWN; /* Prefix and table type mismatch */ + else + res.val.i = net_roa_check(table, v1.val.net, as); + + break; + - case P('f','m'): /* Format */ ++ case FI_FORMAT: /* Format */ + ONEARG; + + res.type = T_STRING; + res.val.s = val_format_str(v1); + break; + - case P('a','s'): /* Birdtest Assert */ ++ case FI_ASSERT: /* Birdtest Assert */ + ONEARG; + + if (v1.type != T_BOOL) + runtime("Should be boolean value"); + + res.type = v1.type; + res.val = v1.val; + + CALL(bt_assert_hook, res.val.i, what); break; default: @@@ -1614,29 -1540,27 +1606,28 @@@ i_same(struct f_inst *f1, struct f_ins if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ return 1; - switch(f1->code) { - case ',': /* fall through */ - case '+': - case '-': - case '*': - case '/': - case '|': - case '&': - case P('m','p'): - case P('m','c'): - case P('!','='): - case P('=','='): - case '<': - case P('<','='): TWOARGS; break; - - case '!': ONEARG; break; - case P('!', '~'): - case '~': TWOARGS; break; - case P('d','e'): ONEARG; break; - case 'T': ONEARG; break; - case P('n','T'): break; - - case P('m','l'): + switch(f1->fi_code) { + case FI_COMMA: /* fall through */ + case FI_ADD: + case FI_SUBTRACT: + case FI_MULTIPLY: + case FI_DIVIDE: + case FI_OR: + case FI_AND: + case FI_PAIR_CONSTRUCT: + case FI_EC_CONSTRUCT: + case FI_NEQ: + case FI_EQ: + case FI_LT: + case FI_LTE: TWOARGS; break; + + case FI_NOT: ONEARG; break; + case FI_NOT_MATCH: + case FI_MATCH: TWOARGS; break; + case FI_DEFINED: ONEARG; break; ++ case FI_TYPE: ONEARG; break; + + case FI_LC_CONSTRUCT: TWOARGS; if (!i_same(INST3(f1).p, INST3(f2).p)) return 0; @@@ -1687,37 -1611,36 +1678,37 @@@ if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) return 0; break; - case 'p': case 'L': ONEARG; break; - case '?': TWOARGS; break; - case '0': case 'E': break; - case P('p',','): ONEARG; A2_SAME; break; - case 'P': - case 'a': A2_SAME; break; - case P('e','a'): A2_SAME; break; - case P('P','S'): - case P('a','S'): - case P('e','S'): ONEARG; A2_SAME; break; - - case 'r': ONEARG; break; - case P('c','p'): ONEARG; break; - case P('R','D'): ONEARG; break; - case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ + case FI_PRINT: case FI_LENGTH: ONEARG; break; + case FI_CONDITION: TWOARGS; break; + case FI_NOP: case FI_EMPTY: break; + case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break; + case FI_PREF_GET: + case FI_RTA_GET: A2_SAME; break; + case FI_EA_GET: A2_SAME; break; + case FI_PREF_SET: + case FI_RTA_SET: + case FI_EA_SET: ONEARG; A2_SAME; break; + + case FI_RETURN: ONEARG; break; + case FI_IP: ONEARG; break; ++ case FI_ROUTE_DISTINGUISHER: ONEARG; break; + case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */ ONEARG; if (!i_same(f1->a2.p, f2->a2.p)) return 0; f2->a2.p = f1->a2.p; break; - case P('c','v'): break; /* internal instruction */ - case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; - case P('i','M'): TWOARGS; break; - case P('A','p'): TWOARGS; break; - case P('C','a'): TWOARGS; break; - case P('a','f'): - case P('a','l'): - case P('a','L'): ONEARG; break; - case P('R','C'): + case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */ + case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; + case FI_IP_MASK: TWOARGS; break; + case FI_PATH_PREPEND: TWOARGS; break; + case FI_CLIST_ADD_DEL: TWOARGS; break; + case FI_AS_PATH_FIRST: + case FI_AS_PATH_LAST: + case FI_AS_PATH_LAST_NAG: ONEARG; break; + case FI_ROA_CHECK: TWOARGS; - /* Does not really make sense - ROA check resuls may change anyway */ + /* Does not really make sense - ROA check results may change anyway */ if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, ((struct f_inst_roa_check *) f2)->rtc->name)) return 0; diff --cc filter/filter.h index 49004c331,09f96084e..b1fc6c290 --- a/filter/filter.h +++ b/filter/filter.h @@@ -14,18 -14,76 +14,83 @@@ #include "nest/route.h" #include "nest/attrs.h" + /* Filter instruction types */ + + #define FI__TWOCHAR(a,b) ((a<<8) | b) + #define FI__LIST \ + F(FI_COMMA, 0, ',') \ + F(FI_ADD, 0, '+') \ + F(FI_SUBTRACT, 0, '-') \ + F(FI_MULTIPLY, 0, '*') \ + F(FI_DIVIDE, 0, '/') \ + F(FI_AND, 0, '&') \ + F(FI_OR, 0, '|') \ + F(FI_PAIR_CONSTRUCT, 'm', 'p') \ + F(FI_EC_CONSTRUCT, 'm', 'c') \ + F(FI_LC_CONSTRUCT, 'm', 'l') \ + F(FI_NEQ, '!', '=') \ + F(FI_EQ, '=', '=') \ + F(FI_LT, 0, '<') \ + F(FI_LTE, '<', '=') \ + F(FI_NOT, 0, '!') \ + F(FI_MATCH, 0, '~') \ + F(FI_NOT_MATCH, '!', '~') \ + F(FI_DEFINED, 'd', 'e') \ ++ F(FI_TYPE, 0, 'T') \ ++ F(FI_IS_V4, 'I', 'i') \ + F(FI_SET, 0, 's') \ + F(FI_CONSTANT, 0, 'c') \ + F(FI_VARIABLE, 0, 'V') \ + F(FI_CONSTANT_INDIRECT, 0, 'C') \ + F(FI_PRINT, 0, 'p') \ + F(FI_CONDITION, 0, '?') \ + F(FI_NOP, 0, '0') \ + F(FI_PRINT_AND_DIE, 'p', ',') \ + F(FI_RTA_GET, 0, 'a') \ + F(FI_RTA_SET, 'a', 'S') \ + F(FI_EA_GET, 'e', 'a') \ + F(FI_EA_SET, 'e', 'S') \ + F(FI_PREF_GET, 0, 'P') \ + F(FI_PREF_SET, 'P', 'S') \ + F(FI_LENGTH, 0, 'L') \ ++ F(FI_ROA_MAXLEN, 'R', 'M') \ ++ F(FI_ROA_ASN, 'R', 'A') \ + F(FI_IP, 'c', 'p') \ ++ F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \ + F(FI_AS_PATH_FIRST, 'a', 'f') \ + F(FI_AS_PATH_LAST, 'a', 'l') \ + F(FI_AS_PATH_LAST_NAG, 'a', 'L') \ + F(FI_RETURN, 0, 'r') \ + F(FI_CALL, 'c', 'a') \ + F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \ + F(FI_SWITCH, 'S', 'W') \ + F(FI_IP_MASK, 'i', 'M') \ + F(FI_EMPTY, 0, 'E') \ + F(FI_PATH_PREPEND, 'A', 'p') \ + F(FI_CLIST_ADD_DEL, 'C', 'a') \ - F(FI_ROA_CHECK, 'R', 'C') ++ F(FI_ROA_CHECK, 'R', 'C') \ ++ F(FI_FORMAT, 0, 'F') \ ++ F(FI_ASSERT, 'a', 's') + + enum f_instruction_code { + #define F(c,a,b) \ + c = FI__TWOCHAR(a,b), + FI__LIST + #undef F + } PACKED; + struct f_inst { /* Instruction */ struct f_inst *next; /* Structure is 16 bytes, anyway */ - u16 code; /* Instruction code, see the interpret() function and P() macro */ + enum f_instruction_code fi_code; - u16 aux; + u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ union { - int i; + uint i; void *p; - } a1; + } a1; /* The first argument */ union { - int i; + uint i; void *p; - } a2; + } a2; /* The second argument */ int lineno; }; @@@ -75,11 -150,16 +152,16 @@@ struct filter struct f_inst *root; }; - 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_inst *f_new_inst(enum f_instruction_code fi_code); + struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da); + struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa); + static inline struct f_dynamic_attr 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 */ + { return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ + static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly) + { return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; } 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_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument); -struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn); +struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); struct f_tree *build_tree(struct f_tree *);