Add a new optimization option, disabled by default, that auto-replaces lookups in single-element anon sets with a standard compare. 'add rule foo bar meta iif { "lo" }' gets replaced with 'add rule foo bar meta iif "lo"'. The former is a set lookup, the latter is a comparision. Comparisions is slightly faster in this special case. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- include/nftables.h | 3 +++ include/rule.h | 6 ++++++ src/evaluate.c | 22 ++++++++++++++++++++-- src/libnftables.c | 9 +++++++++ src/main.c | 8 ++++++++ 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/nftables.h b/include/nftables.h index bbf287e68a4c..23b7fea53f42 100644 --- a/include/nftables.h +++ b/include/nftables.h @@ -216,9 +216,12 @@ int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...) /* XXX: exposing this in libnftables limits public API * to 32 optimization flags. + * + * For now this is internal to nft. */ enum nft_optimization_flags { NFT_OPTIMIZATION_F_REMOVE_DEPS = 1 << 0, + NFT_OPTIMIZATION_F_REPLACE_SINGLE_ELEM_ANON_SETS = 1 << 1, }; #define DEFAULT_OPTIMIZATION_FLAGS NFT_OPTIMIZATION_F_REMOVE_DEPS diff --git a/include/rule.h b/include/rule.h index f469db55bf60..ae23467187ff 100644 --- a/include/rule.h +++ b/include/rule.h @@ -735,6 +735,10 @@ void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc); #include <payload.h> #include <expression.h> +enum eval_ctx_flags { + EVAL_F_REPLACE_SINGLE_ELEM_ANON_SETS = 1 << 0, +}; + /** * struct eval_ctx - evaluation context * @@ -749,6 +753,7 @@ void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc); * @debug_mask: debugging bitmask * @ectx: expression context * @pctx: payload context + * @eval_flags: enum eval_ctx_flags */ struct eval_ctx { struct nft_ctx *nft; @@ -760,6 +765,7 @@ struct eval_ctx { struct stmt *stmt; struct expr_ctx ectx; struct proto_ctx pctx; + unsigned int eval_flags; }; extern int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd); diff --git a/src/evaluate.c b/src/evaluate.c index 6bfc464e677a..088742bfe6b4 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1455,8 +1455,26 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) } } - if (ctx->set && (ctx->set->flags & NFT_SET_CONCAT)) - set->set_flags |= NFT_SET_CONCAT; + if (ctx->set) { + if (ctx->set->flags & NFT_SET_CONCAT) + set->set_flags |= NFT_SET_CONCAT; + } else if ((ctx->eval_flags & EVAL_F_REPLACE_SINGLE_ELEM_ANON_SETS) && + set->size == 1) { + i = list_first_entry(&set->expressions, struct expr, list); + if (i->etype == EXPR_SET_ELEM) { + switch (i->key->etype) { + case EXPR_PREFIX: + case EXPR_RANGE: + case EXPR_VALUE: + *expr = i->key; + i->key = NULL; + expr_free(set); + return 0; + default: + break; + } + } + } set->set_flags |= NFT_SET_CONSTANT; diff --git a/src/libnftables.c b/src/libnftables.c index a1f822cbe2e6..0c17007bac4e 100644 --- a/src/libnftables.c +++ b/src/libnftables.c @@ -412,6 +412,12 @@ static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename, return 0; } +static void eval_ctx_set_flags(struct eval_ctx *ectx, const struct nft_ctx *nft) +{ + if (nft->optimization_flags & NFT_OPTIMIZATION_F_REPLACE_SINGLE_ELEM_ANON_SETS) + ectx->eval_flags |= EVAL_F_REPLACE_SINGLE_ELEM_ANON_SETS; +} + static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, struct list_head *cmds) { @@ -427,6 +433,9 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, .nft = nft, .msgs = msgs, }; + + eval_ctx_set_flags(&ectx, nft); + if (cmd_evaluate(&ectx, cmd) < 0 && ++nft->state->nerrs == nft->parser_max_errors) return -1; diff --git a/src/main.c b/src/main.c index cf00f27f06de..858218c79989 100644 --- a/src/main.c +++ b/src/main.c @@ -88,6 +88,7 @@ enum optimization_feature { OPTIMIZE_UNDEFINED, OPTIMIZE_HELP, OPTIMIZE_REMOVE_DEPENDENCIES, + OPTIMIZE_REMOVE_SINGLE_ELEM_ANON_SET, }; struct nft_opt { @@ -331,6 +332,12 @@ static const struct { .level = OPTIMIZE_REMOVE_DEPENDENCIES, .flag = NFT_OPTIMIZATION_F_REMOVE_DEPS, }, + { + .name = "replace-single-anon-sets", + .help = "replace anonymous sets with one element with single compare", + .level = OPTIMIZE_REMOVE_SINGLE_ELEM_ANON_SET, + .flag = NFT_OPTIMIZATION_F_REPLACE_SINGLE_ELEM_ANON_SETS, + }, }; static void nft_options_error(int argc, char * const argv[], int pos) @@ -426,6 +433,7 @@ static void optimize_settings_set_custom(struct nft_ctx *ctx, char *options) printf("\nPrepend \"no-\" to disable options that are enabled by default.\n"); exit(EXIT_SUCCESS); case OPTIMIZE_REMOVE_DEPENDENCIES: + case OPTIMIZE_REMOVE_SINGLE_ELEM_ANON_SET: break; } if (enable) -- 2.26.3