dfilter: Add a flag to return field values for the tree root

In many grammatical contexts fields are only tested for existence
instead of loading the values into a register, because that's all
that is needed to determine if a filter passes or not. Add a
dfilter option to load the field values from the tree and return
them when a field (including field at a certain protocol layer) is
the root of the filter syntax tree.

This is useful for columns, especially for parsing columns defined
with the layer operator, but it can't completely replace the current
custom column handling because we don't yet return exactly which
hfinfo was present, if more than one has the same abbreviation, and
it's possible for fields with the same abbreviation to have different
strings, and hence different "resolved" values.

$ ./run/dftest -s "@ip.proto#1"
Filter:
 @ip.proto#1

Syntax tree:
 0 FIELD(@ip.proto#[1:1] <FT_BYTES>)

Instructions:
 0000 CHECK_EXISTS_R   ip.proto#[1:1]
 0001 RETURN

$ ./run/dftest -s "@ip.proto#1" --return-vals
Filter:
 @ip.proto#1

Syntax tree:
 0 FIELD(@ip.proto#[1:1] <FT_BYTES>)

Instructions:
 0000 READ_TREE_R      @ip.proto#[1:1]  -> R0
 0001 NO_OP
 0002 RETURN           R0

Related to #18588
This commit is contained in:
John Thacker 2024-02-12 20:23:37 -05:00
parent 098462e703
commit 49934c1d14
3 changed files with 35 additions and 2 deletions

View File

@ -49,6 +49,7 @@ static int opt_debug_level = 0; /* currently up to 2 */
static int opt_flex = 0;
static int opt_lemon = 0;
static int opt_syntax_tree = 0;
static int opt_return_vals = 0;
static int opt_timer = 0;
static long opt_optimize = 1;
static int opt_show_types = 0;
@ -108,6 +109,7 @@ print_usage(int status)
fprintf(fp, " -s, --syntax print syntax tree\n");
fprintf(fp, " -m --macros print saved macros\n");
fprintf(fp, " -t, --timer print elapsed compilation time\n");
fprintf(fp, " -r --return-vals return field values for the tree root\n");
fprintf(fp, " -0, --optimize=0 do not optimize (check syntax)\n");
fprintf(fp, " --types show field value types\n");
/* NOTE: References are loaded during runtime and dftest only does compilation.
@ -216,6 +218,8 @@ compile_filter(const char *text, dfilter_t **dfp)
df_flags |= DF_DEBUG_FLEX;
if (opt_lemon)
df_flags |= DF_DEBUG_LEMON;
if (opt_return_vals)
df_flags |= DF_RETURN_VALUES;
start = g_get_monotonic_time();
ok = dfilter_compile_full(text, dfp, &df_err, df_flags, "dftest");
@ -278,7 +282,7 @@ main(int argc, char **argv)
ws_init_version_info("DFTest", NULL, NULL);
const char *optstring = "hvdDflsmtV0";
const char *optstring = "hvdDflsmrtV0";
static struct ws_option long_options[] = {
{ "help", ws_no_argument, 0, 'h' },
{ "version", ws_no_argument, 0, 'v' },
@ -289,6 +293,7 @@ main(int argc, char **argv)
{ "macros", ws_no_argument, 0, 'm' },
{ "timer", ws_no_argument, 0, 't' },
{ "verbose", ws_no_argument, 0, 'V' },
{ "return-vals", ws_no_argument, 0, 'r' },
{ "optimize", ws_required_argument, 0, 1000 },
{ "types", ws_no_argument, 0, 2000 },
{ "refs", ws_no_argument, 0, 3000 },
@ -335,6 +340,9 @@ main(int argc, char **argv)
case 't':
opt_timer = 1;
break;
case 'r':
opt_return_vals = 1;
break;
case '0':
opt_optimize = 0;
break;

View File

@ -73,6 +73,9 @@ dfilter_expand(const char *expr, df_error_t **err_ret);
#define DF_DEBUG_FLEX (1U << 3)
/* Enable debug trace for lemon. */
#define DF_DEBUG_LEMON (1U << 4)
/* If the root of the syntax tree is a field, load and return the field values.
* By default the field is only checked for existence. */
#define DF_RETURN_VALUES (1U << 5)
/* Compiles a string to a dfilter_t.
* On success, sets the dfilter* pointed to by dfp

View File

@ -657,6 +657,18 @@ gen_exists(dfwork_t *dfw, stnode_t *st_node)
}
}
static dfvm_value_t*
gen_field(dfwork_t *dfw, stnode_t *st_node)
{
dfvm_value_t *val1;
GSList *jumps = NULL;
val1 = gen_entity(dfw, st_node, &jumps);
g_slist_foreach(jumps, fixup_jumps, dfw);
g_slist_free(jumps);
return val1;
}
static dfvm_value_t*
gen_notzero(dfwork_t *dfw, stnode_t *st_node)
{
@ -805,12 +817,22 @@ static dfvm_value_t*
gencode(dfwork_t *dfw, stnode_t *st_node)
{
dfvm_value_t* val = NULL;
/* If the root of the tree is a field, load and return the
* values if we were asked to do so. If not, or anywhere
* other than the root, just test for existence.
*/
bool return_val = dfw->flags & DF_RETURN_VALUES;
dfw->flags &= ~DF_RETURN_VALUES;
switch (stnode_type_id(st_node)) {
case STTYPE_TEST:
gen_test(dfw, st_node);
break;
case STTYPE_FIELD:
gen_exists(dfw, st_node);
if (return_val) {
val = gen_field(dfw, st_node);
} else {
gen_exists(dfw, st_node);
}
break;
case STTYPE_ARITHMETIC:
case STTYPE_FUNCTION: