diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | bird.conf | 62 | ||||
-rw-r--r-- | conf/cf-lex.l | 2 | ||||
-rw-r--r-- | conf/confbase.Y | 3 | ||||
-rw-r--r-- | filter/Makefile | 2 | ||||
-rw-r--r-- | filter/config.Y | 96 | ||||
-rw-r--r-- | filter/f-util.c | 137 | ||||
-rw-r--r-- | filter/filter.c | 212 | ||||
-rw-r--r-- | filter/filter.h | 10 |
9 files changed, 321 insertions, 205 deletions
@@ -9,7 +9,7 @@ all depend: clean: $(MAKE) -C $(objdir) clean - rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core -or -name depend -or -name .#*` + find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core -or -name depend -or -name .#* | xargs rm -f distclean: clean rm -rf $(objdir) @@ -4,42 +4,62 @@ # Yet another comment -router id 62.168.0.1 +router id 62.168.0.1; -define xyzzy = 120+10 +define xyzzy = 120+10; -function startup () int i; { printdebug; printdebug; i = 5; print( i ); i = 1234 + i; print( i ); if 0 then { puts( "You must not ever see this" ); quitbird; } print( 2 ); if 1 then puts( "jedna dve honza jde" ); quitbird; } +function startup () +int i; +{ + print "Bird filter language: selftesting..."; + 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"; -filter testf int j; { j = const(4321); print( j ); } + + print "done"; + quitbird; + print "*** FAIL: this is unreachable"; +} +filter testf +int j; +{ + j = const(4321); + print j; +} protocol rip MyRIP_test { - preference xyzzy - debug all - port 1520 - period 5 - garbagetime 30 - interface "*" + preference xyzzy; + debug all; + port 1520; + period 5; + garbagetime 30; + interface "*"; } protocol device { - disabled - interface "eth*", "ppp*" +# disabled; +# interface "eth*", "ppp*"; } #protocol kernel { -# disabled +# disabled; # learn; # Learn all routes from the kernel # scan time 10; # Scan kernel tables every 10 seconds #} protocol static { -# disabled - route 0.0.0.0/0 via 62.168.0.13 - route 62.168.0.0/25 reject -# route 10.0.0.0/8 reject -# route 10.1.1.0:255.255.255.0 via 62.168.0.3 -# route 10.1.2.0:255.255.255.0 via 62.168.0.3 -# route 10.1.3.0:255.255.255.0 via 62.168.0.4 -# route 10.2.0.0/24 via "arc0" +# disabled; + route 0.0.0.0/0 via 62.168.0.13; + route 62.168.0.0/25 reject; +# route 10.0.0.0/8 reject; +# route 10.1.1.0:255.255.255.0 via 62.168.0.3; +# route 10.1.2.0:255.255.255.0 via 62.168.0.3; +# route 10.1.3.0:255.255.255.0 via 62.168.0.4; +# route 10.2.0.0/24 via "arc0"; } diff --git a/conf/cf-lex.l b/conf/cf-lex.l index b6b0df70..a9e7b542 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -103,7 +103,7 @@ WHITE [ \t] return SYM; } -[={}:;,()+*/%-] { +[={}:;,()+*/%-<>~] { return yytext[0]; } diff --git a/conf/confbase.Y b/conf/confbase.Y index 880b0df5..0598d560 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -37,9 +37,10 @@ CF_DECLS %type <i> expr bool pxlen -%left '=' +%nonassoc '=' '<' '>' %left '+' '-' %left '*' '/' '%' +%left '!' CF_KEYWORDS(DEFINE, ON, OFF, YES, NO) diff --git a/filter/Makefile b/filter/Makefile index 1e7fb684..81bd355b 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,4 +1,4 @@ -source=f-util.c +source=f-util.c filter.c root-rel=../ dir-name=filter diff --git a/filter/config.Y b/filter/config.Y index de178e7c..47612ee3 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -21,11 +21,12 @@ CF_DECLS CF_KEYWORDS(FUNCTION, PRINTDEBUG, PRINT, CONST, PUTS, ACCEPT, REJECT, ERROR, QUITBIRD, INT, BOOL, IP, PREFIX, PAIR, SET, STRING, - IF, THEN, + IF, THEN, ELSE, + TRUE, FALSE, FILTER ) -%type <x> term block cmds cmd function_body +%type <x> term block cmds cmd function_body ifthen constant print_one print_list %type <f> filter filter_body %type <i> type break_command @@ -127,34 +128,37 @@ block: } ; +constant: + CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->arg1 = T_INT; $$->arg2 = $3; } + | NUM { $$ = f_new_inst(); $$->code = 'c'; $$->arg1 = T_INT; $$->arg2 = $1; } + | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->arg1 = T_BOOL; $$->arg2 = 1; } + | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->arg1 = T_BOOL; $$->arg2 = 0; } + | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->arg1 = T_STRING; $$->arg2 = $1; } + ; + term: - term '+' term { - $$ = f_new_inst(); - $$->code = '+'; - $$->arg1 = $1; - $$->arg2 = $3; - } + term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->arg1 = $1; $$->arg2 = $3; } + + | term '=' term { $$ = f_new_inst(); $$->code = '=='; $$->arg1 = $1; $$->arg2 = $3; } + | term '!' '=' term { $$ = f_new_inst(); $$->code = '!='; $$->arg1 = $1; $$->arg2 = $4; } + | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->arg1 = $1; $$->arg2 = $3; } + | term '<' '=' term { $$ = f_new_inst(); $$->code = '<='; $$->arg1 = $1; $$->arg2 = $4; } + | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->arg1 = $3; $$->arg2 = $1; } + | term '>' '=' term { $$ = f_new_inst(); $$->code = '<='; $$->arg1 = $4; $$->arg2 = $1; } + | SYM { $$ = f_new_inst(); switch ($1->class) { case SYM_VARIABLE | T_INT: $$->code = 'i'; - $$->arg1 = &($1->aux); + $$->arg1 = T_INT; + $$->arg2 = &($1->aux); break; default: cf_error("Can not use this class of symbol as variable" ); } } - | CONST '(' expr ')' { - $$ = f_new_inst(); - $$->code = 'c'; - $$->arg1 = $3; - } - | NUM { - $$ = f_new_inst(); - $$->code = 'c'; - $$->arg1 = $1 - } + | constant { $$ = $1; } ; break_command: @@ -162,46 +166,52 @@ break_command: | ACCEPT { $$ = F_ACCEPT } | REJECT { $$ = F_REJECT } | ERROR { $$ = F_ERROR } + | PRINT { $$ = F_NOP } ; -cmd: +ifthen: IF term THEN block { $$ = f_new_inst(); $$->code = '?'; $$->arg1 = $2; $$->arg2 = $4; } + ; + +print_one: + term { $$ = f_new_inst(); $$->code = 'p'; $$->arg1 = $1; $$->arg2 = NULL; } + ; + +print_list: /* EMPTY */ { $$ = NULL; } + | print_one print_list { + if ($1) { + $1->next = $2; + $$ = $1; + } else $$ = $2; + } + ; + +cmd: + ifthen { + $$ = $1; + } + /* FIXME: this leads to shift/reduce conflict. */ + | ifthen ELSE block { + $$ = f_new_inst(); + $$->code = '?'; + $$->arg1 = $1; + $$->arg2 = $3; + } | SYM '=' term ';' { $$ = f_new_inst(); printf( "Ook, we'll set value\n" ); if (($1->class & ~T_MASK) != SYM_VARIABLE) cf_error( "You may only set variables, and this is %x.\n", $1->class ); - $$->code = '='; + $$->code = 's'; $$->arg1 = $1; $$->arg2 = $3; } - | PRINT '(' term ')' ';' { - $$ = f_new_inst(); - printf( "Ook, we'll print something\n" ); - $$->code = 'p'; - $$->arg1 = $3; - $$->arg2 = NULL; - } - | PUTS '(' TEXT ')' ';' { - $$ = f_new_inst(); - $$->code = 'd'; - $$->arg1 = $3; - } - | PRINTDEBUG ';' { - $$ = f_new_inst(); - $$->code = 'D'; - $$->arg1 = $$->arg2 = NULL; - } - | break_command ';' { - $$ = f_new_inst(); - $$->code = '!'; - (int) $$->arg1 = $1; - } + | break_command print_list ';' { $$ = f_new_inst(); $$->code = 'p,'; $$->arg1 = $2; $$->arg2 = $1; } ; CF_END diff --git a/filter/f-util.c b/filter/f-util.c index 6605091e..40805f8a 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -22,119 +22,6 @@ #include "conf/conf.h" #include "filter/filter.h" -struct f_inst *startup_func = NULL; - -#define runtime(x) do { \ - log( L_ERR, x ); \ - res.type = T_RETURN; \ - res.val.i = F_ERROR; \ - return res; \ - } while(0) - -#define ARG(x,y) \ - x = interpret(what->y); \ - if (x.type == T_RETURN) \ - return x; - -#define ONEARG ARG(v1, arg1) -#define TWOARGS ARG(v1, arg1) \ - ARG(v2, arg2) - -static struct f_val -interpret(struct f_inst *what) -{ - struct symbol *sym; - struct f_val v1, v2, res; - - res.type = T_VOID; - if (!what) - return res; - - switch(what->code) { - case ',': - TWOARGS; - break; - case '+': - TWOARGS; - if (v1.type != v2.type) - runtime( "Can not operate with values of incompatible types" ); - - switch (res.type = v1.type) { - case T_VOID: runtime( "Can not operate with values of type void" ); - case T_INT: res.val.i = v1.val.i + v2.val.i; break; - default: runtime( "Usage of unknown type" ); - } - break; - case '=': - ARG(v2, arg2); - sym = what->arg1; - switch (res.type = v2.type) { - case T_VOID: runtime( "Can not assign void values" ); - case T_INT: - if (sym->class != (SYM_VARIABLE | T_INT)) - runtime( "Variable of bad type" ); - sym->aux = v2.val.i; - break; - } - break; - case 'c': - res.type = T_INT; - res.val.i = (int) what->arg1; - break; - case 'i': - res.type = T_INT; - res.val.i = * ((int *) what->arg1); - break; - case 'p': - ONEARG; - printf( "Printing: " ); - switch (v1.type) { - case T_VOID: printf( "(void)" ); break; - case T_INT: printf( "%d", v1.val.i ); break; - default: runtime( "Print of variable of unknown type" ); - } - printf( "\n" ); - break; - case '?': - ONEARG; - if (v1.type != T_INT) - runtime( "If requires integer expression" ); - if (v1.val.i) { - ARG(res,arg2); - } - break; - case 'D': - printf( "DEBUGGING PRINT\n" ); - break; - case '0': - printf( "No operation\n" ); - break; - case 'd': - printf( "Puts: %s\n", (char *) what->arg1 ); - break; - case '!': - switch ((int) what->arg1) { - case F_QUITBIRD: - die( "Filter asked me to die" ); - case F_ACCEPT: - /* Should take care about turning ACCEPT into MODIFY */ - case F_ERROR: - case F_REJECT: - res.type = T_RETURN; - res.val.i = (int) what->arg1; - break; - default: - bug( "unknown return type: can not happen"); - } - break; - default: - bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); - } - if (what->next) - return interpret(what->next); - return res; -} - struct f_inst * f_new_inst(void) { @@ -145,21 +32,6 @@ f_new_inst(void) return ret; } -int -f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool) -{ - struct f_inst *inst; - struct f_val res; - debug( "Running filter `%s'...", filter->name ); - - inst = filter->root; - res = interpret(inst); - if (res.type != T_RETURN) - return F_ERROR; - debug( "done (%d)\n", res.val.i ); - return res.val.i; -} - char * filter_name(struct filter *filter) { @@ -170,12 +42,3 @@ filter_name(struct filter *filter) else return filter->name; } - -void -filters_postconfig(void) -{ - printf( "Launching startup function..." ); - if (startup_func) - interpret(startup_func); - printf( "done\n" ); -} diff --git a/filter/filter.c b/filter/filter.c new file mode 100644 index 00000000..eb40d3c8 --- /dev/null +++ b/filter/filter.c @@ -0,0 +1,212 @@ +/* + * Filters: utility functions + * + * Copyright 1998 Pavel Machek <pavel@ucw.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/signal.h> +#include <setjmp.h> + +#include "nest/bird.h" +#include "lib/lists.h" +#include "lib/resource.h" +#include "lib/socket.h" +#include "nest/route.h" +#include "nest/protocol.h" +#include "nest/iface.h" +#include "conf/conf.h" +#include "filter/filter.h" + +struct f_inst *startup_func = NULL; + +#define runtime(x) do { \ + log( L_ERR x ); \ + res.type = T_RETURN; \ + res.val.i = F_ERROR; \ + return res; \ + } while(0) + +#define ARG(x,y) \ + x = interpret(what->y); \ + if (x.type == T_RETURN) \ + return x; + +#define ONEARG ARG(v1, arg1) +#define TWOARGS ARG(v1, arg1) \ + ARG(v2, arg2) +#define TWOARGS_C TWOARGS \ + if (v1.type != v2.type) \ + runtime( "Can not operate with values of incompatible types" ); + +static struct f_val +interpret(struct f_inst *what) +{ + struct symbol *sym; + struct f_val v1, v2, res; + + res.type = T_VOID; + if (!what) + return res; + + switch(what->code) { + case ',': + TWOARGS; + break; + +/* Binary operators */ + case '+': + TWOARGS_C; + switch (res.type = v1.type) { + case T_VOID: runtime( "Can not operate with values of type void" ); + case T_INT: res.val.i = v1.val.i + v2.val.i; break; + default: runtime( "Usage of unknown type" ); + } + break; + case '/': + TWOARGS_C; + switch (res.type = v1.type) { + case T_VOID: runtime( "Can not operate with values of type void" ); + case T_INT: res.val.i = v1.val.i / v2.val.i; break; + case T_IP: if (v2.type != T_INT) + runtime( "Operator / is <ip>/<int>" ); + break; + default: runtime( "Usage of unknown type" ); + } + break; + +/* Relational operators */ + case '!=': + case '==': + TWOARGS_C; + res.type = T_BOOL; + switch (v1.type) { + case T_VOID: runtime( "Can not operate with values of type void" ); + case T_INT: res.val.i = (v1.val.i == v2.val.i); break; + default: runtime( "Usage of unknown type" ); + } + if (what->code == '!=') + res.val.i = !(res.val.i); + break; + case '<': + TWOARGS_C; + res.type = T_BOOL; + switch (v1.type) { + case T_VOID: runtime( "Can not operate with values of type void" ); + case T_INT: res.val.i = (v1.val.i < v2.val.i); break; + default: runtime( "Usage of unknown type" ); + } + break; + case '<=': + TWOARGS_C; + res.type = T_BOOL; + switch (v1.type) { + case T_VOID: runtime( "Can not operate with values of type void" ); + case T_INT: res.val.i = (v1.val.i <= v2.val.i); break; + default: runtime( "Usage of unknown type" ); + } + break; + +/* Set */ + case 's': + ARG(v2, arg2); + sym = what->arg1; + switch (res.type = v2.type) { + case T_VOID: runtime( "Can not assign void values" ); + case T_INT: + if (sym->class != (SYM_VARIABLE | T_INT)) + runtime( "Variable of bad type" ); + sym->aux = v2.val.i; + break; + } + break; + + case 'c': + res.type = (int) what->arg1; + res.val.i = (int) what->arg2; + break; + case 'i': + res.type = (int) what->arg1; + res.val.i = * ((int *) what->arg2); + break; + case 'p': + ONEARG; + switch (v1.type) { + case T_VOID: printf( "(void)" ); break; + case T_INT: printf( "%d ", v1.val.i ); break; + case T_STRING: printf( "%s", v1.val.i ); break; + default: runtime( "Print of variable of unknown type" ); + } + break; + case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ + ONEARG; + if (v1.type != T_BOOL) + runtime( "If requires bool expression" ); + if (v1.val.i) { + ARG(res,arg2); + res.val.i = 0; + } else res.val.i = 1; + res.type = T_BOOL; + break; + case '0': + printf( "No operation\n" ); + break; + case 'p,': + ONEARG; + printf( "\n" ); + + switch ((int) what->arg2) { + case F_QUITBIRD: + die( "Filter asked me to die" ); + case F_ACCEPT: + /* Should take care about turning ACCEPT into MODIFY */ + case F_ERROR: + case F_REJECT: + res.type = T_RETURN; + res.val.i = (int) what->arg1; + break; + case F_NOP: + break; + default: + bug( "unknown return type: can not happen"); + } + break; + default: + bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); + } + if (what->next) + return interpret(what->next); + return res; +} + +int +f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool) +{ + struct f_inst *inst; + struct f_val res; + debug( "Running filter `%s'...", filter->name ); + + inst = filter->root; + res = interpret(inst); + if (res.type != T_RETURN) + return F_ERROR; + debug( "done (%d)\n", res.val.i ); + return res.val.i; +} + + +void +filters_postconfig(void) +{ + struct f_val res; + printf( "Launching startup function...\n" ); + if (startup_func) + res = interpret(startup_func); + if (res.type = F_ERROR) + die( "Startup function resulted in error." ); + printf( "done\n" ); +} diff --git a/filter/filter.h b/filter/filter.h index d8ee7efa..12943425 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -10,6 +10,7 @@ #define _BIRD_FILT_H_ #include "lib/resource.h" +#include "lib/ip.h" struct f_inst { /* Instruction */ struct f_inst *next; /* Structure is 16 bytes, anyway */ @@ -17,10 +18,17 @@ struct f_inst { /* Instruction */ void *arg1, *arg2; }; +struct prefix { + ip_addr ip; + int len; +}; + struct f_val { int type; union { int i; + struct prefix *px; + char *s; } val; }; @@ -35,6 +43,8 @@ struct f_inst *f_new_inst(void); int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool); char *filter_name(struct filter *filter); + +#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 |