summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bird.conf62
-rw-r--r--conf/cf-lex.l2
-rw-r--r--conf/confbase.Y3
-rw-r--r--filter/Makefile2
-rw-r--r--filter/config.Y96
-rw-r--r--filter/f-util.c137
-rw-r--r--filter/filter.c212
-rw-r--r--filter/filter.h10
9 files changed, 321 insertions, 205 deletions
diff --git a/Makefile b/Makefile
index fb1006d..a2bba64 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/bird.conf b/bird.conf
index 1b5b534..3d22f5a 100644
--- a/bird.conf
+++ b/bird.conf
@@ -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 b6b0df7..a9e7b54 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 880b0df..0598d56 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 1e7fb68..81bd355 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 de178e7..47612ee 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 6605091..40805f8 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 0000000..eb40d3c
--- /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 d8ee7ef..1294342 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