version 1.1.1.1, 2017/08/22 12:33:54
|
version 1.1.1.2, 2021/03/17 19:50:23
|
Line 46
|
Line 46
|
#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 |
|
|
static struct adata * |
static struct adata * |
Line 84 pm_format(struct f_path_mask *p, buffer *buf)
|
Line 82 pm_format(struct f_path_mask *p, buffer *buf)
|
break; |
break; |
|
|
case PM_ASN_EXPR: |
case PM_ASN_EXPR: |
buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val)); | ASSERT(0); |
break; | |
} |
} |
|
|
p = p->next; |
p = p->next; |
Line 590 f_rta_cow(void)
|
Line 587 f_rta_cow(void)
|
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; |
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; |
|
|
#define runtime(x) do { \ |
#define runtime(x) do { \ |
log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \ | if (!(f_flags & FF_SILENT)) \ |
| log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \ |
res.type = T_RETURN; \ |
res.type = T_RETURN; \ |
res.val.i = F_ERROR; \ |
res.val.i = F_ERROR; \ |
return res; \ |
return res; \ |
Line 634 static struct f_val
|
Line 632 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; | |
| |
switch(what->code) { | |
case ',': | |
TWOARGS; | |
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" ); |
Line 657 interpret(struct f_inst *what)
|
Line 649 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" ); |
Line 665 interpret(struct f_inst *what)
|
Line 657 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" ); |
Line 673 interpret(struct f_inst *what)
|
Line 665 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" ); |
Line 683 interpret(struct f_inst *what)
|
Line 675 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; |
Line 701 interpret(struct f_inst *what)
|
Line 693 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" ); |
Line 713 interpret(struct f_inst *what)
|
Line 705 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; |
|
|
Line 761 interpret(struct f_inst *what)
|
Line 753 interpret(struct f_inst *what)
|
break; |
break; |
} |
} |
|
|
case P('m','l'): | case FI_LC_CONSTRUCT: |
{ |
{ |
TWOARGS; |
TWOARGS; |
|
|
Line 779 interpret(struct f_inst *what)
|
Line 771 interpret(struct f_inst *what)
|
break; |
break; |
} |
} |
|
|
|
case FI_PATHMASK_CONSTRUCT: |
|
{ |
|
struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin; |
|
|
|
while (tt) { |
|
*vv = lp_alloc(f_pool, sizeof(struct f_path_mask)); |
|
if (tt->kind == PM_ASN_EXPR) { |
|
struct f_val res = interpret((struct f_inst *) tt->val); |
|
(*vv)->kind = PM_ASN; |
|
if (res.type != T_INT) { |
|
runtime( "Error resolving path mask template: value not an integer" ); |
|
return (struct f_val) { .type = T_VOID }; |
|
} |
|
|
|
(*vv)->val = res.val.i; |
|
} else { |
|
**vv = *tt; |
|
} |
|
tt = tt->next; |
|
vv = &((*vv)->next); |
|
} |
|
|
|
res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin }; |
|
break; |
|
} |
|
|
/* Relational operators */ |
/* Relational operators */ |
|
|
#define COMPARE(x) \ |
#define COMPARE(x) \ |
Line 797 interpret(struct f_inst *what)
|
Line 815 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" ); |
Line 810 interpret(struct f_inst *what)
|
Line 828 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); |
Line 819 interpret(struct f_inst *what)
|
Line 837 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); |
Line 828 interpret(struct f_inst *what)
|
Line 846 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); |
res.val.i = (v1.type != T_VOID); |
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; |
Line 854 interpret(struct f_inst *what)
|
Line 872 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) |
Line 866 interpret(struct f_inst *what)
|
Line 884 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" ); |
Line 884 interpret(struct f_inst *what)
|
Line 902 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)) |
log_commit(*L_INFO, &f_buf); |
log_commit(*L_INFO, &f_buf); |
|
|
switch (what->a2.i) { |
switch (what->a2.i) { |
Line 909 interpret(struct f_inst *what)
|
Line 928 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; |
Line 934 interpret(struct f_inst *what)
|
Line 953 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) |
Line 981 interpret(struct f_inst *what)
|
Line 1000 interpret(struct f_inst *what)
|
rta->hostentry = NULL; |
rta->hostentry = NULL; |
break; |
break; |
|
|
|
case SA_IFNAME: |
|
{ |
|
struct iface *ifa = if_find_by_name(v1.val.s); |
|
if (!ifa) |
|
runtime( "Invalid iface name" ); |
|
|
|
rta->dest = RTD_DEVICE; |
|
rta->gw = IPA_NONE; |
|
rta->iface = ifa; |
|
rta->nexthops = NULL; |
|
rta->hostentry = NULL; |
|
} |
|
break; |
|
|
default: |
default: |
bug("Invalid static attribute access (%x)", res.type); |
bug("Invalid static attribute access (%x)", res.type); |
} |
} |
} |
} |
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; |
Line 1072 interpret(struct f_inst *what)
|
Line 1105 interpret(struct f_inst *what)
|
} |
} |
} |
} |
break; |
break; |
case P('e','S'): | case FI_EA_SET: |
ACCESS_RTE; |
ACCESS_RTE; |
ONEARG; |
ONEARG; |
{ |
{ |
Line 1088 interpret(struct f_inst *what)
|
Line 1121 interpret(struct f_inst *what)
|
|
|
switch (what->aux & EAF_TYPE_MASK) { |
switch (what->aux & EAF_TYPE_MASK) { |
case EAF_TYPE_INT: |
case EAF_TYPE_INT: |
if (v1.type != T_INT) | // Enums are also ints, so allow them in. |
| if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI)) |
runtime( "Setting int attribute to non-int value" ); |
runtime( "Setting int attribute to non-int value" ); |
l->attrs[0].u.data = v1.val.i; |
l->attrs[0].u.data = v1.val.i; |
break; |
break; |
Line 1177 interpret(struct f_inst *what)
|
Line 1211 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) |
Line 1192 interpret(struct f_inst *what)
|
Line 1226 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) { |
Line 1204 interpret(struct f_inst *what)
|
Line 1238 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('c','p'): /* Convert prefix to ... */ | case FI_IP: /* Convert prefix to ... */ |
ONEARG; |
ONEARG; |
if (v1.type != T_PREFIX) |
if (v1.type != T_PREFIX) |
runtime( "Prefix expected" ); |
runtime( "Prefix expected" ); |
Line 1215 interpret(struct f_inst *what)
|
Line 1249 interpret(struct f_inst *what)
|
default: bug( "Unknown prefix to conversion" ); |
default: bug( "Unknown prefix to conversion" ); |
} |
} |
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" ); |
Line 1225 interpret(struct f_inst *what)
|
Line 1259 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" ); |
Line 1235 interpret(struct f_inst *what)
|
Line 1269 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" ); |
Line 1243 interpret(struct f_inst *what)
|
Line 1277 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); |
Line 1278 interpret(struct f_inst *what)
|
Line 1312 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"); |
Line 1291 interpret(struct f_inst *what)
|
Line 1325 interpret(struct f_inst *what)
|
} |
} |
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"); |
Line 1306 interpret(struct f_inst *what)
|
Line 1340 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) |
{ |
{ |
Line 1474 interpret(struct f_inst *what)
|
Line 1508 interpret(struct f_inst *what)
|
|
|
break; |
break; |
|
|
case P('R','C'): /* ROA Check */ | case FI_ROA_CHECK: /* ROA Check */ |
if (what->arg1) |
if (what->arg1) |
{ |
{ |
TWOARGS; |
TWOARGS; |
Line 1493 interpret(struct f_inst *what)
|
Line 1527 interpret(struct f_inst *what)
|
/* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */ |
/* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */ |
eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02)); |
eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02)); |
|
|
if (!e || e->type != EAF_TYPE_AS_PATH) | if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH)) |
runtime("Missing AS_PATH attribute"); |
runtime("Missing AS_PATH attribute"); |
|
|
as_path_get_last(e->u.ptr, &as); |
as_path_get_last(e->u.ptr, &as); |
Line 1508 interpret(struct f_inst *what)
|
Line 1542 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; |
} |
} |
|
|
Line 1538 i_same(struct f_inst *f1, struct f_inst *f2)
|
Line 1570 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_ADD: /* fall through */ |
case '+': | case FI_SUBTRACT: |
case '-': | case FI_MULTIPLY: |
case '*': | case FI_DIVIDE: |
case '/': | case FI_OR: |
case '|': | case FI_AND: |
case '&': | case FI_PAIR_CONSTRUCT: |
case P('m','p'): | case FI_EC_CONSTRUCT: |
case P('m','c'): | case FI_NEQ: |
case P('!','='): | case FI_EQ: |
case P('=','='): | case FI_LT: |
case '<': | case FI_LTE: TWOARGS; break; |
case P('<','='): TWOARGS; break; | |
|
|
case '!': ONEARG; break; | case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a1.p, f2->a1.p)) return 0; break; |
case '~': TWOARGS; break; | |
case P('d','e'): ONEARG; break; | |
|
|
case P('m','l'): | case FI_NOT: ONEARG; break; |
| case FI_NOT_MATCH: |
| case FI_MATCH: TWOARGS; break; |
| case FI_DEFINED: ONEARG; break; |
| |
| 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; |
Line 1581 i_same(struct f_inst *f1, struct f_inst *f2)
|
Line 1615 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: |
Line 1604 i_same(struct f_inst *f1, struct f_inst *f2)
|
Line 1638 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('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 resuls may change anyway */ |
/* Does not really make sense - ROA check resuls may change anyway */ |
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, |
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, |
Line 1648 i_same(struct f_inst *f1, struct f_inst *f2)
|
Line 1682 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); |
} |
} |
Line 1721 f_run(struct filter *filter, struct rte **rte, struct
|
Line 1755 f_run(struct filter *filter, struct rte **rte, struct
|
|
|
|
|
if (res.type != T_RETURN) { |
if (res.type != T_RETURN) { |
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); | if (!(f_flags & FF_SILENT)) |
| log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); |
return F_ERROR; |
return F_ERROR; |
} |
} |
DBG( "done (%u)\n", res.val.i ); |
DBG( "done (%u)\n", res.val.i ); |
Line 1775 f_eval_int(struct f_inst *expr)
|
Line 1810 f_eval_int(struct f_inst *expr)
|
cf_error("Integer expression expected"); |
cf_error("Integer expression expected"); |
|
|
return res.val.i; |
return res.val.i; |
} |
|
|
|
u32 |
|
f_eval_asn(struct f_inst *expr) |
|
{ |
|
/* Called as a part of another interpret call, therefore no log_reset() */ |
|
struct f_val res = interpret(expr); |
|
return (res.type == T_INT) ? res.val.i : 0; |
|
} |
} |
|
|
/** |
/** |