Merge branch 'master' into int-new

This commit is contained in:
Jan Maria Matejka 2018-03-13 16:51:04 +01:00
commit d1ba927b36
5 changed files with 330 additions and 276 deletions

View file

@ -49,6 +49,8 @@ CF_DECLS
struct rtable_config *r; struct rtable_config *r;
struct channel_config *cc; struct channel_config *cc;
struct f_inst *x; struct f_inst *x;
struct f_dynamic_attr fda;
struct f_static_attr fsa;
struct filter *f; struct filter *f;
struct f_tree *e; struct f_tree *e;
struct f_trie *trie; struct f_trie *trie;

View file

@ -12,8 +12,6 @@ CF_HDR
CF_DEFINES CF_DEFINES
#define P(a,b) ((a << 8) | b)
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
@ -157,12 +155,11 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
} }
static inline struct f_inst * static inline struct f_inst *
f_generate_empty(struct f_inst *dyn) f_generate_empty(struct f_dynamic_attr dyn)
{ {
struct f_inst *e = f_new_inst(); struct f_inst *e = f_new_inst(FI_EMPTY);
e->code = 'E';
switch (dyn->aux & EAF_TYPE_MASK) { switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH: case EAF_TYPE_AS_PATH:
e->aux = T_PATH; e->aux = T_PATH;
break; break;
@ -179,9 +176,9 @@ f_generate_empty(struct f_inst *dyn)
cf_error("Can't empty that attribute"); cf_error("Can't empty that attribute");
} }
dyn->code = P('e','S'); struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
dyn->a1.p = e; s->a1.p = e;
return dyn; return s;
} }
@ -190,21 +187,19 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
{ {
struct f_inst *rv; struct f_inst *rv;
if ((t1->code == 'c') && (t2->code == 'c')) { if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT)) if ((t1->aux != T_INT) || (t2->aux != T_INT))
cf_error( "Can't operate with value of non-integer type in pair constructor"); cf_error( "Can't operate with value of non-integer type in pair constructor");
check_u16(t1->a2.i); check_u16(t1->a2.i);
check_u16(t2->a2.i); check_u16(t2->a2.i);
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT);
rv->code = 'c';
rv->aux = T_PAIR; rv->aux = T_PAIR;
rv->a2.i = pair(t1->a2.i, t2->a2.i); rv->a2.i = pair(t1->a2.i, t2->a2.i);
} }
else { else {
rv = f_new_inst(); rv = f_new_inst(FI_PAIR_CONSTRUCT);
rv->code = P('m', 'p');
rv->a1.p = t1; rv->a1.p = t1;
rv->a2.p = t2; rv->a2.p = t2;
} }
@ -219,7 +214,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
int c1 = 0, c2 = 0, ipv4_used = 0; int c1 = 0, c2 = 0, ipv4_used = 0;
u32 key = 0, val2 = 0; u32 key = 0, val2 = 0;
if (tk->code == 'c') { if (tk->fi_code == FI_CONSTANT) {
c1 = 1; c1 = 1;
if (tk->aux == T_INT) { if (tk->aux == T_INT) {
@ -233,7 +228,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
} }
/* IP->Quad implicit conversion */ /* IP->Quad implicit conversion */
else if (tk->code == 'C') { else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
c1 = 1; c1 = 1;
struct f_val *val = tk->a1.p; struct f_val *val = tk->a1.p;
@ -250,7 +245,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
} }
if (tv->code == 'c') { if (tv->fi_code == FI_CONSTANT) {
if (tv->aux != T_INT) if (tv->aux != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor"); cf_error("Can't operate with value of non-integer type in EC constructor");
c2 = 1; c2 = 1;
@ -276,15 +271,13 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
} }
NEW_F_VAL; NEW_F_VAL;
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->code = 'C';
rv->a1.p = val; rv->a1.p = val;
val->type = T_EC; val->type = T_EC;
val->val.ec = ec; val->val.ec = ec;
} }
else { else {
rv = f_new_inst(); rv = f_new_inst(FI_EC_CONSTRUCT);
rv->code = P('m','c');
rv->aux = kind; rv->aux = kind;
rv->a1.p = tk; rv->a1.p = tk;
rv->a2.p = tv; rv->a2.p = tv;
@ -298,12 +291,11 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{ {
struct f_inst *rv; struct f_inst *rv;
if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) { if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->code = 'C';
NEW_F_VAL; NEW_F_VAL;
rv->a1.p = val; rv->a1.p = val;
@ -314,7 +306,7 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{ {
rv = cfg_allocz(sizeof(struct f_inst3)); rv = cfg_allocz(sizeof(struct f_inst3));
rv->lineno = ifs->lino; rv->lineno = ifs->lino;
rv->code = P('m','l'); rv->fi_code = FI_LC_CONSTRUCT;
rv->a1.p = t1; rv->a1.p = t1;
rv->a2.p = t2; rv->a2.p = t2;
INST3(rv).p = t3; INST3(rv).p = t3;
@ -372,8 +364,7 @@ static struct f_inst *
assert_done(struct f_inst *expr, const char *start, const char *end) assert_done(struct f_inst *expr, const char *start, const char *end)
{ {
struct f_inst *i; struct f_inst *i;
i = f_new_inst(); i = f_new_inst(FI_ASSERT);
i->code = P('a','s');
i->a1.p = expr; i->a1.p = expr;
if (end >= start) if (end >= start)
@ -412,7 +403,9 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN %nonassoc THEN
%nonassoc ELSE %nonassoc ELSE
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter filter_body where_filter %type <f> filter filter_body where_filter
%type <i> type break_command ec_kind %type <i> type break_command ec_kind
%type <i32> cnum %type <i32> cnum
@ -543,16 +536,13 @@ where_filter:
/* Construct 'IF term THEN ACCEPT; REJECT;' */ /* Construct 'IF term THEN ACCEPT; REJECT;' */
struct filter *f = cfg_alloc(sizeof(struct filter)); struct filter *f = cfg_alloc(sizeof(struct filter));
struct f_inst *i, *acc, *rej; struct f_inst *i, *acc, *rej;
acc = f_new_inst(); /* ACCEPT */ acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
acc->code = P('p',',');
acc->a1.p = NULL; acc->a1.p = NULL;
acc->a2.i = F_ACCEPT; acc->a2.i = F_ACCEPT;
rej = f_new_inst(); /* REJECT */ rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
rej->code = P('p',',');
rej->a1.p = NULL; rej->a1.p = NULL;
rej->a2.i = F_REJECT; rej->a2.i = F_REJECT;
i = f_new_inst(); /* IF */ i = f_new_inst(FI_CONDITION); /* IF */
i->code = '?';
i->a1.p = $2; i->a1.p = $2;
i->a2.p = acc; i->a2.p = acc;
i->next = rej; i->next = rej;
@ -571,8 +561,7 @@ function_body:
decls '{' cmds '}' { decls '{' cmds '}' {
if ($1) { if ($1) {
/* Prepend instruction to clear local variables */ /* Prepend instruction to clear local variables */
$$ = f_new_inst(); $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
$$->code = P('c','v');
$$->a1.p = $1; $$->a1.p = $1;
$$->next = $3; $$->next = $3;
} else } else
@ -755,7 +744,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
} }
; ;
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
bgp_path_expr: bgp_path_expr:
symbol { $$ = $1; } symbol { $$ = $1; }
@ -776,17 +765,17 @@ bgp_path_tail:
; ;
constant: constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; } | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; } | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
| net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; } | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; } | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
| bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; } | bgp_path { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
; ;
constructor: constructor:
@ -801,7 +790,7 @@ constructor:
* For such cases, we force the dynamic_attr list to contain * For such cases, we force the dynamic_attr list to contain
* at least an invalid token, so it is syntantically correct. * at least an invalid token, so it is syntantically correct.
*/ */
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
rtadot: /* EMPTY, we are not permitted RTA. prefix */ rtadot: /* EMPTY, we are not permitted RTA. prefix */
; ;
@ -813,8 +802,7 @@ function_call:
if ($1->class != SYM_FUNCTION) if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really."); cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name); DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(); $$ = f_new_inst(FI_CALL);
$$->code = P('c','a');
$$->a1.p = inst; $$->a1.p = inst;
$$->a2.p = $1->def; $$->a2.p = $1->def;
sym = $1->aux2; sym = $1->aux2;
@ -831,11 +819,9 @@ function_call:
symbol: symbol:
SYM { SYM {
$$ = f_new_inst();
switch ($1->class & 0xff00) { switch ($1->class & 0xff00) {
case SYM_CONSTANT: $$->code = 'C'; break; case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
case SYM_VARIABLE: $$->code = 'V'; break; case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
default: cf_error("%s: variable expected.", $1->name); default: cf_error("%s: variable expected.", $1->name);
} }
@ -844,57 +830,57 @@ symbol:
} }
static_attr: static_attr:
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; } FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; } | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
| NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; } | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; } | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; } | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; } | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; } | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; } | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; } | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
; ;
term: term:
'(' term ')' { $$ = $2; } '(' term ')' { $$ = $2; }
| term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
| term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; } | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
| term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; } | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
| term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; } | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
| term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; } | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
| term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; } | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; } | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
| term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; } | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
| term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
| term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; } | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
| term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
| term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; } | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
| term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
| term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; } | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
| '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; } | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
| symbol { $$ = $1; } | symbol { $$ = $1; }
| constant { $$ = $1; } | constant { $$ = $1; }
| constructor { $$ = $1; } | constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; } | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
| rtadot static_attr { $$ = $2; $$->code = 'a'; } | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
| rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); } | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
| term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; } | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; }
| term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; } | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; } | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
| term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; } | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
| term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; } | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; }
| term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; } | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; } | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
/* Communities */ /* Communities */
/* This causes one shift/reduce conflict /* This causes one shift/reduce conflict
@ -904,19 +890,19 @@ term:
| rtadot dynamic_attr '.' RESET{ } | rtadot dynamic_attr '.' RESET{ }
*/ */
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; } | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
| FORMAT '(' term ')' { $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; } | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; }
/* | term '.' LEN { $$->code = P('P','l'); } */ /* | term '.' LEN { $$->code = P('P','l'); } */
@ -927,8 +913,7 @@ term:
if ($1->class != SYM_FUNCTION) if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really."); cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name); DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(); $$ = f_new_inst(FI_CALL);
$$->code = P('c','a');
$$->a1.p = inst; $$->a1.p = inst;
$$->a2.p = $1->def; $$->a2.p = $1->def;
sym = $1->aux2; sym = $1->aux2;
@ -953,7 +938,7 @@ break_command:
; ;
print_one: print_one:
term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
; ;
print_list: /* EMPTY */ { $$ = NULL; } print_list: /* EMPTY */ { $$ = NULL; }
@ -967,15 +952,13 @@ print_list: /* EMPTY */ { $$ = NULL; }
; ;
var_listn: term { var_listn: term {
$$ = f_new_inst(); $$ = f_new_inst(FI_SET);
$$->code = 's';
$$->a1.p = NULL; $$->a1.p = NULL;
$$->a2.p = $1; $$->a2.p = $1;
$$->next = NULL; $$->next = NULL;
} }
| term ',' var_listn { | term ',' var_listn {
$$ = f_new_inst(); $$ = f_new_inst(FI_SET);
$$->code = 's';
$$->a1.p = NULL; $$->a1.p = NULL;
$$->a2.p = $1; $$->a2.p = $1;
$$->next = $3; $$->next = $3;
@ -988,73 +971,63 @@ var_list: /* EMPTY */ { $$ = NULL; }
cmd: cmd:
IF term THEN block { IF term THEN block {
$$ = f_new_inst(); $$ = f_new_inst(FI_CONDITION);
$$->code = '?';
$$->a1.p = $2; $$->a1.p = $2;
$$->a2.p = $4; $$->a2.p = $4;
} }
| IF term THEN block ELSE block { | IF term THEN block ELSE block {
struct f_inst *i = f_new_inst(); struct f_inst *i = f_new_inst(FI_CONDITION);
i->code = '?';
i->a1.p = $2; i->a1.p = $2;
i->a2.p = $4; i->a2.p = $4;
$$ = f_new_inst(); $$ = f_new_inst(FI_CONDITION);
$$->code = '?';
$$->a1.p = i; $$->a1.p = i;
$$->a2.p = $6; $$->a2.p = $6;
} }
| SYM '=' term ';' { | SYM '=' term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll set value\n" ); DBG( "Ook, we'll set value\n" );
if (($1->class & ~T_MASK) != SYM_VARIABLE) if (($1->class & ~T_MASK) != SYM_VARIABLE)
cf_error( "You may set only variables." ); cf_error( "You may set only variables." );
$$->code = 's'; $$ = f_new_inst(FI_SET);
$$->a1.p = $1; $$->a1.p = $1;
$$->a2.p = $3; $$->a2.p = $3;
} }
| RETURN term ';' { | RETURN term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll return the value\n" ); DBG( "Ook, we'll return the value\n" );
$$->code = 'r'; $$ = f_new_inst(FI_RETURN);
$$->a1.p = $2; $$->a1.p = $2;
} }
| rtadot dynamic_attr '=' term ';' { | rtadot dynamic_attr '=' term ';' {
$$ = $2; $$ = f_new_inst_da(FI_EA_SET, $2);
$$->code = P('e','S');
$$->a1.p = $4; $$->a1.p = $4;
} }
| rtadot static_attr '=' term ';' { | rtadot static_attr '=' term ';' {
$$ = $2; $$ = f_new_inst_sa(FI_RTA_SET, $2);
if (!$$->a1.i) if (!$$->a1.i)
cf_error( "This static attribute is read-only."); cf_error( "This static attribute is read-only.");
$$->code = P('a','S');
$$->a1.p = $4; $$->a1.p = $4;
} }
| PREFERENCE '=' term ';' { | PREFERENCE '=' term ';' {
$$ = f_new_inst(); $$ = f_new_inst(FI_PREF_SET);
$$->code = P('P','S');
$$->a1.p = $3; $$->a1.p = $3;
} }
| UNSET '(' rtadot dynamic_attr ')' ';' { | UNSET '(' rtadot dynamic_attr ')' ';' {
$$ = $4; $$ = f_new_inst_da(FI_EA_SET, $4);
$$->aux = EAF_TYPE_UNDEF | EAF_TEMP; $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
$$->code = P('e','S');
$$->a1.p = NULL; $$->a1.p = NULL;
} }
| break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; } | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
| function_call ';' { $$ = $1; } | function_call ';' { $$ = $1; }
| CASE term '{' switch_body '}' { | CASE term '{' switch_body '}' {
$$ = f_new_inst(); $$ = f_new_inst(FI_SWITCH);
$$->code = P('S','W');
$$->a1.p = $2; $$->a1.p = $2;
$$->a2.p = build_tree( $4 ); $$->a2.p = build_tree( $4 );
} }
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
; ;

