diff options
-rw-r--r-- | filter/config.Y | 59 | ||||
-rw-r--r-- | filter/data.c | 1 | ||||
-rw-r--r-- | filter/data.h | 8 | ||||
-rw-r--r-- | filter/decl.m4 | 69 | ||||
-rw-r--r-- | filter/f-inst.c | 232 | ||||
-rw-r--r-- | filter/f-inst.h | 1 | ||||
-rw-r--r-- | filter/filter.c | 254 |
7 files changed, 260 insertions, 364 deletions
diff --git a/filter/config.Y b/filter/config.Y index f57575fc..3898748c 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -21,13 +21,9 @@ 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; } -#define f_generate_complex(fi_code, _da, arg) ({ \ - struct f_inst *fi = f_new_inst(fi_code, f_new_inst(FI_EA_GET, _da), arg); \ - fi->result.type = F_LVAL_EA; \ - fi->result.da = _da; \ - fi; \ -}) - +#define f_generate_complex(fi_code, da, arg) \ + f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) + /* * Sets and their items are during parsing handled as lists, linked * through left ptr. The first item in a list also contains a pointer @@ -188,10 +184,7 @@ f_generate_empty(struct f_dynamic_attr dyn) cf_error("Can't empty that attribute"); } - struct f_inst *fi = f_new_inst(FI_CONSTANT, empty); - fi->result.type = F_LVAL_EA; - fi->result.da = dyn; - return fi; + return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); } #if 0 @@ -404,34 +397,31 @@ assert_done(struct f_inst *expr, const char *start, const char *end) static struct f_inst * assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end) { - struct f_inst *getter; + struct f_inst *setter, *getter, *checker; switch (lval->type) { - case F_LVAL_STACK: - bug("This shall never happen"); - case F_LVAL_EXCEPTION: - bug("This shall never happen"); case F_LVAL_VARIABLE: + setter = f_new_inst(FI_VAR_SET, expr, lval->sym); getter = f_new_inst(FI_VAR_GET, lval->sym); break; case F_LVAL_PREFERENCE: + setter = f_new_inst(FI_PREF_SET, expr); getter = f_new_inst(FI_PREF_GET); break; case F_LVAL_SA: + setter = f_new_inst(FI_RTA_SET, expr, lval->sa); getter = f_new_inst(FI_RTA_GET, lval->sa); break; case F_LVAL_EA: + setter = f_new_inst(FI_EA_SET, expr, lval->da); getter = f_new_inst(FI_EA_GET, lval->da); break; + default: + bug("Unknown lval type"); } - struct f_inst *checker = f_new_inst(FI_EQ, expr, getter); - - struct f_inst *setter = cfg_alloc(sizeof(struct f_inst)); - *setter = *expr; - + checker = f_new_inst(FI_EQ, expr, getter); setter->next = checker; - setter->result = *lval; - + return assert_done(setter, start, end); } @@ -995,40 +985,29 @@ cmd: | CF_SYM_KNOWN '=' term ';' { switch ($1->class) { case SYM_VARIABLE_RANGE: - $3->result.type = F_LVAL_VARIABLE; - $3->result.sym = $1; + $$ = f_new_inst(FI_VAR_SET, $3, $1); break; case SYM_ATTRIBUTE: - $3->result.type = F_LVAL_EA; - $3->result.da = *$1->attribute; + $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); break; default: cf_error("Can't assign to symbol %s", $1->name); } - $$ = $3; } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); - $2->result.type = F_LVAL_EXCEPTION; - $2->result.exception = FE_RETURN; - $$ = $2; + $$ = f_new_inst(FI_RETURN, $2); } | dynamic_attr '=' term ';' { - $3->result.type = F_LVAL_EA; - $3->result.da = $1; - $$ = $3; + $$ = f_new_inst(FI_EA_SET, $3, $1); } | static_attr '=' term ';' { if ($1.readonly) cf_error( "This static attribute is read-only."); - - $3->result.type = F_LVAL_SA; - $3->result.sa = $1; - $$ = $3; + $$ = f_new_inst(FI_RTA_SET, $3, $1); } | PREFERENCE '=' term ';' { - $3->result.type = F_LVAL_PREFERENCE; - $$ = $3; + $$ = f_new_inst(FI_PREF_SET, $3); } | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); diff --git a/filter/data.c b/filter/data.c index cb759a59..912e2b00 100644 --- a/filter/data.c +++ b/filter/data.c @@ -525,3 +525,4 @@ val_dump(const struct f_val *v) { val_format(v, &b); return val_dump_buffer; } + diff --git a/filter/data.h b/filter/data.h index 3718cea4..6973008f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -107,15 +107,8 @@ struct f_static_attr { int readonly:1; /* Don't allow writing */ }; -/* Exception bits */ -enum f_exception { - FE_RETURN = 0x1, -}; - /* Filter l-value type */ enum f_lval_type { - F_LVAL_STACK = 0, - F_LVAL_EXCEPTION, F_LVAL_VARIABLE, F_LVAL_PREFERENCE, F_LVAL_SA, @@ -126,7 +119,6 @@ enum f_lval_type { struct f_lval { enum f_lval_type type; union { - enum f_exception exception; const struct symbol *sym; struct f_dynamic_attr da; struct f_static_attr sa; diff --git a/filter/decl.m4 b/filter/decl.m4 index a1d625f3..9934d0ba 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -119,6 +119,8 @@ case INST_NAME(): { m4_undivert(105) #undef what #undef item + dest->items[pos].fi_code = what_->fi_code; + dest->items[pos].lineno = what_->lineno; break; } m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) @@ -234,29 +236,9 @@ do { if (whati->fl$1) { } } while(0)m4_dnl FID_ALL()') -m4_define(RESULT_PTR, ` -FID_INTERPRET_BODY - do { - enum filter_return fret = f_lval_set(fs, &(what->result), $1); - if (fret != F_NOP) return fret; - } while (0)m4_dnl -FID_ALL()') - -m4_define(RESULT, ` -FID_INTERPRET_BODY - do { - struct f_val res_ = { .type = $1, .val.$2 = $3 }; - RESULT_PTR(&res_); - } while (0)m4_dnl -FID_ALL()') - -m4_define(RESULT_VOID, ` -FID_INTERPRET_BODY - do { - struct f_val res_ = { .type = T_VOID }; - RESULT_PTR(&res_); - } while (0)m4_dnl -FID_ALL()') +m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()') +m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') +m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()') m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') @@ -320,16 +302,6 @@ void f_dump_line(const struct f_line *dest, uint indent) for (uint i=0; i<dest->len; i++) { const struct f_line_item *item = &dest->items[i]; debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); - - switch (item->result.type) { - case F_LVAL_STACK: debug("%son stack\n", INDENT); break; - case F_LVAL_EXCEPTION: debug("%s=>exception 0x%x\n", INDENT, item->result.exception); break; - case F_LVAL_VARIABLE: debug("%s=>%s\n", INDENT, item->result.sym->name); break; - case F_LVAL_PREFERENCE: debug("%s=>preference\n", INDENT); break; - case F_LVAL_SA: debug("%s=>sa\n", INDENT); break; - case F_LVAL_EA: debug("%s=>ea\n", INDENT); break; - } - switch (item->fi_code) { FID_WR_PUT(7) default: bug("Unknown instruction %x in f_dump_line", item->fi_code); @@ -346,9 +318,6 @@ linearize(struct f_line *dest, const struct f_inst *what_, uint pos) switch (what_->fi_code) { FID_WR_PUT(8) } - dest->items[pos].fi_code = what_->fi_code; - dest->items[pos].lineno = what_->lineno; - dest->items[pos].result = what_->result; pos++; } return pos; @@ -391,32 +360,6 @@ f_same(const struct f_line *fl1, const struct f_line *fl2) if (f1_->flags != f2_->flags) return 0; - if (f1_->result.type != f2_->result.type) return 0; - switch (f1_->result.type) { - case F_LVAL_STACK: - break; - case F_LVAL_EXCEPTION: - if (f1_->result.exception != f2_->result.exception) - return 0; - break; - case F_LVAL_VARIABLE: - if (strcmp(f1_->result.sym->name, f2_->result.sym->name)) - return 0; - if (f1_->result.sym->class != f2_->result.sym->class) - return 0; - break; - case F_LVAL_PREFERENCE: - break; - case F_LVAL_SA: - if (f1_->result.sa.sa_code != f2_->result.sa.sa_code) - return 0; - break; - case F_LVAL_EA: - if (f1_->result.da.ea_code != f2_->result.da.ea_code) - return 0; - break; - } - switch(f1_->fi_code) { FID_WR_PUT(9) } @@ -439,7 +382,6 @@ struct f_inst { enum f_instruction_code fi_code; /* Instruction code */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ - struct f_lval result; /* Destination */ union { FID_WR_PUT(1) }; @@ -450,7 +392,6 @@ struct f_line_item { enum f_instruction_code fi_code; /* What to do */ enum f_instruction_flags flags; /* Flags, instruction-specific */ uint lineno; /* Where */ - struct f_lval result; /* Destination */ union { FID_WR_PUT(2) }; diff --git a/filter/f-inst.c b/filter/f-inst.c index 3be76d11..749e072c 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -36,7 +36,7 @@ * m4_dnl ACCESS_RTE; this instruction needs route * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes * m4_dnl RESULT(type, union-field, value); putting this on value stack - * m4_dnl RESULT_PTR(vptr); put what is pointed-to on the value stack + * m4_dnl RESULT_OK; legalize what already is on the value stack * m4_dnl } * * Other code is just copied into the interpreter part. @@ -50,37 +50,41 @@ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i + v2.val.i); + res.val.i += v2.val.i; + RESULT_OK; } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i - v2.val.i); + res.val.i -= v2.val.i; + RESULT_OK; } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - RESULT(T_INT, i, v1.val.i * v2.val.i); + res.val.i *= v2.val.i; + RESULT_OK; } INST(FI_DIVIDE, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); - RESULT(T_INT, i, v1.val.i / v2.val.i); + res.val.i /= v2.val.i; + RESULT_OK; } INST(FI_AND, 1, 1) { ARG(1,T_BOOL); - if (v1.val.i) + if (res.val.i) LINE(2,0); else - RESULT_PTR(&(v1)); + RESULT_OK; } INST(FI_OR, 1, 1) { ARG(1,T_BOOL); - if (!v1.val.i) + if (!res.val.i) LINE(2,0); else - RESULT_PTR(&(v1)); + RESULT_OK; } INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); @@ -277,7 +281,8 @@ INST(FI_VAR_GET, 0, 1) { SYMBOL(1); - RESULT_PTR(&(fstk->vstk[curline.vbase + sym->offset])); + res = fstk->vstk[curline.vbase + sym->offset]; + RESULT_OK; } /* some constants have value in a[1], some in *a[0].p, strange. */ @@ -298,7 +303,8 @@ debug("%svalue %s\n", INDENT, val_dump(&item->val)); FID_ALL - RESULT_PTR(&(whati->val)); + res = whati->val; + RESULT_OK; } INST(FI_CONSTANT_DEFINED, 0, 1) { FID_STRUCT_IN @@ -318,7 +324,8 @@ debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); FID_ALL - RESULT_PTR(whati->valp); + res = *whati->valp; + RESULT_OK; } INST(FI_PRINT, 1, 0) { ARG_ANY(1); @@ -391,6 +398,76 @@ } } + INST(FI_RTA_SET, 1, 0) { + ACCESS_RTE; + ARG_ANY(1); + STATIC_ATTR; + if (sa.f_type != v1.type) + runtime( "Attempt to set static attribute to incompatible type" ); + + f_rta_cow(fs); + { + struct rta *rta = (*fs->rte)->attrs; + + switch (sa.sa_code) + { + case SA_FROM: + rta->from = v1.val.ip; + break; + + case SA_GW: + { + ip_addr ip = v1.val.ip; + neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = ip; + rta->nh.iface = n->iface; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + case SA_SCOPE: + rta->scope = v1.val.i; + break; + + case SA_DEST: + { + int i = v1.val.i; + if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) + runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); + + rta->dest = i; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + case SA_IFNAME: + { + struct iface *ifa = if_find_by_name(v1.val.s); + if (!ifa) + runtime( "Invalid iface name" ); + + rta->dest = RTD_UNICAST; + rta->nh.gw = IPA_NONE; + rta->nh.iface = ifa; + rta->nh.next = NULL; + rta->hostentry = NULL; + } + break; + + default: + bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); + } + } + } + INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */ DYNAMIC_ATTR; ACCESS_RTE; @@ -424,7 +501,8 @@ } /* Undefined value */ - RESULT_VOID; + res.type = T_VOID; + RESULT_OK; break; } @@ -457,7 +535,8 @@ RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: - RESULT_VOID; + res.type = T_VOID; + RESULT_OK; break; default: bug("Unknown dynamic attribute type"); @@ -465,6 +544,95 @@ } } + INST(FI_EA_SET, 1, 0) { + ACCESS_RTE; + ACCESS_EATTRS; + ARG_ANY(1); + DYNAMIC_ATTR; + { + struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + + l->next = NULL; + l->flags = EALF_SORTED; + l->count = 1; + l->attrs[0].id = da.ea_code; + l->attrs[0].flags = 0; + l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; + + switch (da.type) { + case EAF_TYPE_INT: + if (v1.type != da.f_type) + runtime( "Setting int attribute to non-int value" ); + l->attrs[0].u.data = v1.val.i; + break; + + case EAF_TYPE_ROUTER_ID: + /* IP->Quad implicit conversion */ + if (val_is_ip4(&v1)) { + l->attrs[0].u.data = ipa_to_u32(v1.val.ip); + break; + } + /* T_INT for backward compatibility */ + if ((v1.type != T_QUAD) && (v1.type != T_INT)) + runtime( "Setting quad attribute to non-quad value" ); + l->attrs[0].u.data = v1.val.i; + break; + + case EAF_TYPE_OPAQUE: + runtime( "Setting opaque attribute is not allowed" ); + break; + case EAF_TYPE_IP_ADDRESS: + if (v1.type != T_IP) + runtime( "Setting ip attribute to non-ip value" ); + int len = sizeof(ip_addr); + struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); + ad->length = len; + (* (ip_addr *) ad->data) = v1.val.ip; + l->attrs[0].u.ptr = ad; + break; + case EAF_TYPE_AS_PATH: + if (v1.type != T_PATH) + runtime( "Setting path attribute to non-path value" ); + l->attrs[0].u.ptr = v1.val.ad; + break; + case EAF_TYPE_BITFIELD: + if (v1.type != T_BOOL) + runtime( "Setting bit in bitfield attribute to non-bool value" ); + { + /* First, we have to find the old value */ + eattr *e = ea_find(*fs->eattrs, da.ea_code); + u32 data = e ? e->u.data : 0; + + if (v1.val.i) + l->attrs[0].u.data = data | (1u << da.bit); + else + l->attrs[0].u.data = data & ~(1u << da.bit); + } + break; + case EAF_TYPE_INT_SET: + if (v1.type != T_CLIST) + runtime( "Setting clist attribute to non-clist value" ); + l->attrs[0].u.ptr = v1.val.ad; + break; + case EAF_TYPE_EC_SET: + if (v1.type != T_ECLIST) + runtime( "Setting eclist attribute to non-eclist value" ); + l->attrs[0].u.ptr = v1.val.ad; + break; + case EAF_TYPE_LC_SET: + if (v1.type != T_LCLIST) + runtime( "Setting lclist attribute to non-lclist value" ); + l->attrs[0].u.ptr = v1.val.ad; + break; + default: bug("Unknown type in e,S"); + } + + f_rta_cow(fs); + l->next = *fs->eattrs; + *fs->eattrs = l; + } + } + INST(FI_EA_UNSET, 0, 0) { DYNAMIC_ATTR; ACCESS_RTE; @@ -492,6 +660,15 @@ RESULT(T_INT, i, (*fs->rte)->pref); } + INST(FI_PREF_SET, 1, 0) { + ACCESS_RTE; + ARG(1,T_INT); + if (v1.val.i > 0xFFFF) + runtime( "Setting preference value out of bounds" ); + f_rte_cow(fs); + (*fs->rte)->pref = v1.val.i; + } + INST(FI_LENGTH, 1, 1) { /* Get length of */ ARG_ANY(1); switch(v1.type) { @@ -567,6 +744,33 @@ RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad)); } + INST(FI_RETURN, 1, 1) { + /* Acquire the return value */ + ARG_ANY(1); + uint retpos = fstk->vcnt; + + /* Drop every sub-block including ourselves */ + while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN)) + ; + + /* Now we are at the caller frame; if no such, try to convert to accept/reject. */ + if (!fstk->ecnt) + if (fstk->vstk[retpos].type == T_BOOL) + if (fstk->vstk[retpos].val.i) + + return F_ACCEPT; + else + return F_REJECT; + else + runtime("Can't return non-bool from non-function"); + + /* Set the value stack position, overwriting the former implicit void */ + fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1; + + /* Copy the return value */ + RESULT_VAL(fstk->vstk[retpos]); + } + INST(FI_CALL, 0, 1) { SYMBOL; diff --git a/filter/f-inst.h b/filter/f-inst.h index ca685ded..f0dcec64 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -84,6 +84,7 @@ static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_t { return (struct f_dynamic_attr) { .type = type, .bit = bit, .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_inst *f_generate_complex(enum f_instruction_code fi_code, 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); /* Hook for call bt_assert() function in configuration */ diff --git a/filter/filter.c b/filter/filter.c index 77378178..ee29522e 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -51,6 +51,12 @@ #include "filter/data.h" +/* Exception bits */ +enum f_exception { + FE_RETURN = 0x1, +}; + + struct filter_stack { /* Value stack for execution */ #define F_VAL_STACK_MAX 4096 @@ -145,7 +151,7 @@ f_rta_cow(struct filter_state *fs) } static char * -val_format_str(struct filter_state *fs, const struct f_val *v) { +val_format_str(struct filter_state *fs, struct f_val *v) { buffer b; LOG_BUFFER_INIT(b); val_format(v, &b); @@ -154,233 +160,6 @@ val_format_str(struct filter_state *fs, const struct f_val *v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; -#define runtime(fmt, ...) do { \ - if (!(fs->flags & FF_SILENT)) \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, \ - (fs->stack->estk[fs->stack->ecnt-1].line->items[fs->stack->estk[fs->stack->ecnt-1].pos-1]).lineno, \ - ##__VA_ARGS__); \ - return F_ERROR; \ -} while(0) - -#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) -#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) - -static inline enum filter_return -f_rta_set(struct filter_state *fs, struct f_static_attr sa, const struct f_val *val) -{ - ACCESS_RTE; - if (sa.f_type != val->type) - runtime( "Attempt to set static attribute to incompatible type" ); - - f_rta_cow(fs); - { - struct rta *rta = (*fs->rte)->attrs; - - switch (sa.sa_code) - { - case SA_FROM: - rta->from = val->val.ip; - return F_NOP; - - case SA_GW: - { - ip_addr ip = val->val.ip; - neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0); - if (!n || (n->scope == SCOPE_HOST)) - runtime( "Invalid gw address" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = ip; - rta->nh.iface = n->iface; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - case SA_SCOPE: - rta->scope = val->val.i; - return F_NOP; - - case SA_DEST: - { - int i = val->val.i; - if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT)) - runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); - - rta->dest = i; - rta->nh.gw = IPA_NONE; - rta->nh.iface = NULL; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - case SA_IFNAME: - { - struct iface *ifa = if_find_by_name(val->val.s); - if (!ifa) - runtime( "Invalid iface name" ); - - rta->dest = RTD_UNICAST; - rta->nh.gw = IPA_NONE; - rta->nh.iface = ifa; - rta->nh.next = NULL; - rta->hostentry = NULL; - } - return F_NOP; - - default: - bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); - } - } -} - -static inline enum filter_return -f_ea_set(struct filter_state *fs, struct f_dynamic_attr da, const struct f_val *val) -{ - ACCESS_RTE; - ACCESS_EATTRS; - { - struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); - - l->next = NULL; - l->flags = EALF_SORTED; - l->count = 1; - l->attrs[0].id = da.ea_code; - l->attrs[0].flags = 0; - l->attrs[0].type = da.type | EAF_ORIGINATED | EAF_FRESH; - - switch (da.type) { - case EAF_TYPE_INT: - if (val->type != da.f_type) - runtime( "Setting int attribute to non-int value" ); - l->attrs[0].u.data = val->val.i; - break; - - case EAF_TYPE_ROUTER_ID: - /* IP->Quad implicit conversion */ - if (val_is_ip4(val)) { - l->attrs[0].u.data = ipa_to_u32(val->val.ip); - break; - } - /* T_INT for backward compatibility */ - if ((val->type != T_QUAD) && (val->type != T_INT)) - runtime( "Setting quad attribute to non-quad value" ); - l->attrs[0].u.data = val->val.i; - break; - - case EAF_TYPE_OPAQUE: - runtime( "Setting opaque attribute is not allowed" ); - break; - case EAF_TYPE_IP_ADDRESS: - if (val->type != T_IP) - runtime( "Setting ip attribute to non-ip value" ); - int len = sizeof(ip_addr); - struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); - ad->length = len; - (* (ip_addr *) ad->data) = val->val.ip; - l->attrs[0].u.ptr = ad; - break; - case EAF_TYPE_AS_PATH: - if (val->type != T_PATH) - runtime( "Setting path attribute to non-path value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_BITFIELD: - if (val->type != T_BOOL) - runtime( "Setting bit in bitfield attribute to non-bool value" ); - { - /* First, we have to find the old value */ - eattr *e = ea_find(*fs->eattrs, da.ea_code); - u32 data = e ? e->u.data : 0; - - if (val->val.i) - l->attrs[0].u.data = data | (1u << da.bit); - else - l->attrs[0].u.data = data & ~(1u << da.bit); - } - break; - case EAF_TYPE_INT_SET: - if (val->type != T_CLIST) - runtime( "Setting clist attribute to non-clist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_EC_SET: - if (val->type != T_ECLIST) - runtime( "Setting eclist attribute to non-eclist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - case EAF_TYPE_LC_SET: - if (val->type != T_LCLIST) - runtime( "Setting lclist attribute to non-lclist value" ); - l->attrs[0].u.ptr = val->val.ad; - break; - default: bug("Unknown type in e,S"); - } - - f_rta_cow(fs); - l->next = *fs->eattrs; - *fs->eattrs = l; - - return F_NOP; - } -} - -static inline enum filter_return -f_lval_set(struct filter_state *fs, const struct f_lval *lv, const struct f_val *val) -{ - switch (lv->type) { - case F_LVAL_STACK: - fs->stack->vstk[fs->stack->vcnt] = *val; - fs->stack->vcnt++; - return F_NOP; - case F_LVAL_EXCEPTION: - { - /* Drop every sub-block including ourselves */ - while ((fs->stack->ecnt-- > 0) && !(fs->stack->estk[fs->stack->ecnt].emask & lv->exception)) - ; - - /* Now we are at the catch frame; if no such, try to convert to accept/reject. */ - if (!fs->stack->ecnt) - if (lv->exception == FE_RETURN) - if (val->type == T_BOOL) - if (val->val.i) - return F_ACCEPT; - else - return F_REJECT; - else - runtime("Can't return non-bool from non-function"); - else - runtime("Unhandled exception 0x%x: %s", lv->exception, val_format_str(fs, val)); - - /* Set the value stack position, overwriting the former implicit void */ - fs->stack->vcnt = fs->stack->estk[fs->stack->ecnt].ventry; - - /* Copy the return value */ - fs->stack->vstk[fs->stack->vcnt - 1] = *val; - return F_NOP; - } - case F_LVAL_VARIABLE: - fs->stack->vstk[fs->stack->estk[fs->stack->ecnt-1].vbase + lv->sym->offset] = *val; - return F_NOP; - case F_LVAL_PREFERENCE: - ACCESS_RTE; - if (val->type != T_INT) - runtime("Preference must be integer, got 0x%02x", val->type); - if (val->val.i > 0xFFFF) - runtime("Preference is at most 65536"); - f_rte_cow(fs); - (*fs->rte)->pref = val->val.i; - return F_NOP; - case F_LVAL_SA: - return f_rta_set(fs, lv->sa, val); - case F_LVAL_EA: - return f_ea_set(fs, lv->da, val); - default: - bug("This shall never happen"); - } -} - /** * interpret * @fs: filter state @@ -430,6 +209,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define v2 fstk->vstk[fstk->vcnt + 1] #define v3 fstk->vstk[fstk->vcnt + 2] +#define runtime(fmt, ...) do { \ + if (!(fs->flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + return F_ERROR; \ +} while(0) + +#define ACCESS_RTE do { if (!fs->rte) runtime("No route to access"); } while (0) +#define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) + #include "filter/inst-interpret.c" #undef res #undef v1 @@ -445,16 +233,6 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) fstk->vcnt -= curline.line->vars; fstk->vcnt -= curline.line->args; fstk->ecnt--; - - /* If the caller wants to store the result somewhere, do it. */ - if (fstk->ecnt) { - const struct f_line_item *caller = &(curline.line->items[curline.pos-1]); - if (caller->result.type != F_LVAL_STACK) { - enum filter_return fret = f_lval_set(fs, &(caller->result), &fstk->vstk[--fstk->vcnt]); - if (fret != F_NOP) - return fret; - } - } } if (fstk->vcnt == 0) { |