summaryrefslogtreecommitdiffstats
path: root/src/netlink_linearize.c
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2018-03-16 00:03:19 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2018-03-16 09:58:39 +0100
commit6979625686ec8d915f5ad5fdc28f24f55b6be3f7 (patch)
treee358bb0c0335622f99c374386ba2f1d8d2dbf20d /src/netlink_linearize.c
parent70b31b1ce73e704d4387b1262e8b97785ffe64f7 (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.c20
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);
}