diff --git a/filter/config.Y b/filter/config.Y index f3e83cfd..9a240763 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -828,7 +828,7 @@ constructor: '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); } - | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); } + | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index b1cdaf0d..d8bbf2bc 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -93,25 +93,6 @@ FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 FID_INTERPRET_BODY') -m4_define(FID_MEMBER_IN, `m4_dnl -FID_LINE_IN()m4_dnl - $1 $2; -FID_STRUCT_IN()m4_dnl - $1 $2; -FID_LINEARIZE_BODY()m4_dnl -item->$2 = whati->$2; -m4_ifelse($3,,,[[ -FID_SAME_BODY()m4_dnl -if ($3) return 0; -]]) -m4_ifelse($4,,,[[ -FID_DUMP_BODY()m4_dnl -debug("%s$4\n", INDENT, $5); -]]) -FID_INTERPRET_EXEC()m4_dnl -const $1 $2 = whati->$2 -FID_INTERPRET_BODY') - # Instruction arguments are needed only until linearization is done. # This puts the arguments into the filter line to be executed before # the instruction itself. @@ -136,6 +117,48 @@ FID_LINEARIZE_BODY pos = linearize(dest, whati->f$1, pos); FID_INTERPRET_BODY()') +# Some instructions accept variable number of arguments. +m4_define(VARARG, ` +FID_NEW_ARGS()m4_dnl + , struct f_inst * fvar +FID_STRUCT_IN()m4_dnl + struct f_inst * fvar; + uint varcount; +FID_LINE_IN()m4_dnl + uint varcount; +FID_NEW_BODY()m4_dnl +whati->varcount = 0; +whati->fvar = fvar; +for (const struct f_inst *child = fvar; child; child = child->next, whati->varcount++) { + what->size += child->size; +FID_IFCONST([[ + if (child->fi_code != FI_CONSTANT) + constargs = 0; +]]) +} +FID_IFCONST([[ + const struct f_inst **items = NULL; + if (constargs) { + items = alloca(whati->varcount * sizeof(struct f_inst *)); + const struct f_inst *child = fvar; + for (uint i=0; child; i++) + child = (items[i] = child)->next; + } +]]) +FID_LINEARIZE_BODY()m4_dnl + pos = linearize(dest, whati->fvar, pos); + item->varcount = whati->varcount; +FID_DUMP_BODY()m4_dnl + debug("%snumber of varargs %u\n", INDENT, item->varcount); +FID_SAME_BODY()m4_dnl + if (f1->varcount != f2->varcount) return 0; +FID_INTERPRET_BODY() +FID_HIC(,[[ + if (fstk->vcnt < whati->varcount) runtime("Stack underflow"); + fstk->vcnt -= whati->varcount; +]],) +') + # Some arguments need to check their type. After that, ARG_ANY is called. m4_define(ARG, `ARG_ANY($1) FID_INTERPRET_EXEC()m4_dnl @@ -410,6 +433,7 @@ fi_constant(struct f_inst *what, struct f_val val) #define v1 whati->f1->i_FI_CONSTANT.val #define v2 whati->f2->i_FI_CONSTANT.val #define v3 whati->f3->i_FI_CONSTANT.val +#define vv(i) items[i]->i_FI_CONSTANT.val #define runtime(fmt, ...) cf_error("filter preevaluation, line %d: " fmt, ifs->lino, ##__VA_ARGS__) #define fpool cfg_mem #define falloc(size) cfg_alloc(size) @@ -418,6 +442,7 @@ FID_WR_PUT(3) #undef v1 #undef v2 #undef v3 +#undef vv /* Line dumpers */ #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) diff --git a/filter/f-inst.c b/filter/f-inst.c index 7d41efe6..f1304833 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -60,8 +60,9 @@ * * 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 ARG(num, type); argument, its id (in data fields) and type accessible by v1, v2, v3 + * m4_dnl ARG_ANY(num); argument with no type check accessible by v1, v2, v3 + * m4_dnl VARARG; variable-length argument list; accessible by vv(i) and whati->varcount * m4_dnl LINE(num, unused); this argument has to be converted to its own f_line * m4_dnl SYMBOL; symbol handed from config * m4_dnl STATIC_ATTR; static attribute definition @@ -297,45 +298,19 @@ } INST(FI_PATHMASK_CONSTRUCT, 0, 1) { - ARG_ANY(1); - FID_MEMBER(uint, count, f1->count != f2->count, number of items %u, item->count); + VARARG; - FID_NEW_BODY - uint len = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++); + struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->varcount * sizeof(struct f_path_mask_item)); + pm->len = whati->varcount; - whati->count = len; - struct f_inst **items; - if (constargs) { - items = alloca(len * sizeof(struct f_inst *)); - for (uint i=0; f1; i++) { - items[i] = f1; - f1 = f1->next; - items[i]->next = 0; - } - whati->f1 = NULL; - } - FID_INTERPRET_BODY - - FID_INTERPRET_EXEC - 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); - -#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] - - FID_INTERPRET_NEW -#define pv(i) items[i]->i_FI_CONSTANT.val - - FID_INTERPRET_BODY - struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item)); - for (uint i=0; icount; i++) { - switch (pv(i).type) { + for (uint i=0; ivarcount; i++) { + switch (vv(i).type) { case T_PATH_MASK_ITEM: - pm->item[i] = pv(i).val.pmi; + pm->item[i] = vv(i).val.pmi; break; case T_INT: pm->item[i] = (struct f_path_mask_item) { - .asn = pv(i).val.i, + .asn = vv(i).val.i, .kind = PM_ASN, }; break; @@ -343,13 +318,7 @@ runtime( "Error resolving path mask template: value not an integer" ); } } -#undef pv - FID_INTERPRET_EXEC - fstk->vcnt -= whati->count; - FID_INTERPRET_BODY - - pm->len = whati->count; RESULT(T_PATH_MASK, path_mask, pm); } @@ -479,24 +448,11 @@ INST(FI_PRINT, 0, 0) { NEVER_CONSTANT; - ARG_ANY(1); - FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count); + VARARG; - FID_NEW_BODY - uint len = 0; - for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) - ; - whati->count = len; - - FID_INTERPRET_BODY - -#define pv(i) fstk->vstk[fstk->vcnt - whati->count + (i)] - if (whati->count && !(fs->flags & FF_SILENT)) - for (uint i=0; icount; i++) - val_format(&(pv(i)), &fs->buf); -#undef pv - - fstk->vcnt -= whati->count; + if (whati->varcount && !(fs->flags & FF_SILENT)) + for (uint i=0; ivarcount; i++) + val_format(&(vv(i)), &fs->buf); } INST(FI_DIE, 0, 0) { diff --git a/filter/filter.c b/filter/filter.c index 0d727449..2aa2f629 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -190,9 +190,10 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) switch (what->fi_code) { #define res fstk->vstk[fstk->vcnt] -#define v1 fstk->vstk[fstk->vcnt] -#define v2 fstk->vstk[fstk->vcnt + 1] -#define v3 fstk->vstk[fstk->vcnt + 2] +#define vv(i) fstk->vstk[fstk->vcnt + (i)] +#define v1 vv(0) +#define v2 vv(1) +#define v3 vv(2) #define runtime(fmt, ...) do { \ if (!(fs->flags & FF_SILENT)) \