Skip to content

Commit b9ccc07

Browse files
Laura Garcia Liebanaummakynes
authored andcommitted
netfilter: nft_hash: add map lookups for hashing operations
This patch creates new attributes to accept a map as argument and then perform the lookup with the generated hash accordingly. Both current hash functions are supported: Jenkins and Symmetric Hash. Signed-off-by: Laura Garcia Liebana <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 978d8f9 commit b9ccc07

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,8 @@ enum nft_hash_types {
856856
* @NFTA_HASH_SEED: seed value (NLA_U32)
857857
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
858858
* @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
859+
* @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING)
860+
* @NFTA_HASH_SET_ID: id of the map (NLA_U32)
859861
*/
860862
enum nft_hash_attributes {
861863
NFTA_HASH_UNSPEC,
@@ -866,6 +868,8 @@ enum nft_hash_attributes {
866868
NFTA_HASH_SEED,
867869
NFTA_HASH_OFFSET,
868870
NFTA_HASH_TYPE,
871+
NFTA_HASH_SET_NAME,
872+
NFTA_HASH_SET_ID,
869873
__NFTA_HASH_MAX,
870874
};
871875
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)

net/netfilter/nft_hash.c

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct nft_jhash {
2525
u32 modulus;
2626
u32 seed;
2727
u32 offset;
28+
struct nft_set *map;
2829
};
2930

3031
static void nft_jhash_eval(const struct nft_expr *expr,
@@ -35,14 +36,39 @@ static void nft_jhash_eval(const struct nft_expr *expr,
3536
const void *data = &regs->data[priv->sreg];
3637
u32 h;
3738

38-
h = reciprocal_scale(jhash(data, priv->len, priv->seed), priv->modulus);
39+
h = reciprocal_scale(jhash(data, priv->len, priv->seed),
40+
priv->modulus);
41+
3942
regs->data[priv->dreg] = h + priv->offset;
4043
}
4144

45+
static void nft_jhash_map_eval(const struct nft_expr *expr,
46+
struct nft_regs *regs,
47+
const struct nft_pktinfo *pkt)
48+
{
49+
struct nft_jhash *priv = nft_expr_priv(expr);
50+
const void *data = &regs->data[priv->sreg];
51+
const struct nft_set *map = priv->map;
52+
const struct nft_set_ext *ext;
53+
u32 result;
54+
bool found;
55+
56+
result = reciprocal_scale(jhash(data, priv->len, priv->seed),
57+
priv->modulus) + priv->offset;
58+
59+
found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
60+
if (!found)
61+
return;
62+
63+
nft_data_copy(&regs->data[priv->dreg],
64+
nft_set_ext_data(ext), map->dlen);
65+
}
66+
4267
struct nft_symhash {
4368
enum nft_registers dreg:8;
4469
u32 modulus;
4570
u32 offset;
71+
struct nft_set *map;
4672
};
4773

4874
static void nft_symhash_eval(const struct nft_expr *expr,
@@ -58,6 +84,28 @@ static void nft_symhash_eval(const struct nft_expr *expr,
5884
regs->data[priv->dreg] = h + priv->offset;
5985
}
6086

87+
static void nft_symhash_map_eval(const struct nft_expr *expr,
88+
struct nft_regs *regs,
89+
const struct nft_pktinfo *pkt)
90+
{
91+
struct nft_symhash *priv = nft_expr_priv(expr);
92+
struct sk_buff *skb = pkt->skb;
93+
const struct nft_set *map = priv->map;
94+
const struct nft_set_ext *ext;
95+
u32 result;
96+
bool found;
97+
98+
result = reciprocal_scale(__skb_get_hash_symmetric(skb),
99+
priv->modulus) + priv->offset;
100+
101+
found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
102+
if (!found)
103+
return;
104+
105+
nft_data_copy(&regs->data[priv->dreg],
106+
nft_set_ext_data(ext), map->dlen);
107+
}
108+
61109
static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
62110
[NFTA_HASH_SREG] = { .type = NLA_U32 },
63111
[NFTA_HASH_DREG] = { .type = NLA_U32 },
@@ -66,6 +114,9 @@ static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
66114
[NFTA_HASH_SEED] = { .type = NLA_U32 },
67115
[NFTA_HASH_OFFSET] = { .type = NLA_U32 },
68116
[NFTA_HASH_TYPE] = { .type = NLA_U32 },
117+
[NFTA_HASH_SET_NAME] = { .type = NLA_STRING,
118+
.len = NFT_SET_MAXNAMELEN - 1 },
119+
[NFTA_HASH_SET_ID] = { .type = NLA_U32 },
69120
};
70121

71122
static int nft_jhash_init(const struct nft_ctx *ctx,
@@ -115,6 +166,23 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
115166
NFT_DATA_VALUE, sizeof(u32));
116167
}
117168

