Commit 5f48846d authored by Phil Sutter's avatar Phil Sutter Committed by Pablo Neira Ayuso

netfilter: nf_tables: Enable fast nft_cmp for inverted matches

Add a boolean indicating NFT_CMP_NEQ. To include it into the match
decision, it is sufficient to XOR it with the data comparison's result.

While being at it, store the mask that is calculated during expression
init and free the eval routine from having to recalculate it each time.
Signed-off-by: default avatarPhil Sutter <phil@nwl.cc>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent ab6c41ee
...@@ -25,8 +25,10 @@ void nf_tables_core_module_exit(void); ...@@ -25,8 +25,10 @@ void nf_tables_core_module_exit(void);
struct nft_cmp_fast_expr { struct nft_cmp_fast_expr {
u32 data; u32 data;
u32 mask;
enum nft_registers sreg:8; enum nft_registers sreg:8;
u8 len; u8 len;
bool inv;
}; };
struct nft_immediate_expr { struct nft_immediate_expr {
......
...@@ -51,9 +51,8 @@ static void nft_cmp_fast_eval(const struct nft_expr *expr, ...@@ -51,9 +51,8 @@ static void nft_cmp_fast_eval(const struct nft_expr *expr,
struct nft_regs *regs) struct nft_regs *regs)
{ {
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
u32 mask = nft_cmp_fast_mask(priv->len);
if ((regs->data[priv->sreg] & mask) == priv->data) if (((regs->data[priv->sreg] & priv->mask) == priv->data) ^ priv->inv)
return; return;
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
} }
......
...@@ -167,7 +167,6 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx, ...@@ -167,7 +167,6 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
struct nft_data_desc desc; struct nft_data_desc desc;
struct nft_data data; struct nft_data data;
u32 mask;
int err; int err;
err = nft_data_init(NULL, &data, sizeof(data), &desc, err = nft_data_init(NULL, &data, sizeof(data), &desc,
...@@ -181,10 +180,11 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx, ...@@ -181,10 +180,11 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
return err; return err;
desc.len *= BITS_PER_BYTE; desc.len *= BITS_PER_BYTE;
mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & mask; priv->mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & priv->mask;
priv->len = desc.len; priv->len = desc.len;
priv->inv = ntohl(nla_get_be32(tb[NFTA_CMP_OP])) != NFT_CMP_EQ;
return 0; return 0;
} }
...@@ -201,7 +201,7 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx, ...@@ -201,7 +201,7 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,
}, },
.sreg = priv->sreg, .sreg = priv->sreg,
.len = priv->len / BITS_PER_BYTE, .len = priv->len / BITS_PER_BYTE,
.op = NFT_CMP_EQ, .op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ,
}; };
return __nft_cmp_offload(ctx, flow, &cmp); return __nft_cmp_offload(ctx, flow, &cmp);
...@@ -210,11 +210,12 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx, ...@@ -210,11 +210,12 @@ static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,
static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr) static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
enum nft_cmp_ops op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ;
struct nft_data data; struct nft_data data;
if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg)) if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ))) if (nla_put_be32(skb, NFTA_CMP_OP, htonl(op)))
goto nla_put_failure; goto nla_put_failure;
data.data[0] = priv->data; data.data[0] = priv->data;
...@@ -272,7 +273,7 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) ...@@ -272,7 +273,7 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
goto err1; goto err1;
} }
if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ) if (desc.len <= sizeof(u32) && (op == NFT_CMP_EQ || op == NFT_CMP_NEQ))
return &nft_cmp_fast_ops; return &nft_cmp_fast_ops;
return &nft_cmp_ops; return &nft_cmp_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment