diff --git a/filter/config.Y b/filter/config.Y index 05608c95..856189ec 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -6,7 +6,7 @@ * Can be freely distributed and used under the terms of the GNU GPL. * FIXME (nonurgent): define keyword - FIXME: whole system of paths, path ~ string, path.prepend(), path.originate + FIXME (for BGP): whole system of paths, path ~ string, path.prepend(), path.originate FIXME: create community lists FIXME: '! =' should not be permitted. Ze `!=' by nemelo byt totez jako `! =' Nadefinujes si pres %token novy token a do cf-lex.l pridas nove pravidlo, ktere jej rozpoznava. Napriklad != return NEQ; FIXME: IP addresses in ipv6 @@ -25,9 +25,11 @@ CF_HDR #include "nest/route.h" #include +#define P(a,b) ((a<<8) | b) + CF_DECLS -CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, UNSET, +CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, UNSET, RETURN, ACCEPT, REJECT, ERROR, QUITBIRD, INT, BOOL, IP, PREFIX, PAIR, SET, STRING, IF, THEN, ELSE, CASE, @@ -41,7 +43,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, UNSET, %nonassoc THEN %nonassoc ELSE -%type term block cmds cmd function_body constant print_one print_list var_list var_listn any_dynamic +%type term block cmds cmd function_body constant print_one print_list var_list var_listn any_dynamic function_call %type filter filter_body where_filter %type type break_command pair %type set_item set_items switch_body @@ -132,11 +134,11 @@ where_filter: struct filter *f = cfg_alloc(sizeof(struct filter)); struct f_inst *i, *acc, *rej; acc = f_new_inst(); /* ACCEPT */ - acc->code = 'p,'; + acc->code = P('p',','); acc->a1.p = NULL; acc->a2.i = F_ACCEPT; rej = f_new_inst(); /* REJECT */ - rej->code = 'p,'; + rej->code = P('p',','); rej->a1.p = NULL; rej->a2.i = F_REJECT; i = f_new_inst(); /* IF */ @@ -274,17 +276,41 @@ any_dynamic: rtadot: /* EMPTY, we are not permitted RTA. prefix */ ; +function_call: + SYM '(' var_list ')' { + struct symbol *sym; + struct f_inst *inst = $3; + if ($1->class != SYM_FUNCTION) + cf_error("You can not call something which is not function. Really."); + printf("You are calling function %s\n", $1->name); + $$ = f_new_inst(); + $$->code = P('c','a'); + $$->a1.p = inst; + $$->a2.p = $1->aux2; + sym = (void *) $1->aux; + while (sym || inst) { + if (!sym || !inst) + cf_error("wrong number of arguments for function %s.", $1->name); + printf( "You should pass parameter called %s\n", sym->name); + inst->a1.p = sym; + sym = (void *) sym->aux; + inst = inst->next; + } + } + ; + + term: '(' 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 = P('=','='); $$->a1.p = $1; $$->a2.p = $3; } + | term '!' '=' term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $4; } | 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 = P('<','='); $$->a1.p = $1; $$->a2.p = $4; } | 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 = P('<','='); $$->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; } + | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } | constant { $$ = $1; } | SYM { @@ -308,11 +334,12 @@ term: | rtadot NET { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_PREFIX; $$->a2.i = 0x12345678; } | rtadot SOURCE { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, gw); } - | rtadot any_dynamic { $$ = $2; $$->code = 'ea'; } + | rtadot any_dynamic { $$ = $2; $$->code = P('e','a'); } - | term '.' IP { $$ = f_new_inst(); $$->code = 'cp'; $$->a1.p = $1; $$->aux = T_IP; } - | term '.' LEN { $$ = f_new_inst(); $$->code = 'cp'; $$->a1.p = $1; $$->aux = T_INT; } - | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = 'iM'; $$->a1.p = $1; $$->a2.p = $5; } + | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } + | term '.' LEN { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_INT; } + | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } + | function_call { $$ = $1; /* 1 shift/reduce conflict */ } ; break_command: @@ -383,41 +410,28 @@ cmd: $$->a1.p = $1; $$->a2.p = $3; } + | RETURN term ';' { + $$ = f_new_inst(); + printf( "Ook, we'll return the value\n" ); + $$->code = 'r'; + $$->a1.p = $2; + } | rtadot any_dynamic '=' term ';' { $$ = $2; - $$->code = 'eS'; + $$->code = P('e','S'); $$->a1.p = $4; } | UNSET '(' rtadot any_dynamic ')' ';' { $$ = $4; $$->aux = T_VOID; - $$->code = 'eS'; + $$->code = P('e','S'); $$->a1.p = NULL; } - | break_command print_list ';' { $$ = f_new_inst(); $$->code = 'p,'; $$->a1.p = $2; $$->a2.i = $1; } - | SYM '(' var_list ')' ';' { - struct symbol *sym; - struct f_inst *inst = $3; - if ($1->class != SYM_FUNCTION) - cf_error("You can not call something which is not function. Really."); - printf("You are calling function %s\n", $1->name); - $$ = f_new_inst(); - $$->code = 'ca'; - $$->a1.p = inst; - $$->a2.p = $1->aux2; - sym = (void *) $1->aux; - while (sym || inst) { - if (!sym || !inst) - cf_error("wrong number of arguments for function %s.", $1->name); - printf( "You should pass parameter called %s\n", sym->name); - inst->a1.p = sym; - sym = (void *) sym->aux; - inst = inst->next; - } - } + | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; } + | function_call ';' { $$ = $1; } | CASE term '{' switch_body '}' { $$ = f_new_inst(); - $$->code = 'SW'; + $$->code = P('S','W'); $$->a1.p = $2; $$->a2.p = build_tree( $4 ); } diff --git a/filter/filter.c b/filter/filter.c index 103710ea..cbbd1b58 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -26,6 +26,8 @@ #include "conf/conf.h" #include "filter/filter.h" +#define P(a,b) ((a<<8) | b) + struct f_inst *startup_func = NULL; #define CMP_ERROR 999 @@ -150,7 +152,7 @@ static struct linpool *f_pool; #define ARG(x,y) \ x = interpret(what->y); \ - if (x.type == T_RETURN) \ + if (x.type & T_RETURN) \ return x; #define ONEARG ARG(v1, a1.p) @@ -208,10 +210,10 @@ interpret(struct f_inst *what) res.val.i = (x); \ break; - case '!=': COMPARE(i!=0); - case '==': COMPARE(i==0); + case P('!','='): COMPARE(i!=0); + case P('=','='): COMPARE(i==0); case '<': COMPARE(i==-1); - case '<=': COMPARE(i!=1); + case P('<','='): COMPARE(i!=1); case '~': TWOARGS; @@ -220,7 +222,7 @@ interpret(struct f_inst *what) if (res.val.i == CMP_ERROR) runtime( "~ applied on unknown type pair" ); break; - case 'de': + case P('d','e'): ONEARG; res.type = T_BOOL; res.val.i = (v1.type != T_VOID); @@ -270,7 +272,7 @@ interpret(struct f_inst *what) case '0': printf( "No operation\n" ); break; - case 'p,': + case P('p',','): ONEARG; if (what->a2.i != F_NONL) printf( "\n" ); @@ -314,9 +316,10 @@ interpret(struct f_inst *what) } } break; - case 'ea': /* Access to extended attributes [hmm, but we need it read/write, do we?] */ + case P('e','a'): /* Access to extended attributes */ { eattr *e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); + /* FIXME: should I search in tmp_attrs, too, or what ? */ if (!e) { res.type = T_VOID; break; @@ -329,7 +332,7 @@ interpret(struct f_inst *what) } } break; - case 'eS': + case P('e','S'): ONEARG; if (v1.type != what->aux) runtime("Wrong type when setting dynamic attribute\n"); @@ -358,7 +361,7 @@ interpret(struct f_inst *what) } break; - case 'cp': /* Convert prefix to ... */ + case P('c','p'): /* Convert prefix to ... */ ONEARG; if (v1.type != T_PREFIX) runtime( "Can not convert non-prefix this way" ); @@ -369,11 +372,19 @@ interpret(struct f_inst *what) default: bug( "Unknown prefix to conversion\n" ); } break; - case 'ca': /* CALL */ + case 'r': + ONEARG; + res = v1; + res.type |= T_RETURN; + break; + case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */ ONEARG; res = interpret(what->a2.p); + if (res.type == T_RETURN) + return res; + res.type &= ~T_RETURN; break; - case 'SW': + case P('S','W'): ONEARG; { struct f_tree *t = find_tree(what->a2.p, v1); @@ -390,7 +401,7 @@ interpret(struct f_inst *what) return interpret(t->data); } break; - case 'iM': /* IP.MASK(val) */ + case P('i','M'): /* IP.MASK(val) */ TWOARGS; if (v2.type != T_INT) runtime( "Can not use this type for mask."); @@ -410,6 +421,7 @@ interpret(struct f_inst *what) return res; } +#undef ARG #define ARG(x,y) \ if (!i_same(f1->y, f2->y)) \ return 0; @@ -436,13 +448,13 @@ i_same(struct f_inst *f1, struct f_inst *f2) case ',': /* fall through */ case '+': case '/': - case '!=': - case '==': + case P('!','='): + case P('=','='): case '<': - case '<=': TWOARGS; break; + case P('<','='): TWOARGS; break; case '~': TWOARGS; break; - case 'de': ONEARG; break; + case P('d','e'): ONEARG; break; case 's': ARG(v2, a2.p); @@ -465,23 +477,25 @@ i_same(struct f_inst *f1, struct f_inst *f2) case 'p': ONEARG; break; case '?': TWOARGS; break; case '0': break; - case 'p,': ONEARG; A2_SAME; break; + case P('p',','): ONEARG; A2_SAME; break; case 'a': A2_SAME; break; - case 'ea': A2_SAME; break; - case 'eS': ONEARG; A2_SAME; break; + case P('e','a'): A2_SAME; break; + case P('e','S'): ONEARG; A2_SAME; break; - case 'cp': ONEARG; break; - case 'ca': /* CALL, FIXME: exponential in some cases */ + case 'r': ONEARG; break; + case P('c','p'): ONEARG; break; + case P('c','a'): /* CALL, FIXME: exponential in some cases */ ONEARG; if (!i_same(f1->a2.p, f2->a2.p)) return 0; break; - case 'SW': ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; - case 'iM': TWOARGS; break; + case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; + case P('i','M'): TWOARGS; break; default: bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); } return i_same(f1->next, f2->next); } -/* FIXME: tmp_attrs is unreferenced. That can't be right */ +/* FIXME: tmp_attrs is unreferenced. That can't be right. + Strange. look at eS how dynamic attrs are set. */ int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool) { @@ -500,8 +514,6 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc return res.val.i; } - - void filters_postconfig(void) { diff --git a/filter/filter.h b/filter/filter.h index ace72e47..a08f1267 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -91,16 +91,15 @@ void val_print(struct f_val v); /* Internal types */ /* Do not use type of zero, that way we'll see errors easier. */ #define T_VOID 1 -#define T_RETURN 2 /* User visible types, which fit in int */ #define T_INT 0x10 #define T_BOOL 0x11 #define T_PAIR 0x12 -/* Put enumerational types in 0x30..0x7f range */ +/* Put enumerational types in 0x30..0x3f range */ #define T_ENUM_LO 0x30 -#define T_ENUM_HI 0x7f +#define T_ENUM_HI 0x3f #define T_ENUM_RTS 0x30 @@ -111,6 +110,7 @@ void val_print(struct f_val v); #define T_PREFIX 0x21 #define T_STRING 0x22 +#define T_RETURN 0x40 #define T_SET 0x80 struct f_tree { @@ -121,4 +121,6 @@ struct f_tree { #define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); +/* Create pair from two letters */ + #endif diff --git a/filter/test.conf b/filter/test.conf index 616dbc58..e42feadb 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -8,7 +8,7 @@ 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; int i; @@ -23,7 +23,13 @@ int i; } } -function startup () +function fifteen() +{ + print "fifteen called"; + return 15; +} + +function startup() int i; prefix px; ip p; @@ -58,6 +64,9 @@ ip p; callme ( 4, 2 ); callme ( 7, 2 ); + i = fifteen(); + print "Testing function calls: 15 = " i; + print "done"; quitbird; # print "*** FAIL: this is unreachable";