diff options
author | Phil Sutter <phil@nwl.cc> | 2018-03-16 00:03:19 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-03-16 09:58:39 +0100 |
commit | 6979625686ec8d915f5ad5fdc28f24f55b6be3f7 (patch) | |
tree | e358bb0c0335622f99c374386ba2f1d8d2dbf20d /src/netlink_linearize.c | |
parent | 70b31b1ce73e704d4387b1262e8b97785ffe64f7 (diff) |
relational: Eliminate meta OPs
With a bit of code reorganization, relational meta OPs OP_RANGE,
OP_FLAGCMP and OP_LOOKUP become unused and can be removed. The only meta
OP left is OP_IMPLICIT which is usually treated as alias to OP_EQ.
Though it needs to stay in place for one reason: When matching against a
bitmask (e.g. TCP flags or conntrack states), it has a different
meaning:
| nft --debug=netlink add rule ip t c tcp flags syn
| ip t c
| [ meta load l4proto => reg 1 ]
| [ cmp eq reg 1 0x00000006 ]
| [ payload load 1b @ transport header + 13 => reg 1 ]
| [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]
| [ cmp neq reg 1 0x00000000 ]
| nft --debug=netlink add rule ip t c tcp flags == syn
| ip t c
| [ meta load l4proto => reg 1 ]
| [ cmp eq reg 1 0x00000006 ]
| [ payload load 1b @ transport header + 13 => reg 1 ]
| [ cmp eq reg 1 0x00000002 ]
OP_IMPLICIT creates a match which just checks the given flag is present,
while OP_EQ creates a match which ensures the given flag and no other is
present.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r-- | src/netlink_linearize.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index be1c750c..dce8f5ce 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -297,6 +297,7 @@ static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op) { switch (op) { case OP_EQ: + case OP_IMPLICIT: return NFT_CMP_EQ; case OP_NEQ: return NFT_CMP_NEQ; @@ -316,6 +317,9 @@ static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op) static void netlink_gen_range(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg); +static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg); static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx, const struct expr *expr, @@ -362,6 +366,8 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx, case EXPR_SET: case EXPR_SET_REF: return netlink_gen_lookup(ctx, expr, dreg); + case EXPR_LIST: + return netlink_gen_flagcmp(ctx, expr, dreg); case EXPR_PREFIX: sreg = get_register(ctx, expr->left); if (expr_basetype(expr->left)->type != TYPE_STRING) { @@ -376,6 +382,11 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx, } break; default: + if (expr->op == OP_IMPLICIT && + expr->right->dtype->basetype != NULL && + expr->right->dtype->basetype->type == TYPE_BITMASK) + return netlink_gen_flagcmp(ctx, expr, dreg); + sreg = get_register(ctx, expr->left); len = div_round_up(expr->right->len, BITS_PER_BYTE); right = expr->right; @@ -421,8 +432,8 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx, nld.value, nld.len); nftnl_rule_add_expr(ctx->nlr, nle); break; - case OP_RANGE: case OP_EQ: + case OP_IMPLICIT: nle = alloc_nft_expr("cmp"); netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, @@ -491,6 +502,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx, enum nft_registers dreg) { switch (expr->op) { + case OP_IMPLICIT: case OP_EQ: case OP_NEQ: case OP_LT: @@ -498,12 +510,6 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx, case OP_LTE: case OP_GTE: return netlink_gen_cmp(ctx, expr, dreg); - case OP_RANGE: - return netlink_gen_range(ctx, expr, dreg); - case OP_FLAGCMP: - return netlink_gen_flagcmp(ctx, expr, dreg); - case OP_LOOKUP: - return netlink_gen_lookup(ctx, expr, dreg); default: BUG("invalid relational operation %u\n", expr->op); } |