diff --git a/bird.conf b/bird.conf index 443a6d76..0b866f62 100644 --- a/bird.conf +++ b/bird.conf @@ -26,10 +26,12 @@ int i; function startup () int i; prefix px; +ip p; { print "Testing filter language:"; i = 4; i = 1230 + i; + i = ( i + 0 ); print " arithmetics: 1234 = " i; printn " if statements "; if i = 4 then { print "*** FAIL: if 0"; quitbird; } else printn "."; @@ -37,11 +39,13 @@ prefix px; if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; } if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok"; - print " data types; must be true: " 1.2.3.4 = 1.2.3.4 "," 1 ~ [1,2,3] "," 5 ~ [1..20] "," 2 ~ [ 1, 2, 3 ] "," 5 ~ [ 4 .. 7 ] "," 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ] "," 1.2.3.4 ~ 1.2.3.4/8 "," 1.2.3.4/8 ~ 1.2.3.4/8 "," 1.2.3.4/8 ~ 1.2.3.4/8+ "," 1.2.3.4/16 ~ 1.2.3.4/8{ 15 , 16 }; + print " data types; must be true: " 1.2.3.4 = 1.2.3.4 "," 1 ~ [1,2,3] "," 5 ~ [1..20] "," 2 ~ [ 1, 2, 3 ] "," 5 ~ [ 4 .. 7 ] "," 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ] "," 1.2.3.4 ~ 1.2.3.4/8 "," 1.2.3.4/8 ~ 1.2.3.4/8 "," 1.2.3.4/8 ~ 1.2.3.4/8+ "," 1.2.3.4/16 ~ 1.2.3.4/8{ 15 , 16 } "," defined(1) "," defined(1.2.3.4); print " data types: must be false: " 1 ~ [ 2, 3, 4 ] "," 5 ~ [ 2, 3, 4, 7..11 ] "," 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ] "," (1,2) > (2,2) "," (1,1) > (1,1) "," 1.2.3.4/8 ~ 1.2.3.4/8- "," 1.2.3.4/17 ~ 1.2.3.4/8{ 15 , 16 }; px = 1.2.3.4/18; print "Testing prefixes: 1.2.3.4/18 = " px; + p = 127.1.2.3; + print "Testing mask : 127.0.0.0 = " p.mask(8); print "Testing pairs: (1,2) = " (1,2); print "What will this do? " [ 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 5 ]; diff --git a/conf/confbase.Y b/conf/confbase.Y index 4a942878..0ec74538 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -46,7 +46,7 @@ CF_DECLS %type expr bool pxlen datetime -%nonassoc '=' '<' '>' '~' IF ELSE '.' +%nonassoc '=' '<' '>' '~' '.' %left '+' '-' %left '*' '/' '%' %left '!' diff --git a/filter/config.Y b/filter/config.Y index 1e4bafef..a12766e7 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -5,12 +5,11 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * - FIXME: define keyword - FIXME: create ip.mask(x) function + FIXME (nonurgent): define keyword FIXME: whole system of paths, path ~ string, path.prepend(), path.originate FIXME: create community lists FIXME: enumerational types - FIXME: defined() keyword + FIXME: write access to dynamic attributes. */ CF_HDR @@ -32,11 +31,15 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, TRUE, FALSE, RTA, FROM, GW, NET, MASK, RIP_METRIC, RIP_TAG, LEN, + DEFINED, IMPOSSIBLE, FILTER ) -%type term block cmds cmd function_body ifthen constant print_one print_list var_list var_listn +%nonassoc THEN +%nonassoc ELSE ';' + +%type term block cmds cmd function_body ifthen constant print_one print_list var_list var_listn any_dynamic %type filter filter_body %type type break_command pair %type set_item set_items switch_body @@ -237,8 +240,15 @@ constant: | '[' set_items ']' { printf( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_SET; $$->a2.p = build_tree($2); printf( "ook\n" ); } ; +any_dynamic: + RIP_METRIC { $$ = f_new_inst(); $$->a1.i = T_INT; $$->a2.i = EA_RIP_METRIC;} + | RIP_TAG { $$ = f_new_inst(); $$->a1.i = T_INT; $$->a2.i = EA_RIP_TAG; } + ; + + term: - term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } + '(' term ')' { $$ = $2; } + | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } | term '=' term { $$ = f_new_inst(); $$->code = '=='; $$->a1.p = $1; $$->a2.p = $3; } | term '!' '=' term { $$ = f_new_inst(); $$->code = '!='; $$->a1.p = $1; $$->a2.p = $4; } | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } @@ -246,6 +256,7 @@ term: | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } | term '>' '=' term { $$ = f_new_inst(); $$->code = '<='; $$->a1.p = $4; $$->a2.p = $1; } | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } + | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = 'de'; $$->a1.p = $3; } | SYM { $$ = f_new_inst(); @@ -267,7 +278,7 @@ term: | RTA '.' GW { $$ = f_new_inst(); $$->code = 'a'; $$->a1.i = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); } | RTA '.' NET { $$ = f_new_inst(); $$->code = 'a'; $$->a1.i = T_PREFIX; $$->a2.i = 0x12345678; } - | RTA '.' RIP_METRIC { $$ = f_new_inst(); $$->code = 'ea'; $$->a1.i = T_INT; $$->a2.i = EA_RIP_METRIC; } + | RTA '.' any_dynamic { $$ = $3; $$->code = 'ea'; } | term '.' IP { $$ = f_new_inst(); $$->code = 'cp'; $$->a1.p = $1; $$->a2.i = T_IP; } | term '.' LEN { $$ = f_new_inst(); $$->code = 'cp'; $$->a1.p = $1; $$->a2.i = T_INT; } diff --git a/filter/filter.c b/filter/filter.c index 99d47bc1..a6030ae7 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -62,6 +62,7 @@ val_compare(struct f_val v1, struct f_val v2) if (v1.type != v2.type) return CMP_ERROR; switch (v1.type) { + case T_ENUM: case T_INT: case T_PAIR: if (v1.val.i == v2.val.i) return 0; @@ -219,6 +220,11 @@ interpret(struct f_inst *what) if (res.val.i == CMP_ERROR) runtime( "~ applied on unknown type pair" ); break; + case 'de': + ONEARG; + res.type = T_BOOL; + res.val.i = (v1.type != T_VOID); + break; /* Set to indirect value, a1 = variable, a2 = value */ case 's': @@ -226,6 +232,7 @@ interpret(struct f_inst *what) sym = what->a1.p; switch (res.type = v2.type) { case T_VOID: runtime( "Can not assign void values" ); + case T_ENUM: case T_INT: case T_IP: case T_PREFIX: @@ -352,8 +359,16 @@ interpret(struct f_inst *what) } break; case 'iM': /* IP.MASK(val) */ - TWOARGS_C; - bug( "Should implement ip.mask\n" ); + TWOARGS; + if (v2.type != T_INT) + runtime( "Can not use this type for mask."); + 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); + } break; default: bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); diff --git a/filter/filter.h b/filter/filter.h index 4cdf8f6b..ebb09254 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -92,7 +92,12 @@ void val_print(struct f_val v); #define T_INT 0x10 #define T_BOOL 0x11 #define T_PAIR 0x12 -#define T_ENUM 0x13 + +/* Put enumerational types in 0x30..0x7f range */ +#define T_ENUM_LO 0x30 +#define T_ENUM_HI 0x7f + +#define T_ENUM T_ENUM_LO ... T_ENUM_HI /* Bigger ones */ #define T_IP 0x20