Filter: Converted FI_PRINT and FI_PATHMASK_CONSTRUCT to VARARG

This commit is contained in:
Maria Matejka 2019-07-15 15:12:18 +02:00
parent c29d73a06a
commit c0999a149c
4 changed files with 63 additions and 81 deletions

View file

@ -828,7 +828,7 @@ constructor:
'(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
| '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } | '(' 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); } | '(' 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); }
; ;

View file

@ -93,25 +93,6 @@ FID_INTERPRET_EXEC()m4_dnl
const $1 $2 = whati->$2 const $1 $2 = whati->$2
FID_INTERPRET_BODY') 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. # Instruction arguments are needed only until linearization is done.
# This puts the arguments into the filter line to be executed before # This puts the arguments into the filter line to be executed before
# the instruction itself. # the instruction itself.
@ -136,6 +117,48 @@ FID_LINEARIZE_BODY
pos = linearize(dest, whati->f$1, pos); pos = linearize(dest, whati->f$1, pos);
FID_INTERPRET_BODY()') 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. # Some arguments need to check their type. After that, ARG_ANY is called.
m4_define(ARG, `ARG_ANY($1) m4_define(ARG, `ARG_ANY($1)
FID_INTERPRET_EXEC()m4_dnl 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 v1 whati->f1->i_FI_CONSTANT.val
#define v2 whati->f2->i_FI_CONSTANT.val #define v2 whati->f2->i_FI_CONSTANT.val
#define v3 whati->f3->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 runtime(fmt, ...) cf_error("filter preevaluation, line %d: " fmt, ifs->lino, ##__VA_ARGS__)
#define fpool cfg_mem #define fpool cfg_mem
#define falloc(size) cfg_alloc(size) #define falloc(size) cfg_alloc(size)
@ -418,6 +442,7 @@ FID_WR_PUT(3)
#undef v1 #undef v1
#undef v2 #undef v2
#undef v3 #undef v3
#undef vv
/* Line dumpers */ /* Line dumpers */
#define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)

View file

@ -60,8 +60,9 @@
* *
* What is the syntax here? * What is the syntax here?
* m4_dnl INST(FI_NOP, in, out) { enum value, input args, output args * 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(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 * 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 LINE(num, unused); this argument has to be converted to its own f_line
* m4_dnl SYMBOL; symbol handed from config * m4_dnl SYMBOL; symbol handed from config
* m4_dnl STATIC_ATTR; static attribute definition * m4_dnl STATIC_ATTR; static attribute definition
@ -297,45 +298,19 @@
} }
INST(FI_PATHMASK_CONSTRUCT, 0, 1) { INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
ARG_ANY(1); VARARG;
FID_MEMBER(uint, count, f1->count != f2->count, number of items %u, item->count);
FID_NEW_BODY struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->varcount * sizeof(struct f_path_mask_item));
uint len = 0; pm->len = whati->varcount;
for (const struct f_inst *tt = f1; tt; tt = tt->next, len++);
whati->count = len; for (uint i=0; i<whati->varcount; i++) {
struct f_inst **items; switch (vv(i).type) {
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; i<whati->count; i++) {
switch (pv(i).type) {
case T_PATH_MASK_ITEM: case T_PATH_MASK_ITEM:
pm->item[i] = pv(i).val.pmi; pm->item[i] = vv(i).val.pmi;
break; break;
case T_INT: case T_INT:
pm->item[i] = (struct f_path_mask_item) { pm->item[i] = (struct f_path_mask_item) {
.asn = pv(i).val.i, .asn = vv(i).val.i,
.kind = PM_ASN, .kind = PM_ASN,
}; };
break; break;
@ -343,13 +318,7 @@
runtime( "Error resolving path mask template: value not an integer" ); 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); RESULT(T_PATH_MASK, path_mask, pm);
} }
@ -479,24 +448,11 @@
INST(FI_PRINT, 0, 0) { INST(FI_PRINT, 0, 0) {
NEVER_CONSTANT; NEVER_CONSTANT;
ARG_ANY(1); VARARG;
FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count);
FID_NEW_BODY if (whati->varcount && !(fs->flags & FF_SILENT))
uint len = 0; for (uint i=0; i<whati->varcount; i++)
for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) val_format(&(vv(i)), &fs->buf);
;
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; i<whati->count; i++)
val_format(&(pv(i)), &fs->buf);
#undef pv
fstk->vcnt -= whati->count;
} }
INST(FI_DIE, 0, 0) { INST(FI_DIE, 0, 0) {

View file

@ -190,9 +190,10 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
switch (what->fi_code) { switch (what->fi_code) {
#define res fstk->vstk[fstk->vcnt] #define res fstk->vstk[fstk->vcnt]
#define v1 fstk->vstk[fstk->vcnt] #define vv(i) fstk->vstk[fstk->vcnt + (i)]
#define v2 fstk->vstk[fstk->vcnt + 1] #define v1 vv(0)
#define v3 fstk->vstk[fstk->vcnt + 2] #define v2 vv(1)
#define v3 vv(2)
#define runtime(fmt, ...) do { \ #define runtime(fmt, ...) do { \
if (!(fs->flags & FF_SILENT)) \ if (!(fs->flags & FF_SILENT)) \