From d3dd620b96c5960207b9321b416423b8130a4df7 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 12 Oct 1999 06:27:42 +0000 Subject: [PATCH] Filters: permit variables of prefix types, cleanup around variables. TODO list added, hopefully complete. Use new features of filters in bird.conf --- bird.conf | 41 ++++++++++-------------- filter/config.Y | 83 ++++++++++++++++++++++++++++++++++++------------- filter/filter.c | 28 +++++++++++------ filter/filter.h | 18 ++++++++--- 4 files changed, 110 insertions(+), 60 deletions(-) diff --git a/bird.conf b/bird.conf index 476ccf30..b1220c32 100644 --- a/bird.conf +++ b/bird.conf @@ -13,7 +13,7 @@ function callme (int arg1; int arg2;) print "Function callme called arguments " arg1 " and " arg2; case arg1 { - 2: { print "dva"; print "jeste jednou dva"; } + 2: print "dva"; print "jeste jednou dva"; [ 3 .. 5 ]: print "tri az pet"; else: print "neco jineho"; } @@ -22,37 +22,30 @@ function callme (int arg1; int arg2;) function startup () int i; prefix px; - { - print "Bird filter language: selftesting..."; + print "Testing filter language:"; i = 4; i = 1230 + i; - print "Testing arithmetics: 1234 = " i; - if i = 4 then { print "*** FAIL: if 0"; quitbird; } else print "test 1 passed"; - if 1234 = i then print "test 2 passed"; else { print "*** FAIL: if 1 else"; } - if 1 <= 1 then print "test 3 passed"; else { print "*** FAIL: test 3"; } - if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "test 4 passed"; + print " arithmetics: 1234 = " i; + printn " if statements "; + if i = 4 then { print "*** FAIL: if 0"; quitbird; } else printn "."; + if 1234 = i then printn "."; else { print "*** FAIL: if 1 else"; } + if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; } + if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok"; - print "Testing IP addresses: 1.2.3.4 = " 1.2.3.4; - print "Testing sets of ints = " [ 1, 2, 3 ]; - print "Testing sets of ints = " [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]; - print "Testing sets of IPs = " [ 1.2.3.4, 2.3.4.5, 3.4.5.6 ]; - print "Sets: true = " 1 ~ [ 1, 2, 3 ]; - print " false = " 1 ~ [ 2, 3, 4 ]; - print "a..b: true = " 5 ~ [ 4 .. 7 ]; - print " false = " 5 ~ [ 2, 3, 4, 7..11 ]; - print "IPsets: true = " 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ]; - print " false = " 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ]; + 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 "Testing prefixes: 1.2.3.4/18 = " 1.2.3.4/18; + px = 1.2.3.4/18; + print "Testing prefixes: 1.2.3.4/18 = " px; print "Testing pairs: (1,2) = " (1,2); print "Testing functions..."; - callme ( 1, 2, ); - callme ( 2, 2, ); - callme ( 3, 2, ); - callme ( 4, 2, ); - callme ( 7, 2, ); + callme ( 1, 2 ); + callme ( 2, 2 ); + callme ( 3, 2 ); + callme ( 4, 2 ); + callme ( 7, 2 ); print "done"; quitbird; diff --git a/filter/config.Y b/filter/config.Y index 9d0cc747..93854836 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -5,16 +5,13 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * - FIXME: prefix variables, make prefix.ip and prefix.length work FIXME: define keyword - FIXME: case without { }'s - FIXME: allow px+, px- px^pair in prefix sets + 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: do not allow function call by callme(1,2,) - FIXME: pairs of integers: define compare + FIXME: make case faster */ CF_HDR @@ -29,12 +26,12 @@ CF_HDR CF_DECLS -CF_KEYWORDS(FUNCTION, PRINT, CONST, +CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, ACCEPT, REJECT, ERROR, QUITBIRD, INT, BOOL, IP, PREFIX, PAIR, SET, STRING, IF, THEN, ELSE, CASE, TRUE, FALSE, - RTA, FROM, GW, NET, + RTA, FROM, GW, NET, MASK, LEN, IMPOSSIBLE, FILTER @@ -42,9 +39,9 @@ CF_KEYWORDS(FUNCTION, PRINT, CONST, %type term block cmds cmd function_body ifthen constant print_one print_list var_list switch_body %type filter filter_body -%type type break_command +%type type break_command pair %type set_item set_items -%type set_atom +%type set_atom prefix prefix_s ipa %type decls function_params CF_GRAMMAR @@ -80,6 +77,12 @@ decls: /* EMPTY */ { $$ = NULL; } cf_define_symbol($2, SYM_VARIABLE | $1, NULL); printf( "New variable %s type %x\n", $2->name, $1 ); $2->aux = $4; + { + struct f_val * val; + val = cfg_alloc(sizeof(struct f_val)); + val->type = $1; + $2->aux2 = val; + } $$=$2; } ; @@ -146,10 +149,36 @@ block: } ; +/* + * Simple types, their bison value is int + */ +pair: + '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; } + ; + +/* + * Complex types, their bison value is struct f_val + */ +prefix_s: + IPA '/' NUM { $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3; printf( "ook, we have prefix here\n" ); } + ; + +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? */ + ; + +ipa: + IPA { $$.type = T_IP; $$.val.ip = $1; } + ; + set_atom: - NUM { $$.type = T_INT; $$.val.i = $1; } - | IPA { $$.type = T_IP; $$.val.ip = $1; } - + NUM { $$.type = T_INT; $$.val.i = $1; } + | pair { $$.type = T_PAIR; $$.val.i = $1; } + | ipa { $$ = $1; } + | prefix { $$ = $1; } ; set_item: @@ -162,15 +191,16 @@ set_items: | set_items ',' set_item { $$ = $3; $$->left = $1; } ; + constant: CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_INT; $$->a2.i = $3; } | NUM { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_INT; $$->a2.i = $1; } | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_BOOL; $$->a2.i = 1; } | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_BOOL; $$->a2.i = 0; } | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_STRING; $$->a2.p = $1; } - | '(' NUM ',' NUM ')' { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_PAIR; $$->a2.i = $2 << 16 | $4; } - | IPA { struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.ip = $1; } - | IPA '/' NUM { struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_PREFIX; val->val.px.ip = $1; val->val.px.len = $3; printf( "ook, we have prefix here\n" ); } + | 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; } | '[' 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" ); } ; @@ -188,9 +218,11 @@ term: $$ = f_new_inst(); switch ($1->class) { case SYM_VARIABLE | T_INT: - $$->code = 'i'; - $$->a1.i = T_INT; - $$->a2.p = &($1->aux); + case SYM_VARIABLE | T_PAIR: + case SYM_VARIABLE | T_PREFIX: + case SYM_VARIABLE | T_IP: + $$->code = 'C'; + $$->a1.p = $1->aux2; break; default: cf_error("Can not use this class of symbol as variable." ); @@ -204,6 +236,7 @@ term: | 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; } + | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = 'iM'; $$->a1.p = $1; $$->a2.p = $5; } ; break_command: @@ -212,6 +245,7 @@ break_command: | REJECT { $$ = F_REJECT } | ERROR { $$ = F_ERROR } | PRINT { $$ = F_NOP } + | PRINTN { $$ = F_NONL } ; ifthen: @@ -236,7 +270,13 @@ print_list: /* EMPTY */ { $$ = NULL; } } ; -var_list: /* EMPTY */ { $$ = NULL; } +var_list: term { + $$ = f_new_inst(); + $$->code = 's'; + $$->a1.p = NULL; + $$->a2.p = $1; + $$->next = NULL; + } | term ',' var_list { $$ = f_new_inst(); $$->code = 's'; @@ -246,15 +286,16 @@ var_list: /* EMPTY */ { $$ = NULL; } } ; +/* 2 shift/reduce conflicts here. Curable by replacing cmds with block which breaks syntax */ switch_body: /* EMPTY */ { $$ = NULL; } - | term ':' block switch_body { + | term ':' cmds switch_body { $$ = f_new_inst(); $$->code = 'of'; $$->a1.p = $1; $$->a2.p = $3; $$->next = $4; } - | ELSE ':' block { + | ELSE ':' cmds { $$ = f_new_inst(); $$->code = 'el'; $$->a1.p = NULL; diff --git a/filter/filter.c b/filter/filter.c index d317fcc0..f6b2d4be 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -58,6 +58,7 @@ val_compare(struct f_val v1, struct f_val v2) return CMP_ERROR; switch (v1.type) { case T_INT: + case T_PAIR: if (v1.val.i == v2.val.i) return 0; if (v1.val.i < v2.val.i) return -1; return 1; @@ -209,31 +210,32 @@ interpret(struct f_inst *what) runtime( "~ applied on unknown type pair" ); break; - /* Set to consant, a1 = type, a2 = value */ + /* Set to indirect value, a1 = variable, a2 = value */ case 's': ARG(v2, a2.p); sym = what->a1.p; switch (res.type = v2.type) { case T_VOID: runtime( "Can not assign void values" ); case T_INT: - if (sym->class != (SYM_VARIABLE | T_INT)) + case T_IP: + case T_PREFIX: + case T_PAIR: + if (sym->class != (SYM_VARIABLE | v2.type)) runtime( "Variable of bad type" ); - sym->aux = v2.val.i; + * (struct f_val *) sym->aux2 = v2; break; + default: + bug( "Set to invalid type\n" ); } break; - case 'c': + case 'c': /* integer (or simple type) constant */ res.type = what->a1.i; - res.val.i = (int) what->a2.p; + res.val.i = what->a2.i; break; case 'C': res = * ((struct f_val *) what->a1.p); break; - case 'i': - res.type = what->a1.i; - res.val.i = * ((int *) what->a2.p); - break; case 'p': ONEARG; val_print(v1); @@ -253,7 +255,8 @@ interpret(struct f_inst *what) break; case 'p,': ONEARG; - printf( "\n" ); + if (what->a2.i != F_NONL) + printf( "\n" ); switch (what->a2.i) { case F_QUITBIRD: @@ -265,6 +268,7 @@ interpret(struct f_inst *what) res.type = T_RETURN; res.val.i = what->a1.i; break; + case F_NONL: case F_NOP: break; default: @@ -309,6 +313,10 @@ interpret(struct f_inst *what) ONEARG; interpret_switch(what->a2.p, v1); break; + case 'iM': /* IP.MASK(val) */ + TWOARGS_C; + bug( "Should implement ip.mask\n" ); + break; default: bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); } diff --git a/filter/filter.h b/filter/filter.h index f32a98eb..ac7162ec 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -31,6 +31,11 @@ struct f_inst { /* Instruction */ 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) */ }; struct f_val { @@ -66,11 +71,12 @@ int val_compare(struct f_val v1, struct f_val v2); void val_print(struct f_val v); #define F_NOP 0 -#define F_ACCEPT 1 /* Need to preserve ordering: accepts < rejects! */ -#define F_MODIFY 2 /* FIXME: Introduce modification flags instead? */ -#define F_REJECT 3 -#define F_ERROR 4 -#define F_QUITBIRD 5 +#define F_NONL 1 +#define F_ACCEPT 2 /* Need to preserve ordering: accepts < rejects! */ +#define F_MODIFY 3 /* FIXME: Introduce modification flags instead? */ +#define F_REJECT 4 +#define F_ERROR 5 +#define F_QUITBIRD 6 #define FILTER_ACCEPT NULL #define FILTER_REJECT ((void *) 1) @@ -101,4 +107,6 @@ struct f_tree { void *data; }; +#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); + #endif