Skip to content

Commit cb7dbfd

Browse files
kaberummakynes
authored andcommitted
netfilter: nf_tables: add optimized data comparison for small values
Add an optimized version of nft_data_cmp() that only handles values of to 4 bytes length. This patch includes original Patrick McHardy's patch entitled (nf_tables: inline nft_cmp_fast_eval() into main evaluation loop). Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent ef1f7df commit cb7dbfd

File tree

3 files changed

+118
-24
lines changed

3 files changed

+118
-24
lines changed

include/net/netfilter/nf_tables_core.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ extern void nf_tables_core_module_exit(void);
77
extern int nft_immediate_module_init(void);
88
extern void nft_immediate_module_exit(void);
99

10+
struct nft_cmp_fast_expr {
11+
u32 data;
12+
enum nft_registers sreg:8;
13+
u8 len;
14+
};
15+
16+
extern const struct nft_expr_ops nft_cmp_fast_ops;
17+
1018
extern int nft_cmp_module_init(void);
1119
extern void nft_cmp_module_exit(void);
1220

net/netfilter/nf_tables_core.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@
2020
#include <net/netfilter/nf_tables_core.h>
2121
#include <net/netfilter/nf_tables.h>
2222

23+
static void nft_cmp_fast_eval(const struct nft_expr *expr,
24+
struct nft_data data[NFT_REG_MAX + 1])
25+
{
26+
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
27+
u32 mask;
28+
29+
mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - priv->len);
30+
if ((data[priv->sreg].data[0] & mask) == priv->data)
31+
return;
32+
data[NFT_REG_VERDICT].verdict = NFT_BREAK;
33+
}
34+
2335
unsigned int nft_do_chain(const struct nf_hook_ops *ops,
2436
struct sk_buff *skb,
2537
const struct net_device *in,
@@ -48,7 +60,11 @@ unsigned int nft_do_chain(const struct nf_hook_ops *ops,
4860
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
4961
list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
5062
nft_rule_for_each_expr(expr, last, rule) {
51-
expr->ops->eval(expr, data, &pkt);
63+
if (expr->ops == &nft_cmp_fast_ops)
64+
nft_cmp_fast_eval(expr, data);
65+
else
66+
expr->ops->eval(expr, data, &pkt);
67+
5268
if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
5369
break;
5470
}

net/netfilter/nft_cmp.c

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,32 +75,11 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
7575
struct nft_data_desc desc;
7676
int err;
7777

78-
if (tb[NFTA_CMP_SREG] == NULL ||
79-
tb[NFTA_CMP_OP] == NULL ||
80-
tb[NFTA_CMP_DATA] == NULL)
81-
return -EINVAL;
82-
8378
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
84-
err = nft_validate_input_register(priv->sreg);
85-
if (err < 0)
86-
return err;
87-
8879
priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
89-
switch (priv->op) {
90-
case NFT_CMP_EQ:
91-
case NFT_CMP_NEQ:
92-
case NFT_CMP_LT:
93-
case NFT_CMP_LTE:
94-
case NFT_CMP_GT:
95-
case NFT_CMP_GTE:
96-
break;
97-
default:
98-
return -EINVAL;
99-
}
10080

10181
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
102-
if (err < 0)
103-
return err;
82+
BUG_ON(err < 0);
10483

10584
priv->len = desc.len;
10685
return 0;
@@ -133,9 +112,100 @@ static const struct nft_expr_ops nft_cmp_ops = {
133112
.dump = nft_cmp_dump,
134113
};
135114

115+
static int nft_cmp_fast_init(const struct nft_ctx *ctx,
116+
const struct nft_expr *expr,
117+
const struct nlattr * const tb[])
118+
{
119+
struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
120+
struct nft_data_desc desc;
121+
struct nft_data data;
122+
u32 mask;
123+
int err;
124+
125+
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
126+
127+
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
128+
BUG_ON(err < 0);
129+
desc.len *= BITS_PER_BYTE;
130+
131+
mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - desc.len);
132+
priv->data = data.data[0] & mask;
133+
priv->len = desc.len;
134+
return 0;
135+
}
136+
137+
static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
138+
{
139+
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
140+
struct nft_data data;
141+
142+
if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
143+
goto nla_put_failure;
144+
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
145+
goto nla_put_failure;
146+
147+
data.data[0] = priv->data;
148+
if (nft_data_dump(skb, NFTA_CMP_DATA, &data,
149+
NFT_DATA_VALUE, priv->len / BITS_PER_BYTE) < 0)
150+
goto nla_put_failure;
151+
return 0;
152+
153+
nla_put_failure:
154+
return -1;
155+
}
156+
157+
const struct nft_expr_ops nft_cmp_fast_ops = {
158+
.type = &nft_cmp_type,
159+
.size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_fast_expr)),
160+
.eval = NULL, /* inlined */
161+
.init = nft_cmp_fast_init,
162+
.dump = nft_cmp_fast_dump,
163+
};
164+
165+
static const struct nft_expr_ops *nft_cmp_select_ops(const struct nlattr * const tb[])
166+
{
167+
struct nft_data_desc desc;
168+
struct nft_data data;
169+
enum nft_registers sreg;
170+
enum nft_cmp_ops op;
171+
int err;
172+
173+
if (tb[NFTA_CMP_SREG] == NULL ||
174+
tb[NFTA_CMP_OP] == NULL ||
175+
tb[NFTA_CMP_DATA] == NULL)
176+
return ERR_PTR(-EINVAL);
177+
178+
sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
179+
err = nft_validate_input_register(sreg);
180+
if (err < 0)
181+
return ERR_PTR(err);
182+
183+
op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
184+
switch (op) {
185+
case NFT_CMP_EQ:
186+
case NFT_CMP_NEQ:
187+
case NFT_CMP_LT:
188+
case NFT_CMP_LTE:
189+
case NFT_CMP_GT:
190+
case NFT_CMP_GTE:
191+
break;
192+
default:
193+
return ERR_PTR(-EINVAL);
194+
}
195+
196+
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
197+
if (err < 0)
198+
return ERR_PTR(err);
199+
200+
if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ)
201+
return &nft_cmp_fast_ops;
202+
else
203+
return &nft_cmp_ops;
204+
}
205+
136206
static struct nft_expr_type nft_cmp_type __read_mostly = {
137207
.name = "cmp",
138-
.ops = &nft_cmp_ops,
208+
.select_ops = nft_cmp_select_ops,
139209
.policy = nft_cmp_policy,
140210
.maxattr = NFTA_CMP_MAX,
141211
.owner = THIS_MODULE,

0 commit comments

Comments
 (0)