2 * Copyright (c) 2016 Laura Garcia <nevola@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/netlink.h>
14 #include <linux/netfilter.h>
15 #include <linux/netfilter/nf_tables.h>
16 #include <net/netfilter/nf_tables.h>
17 #include <net/netfilter/nf_tables_core.h>
18 #include <linux/jhash.h>
31 static void nft_jhash_eval(const struct nft_expr *expr,
32 struct nft_regs *regs,
33 const struct nft_pktinfo *pkt)
35 struct nft_jhash *priv = nft_expr_priv(expr);
36 const void *data = ®s->data[priv->sreg];
39 h = reciprocal_scale(jhash(data, priv->len, priv->seed),
42 regs->data[priv->dreg] = h + priv->offset;
45 static void nft_jhash_map_eval(const struct nft_expr *expr,
46 struct nft_regs *regs,
47 const struct nft_pktinfo *pkt)
49 struct nft_jhash *priv = nft_expr_priv(expr);
50 const void *data = ®s->data[priv->sreg];
51 const struct nft_set *map = priv->map;
52 const struct nft_set_ext *ext;
56 result = reciprocal_scale(jhash(data, priv->len, priv->seed),
57 priv->modulus) + priv->offset;
59 found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
63 nft_data_copy(®s->data[priv->dreg],
64 nft_set_ext_data(ext), map->dlen);
74 static void nft_symhash_eval(const struct nft_expr *expr,
75 struct nft_regs *regs,
76 const struct nft_pktinfo *pkt)
78 struct nft_symhash *priv = nft_expr_priv(expr);
79 struct sk_buff *skb = pkt->skb;
82 h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus);
84 regs->data[priv->dreg] = h + priv->offset;
87 static void nft_symhash_map_eval(const struct nft_expr *expr,
88 struct nft_regs *regs,
89 const struct nft_pktinfo *pkt)
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;
98 result = reciprocal_scale(__skb_get_hash_symmetric(skb),
99 priv->modulus) + priv->offset;
101 found = map->ops->lookup(nft_net(pkt), map, &result, &ext);
105 nft_data_copy(®s->data[priv->dreg],
106 nft_set_ext_data(ext), map->dlen);
109 static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
110 [NFTA_HASH_SREG] = { .type = NLA_U32 },
111 [NFTA_HASH_DREG] = { .type = NLA_U32 },
112 [NFTA_HASH_LEN] = { .type = NLA_U32 },
113 [NFTA_HASH_MODULUS] = { .type = NLA_U32 },
114 [NFTA_HASH_SEED] = { .type = NLA_U32 },
115 [NFTA_HASH_OFFSET] = { .type = NLA_U32 },
116 [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 },
122 static int nft_jhash_init(const struct nft_ctx *ctx,
123 const struct nft_expr *expr,
124 const struct nlattr * const tb[])
126 struct nft_jhash *priv = nft_expr_priv(expr);
130 if (!tb[NFTA_HASH_SREG] ||
131 !tb[NFTA_HASH_DREG] ||
132 !tb[NFTA_HASH_LEN] ||
133 !tb[NFTA_HASH_MODULUS])
136 if (tb[NFTA_HASH_OFFSET])
137 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
139 err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
147 err = nft_parse_register_load(tb[NFTA_HASH_SREG], &priv->sreg, len);
151 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
152 if (priv->modulus < 1)
155 if (priv->offset + priv->modulus - 1 < priv->offset)
158 if (tb[NFTA_HASH_SEED]) {
159 priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
161 priv->autogen_seed = true;
162 get_random_bytes(&priv->seed, sizeof(priv->seed));
165 return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG], &priv->dreg,
166 NULL, NFT_DATA_VALUE, sizeof(u32));
169 static int nft_jhash_map_init(const struct nft_ctx *ctx,
170 const struct nft_expr *expr,
171 const struct nlattr * const tb[])
173 struct nft_jhash *priv = nft_expr_priv(expr);
174 u8 genmask = nft_genmask_next(ctx->net);
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 return PTR_ERR_OR_ZERO(priv->map);
183 static int nft_symhash_init(const struct nft_ctx *ctx,
184 const struct nft_expr *expr,
185 const struct nlattr * const tb[])
187 struct nft_symhash *priv = nft_expr_priv(expr);
189 if (!tb[NFTA_HASH_DREG] ||
190 !tb[NFTA_HASH_MODULUS])
193 if (tb[NFTA_HASH_OFFSET])
194 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
196 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
197 if (priv->modulus < 1)
200 if (priv->offset + priv->modulus - 1 < priv->offset)
203 return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG],
204 &priv->dreg, NULL, NFT_DATA_VALUE,
208 static int nft_symhash_map_init(const struct nft_ctx *ctx,
209 const struct nft_expr *expr,
210 const struct nlattr * const tb[])
212 struct nft_jhash *priv = nft_expr_priv(expr);
213 u8 genmask = nft_genmask_next(ctx->net);
215 nft_symhash_init(ctx, expr, tb);
216 priv->map = nft_set_lookup_global(ctx->net, ctx->table,
217 tb[NFTA_HASH_SET_NAME],
218 tb[NFTA_HASH_SET_ID], genmask);
219 return PTR_ERR_OR_ZERO(priv->map);
222 static int nft_jhash_dump(struct sk_buff *skb,
223 const struct nft_expr *expr)
225 const struct nft_jhash *priv = nft_expr_priv(expr);
227 if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg))
228 goto nla_put_failure;
229 if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
230 goto nla_put_failure;
231 if (nla_put_be32(skb, NFTA_HASH_LEN, htonl(priv->len)))
232 goto nla_put_failure;
233 if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
234 goto nla_put_failure;
235 if (!priv->autogen_seed &&
236 nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
237 goto nla_put_failure;
238 if (priv->offset != 0)
239 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
240 goto nla_put_failure;
241 if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_JENKINS)))
242 goto nla_put_failure;
249 static int nft_jhash_map_dump(struct sk_buff *skb,
250 const struct nft_expr *expr)
252 const struct nft_jhash *priv = nft_expr_priv(expr);
254 if (nft_jhash_dump(skb, expr) ||
255 nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name))
261 static int nft_symhash_dump(struct sk_buff *skb,
262 const struct nft_expr *expr)
264 const struct nft_symhash *priv = nft_expr_priv(expr);
266 if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
267 goto nla_put_failure;
268 if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
269 goto nla_put_failure;
270 if (priv->offset != 0)
271 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
272 goto nla_put_failure;
273 if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_SYM)))
274 goto nla_put_failure;
281 static int nft_symhash_map_dump(struct sk_buff *skb,
282 const struct nft_expr *expr)
284 const struct nft_symhash *priv = nft_expr_priv(expr);
286 if (nft_symhash_dump(skb, expr) ||
287 nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name))
293 static struct nft_expr_type nft_hash_type;
294 static const struct nft_expr_ops nft_jhash_ops = {
295 .type = &nft_hash_type,
296 .size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
297 .eval = nft_jhash_eval,
298 .init = nft_jhash_init,
299 .dump = nft_jhash_dump,
302 static const struct nft_expr_ops nft_jhash_map_ops = {
303 .type = &nft_hash_type,
304 .size = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
305 .eval = nft_jhash_map_eval,
306 .init = nft_jhash_map_init,
307 .dump = nft_jhash_map_dump,
310 static const struct nft_expr_ops nft_symhash_ops = {
311 .type = &nft_hash_type,
312 .size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
313 .eval = nft_symhash_eval,
314 .init = nft_symhash_init,
315 .dump = nft_symhash_dump,
318 static const struct nft_expr_ops nft_symhash_map_ops = {
319 .type = &nft_hash_type,
320 .size = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
321 .eval = nft_symhash_map_eval,
322 .init = nft_symhash_map_init,
323 .dump = nft_symhash_map_dump,
326 static const struct nft_expr_ops *
327 nft_hash_select_ops(const struct nft_ctx *ctx,
328 const struct nlattr * const tb[])
332 if (!tb[NFTA_HASH_TYPE])
333 return &nft_jhash_ops;
335 type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE]));
338 if (tb[NFTA_HASH_SET_NAME])
339 return &nft_symhash_map_ops;
340 return &nft_symhash_ops;
341 case NFT_HASH_JENKINS:
342 if (tb[NFTA_HASH_SET_NAME])
343 return &nft_jhash_map_ops;
344 return &nft_jhash_ops;
348 return ERR_PTR(-EOPNOTSUPP);
351 static struct nft_expr_type nft_hash_type __read_mostly = {
353 .select_ops = nft_hash_select_ops,
354 .policy = nft_hash_policy,
355 .maxattr = NFTA_HASH_MAX,
356 .owner = THIS_MODULE,
359 static int __init nft_hash_module_init(void)
361 return nft_register_expr(&nft_hash_type);
364 static void __exit nft_hash_module_exit(void)
366 nft_unregister_expr(&nft_hash_type);
369 module_init(nft_hash_module_init);
370 module_exit(nft_hash_module_exit);
372 MODULE_LICENSE("GPL");
373 MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>");
374 MODULE_ALIAS_NFT_EXPR("hash");