Filter: Instruction codes named as enum

The two-letter instructions were quite messy but they could be easily
read from memory dumps. Now GDB (since 2012) supports pretty printing
enum values and GCC checks the switch construction for missing enum
values so we are converting the nice two-byte values to enums.

Anyway, the enum still keeps the old two-byte values to be able to read
the instruction codes even without GDB from plain memory dump.
This commit is contained in:
Maria Jan Matejka 2017-10-19 12:39:44 +02:00 committed by Jan Maria Matejka
parent 2d6d4b8053
commit 5a14df3950
5 changed files with 305 additions and 252 deletions

View file

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

View file

@ -12,8 +12,6 @@ CF_HDR
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_a(u32 p) { return p >> 16; }
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 *
f_generate_empty(struct f_inst *dyn)
f_generate_empty(struct f_dynamic_attr dyn)
{
struct f_inst *e = f_new_inst();
e->code = 'E';
struct f_inst *e = f_new_inst(FI_EMPTY);
switch (dyn->aux & EAF_TYPE_MASK) {
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
e->aux = T_PATH;
break;
@ -179,9 +176,9 @@ f_generate_empty(struct f_inst *dyn)
cf_error("Can't empty that attribute");
}
dyn->code = P('e','S');
dyn->a1.p = e;
return dyn;
struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
s->a1.p = e;
return s;
}
@ -190,21 +187,19 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
{
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))
cf_error( "Can't operate with value of non-integer type in pair constructor");
check_u16(t1->a2.i);
check_u16(t2->a2.i);
rv = f_new_inst();
rv->code = 'c';
rv = f_new_inst(FI_CONSTANT);
rv->aux = T_PAIR;
rv->a2.i = pair(t1->a2.i, t2->a2.i);
}
else {
rv = f_new_inst();
rv->code = P('m', 'p');
rv = f_new_inst(FI_PAIR_CONSTRUCT);
rv->a1.p = t1;
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;
u32 key = 0, val2 = 0;
if (tk->code == 'c') {
if (tk->fi_code == FI_CONSTANT) {
c1 = 1;
if (tk->aux == T_INT) {
@ -234,7 +229,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
#ifndef IPV6
/* IP->Quad implicit conversion */
else if (tk->code == 'C') {
else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
c1 = 1;
struct f_val *val = tk->a1.p;
@ -252,7 +247,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
}
#endif
if (tv->code == 'c') {
if (tv->fi_code == FI_CONSTANT) {
if (tv->aux != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor");
c2 = 1;
@ -278,15 +273,13 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
}
NEW_F_VAL;
rv = f_new_inst();
rv->code = 'C';
rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->a1.p = val;
val->type = T_EC;
val->val.ec = ec;
}
else {
rv = f_new_inst();
rv->code = P('m','c');
rv = f_new_inst(FI_EC_CONSTRUCT);
rv->aux = kind;
rv->a1.p = tk;
rv->a2.p = tv;
@ -300,12 +293,11 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{
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))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
rv = f_new_inst();
rv->code = 'C';
rv = f_new_inst(FI_CONSTANT_INDIRECT);
NEW_F_VAL;
rv->a1.p = val;
@ -316,7 +308,7 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{
rv = cfg_allocz(sizeof(struct f_inst3));
rv->lineno = ifs->lino;
rv->code = P('m','l');
rv->fi_code = FI_LC_CONSTRUCT;
rv->a1.p = t1;
rv->a2.p = t2;
INST3(rv).p = t3;
@ -348,7 +340,9 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN
%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 <i> type break_command ec_kind
%type <i32> cnum
@ -461,16 +455,13 @@ where_filter:
/* Construct 'IF term THEN ACCEPT; REJECT;' */
struct filter *f = cfg_alloc(sizeof(struct filter));
struct f_inst *i, *acc, *rej;
acc = f_new_inst(); /* ACCEPT */
acc->code = P('p',',');
acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
acc->a1.p = NULL;
acc->a2.i = F_ACCEPT;
rej = f_new_inst(); /* REJECT */
rej->code = P('p',',');
rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
rej->a1.p = NULL;
rej->a2.i = F_REJECT;
i = f_new_inst(); /* IF */
i->code = '?';
i = f_new_inst(FI_CONDITION); /* IF */
i->a1.p = $2;
i->a2.p = acc;
i->next = rej;
@ -489,8 +480,7 @@ function_body:
decls '{' cmds '}' {
if ($1) {
/* Prepend instruction to clear local variables */
$$ = f_new_inst();
$$->code = P('c','v');
$$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
$$->a1.p = $1;
$$->next = $3;
} else
@ -680,7 +670,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:
symbol { $$ = $1; }
@ -708,17 +698,17 @@ bgp_path_tail2:
;
constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
| fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
| RTRID { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_QUAD; $$->a2.i = $1; }
| '[' 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" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->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; }
NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
| '[' 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(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
| 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:
@ -733,7 +723,7 @@ constructor:
* For such cases, we force the dynamic_attr list to contain
* 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 */
;
@ -745,8 +735,7 @@ function_call:
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst();
$$->code = P('c','a');
$$ = f_new_inst(FI_CALL);
$$->a1.p = inst;
$$->a2.p = $1->def;
sym = $1->aux2;
@ -763,11 +752,9 @@ function_call:
symbol:
SYM {
$$ = f_new_inst();
switch ($1->class & 0xff00) {
case SYM_CONSTANT: $$->code = 'C'; break;
case SYM_VARIABLE: $$->code = 'V'; break;
case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
default: cf_error("%s: variable expected.", $1->name);
}
@ -776,53 +763,53 @@ symbol:
}
static_attr:
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
| NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = SA_NET; }
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
| CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; }
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
| GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
| NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); }
| PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
| SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
| SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
| CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
| DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
;
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 = $3; }
| term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
| term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; }
| term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
| term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
| term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
| term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
| term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
| term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
| term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
| term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; }
| '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
| term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
| term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
| term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->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(FI_AND); $$->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(FI_EQ); $$->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(FI_LT); $$->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(FI_LT); $$->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(FI_MATCH); $$->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(FI_NOT); $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
| symbol { $$ = $1; }
| constant { $$ = $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 '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
/* Communities */
/* This causes one shift/reduce conflict
@ -832,20 +819,18 @@ term:
| rtadot dynamic_attr '.' RESET{ }
*/
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->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'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
| ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
/* | term '.' LEN { $$->code = P('P','l'); } */
/* function_call is inlined here */
| SYM '(' var_list ')' {
struct symbol *sym;
@ -853,8 +838,7 @@ term:
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst();
$$->code = P('c','a');
$$ = f_new_inst(FI_CALL);
$$->a1.p = inst;
$$->a2.p = $1->def;
sym = $1->aux2;
@ -879,7 +863,7 @@ break_command:
;
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; }
@ -893,15 +877,13 @@ print_list: /* EMPTY */ { $$ = NULL; }
;
var_listn: term {
$$ = f_new_inst();
$$->code = 's';
$$ = f_new_inst(FI_SET);
$$->a1.p = NULL;
$$->a2.p = $1;
$$->next = NULL;
}
| term ',' var_listn {
$$ = f_new_inst();
$$->code = 's';
$$ = f_new_inst(FI_SET);
$$->a1.p = NULL;
$$->a2.p = $1;
$$->next = $3;
@ -914,74 +896,64 @@ var_list: /* EMPTY */ { $$ = NULL; }
cmd:
IF term THEN block {
$$ = f_new_inst();
$$->code = '?';
$$ = f_new_inst(FI_CONDITION);
$$->a1.p = $2;
$$->a2.p = $4;
}
| IF term THEN block ELSE block {
struct f_inst *i = f_new_inst();
i->code = '?';
struct f_inst *i = f_new_inst(FI_CONDITION);
i->a1.p = $2;
i->a2.p = $4;
$$ = f_new_inst();
$$->code = '?';
$$ = f_new_inst(FI_CONDITION);
$$->a1.p = i;
$$->a2.p = $6;
}
| SYM '=' term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll set value\n" );
if (($1->class & ~T_MASK) != SYM_VARIABLE)
cf_error( "You may set only variables." );
$$->code = 's';
$$ = f_new_inst(FI_SET);
$$->a1.p = $1;
$$->a2.p = $3;
}
| RETURN term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll return the value\n" );
$$->code = 'r';
$$ = f_new_inst(FI_RETURN);
$$->a1.p = $2;
}
| rtadot dynamic_attr '=' term ';' {
$$ = $2;
$$->code = P('e','S');
$$ = f_new_inst_da(FI_EA_SET, $2);
$$->a1.p = $4;
}
| rtadot static_attr '=' term ';' {
$$ = $2;
$$ = f_new_inst_sa(FI_RTA_SET, $2);
if (!$$->a1.i)
cf_error( "This static attribute is read-only.");
$$->code = P('a','S');
$$->a1.p = $4;
}
| PREFERENCE '=' term ';' {
$$ = f_new_inst();
$$->code = P('P','S');
$$ = f_new_inst(FI_PREF_SET);
$$->a1.p = $3;
}
| UNSET '(' rtadot dynamic_attr ')' ';' {
$$ = $4;
$$ = f_new_inst_da(FI_EA_SET, $4);
$$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
$$->code = P('e','S');
$$->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; }
| CASE term '{' switch_body '}' {
$$ = f_new_inst();
$$->code = P('S','W');
$$ = f_new_inst(FI_SWITCH);
$$->a1.p = $2;
$$->a2.p = build_tree( $4 );
}
| 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 '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $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( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
;
CF_END

View file

@ -2,6 +2,7 @@
* Filters: utility functions
*
* 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.
*/
@ -13,43 +14,48 @@
#define P(a,b) ((a<<8) | b)
struct f_inst *
f_new_inst(void)
f_new_inst(enum f_instruction_code fi_code)
{
struct f_inst * ret;
ret = cfg_alloc(sizeof(struct f_inst));
ret->code = ret->aux = 0;
ret->arg1 = ret->arg2 = ret->next = NULL;
ret = cfg_allocz(sizeof(struct f_inst));
ret->fi_code = fi_code;
ret->lineno = ifs->lino;
return ret;
}
struct f_inst *
f_new_dynamic_attr(int type, int f_type UNUSED, 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 *f = f_new_inst();
f->aux = type;
f->a2.i = code;
return f;
struct f_inst *ret = f_new_inst(fi_code);
ret->aux = da.type;
ret->a2.i = da.ea_code;
return ret;
}
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 ) )
*/
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(),
*oper = f_new_inst(),
*get_dyn = dyn;
struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
*oper = f_new_inst(operation),
*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->a1.p = get_dyn;
oper->a2.p = argument;
set_dyn->code = P('e','S');
set_dyn->a1.p = oper;
return set_dyn;
}
@ -59,7 +65,7 @@ struct f_inst *
f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn)
{
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.arg1 = prefix;
ret->i.arg2 = asn;

View file

@ -46,8 +46,6 @@
#include "conf/conf.h"
#include "filter/filter.h"
#define P(a,b) ((a<<8) | b)
#define CMP_ERROR 999
static struct adata *
@ -644,13 +642,13 @@ interpret(struct f_inst *what)
if (!what)
return res;
switch(what->code) {
case ',':
switch(what->fi_code) {
case FI_COMMA:
TWOARGS;
break;
/* Binary operators */
case '+':
case FI_ADD:
TWOARGS_C;
switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" );
@ -658,7 +656,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" );
}
break;
case '-':
case FI_SUBTRACT:
TWOARGS_C;
switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" );
@ -666,7 +664,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" );
}
break;
case '*':
case FI_MULTIPLY:
TWOARGS_C;
switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" );
@ -674,7 +672,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" );
}
break;
case '/':
case FI_DIVIDE:
TWOARGS_C;
switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" );
@ -684,12 +682,12 @@ interpret(struct f_inst *what)
}
break;
case '&':
case '|':
case FI_AND:
case FI_OR:
ARG(v1, a1.p);
if (v1.type != T_BOOL)
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.val.i = v1.val.i;
break;
@ -702,7 +700,7 @@ interpret(struct f_inst *what)
res.val.i = v2.val.i;
break;
case P('m','p'):
case FI_PAIR_CONSTRUCT:
TWOARGS;
if ((v1.type != T_INT) || (v2.type != T_INT))
runtime( "Can't operate with value of non-integer type in pair constructor" );
@ -714,7 +712,7 @@ interpret(struct f_inst *what)
res.type = T_PAIR;
break;
case P('m','c'):
case FI_EC_CONSTRUCT:
{
TWOARGS;
@ -762,7 +760,7 @@ interpret(struct f_inst *what)
break;
}
case P('m','l'):
case FI_LC_CONSTRUCT:
{
TWOARGS;
@ -798,12 +796,12 @@ interpret(struct f_inst *what)
res.val.i = (x); \
break;
case P('!','='): SAME(!i);
case P('=','='): SAME(i);
case '<': COMPARE(i==-1);
case P('<','='): COMPARE(i!=1);
case FI_NEQ: SAME(!i);
case FI_EQ: SAME(i);
case FI_LT: COMPARE(i==-1);
case FI_LTE: COMPARE(i!=1);
case '!':
case FI_NOT:
ONEARG;
if (v1.type != T_BOOL)
runtime( "Not applied to non-boolean" );
@ -811,7 +809,7 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i;
break;
case '~':
case FI_MATCH:
TWOARGS;
res.type = T_BOOL;
res.val.i = val_in_range(v1, v2);
@ -820,7 +818,7 @@ interpret(struct f_inst *what)
res.val.i = !!res.val.i;
break;
case P('!','~'):
case FI_NOT_MATCH:
TWOARGS;
res.type = T_BOOL;
res.val.i = val_in_range(v1, v2);
@ -829,14 +827,14 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i;
break;
case P('d','e'):
case FI_DEFINED:
ONEARG;
res.type = T_BOOL;
res.val.i = (v1.type != T_VOID);
break;
/* Set to indirect value, a1 = variable, a2 = value */
case 's':
case FI_SET:
ARG(v2, a2.p);
sym = what->a1.p;
vp = sym->def;
@ -855,7 +853,7 @@ interpret(struct f_inst *what)
break;
/* 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;
if (res.type == T_PREFIX_SET)
@ -867,15 +865,15 @@ interpret(struct f_inst *what)
else
res.val.i = what->a2.i;
break;
case 'V':
case 'C':
case FI_VARIABLE:
case FI_CONSTANT_INDIRECT:
res = * ((struct f_val *) what->a1.p);
break;
case 'p':
case FI_PRINT:
ONEARG;
val_format(v1, &f_buf);
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;
if (v1.type != T_BOOL)
runtime( "If requires boolean expression" );
@ -885,10 +883,10 @@ interpret(struct f_inst *what)
} else res.val.i = 1;
res.type = T_BOOL;
break;
case '0':
case FI_NOP:
debug( "No operation\n" );
break;
case P('p',','):
case FI_PRINT_AND_DIE:
ONEARG;
if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
!(f_flags & FF_SILENT))
@ -911,7 +909,7 @@ interpret(struct f_inst *what)
bug( "unknown return type: Can't happen");
}
break;
case 'a': /* rta access */
case FI_RTA_GET: /* rta access */
{
ACCESS_RTE;
struct rta *rta = (*f_rte)->attrs;
@ -936,7 +934,7 @@ interpret(struct f_inst *what)
}
}
break;
case P('a','S'):
case FI_RTA_SET:
ACCESS_RTE;
ONEARG;
if (what->aux != v1.type)
@ -988,7 +986,7 @@ interpret(struct f_inst *what)
}
}
break;
case P('e','a'): /* Access to extended attributes */
case FI_EA_GET: /* Access to extended attributes */
ACCESS_RTE;
{
eattr *e = NULL;
@ -1074,7 +1072,7 @@ interpret(struct f_inst *what)
}
}
break;
case P('e','S'):
case FI_EA_SET:
ACCESS_RTE;
ONEARG;
{
@ -1180,12 +1178,12 @@ interpret(struct f_inst *what)
}
}
break;
case 'P':
case FI_PREF_GET:
ACCESS_RTE;
res.type = T_INT;
res.val.i = (*f_rte)->pref;
break;
case P('P','S'):
case FI_PREF_SET:
ACCESS_RTE;
ONEARG;
if (v1.type != T_INT)
@ -1195,7 +1193,7 @@ interpret(struct f_inst *what)
f_rte_cow();
(*f_rte)->pref = v1.val.i;
break;
case 'L': /* Get length of */
case FI_LENGTH: /* Get length of */
ONEARG;
res.type = T_INT;
switch(v1.type) {
@ -1207,7 +1205,7 @@ interpret(struct f_inst *what)
default: runtime( "Prefix, path, clist or eclist expected" );
}
break;
case P('c','p'): /* Convert prefix to ... */
case FI_IP: /* Convert prefix to ... */
ONEARG;
if (v1.type != T_PREFIX)
runtime( "Prefix expected" );
@ -1218,7 +1216,7 @@ interpret(struct f_inst *what)
default: bug( "Unknown prefix to conversion" );
}
break;
case P('a','f'): /* Get first ASN from AS PATH */
case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
ONEARG;
if (v1.type != T_PATH)
runtime( "AS path expected" );
@ -1228,7 +1226,7 @@ interpret(struct f_inst *what)
res.type = T_INT;
res.val.i = as;
break;
case P('a','l'): /* Get last ASN from AS PATH */
case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */
ONEARG;
if (v1.type != T_PATH)
runtime( "AS path expected" );
@ -1238,7 +1236,7 @@ interpret(struct f_inst *what)
res.type = T_INT;
res.val.i = as;
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;
if (v1.type != T_PATH)
runtime( "AS path expected" );
@ -1246,23 +1244,23 @@ interpret(struct f_inst *what)
res.type = T_INT;
res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
break;
case 'r':
case FI_RETURN:
ONEARG;
res = v1;
res.type |= T_RETURN;
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;
res = interpret(what->a2.p);
if (res.type == T_RETURN)
return res;
res.type &= ~T_RETURN;
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)
((struct f_val *) sym->def)->type = T_VOID;
break;
case P('S','W'):
case FI_SWITCH:
ONEARG;
{
struct f_tree *t = find_tree(what->a2.p, v1);
@ -1281,7 +1279,7 @@ interpret(struct f_inst *what)
return res;
}
break;
case P('i','M'): /* IP.MASK(val) */
case FI_IP_MASK: /* IP.MASK(val) */
TWOARGS;
if (v2.type != T_INT)
runtime( "Integer expected");
@ -1294,11 +1292,11 @@ interpret(struct f_inst *what)
}
break;
case 'E': /* Create empty attribute */
case FI_EMPTY: /* Create empty attribute */
res.type = what->aux;
res.val.ad = adata_empty(f_pool, 0);
break;
case P('A','p'): /* Path prepend */
case FI_PATH_PREPEND: /* Path prepend */
TWOARGS;
if (v1.type != T_PATH)
runtime("Can't prepend to non-path");
@ -1309,7 +1307,7 @@ interpret(struct f_inst *what)
res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
break;
case P('C','a'): /* (Extended) Community list add or delete */
case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */
TWOARGS;
if (v1.type == T_PATH)
{
@ -1477,7 +1475,7 @@ interpret(struct f_inst *what)
break;
case P('R','C'): /* ROA Check */
case FI_ROA_CHECK: /* ROA Check */
if (what->arg1)
{
TWOARGS;
@ -1511,7 +1509,7 @@ interpret(struct f_inst *what)
break;
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);
@ -1541,38 +1539,38 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 1;
if (f1->aux != f2->aux)
return 0;
if (f1->code != f2->code)
if (f1->fi_code != f2->fi_code)
return 0;
if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
return 1;
switch(f1->code) {
case ',': /* fall through */
case '+':
case '-':
case '*':
case '/':
case '|':
case '&':
case P('m','p'):
case P('m','c'):
case P('!','='):
case P('=','='):
case '<':
case P('<','='): TWOARGS; break;
switch(f1->fi_code) {
case FI_COMMA: /* fall through */
case FI_ADD:
case FI_SUBTRACT:
case FI_MULTIPLY:
case FI_DIVIDE:
case FI_OR:
case FI_AND:
case FI_PAIR_CONSTRUCT:
case FI_EC_CONSTRUCT:
case FI_NEQ:
case FI_EQ:
case FI_LT:
case FI_LTE: TWOARGS; break;
case '!': ONEARG; break;
case P('!', '~'):
case '~': TWOARGS; break;
case P('d','e'): ONEARG; break;
case FI_NOT: ONEARG; break;
case FI_NOT_MATCH:
case FI_MATCH: TWOARGS; break;
case FI_DEFINED: ONEARG; break;
case P('m','l'):
case FI_LC_CONSTRUCT:
TWOARGS;
if (!i_same(INST3(f1).p, INST3(f2).p))
return 0;
break;
case 's':
case FI_SET:
ARG(v2, a2.p);
{
struct symbol *s1, *s2;
@ -1585,7 +1583,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
}
break;
case 'c':
case FI_CONSTANT:
switch (f1->aux) {
case T_PREFIX_SET:
@ -1608,43 +1606,43 @@ i_same(struct f_inst *f1, struct f_inst *f2)
}
break;
case 'C':
case FI_CONSTANT_INDIRECT:
if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
return 0;
break;
case 'V':
case FI_VARIABLE:
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0;
break;
case 'p': case 'L': ONEARG; break;
case '?': TWOARGS; break;
case '0': case 'E': break;
case P('p',','): ONEARG; A2_SAME; break;
case 'P':
case 'a': A2_SAME; break;
case P('e','a'): A2_SAME; break;
case P('P','S'):
case P('a','S'):
case P('e','S'): ONEARG; A2_SAME; break;
case FI_PRINT: case FI_LENGTH: ONEARG; break;
case FI_CONDITION: TWOARGS; break;
case FI_NOP: case FI_EMPTY: break;
case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
case FI_PREF_GET:
case FI_RTA_GET: A2_SAME; break;
case FI_EA_GET: A2_SAME; break;
case FI_PREF_SET:
case FI_RTA_SET:
case FI_EA_SET: ONEARG; A2_SAME; break;
case 'r': ONEARG; break;
case P('c','p'): ONEARG; break;
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
case FI_RETURN: ONEARG; break;
case FI_IP: ONEARG; break;
case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
ONEARG;
if (!i_same(f1->a2.p, f2->a2.p))
return 0;
f2->a2.p = f1->a2.p;
break;
case P('c','v'): break; /* internal instruction */
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
case P('i','M'): TWOARGS; break;
case P('A','p'): TWOARGS; break;
case P('C','a'): TWOARGS; break;
case P('a','f'):
case P('a','l'):
case P('a','L'): ONEARG; break;
case P('R','C'):
case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
case FI_IP_MASK: TWOARGS; break;
case FI_PATH_PREPEND: TWOARGS; break;
case FI_CLIST_ADD_DEL: TWOARGS; break;
case FI_AS_PATH_FIRST:
case FI_AS_PATH_LAST:
case FI_AS_PATH_LAST_NAG: ONEARG; break;
case FI_ROA_CHECK:
TWOARGS;
/* Does not really make sense - ROA check resuls may change anyway */
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
@ -1652,7 +1650,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 0;
break;
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);
}

View file

@ -14,9 +14,67 @@
#include "nest/route.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_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_IP, 'c', 'p') \
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')
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 *next; /* Structure is 16 bytes, anyway */
u16 code;
enum f_instruction_code fi_code;
u16 aux;
union {
int i;
@ -75,15 +133,32 @@ struct f_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 {
char *name;
struct f_inst *root;
};
struct f_inst *f_new_inst(void);
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(enum f_instruction_code fi_code);
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_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 symbol *sym, struct f_inst *prefix, struct f_inst *asn);