View file

@ -2,6 +2,7 @@
* Filters: utility functions * Filters: utility functions
* *
* Copyright 1998 Pavel Machek <pavel@ucw.cz> * Copyright 1998 Pavel Machek <pavel@ucw.cz>
* 2017 Jan Maria Matejka <mq@ucw.cz>
* *
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -13,43 +14,48 @@
#define P(a,b) ((a<<8) | b) #define P(a,b) ((a<<8) | b)
struct f_inst * struct f_inst *
f_new_inst(void) f_new_inst(enum f_instruction_code fi_code)
{ {
struct f_inst * ret; struct f_inst * ret;
ret = cfg_alloc(sizeof(struct f_inst)); ret = cfg_allocz(sizeof(struct f_inst));
ret->code = ret->aux = 0; ret->fi_code = fi_code;
ret->arg1 = ret->arg2 = ret->next = NULL;
ret->lineno = ifs->lino; ret->lineno = ifs->lino;
return ret; return ret;
} }
struct f_inst * struct f_inst *
f_new_dynamic_attr(int type, int f_type, int code) f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
{ {
/* FIXME: Remove the f_type parameter? */ struct f_inst *ret = f_new_inst(fi_code);
struct f_inst *f = f_new_inst(); ret->aux = (da.f_type << 8) | da.type;
f->aux = (f_type << 8) | type; ret->a2.i = da.ea_code;
f->a2.i = code; return ret;
return f; }
struct f_inst *
f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
{
struct f_inst *ret = f_new_inst(fi_code);
ret->aux = sa.f_type;
ret->a2.i = sa.sa_code;
ret->a1.i = sa.readonly;
return ret;
} }
/* /*
* Generate set_dynamic( operation( get_dynamic(), argument ) ) * Generate set_dynamic( operation( get_dynamic(), argument ) )
*/ */
struct f_inst * struct f_inst *
f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument) f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
{ {
struct f_inst *set_dyn = f_new_inst(), struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
*oper = f_new_inst(), *oper = f_new_inst(operation),
*get_dyn = dyn; *get_dyn = f_new_inst_da(FI_EA_GET, da);
*set_dyn = *get_dyn;
get_dyn->code = P('e','a');
oper->code = operation;
oper->aux = operation_aux; oper->aux = operation_aux;
oper->a1.p = get_dyn; oper->a1.p = get_dyn;
oper->a2.p = argument; oper->a2.p = argument;
set_dyn->code = P('e','S');
set_dyn->a1.p = oper; set_dyn->a1.p = oper;
return set_dyn; return set_dyn;
} }
@ -58,7 +64,7 @@ struct f_inst *
f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
{ {
struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check)); struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
ret->i.code = P('R','C'); ret->i.fi_code = FI_ROA_CHECK;
ret->i.lineno = ifs->lino; ret->i.lineno = ifs->lino;
ret->i.arg1 = prefix; ret->i.arg1 = prefix;
ret->i.arg2 = asn; ret->i.arg2 = asn;

