X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=filter%2Ff-inst.c;h=d48a60866f526ef6148813bc092538106fe85d02;hb=f74d19765ea3fafdff8fd3443f50a7b309babe89;hp=4ab46529fee7b2753d8b98dabf3497240b9dd985;hpb=132529ce8908661fd2baa0758c335006fb039ef0;p=thirdparty%2Fbird.git diff --git a/filter/f-inst.c b/filter/f-inst.c index 4ab46529f..d48a60866 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -7,47 +7,81 @@ * * Can be freely distributed and used under the terms of the GNU GPL. * + * Filter instructions. You shall define your instruction only here + * and nowhere else. + * + * Beware. This file is interpreted by M4 macros. These macros + * may be more stupid than you could imagine. If something strange + * happens after changing this file, compare the results before and + * after your change (see the Makefile to find out where the results are) + * and see what really happened. + * + * This file is not directly a C source code -> it is a generator input + * for several C sources; every instruction block gets expanded into many + * different places. + * + * What is the syntax here? + * m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args + * m4_dnl ARG(num, type); argument, its id (in data fields) and type + * m4_dnl ARG_ANY(num); argument with no type check + * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line + * m4_dnl ECS; extended community subtype + * m4_dnl COUNT(unused); simply a uint + * m4_dnl SYMBOL; symbol handed from config + * m4_dnl FRET; filter return value + * m4_dnl STATIC_ATTR; static attribute definition + * m4_dnl DYNAMIC_ATTR; dynamic attribute definition + * m4_dnl RTC; route table config + * m4_dnl TREE; a tree + * 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_VAL(value-struct); pass the struct f_val directly + * m4_dnl RESULT_VOID; return undef + * m4_dnl } + * + * Other code is just copied into the interpreter part. + * + * If you want to write something really special, see FI_CALL + * or FI_CONSTANT or whatever else to see how to use the FID_* + * macros. */ /* Binary operators */ INST(FI_ADD, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i += v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i + v2.val.i); } INST(FI_SUBTRACT, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i -= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i - v2.val.i); } INST(FI_MULTIPLY, 2, 1) { ARG(1,T_INT); ARG(2,T_INT); - res.val.i *= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i * v2.val.i); } 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" ); - res.val.i /= v2.val.i; - RESULT_OK; + RESULT(T_INT, i, v1.val.i / v2.val.i); } INST(FI_AND, 1, 1) { ARG(1,T_BOOL); - if (res.val.i) + if (v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_VAL(v1); } INST(FI_OR, 1, 1) { ARG(1,T_BOOL); - if (!res.val.i) + if (!v1.val.i) LINE(2,0); else - RESULT_OK; + RESULT_VAL(v1); } INST(FI_PAIR_CONSTRUCT, 2, 1) { ARG(1,T_INT); @@ -116,16 +150,15 @@ if (tt->fi_code != FI_CONSTANT) dyn++; - what->count = len; - FID_END + whati->count = len; + FID_ALL - if (vstk.cnt < what->count) /* TODO: make this check systematic */ - runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count); + if (fstk->vcnt < whati->count) /* TODO: make this check systematic */ + runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count); - struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item)); - for (uint i=0; icount; i++) { -//#define pv vstk.val[vstk.cnt-i-1] -#define pv vstk.val[vstk.cnt - what->count + i] + struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); + for (uint i=0; icount; i++) { +#define pv fstk->vstk[fstk->vcnt - whati->count + i] switch (pv.type) { case T_PATH_MASK_ITEM: pm->item[i] = pv.val.pmi; @@ -141,8 +174,8 @@ } } - vstk.cnt -= what->count; - pm->len = what->count; + fstk->vcnt -= whati->count; + pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); } @@ -197,7 +230,7 @@ ARG_ANY(1); ARG_ANY(2); int i = val_in_range(&v1, &v2); - if (res.val.i == F_CMP_ERROR) + if (i == F_CMP_ERROR) runtime( "!~ applied on unknown type pair" ); RESULT(T_BOOL, i, !i); } @@ -225,37 +258,68 @@ } /* Set to indirect value prepared in v1 */ - INST(FI_SET, 1, 0) { - ARG_ANY(2); - SYMBOL(1); + INST(FI_VAR_SET, 1, 0) { + ARG_ANY(1); + SYMBOL; if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID)) { /* IP->Quad implicit conversion */ if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1)) - { - *((struct f_val *) sym->def) = (struct f_val) { + v1 = (struct f_val) { .type = T_QUAD, .val.i = ipa_to_u32(v1.val.ip), - }; - break; - } - runtime( "Assigning to variable of incompatible type" ); + }; + else + runtime( "Assigning to variable of incompatible type" ); } - *((struct f_val *) sym->def) = v1; + + fstk->vstk[curline.vbase + sym->offset] = v1; + } + + INST(FI_VAR_GET, 0, 1) { + SYMBOL(1); + RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]); } /* some constants have value in a[1], some in *a[0].p, strange. */ INST(FI_CONSTANT, 0, 1) { /* integer (or simple type) constant, string, set, or prefix_set */ - VALI; // res = what->val; - RESULT_OK; - } - INST(FI_VARIABLE, 0, 1) { - VAR; - RESULT_OK; + FID_LINE_IN + struct f_val val; + FID_STRUCT_IN + struct f_val val; + FID_NEW_ARGS + , const struct f_val val + FID_NEW_BODY + whati->val = val; + FID_LINEARIZE_BODY + item->val = whati->val; + FID_SAME_BODY + if (!val_same(&(f1->val), &(f2->val))) return 0; + FID_DUMP_BODY + debug("%svalue %s\n", INDENT, val_dump(&item->val)); + FID_ALL + + RESULT_VAL(whati->val); } - INST(FI_CONSTANT_INDIRECT, 0, 1) { - VALP; - RESULT_OK; + INST(FI_CONSTANT_DEFINED, 0, 1) { + FID_STRUCT_IN + const struct symbol *sym; + FID_LINE_IN + const struct symbol *sym; + const struct f_val *valp; + FID_NEW_ARGS + , const struct symbol *sym + FID_NEW_BODY + whati->sym = sym; + FID_LINEARIZE_BODY + item->valp = (item->sym = whati->sym)->val; + FID_SAME_BODY + if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0; + FID_DUMP_BODY + debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp)); + FID_ALL + + RESULT_VAL(*whati->valp); } INST(FI_PRINT, 1, 0) { ARG_ANY(1); @@ -269,18 +333,18 @@ LINE(3,1); } INST(FI_PRINT_AND_DIE, 0, 0) { - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY { uint opos = pos; - FID_END + FID_ALL ARG_ANY(1); - FID_POSTFIXIFY_BODY + FID_LINEARIZE_BODY if (opos < pos) dest->items[pos].flags |= FIF_PRINTED; } - FID_END + FID_ALL FRET(2); @@ -431,8 +495,7 @@ } /* Undefined value */ - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; } @@ -465,8 +528,7 @@ RESULT(T_LCLIST, ad, e->u.ptr); break; case EAF_TYPE_UNDEF: - res.type = T_VOID; - RESULT_OK; + RESULT_VOID; break; default: bug("Unknown dynamic attribute type"); @@ -576,7 +638,7 @@ l->count = 1; l->attrs[0].id = da.ea_code; l->attrs[0].flags = 0; - l->attrs[0].type = EAF_TYPE_UNDEF | EAF_TEMP | EAF_ORIGINATED | EAF_FRESH; + l->attrs[0].type = EAF_TYPE_UNDEF | EAF_ORIGINATED | EAF_FRESH; l->attrs[0].u.data = 0; f_rta_cow(fs); @@ -677,16 +739,16 @@ INST(FI_RETURN, 1, 1) { /* Acquire the return value */ ARG_ANY(1); - uint retpos = vstk.cnt; + uint retpos = fstk->vcnt; /* Drop every sub-block including ourselves */ - while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN)) + 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 (!estk.cnt) - if (vstk.val[retpos].type == T_BOOL) - if (vstk.val[retpos].val.i) + if (!fstk->ecnt) + if (fstk->vstk[retpos].type == T_BOOL) + if (fstk->vstk[retpos].val.i) return F_ACCEPT; else @@ -694,44 +756,31 @@ else runtime("Can't return non-bool from non-function"); - /* Set the value stack position */ - vstk.cnt = estk.item[estk.cnt].ventry; + /* Set the value stack position, overwriting the former implicit void */ + fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1; /* Copy the return value */ - RESULT_VAL(vstk.val[retpos]); + RESULT_VAL(fstk->vstk[retpos]); } INST(FI_CALL, 0, 1) { - /* Do not use the symbol on execution */ - if (0) { - UNUSED SYMBOL; - } - - /* Postfixify extracts the function body from the symbol */ - FID_POSTFIXIFY_BODY - dest->items[pos].lines[0] = what->sym->def; - FID_END + SYMBOL; - /* First push the body on stack */ - LINEX(what->lines[0]); + /* Push the body on stack */ + LINEX(sym->function); curline.emask |= FE_RETURN; - - /* Then push the arguments */ - LINE(1,1); - - FID_NEW_BODY - if (sym->class != SYM_FUNCTION) - cf_error("You can't call something which is not a function. Really."); - - uint count = 0; - for (const struct f_inst *inst = f1; inst; inst = inst->next) - count++; - - if (count != sym->aux2) - cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count); - FID_END - - /* FIXME: Optimization of function comparison. */ + + /* Before this instruction was called, there was the T_VOID + * automatic return value pushed on value stack and also + * sym->function->args function arguments. Setting the + * vbase to point to first argument. */ + ASSERT(curline.ventry >= sym->function->args); + curline.ventry -= sym->function->args; + curline.vbase = curline.ventry; + + /* Storage for local variables */ + memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars); + fstk->vcnt += sym->function->vars; } INST(FI_DROP_RESULT, 1, 0) { @@ -741,10 +790,10 @@ INST(FI_SWITCH, 1, 0) { ARG_ANY(1); TREE; - const struct f_tree *t = find_tree(what->tree, &v1); + const struct f_tree *t = find_tree(tree, &v1); if (!t) { v1.type = T_VOID; - t = find_tree(what->tree, &v1); + t = find_tree(tree, &v1); if (!t) { debug( "No else statement?\n"); break;