diff --git a/bird.conf b/bird.conf index 3b8f6a7b..09290def 100644 --- a/bird.conf +++ b/bird.conf @@ -8,7 +8,9 @@ router id 62.168.0.1; define xyzzy = 120+10; -function callme (int arg1; int arg2;) +function callme ( int arg1; int arg2 ) +int local1; +int local2; { print "Function callme called arguments " arg1 " and " arg2; @@ -33,8 +35,8 @@ 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 ]; - 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); + 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 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; @@ -60,6 +62,8 @@ int j; { print "Heya, filtering route to " rta.net.ip " prefixlen " rta.net.len; print "This route was from " rta.from; + j = 7; + j = 17; accept; } diff --git a/filter/config.Y b/filter/config.Y index d5a9dca9..d9f72fb5 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -6,11 +6,11 @@ * Can be freely distributed and used under the terms of the GNU GPL. * FIXME: define keyword - FIXME: make px+, px- px^pair work in prefix sets FIXME: create ip.mask(x) function FIXME: whole system of paths, path ~ string, path.prepend(), path.originate FIXME: create community lists FIXME: access to dynamic attributes + FIXME: local namespace for functions */ CF_HDR @@ -30,18 +30,18 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, INT, BOOL, IP, PREFIX, PAIR, SET, STRING, IF, THEN, ELSE, CASE, TRUE, FALSE, - RTA, FROM, GW, NET, MASK, + RTA, FROM, GW, NET, MASK, RIP_METRIC, RIP_TAG, LEN, IMPOSSIBLE, FILTER ) -%type term block cmds cmd function_body ifthen constant print_one print_list var_list +%type term block cmds cmd function_body ifthen constant print_one print_list var_list var_listn %type filter filter_body %type type break_command pair %type set_item set_items switch_body %type set_atom prefix prefix_s ipa -%type decls function_params +%type decls declsn one_decl function_params CF_GRAMMAR @@ -71,11 +71,11 @@ type: } ; -decls: /* EMPTY */ { $$ = NULL; } - | type SYM ';' decls { +one_decl: + type SYM { cf_define_symbol($2, SYM_VARIABLE | $1, NULL); printf( "New variable %s type %x\n", $2->name, $1 ); - $2->aux = $4; + $2->aux = NULL; { struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); @@ -86,6 +86,24 @@ decls: /* EMPTY */ { $$ = NULL; } } ; +/* Decls with ';' at the end */ +decls: /* EMPTY */ { $$ = NULL; } + | one_decl ';' decls { + $$ = $1; + $$->aux = $3; + } + ; + +/* Declarations that have no ';' at the end. + Ouch, this is responsible for 13 or so shift/reduce conflicts. */ +declsn: one_decl { $$ = $1; } + | declsn ';' one_decl { + $$ = $3; + $$->aux = $1; + } + ; + + filter_body: function_body { struct filter *f = cfg_alloc(sizeof(struct filter)); @@ -104,7 +122,8 @@ filter: ; function_params: - '(' decls ')' { printf( "Have function parameters\n" ); $$=$2; } + '(' declsn ')' { printf( "Have function parameters\n" ); $$=$2; } + | '(' ')' { $$=NULL; } ; function_body: @@ -166,11 +185,11 @@ prefix: prefix_s { $$ = $1; } | prefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; } | prefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; } -/* | prefix_s '{' NUM ',' NUM '}' How should this be done? */ + | prefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); } ; ipa: - IPA { $$.type = T_IP; $$.val.ip = $1; } + IPA { $$.type = T_IP; $$.val.px.ip = $1; } ; set_atom: @@ -213,7 +232,8 @@ constant: | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_STRING; $$->a2.p = $1; } | pair { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_PAIR; $$->a2.i = $1; } | ipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } - | prefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } + /* Replace with prefix_s to get rid of shift/reduce conflicts. */ + | prefix {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } | '[' 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" ); } ; @@ -245,7 +265,9 @@ term: | RTA '.' FROM { $$ = f_new_inst(); $$->code = 'a'; $$->a1.i = T_IP; $$->a2.i = OFFSETOF(struct rta, from); } | 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 '.' 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; } | 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; } @@ -283,14 +305,14 @@ print_list: /* EMPTY */ { $$ = NULL; } } ; -var_list: term { +var_listn: term { $$ = f_new_inst(); $$->code = 's'; $$->a1.p = NULL; $$->a2.p = $1; $$->next = NULL; } - | term ',' var_list { + | term ',' var_listn { $$ = f_new_inst(); $$->code = 's'; $$->a1.p = NULL; @@ -299,6 +321,10 @@ var_list: term { } ; +var_list: /* EMPTY */ { $$ = NULL; } + | var_listn { $$ = $1; } + ; + cmd: ifthen { $$ = $1; diff --git a/filter/filter.c b/filter/filter.c index dc8235ed..e913bf60 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -5,8 +5,6 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * - * FIXME: local namespace for functions - * * Notice that pair is stored as integer: first << 16 | second */ @@ -70,16 +68,55 @@ val_compare(struct f_val v1, struct f_val v2) if (v1.val.i < v2.val.i) return -1; return 1; case T_IP: - return ipa_compare(v1.val.ip, v2.val.ip); + case T_PREFIX: + return ipa_compare(v1.val.px.ip, v2.val.px.ip); default: { printf( "Error comparing\n" ); return CMP_ERROR; } } } +int +val_simple_in_range(struct f_val v1, struct f_val v2) +{ + if ((v1.type == T_IP) && (v2.type == T_PREFIX)) + return !(ipa_compare(ipa_and(v2.val.px.ip, ipa_mkmask(v2.val.px.len)), ipa_and(v1.val.px.ip, ipa_mkmask(v2.val.px.len)))); + + if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) { + ip_addr mask; + if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE)) + return CMP_ERROR; + mask = ipa_mkmask( v2.val.px.len & LEN_MASK ); + if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask))) + return 0; + /* FIXME: read rpsl or better ask mj: is it really like this? */ + if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK))) + return 0; + if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK))) + return 0; + if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16))) + || (v1.val.px.len > (0xff & (v2.val.px.len >> 8))))) + return 0; + return 1; + } + return CMP_ERROR; +} + int val_in_range(struct f_val v1, struct f_val v2) { - if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET)) - return !! find_tree(v2.val.t, v1); + int res; + + res = val_simple_in_range(v1, v2); + + if (res != CMP_ERROR) + return res; + + if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET)) { + 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; } @@ -108,7 +145,7 @@ val_print(struct f_val v) case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break; case T_INT: PRINTF( "%d ", v.val.i ); break; case T_STRING: PRINTF( "%s", v.val.s ); break; - case T_IP: PRINTF( "%I", v.val.ip ); break; + case T_IP: PRINTF( "%I", v.val.px.ip ); break; case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break; case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break; case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break; @@ -254,7 +291,7 @@ interpret(struct f_inst *what) res.type = what->a1.i; switch(res.type) { case T_IP: - res.val.ip = * (ip_addr *) ((char *) rta + what->a2.i); + res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i); break; case T_PREFIX: /* Warning: this works only for prefix of network */ { @@ -267,6 +304,9 @@ interpret(struct f_inst *what) } } break; + case 'ea': /* Access to extended attributes [hmm, but we need it read/write, do we?] */ + bug( "Implement me" ); + break; case 'cp': /* Convert prefix to ... */ ONEARG; if (v1.type != T_PREFIX) @@ -274,7 +314,7 @@ interpret(struct f_inst *what) res.type = what->a2.i; switch(res.type) { case T_INT: res.val.i = v1.val.px.len; break; - case T_IP: res.val.ip = v1.val.px.ip; break; + case T_IP: res.val.px.ip = v1.val.px.ip; break; default: bug( "Unknown prefix to conversion\n" ); } break; diff --git a/filter/filter.h b/filter/filter.h index ac7162ec..4cdf8f6b 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -32,17 +32,17 @@ struct prefix { ip_addr ip; int len; #define LEN_MASK 0xff -#define LEN_PLUS 0x10000 -#define LEN_MINUS 0x20000 -#define LEN_RANGE 0x40000 - /* If range then prefix must be in range (len >> 8 & 0xff, len & 0xff) */ +#define LEN_PLUS 0x1000000 +#define LEN_MINUS 0x2000000 +#define LEN_RANGE 0x4000000 + /* If range then prefix must be in range (len >> 16 & 0xff, len >> 8 & 0xff) */ }; struct f_val { int type; union { int i; - ip_addr ip; + /* ip_addr ip; Folded into prefix */ struct prefix px; char *s; struct f_tree *t;