View file

@ -48,8 +48,6 @@
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h" #include "filter/filter.h"
#define P(a,b) ((a<<8) | b)
#define CMP_ERROR 999 #define CMP_ERROR 999
void (*bt_assert_hook)(int result, struct f_inst *assert); void (*bt_assert_hook)(int result, struct f_inst *assert);
@ -462,7 +460,6 @@ val_in_range(struct f_val v1, struct f_val v2)
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i); return int_set_contains(v2.val.ad, v1.val.i);
/* IP->Quad implicit conversion */ /* IP->Quad implicit conversion */
if (val_is_ip4(v1) && (v2.type == T_CLIST)) if (val_is_ip4(v1) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip)); return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
@ -632,22 +629,20 @@ static struct f_val
interpret(struct f_inst *what) interpret(struct f_inst *what)
{ {
struct symbol *sym; struct symbol *sym;
struct f_val v1, v2, res, *vp; struct f_val v1, v2, res = { .type = T_VOID }, *vp;
unsigned u1, u2; unsigned u1, u2;
int i; int i;
u32 as; u32 as;
for ( ; what; what = what->next) {
res.type = T_VOID; res.type = T_VOID;
if (!what) switch(what->fi_code) {
return res; case FI_COMMA:
switch(what->code) {
case ',':
TWOARGS; TWOARGS;
break; break;
/* Binary operators */ /* Binary operators */
case '+': case FI_ADD:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -655,7 +650,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '-': case FI_SUBTRACT:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -663,7 +658,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '*': case FI_MULTIPLY:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -671,7 +666,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '/': case FI_DIVIDE:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -681,12 +676,12 @@ interpret(struct f_inst *what)
} }
break; break;
case '&': case FI_AND:
case '|': case FI_OR:
ARG(v1, a1.p); ARG(v1, a1.p);
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "Can't do boolean operation on non-booleans" ); runtime( "Can't do boolean operation on non-booleans" );
if (v1.val.i == (what->code == '|')) { if (v1.val.i == (what->fi_code == FI_OR)) {
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = v1.val.i; res.val.i = v1.val.i;
break; break;
@ -699,7 +694,7 @@ interpret(struct f_inst *what)
res.val.i = v2.val.i; res.val.i = v2.val.i;
break; break;
case P('m','p'): case FI_PAIR_CONSTRUCT:
TWOARGS; TWOARGS;
if ((v1.type != T_INT) || (v2.type != T_INT)) if ((v1.type != T_INT) || (v2.type != T_INT))
runtime( "Can't operate with value of non-integer type in pair constructor" ); runtime( "Can't operate with value of non-integer type in pair constructor" );
@ -711,7 +706,7 @@ interpret(struct f_inst *what)
res.type = T_PAIR; res.type = T_PAIR;
break; break;
case P('m','c'): case FI_EC_CONSTRUCT:
{ {
TWOARGS; TWOARGS;
@ -757,7 +752,7 @@ interpret(struct f_inst *what)
break; break;
} }
case P('m','l'): case FI_LC_CONSTRUCT:
{ {
TWOARGS; TWOARGS;
@ -793,12 +788,12 @@ interpret(struct f_inst *what)
res.val.i = (x); \ res.val.i = (x); \
break; break;
case P('!','='): SAME(!i); case FI_NEQ: SAME(!i);
case P('=','='): SAME(i); case FI_EQ: SAME(i);
case '<': COMPARE(i==-1); case FI_LT: COMPARE(i==-1);
case P('<','='): COMPARE(i!=1); case FI_LTE: COMPARE(i!=1);
case '!': case FI_NOT:
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "Not applied to non-boolean" ); runtime( "Not applied to non-boolean" );
@ -806,7 +801,7 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i; res.val.i = !res.val.i;
break; break;
case '~': case FI_MATCH:
TWOARGS; TWOARGS;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
@ -815,7 +810,7 @@ interpret(struct f_inst *what)
res.val.i = !!res.val.i; res.val.i = !!res.val.i;
break; break;
case P('!','~'): case FI_NOT_MATCH:
TWOARGS; TWOARGS;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
@ -824,12 +819,12 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i; res.val.i = !res.val.i;
break; break;
case P('d','e'): case FI_DEFINED:
ONEARG; ONEARG;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = (v1.type != T_VOID) && !undef_value(v1); res.val.i = (v1.type != T_VOID) && !undef_value(v1);
break; break;
case 'T': case FI_TYPE:
ONEARG; ONEARG;
switch (v1.type) switch (v1.type)
{ {
@ -841,7 +836,7 @@ interpret(struct f_inst *what)
runtime( "Can't determine type of this item" ); runtime( "Can't determine type of this item" );
} }
break; break;
case P('I','i'): case FI_IS_V4:
ONEARG; ONEARG;
if (v1.type != T_IP) if (v1.type != T_IP)
runtime( "IP version check needs an IP address" ); runtime( "IP version check needs an IP address" );
@ -850,7 +845,7 @@ interpret(struct f_inst *what)
break; break;
/* Set to indirect value, a1 = variable, a2 = value */ /* Set to indirect value, a1 = variable, a2 = value */
case 's': case FI_SET:
ARG(v2, a2.p); ARG(v2, a2.p);
sym = what->a1.p; sym = what->a1.p;
vp = sym->def; vp = sym->def;
@ -869,7 +864,7 @@ interpret(struct f_inst *what)
break; break;
/* some constants have value in a2, some in *a1.p, strange. */ /* some constants have value in a2, some in *a1.p, strange. */
case 'c': /* integer (or simple type) constant, string, set, or prefix_set */ case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */
res.type = what->aux; res.type = what->aux;
if (res.type == T_PREFIX_SET) if (res.type == T_PREFIX_SET)
@ -881,15 +876,15 @@ interpret(struct f_inst *what)
else else
res.val.i = what->a2.i; res.val.i = what->a2.i;
break; break;
case 'V': case FI_VARIABLE:
case 'C': case FI_CONSTANT_INDIRECT:
res = * ((struct f_val *) what->a1.p); res = * ((struct f_val *) what->a1.p);
break; break;
case 'p': case FI_PRINT:
ONEARG; ONEARG;
val_format(v1, &f_buf); val_format(v1, &f_buf);
break; break;
case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "If requires boolean expression" ); runtime( "If requires boolean expression" );
@ -899,10 +894,10 @@ interpret(struct f_inst *what)
} else res.val.i = 1; } else res.val.i = 1;
res.type = T_BOOL; res.type = T_BOOL;
break; break;
case '0': case FI_NOP:
debug( "No operation\n" ); debug( "No operation\n" );
break; break;
case P('p',','): case FI_PRINT_AND_DIE:
ONEARG; ONEARG;
if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
!(f_flags & FF_SILENT)) !(f_flags & FF_SILENT))
@ -925,7 +920,7 @@ interpret(struct f_inst *what)
bug( "unknown return type: Can't happen"); bug( "unknown return type: Can't happen");
} }
break; break;
case 'a': /* rta access */ case FI_RTA_GET: /* rta access */
{ {
ACCESS_RTE; ACCESS_RTE;
struct rta *rta = (*f_rte)->attrs; struct rta *rta = (*f_rte)->attrs;
@ -948,7 +943,7 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('a','S'): case FI_RTA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
if (what->aux != v1.type) if (what->aux != v1.type)
@ -1000,7 +995,7 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('e','a'): /* Access to extended attributes */ case FI_EA_GET: /* Access to extended attributes */
ACCESS_RTE; ACCESS_RTE;
{ {
eattr *e = NULL; eattr *e = NULL;
@ -1094,7 +1089,7 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('e','S'): case FI_EA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
{ {
@ -1198,12 +1193,12 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case 'P': case FI_PREF_GET:
ACCESS_RTE; ACCESS_RTE;
res.type = T_INT; res.type = T_INT;
res.val.i = (*f_rte)->pref; res.val.i = (*f_rte)->pref;
break; break;
case P('P','S'): case FI_PREF_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
if (v1.type != T_INT) if (v1.type != T_INT)
@ -1213,7 +1208,7 @@ interpret(struct f_inst *what)
f_rte_cow(); f_rte_cow();
(*f_rte)->pref = v1.val.i; (*f_rte)->pref = v1.val.i;
break; break;
case 'L': /* Get length of */ case FI_LENGTH: /* Get length of */
ONEARG; ONEARG;
res.type = T_INT; res.type = T_INT;
switch(v1.type) { switch(v1.type) {
@ -1225,7 +1220,7 @@ interpret(struct f_inst *what)
default: runtime( "Prefix, path, clist or eclist expected" ); default: runtime( "Prefix, path, clist or eclist expected" );
} }
break; break;
case P('R','m'): /* Get ROA max prefix length */ case FI_ROA_MAXLEN: /* Get ROA max prefix length */
ONEARG; ONEARG;
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (v1.type != T_NET || !net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
@ -1235,7 +1230,7 @@ interpret(struct f_inst *what)
((net_addr_roa4 *) v1.val.net)->max_pxlen : ((net_addr_roa4 *) v1.val.net)->max_pxlen :
((net_addr_roa6 *) v1.val.net)->max_pxlen; ((net_addr_roa6 *) v1.val.net)->max_pxlen;
break; break;
case P('R','a'): /* Get ROA ASN */ case FI_ROA_ASN: /* Get ROA ASN */
ONEARG; ONEARG;
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (v1.type != T_NET || !net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
@ -1245,14 +1240,14 @@ interpret(struct f_inst *what)
((net_addr_roa4 *) v1.val.net)->asn : ((net_addr_roa4 *) v1.val.net)->asn :
((net_addr_roa6 *) v1.val.net)->asn; ((net_addr_roa6 *) v1.val.net)->asn;
break; break;
case P('c','p'): /* Convert prefix to ... */ case FI_IP: /* Convert prefix to ... */
ONEARG; ONEARG;
if (v1.type != T_NET) if (v1.type != T_NET)
runtime( "Prefix expected" ); runtime( "Prefix expected" );
res.type = T_IP; res.type = T_IP;
res.val.ip = net_prefix(v1.val.net); res.val.ip = net_prefix(v1.val.net);
break; break;
case P('R','D'): case FI_ROUTE_DISTINGUISHER:
ONEARG; ONEARG;
if (v1.type != T_NET) if (v1.type != T_NET)
runtime( "Prefix expected" ); runtime( "Prefix expected" );
@ -1261,7 +1256,7 @@ interpret(struct f_inst *what)
res.type = T_RD; res.type = T_RD;
res.val.ec = net_rd(v1.val.net); res.val.ec = net_rd(v1.val.net);
break; break;
case P('a','f'): /* Get first ASN from AS PATH */ case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1271,7 +1266,7 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as; res.val.i = as;
break; break;
case P('a','l'): /* Get last ASN from AS PATH */ case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1281,7 +1276,7 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as; res.val.i = as;
break; break;
case P('a','L'): /* Get last ASN from non-aggregated part of AS PATH */ case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1289,23 +1284,23 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as_path_get_last_nonaggregated(v1.val.ad); res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
break; break;
case 'r': case FI_RETURN:
ONEARG; ONEARG;
res = v1; res = v1;
res.type |= T_RETURN; res.type |= T_RETURN;
return res; return res;
case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */ case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */
ONEARG; ONEARG;
res = interpret(what->a2.p); res = interpret(what->a2.p);
if (res.type == T_RETURN) if (res.type == T_RETURN)
return res; return res;
res.type &= ~T_RETURN; res.type &= ~T_RETURN;
break; break;
case P('c','v'): /* Clear local variables */ case FI_CLEAR_LOCAL_VARS: /* Clear local variables */
for (sym = what->a1.p; sym != NULL; sym = sym->aux2) for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
((struct f_val *) sym->def)->type = T_VOID; ((struct f_val *) sym->def)->type = T_VOID;
break; break;
case P('S','W'): case FI_SWITCH:
ONEARG; ONEARG;
{ {
struct f_tree *t = find_tree(what->a2.p, v1); struct f_tree *t = find_tree(what->a2.p, v1);
@ -1324,7 +1319,7 @@ interpret(struct f_inst *what)
return res; return res;
} }
break; break;
case P('i','M'): /* IP.MASK(val) */ case FI_IP_MASK: /* IP.MASK(val) */
TWOARGS; TWOARGS;
if (v2.type != T_INT) if (v2.type != T_INT)
runtime( "Integer expected"); runtime( "Integer expected");
@ -1337,11 +1332,11 @@ interpret(struct f_inst *what)
ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))); ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
break; break;
case 'E': /* Create empty attribute */ case FI_EMPTY: /* Create empty attribute */
res.type = what->aux; res.type = what->aux;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = adata_empty(f_pool, 0);
break; break;
case P('A','p'): /* Path prepend */ case FI_PATH_PREPEND: /* Path prepend */
TWOARGS; TWOARGS;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime("Can't prepend to non-path"); runtime("Can't prepend to non-path");
@ -1352,7 +1347,7 @@ interpret(struct f_inst *what)
res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i); res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
break; break;
case P('C','a'): /* (Extended) Community list add or delete */ case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */
TWOARGS; TWOARGS;
if (v1.type == T_PATH) if (v1.type == T_PATH)
{ {
@ -1518,8 +1513,7 @@ interpret(struct f_inst *what)
break; break;
case FI_ROA_CHECK: /* ROA Check */
case P('R','C'): /* ROA Check */
if (what->arg1) if (what->arg1)
{ {
TWOARGS; TWOARGS;
@ -1559,14 +1553,14 @@ interpret(struct f_inst *what)
break; break;
case P('f','m'): /* Format */ case FI_FORMAT: /* Format */
ONEARG; ONEARG;
res.type = T_STRING; res.type = T_STRING;
res.val.s = val_format_str(v1); res.val.s = val_format_str(v1);
break; break;
case P('a','s'): /* Birdtest Assert */ case FI_ASSERT: /* Birdtest Assert */
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
@ -1579,10 +1573,8 @@ interpret(struct f_inst *what)
break; break;
default: default:
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
} }}
if (what->next)
return interpret(what->next);
return res; return res;
} }
@ -1609,40 +1601,39 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 1; return 1;
if (f1->aux != f2->aux) if (f1->aux != f2->aux)
return 0; return 0;
if (f1->code != f2->code) if (f1->fi_code != f2->fi_code)
return 0; return 0;
if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
return 1; return 1;
switch(f1->code) { switch(f1->fi_code) {
case ',': /* fall through */ case FI_COMMA: /* fall through */
case '+': case FI_ADD:
case '-': case FI_SUBTRACT:
case '*': case FI_MULTIPLY:
case '/': case FI_DIVIDE:
case '|': case FI_OR:
case '&': case FI_AND:
case P('m','p'): case FI_PAIR_CONSTRUCT:
case P('m','c'): case FI_EC_CONSTRUCT:
case P('!','='): case FI_NEQ:
case P('=','='): case FI_EQ:
case '<': case FI_LT:
case P('<','='): TWOARGS; break; case FI_LTE: TWOARGS; break;
case '!': ONEARG; break; case FI_NOT: ONEARG; break;
case P('!', '~'): case FI_NOT_MATCH:
case '~': TWOARGS; break; case FI_MATCH: TWOARGS; break;
case P('d','e'): ONEARG; break; case FI_DEFINED: ONEARG; break;
case 'T': ONEARG; break; case FI_TYPE: ONEARG; break;
case P('n','T'): break;
case P('m','l'): case FI_LC_CONSTRUCT:
TWOARGS; TWOARGS;
if (!i_same(INST3(f1).p, INST3(f2).p)) if (!i_same(INST3(f1).p, INST3(f2).p))
return 0; return 0;
break; break;
case 's': case FI_SET:
ARG(v2, a2.p); ARG(v2, a2.p);
{ {
struct symbol *s1, *s2; struct symbol *s1, *s2;
@ -1655,7 +1646,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
} }
break; break;
case 'c': case FI_CONSTANT:
switch (f1->aux) { switch (f1->aux) {
case T_PREFIX_SET: case T_PREFIX_SET:
@ -1678,44 +1669,44 @@ i_same(struct f_inst *f1, struct f_inst *f2)
} }
break; break;
case 'C': case FI_CONSTANT_INDIRECT:
if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
return 0; return 0;
break; break;
case 'V': case FI_VARIABLE:
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0; return 0;
break; break;
case 'p': case 'L': ONEARG; break; case FI_PRINT: case FI_LENGTH: ONEARG; break;
case '?': TWOARGS; break; case FI_CONDITION: TWOARGS; break;
case '0': case 'E': break; case FI_NOP: case FI_EMPTY: break;
case P('p',','): ONEARG; A2_SAME; break; case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
case 'P': case FI_PREF_GET:
case 'a': A2_SAME; break; case FI_RTA_GET: A2_SAME; break;
case P('e','a'): A2_SAME; break; case FI_EA_GET: A2_SAME; break;
case P('P','S'): case FI_PREF_SET:
case P('a','S'): case FI_RTA_SET:
case P('e','S'): ONEARG; A2_SAME; break; case FI_EA_SET: ONEARG; A2_SAME; break;
case 'r': ONEARG; break; case FI_RETURN: ONEARG; break;
case P('c','p'): ONEARG; break; case FI_IP: ONEARG; break;
case P('R','D'): ONEARG; break; case FI_ROUTE_DISTINGUISHER: ONEARG; break;
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
ONEARG; ONEARG;
if (!i_same(f1->a2.p, f2->a2.p)) if (!i_same(f1->a2.p, f2->a2.p))
return 0; return 0;
f2->a2.p = f1->a2.p; f2->a2.p = f1->a2.p;
break; break;
case P('c','v'): break; /* internal instruction */ case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
case P('i','M'): TWOARGS; break; case FI_IP_MASK: TWOARGS; break;
case P('A','p'): TWOARGS; break; case FI_PATH_PREPEND: TWOARGS; break;
case P('C','a'): TWOARGS; break; case FI_CLIST_ADD_DEL: TWOARGS; break;
case P('a','f'): case FI_AS_PATH_FIRST:
case P('a','l'): case FI_AS_PATH_LAST:
case P('a','L'): ONEARG; break; case FI_AS_PATH_LAST_NAG: ONEARG; break;
case P('R','C'): case FI_ROA_CHECK:
TWOARGS; TWOARGS;
/* Does not really make sense - ROA check results may change anyway */ /* Does not really make sense - ROA check results may change anyway */
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
@ -1723,7 +1714,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 0; return 0;
break; break;
default: default:
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
} }
return i_same(f1->next, f2->next); return i_same(f1->next, f2->next);
} }

View file

@ -14,9 +14,74 @@
#include "nest/route.h" #include "nest/route.h"
#include "nest/attrs.h" #include "nest/attrs.h"
/* Filter instruction types */
#define FI__TWOCHAR(a,b) ((a<<8) | b)
#define FI__LIST \
F(FI_COMMA, 0, ',') \
F(FI_ADD, 0, '+') \
F(FI_SUBTRACT, 0, '-') \
F(FI_MULTIPLY, 0, '*') \
F(FI_DIVIDE, 0, '/') \
F(FI_AND, 0, '&') \
F(FI_OR, 0, '|') \
F(FI_PAIR_CONSTRUCT, 'm', 'p') \
F(FI_EC_CONSTRUCT, 'm', 'c') \
F(FI_LC_CONSTRUCT, 'm', 'l') \
F(FI_NEQ, '!', '=') \
F(FI_EQ, '=', '=') \
F(FI_LT, 0, '<') \
F(FI_LTE, '<', '=') \
F(FI_NOT, 0, '!') \
F(FI_MATCH, 0, '~') \
F(FI_NOT_MATCH, '!', '~') \
F(FI_DEFINED, 'd', 'e') \
F(FI_TYPE, 0, 'T') \
F(FI_IS_V4, 'I', 'i') \
F(FI_SET, 0, 's') \
F(FI_CONSTANT, 0, 'c') \
F(FI_VARIABLE, 0, 'V') \
F(FI_CONSTANT_INDIRECT, 0, 'C') \
F(FI_PRINT, 0, 'p') \
F(FI_CONDITION, 0, '?') \
F(FI_NOP, 0, '0') \
F(FI_PRINT_AND_DIE, 'p', ',') \
F(FI_RTA_GET, 0, 'a') \
F(FI_RTA_SET, 'a', 'S') \
F(FI_EA_GET, 'e', 'a') \
F(FI_EA_SET, 'e', 'S') \
F(FI_PREF_GET, 0, 'P') \
F(FI_PREF_SET, 'P', 'S') \
F(FI_LENGTH, 0, 'L') \
F(FI_ROA_MAXLEN, 'R', 'M') \
F(FI_ROA_ASN, 'R', 'A') \
F(FI_IP, 'c', 'p') \
F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \
F(FI_AS_PATH_FIRST, 'a', 'f') \
F(FI_AS_PATH_LAST, 'a', 'l') \
F(FI_AS_PATH_LAST_NAG, 'a', 'L') \
F(FI_RETURN, 0, 'r') \
F(FI_CALL, 'c', 'a') \
F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \
F(FI_SWITCH, 'S', 'W') \
F(FI_IP_MASK, 'i', 'M') \
F(FI_EMPTY, 0, 'E') \
F(FI_PATH_PREPEND, 'A', 'p') \
F(FI_CLIST_ADD_DEL, 'C', 'a') \
F(FI_ROA_CHECK, 'R', 'C') \
F(FI_FORMAT, 0, 'F') \
F(FI_ASSERT, 'a', 's')
enum f_instruction_code {
#define F(c,a,b) \
c = FI__TWOCHAR(a,b),
FI__LIST
#undef F
} PACKED;
struct f_inst { /* Instruction */ struct f_inst { /* Instruction */
struct f_inst *next; /* Structure is 16 bytes, anyway */ struct f_inst *next; /* Structure is 16 bytes, anyway */
u16 code; /* Instruction code, see the interpret() function and P() macro */ enum f_instruction_code fi_code;
u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union { union {
uint i; uint i;
@ -70,15 +135,32 @@ struct f_val {
} val; } val;
}; };
struct f_dynamic_attr {
int type;
int f_type;
int ea_code;
};
struct f_static_attr {
int f_type;
int sa_code;
int readonly;
};
struct filter { struct filter {
char *name; char *name;
struct f_inst *root; struct f_inst *root;
}; };
struct f_inst *f_new_inst(void); struct f_inst *f_new_inst(enum f_instruction_code fi_code);
struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */ struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
struct f_tree *f_new_tree(void); struct f_tree *f_new_tree(void);
struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument); struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);