169+
static int nft_jhash_map_init(const struct nft_ctx *ctx,
170+
const struct nft_expr *expr,
171+
const struct nlattr * const tb[])
172+
{
173+
struct nft_jhash *priv = nft_expr_priv(expr);
174+
u8 genmask = nft_genmask_next(ctx->net);
175+
176+
nft_jhash_init(ctx, expr, tb);
177+
priv->map = nft_set_lookup_global(ctx->net, ctx->table,
178+
tb[NFTA_HASH_SET_NAME],
179+
tb[NFTA_HASH_SET_ID], genmask);
180+
if (IS_ERR(priv->map))
181+
return PTR_ERR(priv->map);
182+
183+
return 0;
184+
}
185+
118186
static int nft_symhash_init(const struct nft_ctx *ctx,
119187
const struct nft_expr *expr,
120188
const struct nlattr * const tb[])
@@ -141,6 +209,23 @@ static int nft_symhash_init(const struct nft_ctx *ctx,
141209
NFT_DATA_VALUE, sizeof(u32));
142210
}
143211

212+
static int nft_symhash_map_init(const struct nft_ctx *ctx,
213+
const struct nft_expr *expr,
214+
const struct nlattr * const tb[])
215+
{
216+
struct nft_jhash *priv = nft_expr_priv(expr);
217+
u8 genmask = nft_genmask_next(ctx->net);
218+
219+
nft_symhash_init(ctx, expr, tb);
220+
priv->map = nft_set_lookup_global(ctx->net, ctx->table,
221+
tb[NFTA_HASH_SET_NAME],
222+
tb[NFTA_HASH_SET_ID], genmask);
223+
if (IS_ERR(priv->map))
224+
return PTR_ERR(priv->map);
225+
226+
return 0;
227+
}
228+
144229
static int nft_jhash_dump(struct sk_buff *skb,
145230
const struct nft_expr *expr)
146231
{
@@ -168,6 +253,18 @@ static int nft_jhash_dump(struct sk_buff *skb,
168253
return -1;
169254
}
170255

256+
static int nft_jhash_map_dump(struct sk_buff *skb,
257+
const struct nft_expr *expr)
258+
{
259+
const struct nft_jhash *priv = nft_expr_priv(expr);
260+
261+
if (nft_jhash_dump(skb, expr) ||
262+
nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name))
263+
return -1;
264+
265+
return 0;
266+
}
267+
171268
static int nft_symhash_dump(struct sk_buff *skb,
172269
const struct nft_expr *expr)
173270
{
@@ -188,6 +285,18 @@ static int nft_symhash_dump(struct sk_buff *skb,
188285
return -1;
189286
}
190287

288+
static int nft_symhash_map_dump(struct sk_buff *skb,
289+
const struct nft_expr *expr)
290+
{
291+
const struct nft_symhash *priv = nft_expr_priv(expr);
292+
293+
if (nft_symhash_dump(skb, expr) ||
294+
nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name))
295+
return -1;
296+
297+
return 0;
298+
}
299+
191300
static struct nft_expr_type nft_hash_type;
192301
static const struct nft_expr_ops nft_jhash_ops = {
193302
.type = &nft_hash_type,
@@ -197,6 +306,14 @@ static const struct nft_expr_ops nft_jhash_ops = {
197306
.dump = nft_jhash_dump,
198307
};
199308

309+
static const struct nft_expr_ops nft_jhash_map_ops = {
310+
.type = &nft_hash_type,
311+
.size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
312+
.eval = nft_jhash_map_eval,
313+
.init = nft_jhash_map_init,
314+
.dump = nft_jhash_map_dump,
315+
};
316+
200317
static const struct nft_expr_ops nft_symhash_ops = {
201318
.type = &nft_hash_type,
202319
.size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
@@ -205,6 +322,14 @@ static const struct nft_expr_ops nft_symhash_ops = {
205322
.dump = nft_symhash_dump,
206323
};
207324

325+
static const struct nft_expr_ops nft_symhash_map_ops = {
326+
.type = &nft_hash_type,
327+
.size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
328+
.eval = nft_symhash_map_eval,
329+
.init = nft_symhash_map_init,
330+
.dump = nft_symhash_map_dump,
331+
};
332+
208333
static const struct nft_expr_ops *
209334
nft_hash_select_ops(const struct nft_ctx *ctx,
210335
const struct nlattr * const tb[])
@@ -217,8 +342,12 @@ nft_hash_select_ops(const struct nft_ctx *ctx,
217342
type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE]));
218343
switch (type) {
219344
case NFT_HASH_SYM:
345+
if (tb[NFTA_HASH_SET_NAME])
346+
return &nft_symhash_map_ops;
220347
return &nft_symhash_ops;
221348
case NFT_HASH_JENKINS:
349+
if (tb[NFTA_HASH_SET_NAME])
350+
return &nft_jhash_map_ops;
222351
return &nft_jhash_ops;
223352
default:
224353
break;

0 commit comments

Comments
 (0)