1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
4 *
5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/list.h>
12 #include <linux/log2.h>
13 #include <linux/jhash.h>
14 #include <linux/netlink.h>
15 #include <linux/workqueue.h>
16 #include <linux/rhashtable.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter/nf_tables.h>
19 #include <net/netfilter/nf_tables_core.h>
20
21 /* We target a hash table size of 4, element hint is 75% of final size */
22 #define NFT_RHASH_ELEMENT_HINT 3
23
24 struct nft_rhash {
25 struct rhashtable ht;
26 struct delayed_work gc_work;
27 u32 wq_gc_seq;
28 };
29
30 struct nft_rhash_elem {
31 struct nft_elem_priv priv;
32 struct rhash_head node;
33 u32 wq_gc_seq;
34 struct nft_set_ext ext;
35 };
36
37 struct nft_rhash_cmp_arg {
38 const struct nft_set *set;
39 const u32 *key;
40 u8 genmask;
41 u64 tstamp;
42 };
43
nft_rhash_key(const void * data,u32 len,u32 seed)44 static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
45 {
46 const struct nft_rhash_cmp_arg *arg = data;
47
48 return jhash(arg->key, len, seed);
49 }
50
nft_rhash_obj(const void * data,u32 len,u32 seed)51 static inline u32 nft_rhash_obj(const void *data, u32 len, u32 seed)
52 {
53 const struct nft_rhash_elem *he = data;
54
55 return jhash(nft_set_ext_key(&he->ext), len, seed);
56 }
57
nft_rhash_cmp(struct rhashtable_compare_arg * arg,const void * ptr)58 static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg,
59 const void *ptr)
60 {
61 const struct nft_rhash_cmp_arg *x = arg->key;
62 const struct nft_rhash_elem *he = ptr;
63
64 if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
65 return 1;
66 if (nft_set_elem_is_dead(&he->ext))
67 return 1;
68 if (__nft_set_elem_expired(&he->ext, x->tstamp))
69 return 1;
70 if (!nft_set_elem_active(&he->ext, x->genmask))
71 return 1;
72 return 0;
73 }
74
75 static const struct rhashtable_params nft_rhash_params = {
76 .head_offset = offsetof(struct nft_rhash_elem, node),
77 .hashfn = nft_rhash_key,
78 .obj_hashfn = nft_rhash_obj,
79 .obj_cmpfn = nft_rhash_cmp,
80 .automatic_shrinking = true,
81 };
82
83 INDIRECT_CALLABLE_SCOPE
84 const struct nft_set_ext *
nft_rhash_lookup(const struct net * net,const struct nft_set * set,const u32 * key)85 nft_rhash_lookup(const struct net *net, const struct nft_set *set,
86 const u32 *key)
87 {
88 struct nft_rhash *priv = nft_set_priv(set);
89 const struct nft_rhash_elem *he;
90 struct nft_rhash_cmp_arg arg = {
91 .genmask = nft_genmask_cur(net),
92 .set = set,
93 .key = key,
94 .tstamp = get_jiffies_64(),
95 };
96
97 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
98 if (he != NULL)
99 return &he->ext;
100
101 return NULL;
102 }
103
104 static struct nft_elem_priv *
nft_rhash_get(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem,unsigned int flags)105 nft_rhash_get(const struct net *net, const struct nft_set *set,
106 const struct nft_set_elem *elem, unsigned int flags)
107 {
108 struct nft_rhash *priv = nft_set_priv(set);
109 struct nft_rhash_elem *he;
110 struct nft_rhash_cmp_arg arg = {
111 .genmask = nft_genmask_cur(net),
112 .set = set,
113 .key = elem->key.val.data,
114 .tstamp = get_jiffies_64(),
115 };
116
117 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
118 if (he != NULL)
119 return &he->priv;
120
121 return ERR_PTR(-ENOENT);
122 }
123
124 static const struct nft_set_ext *
nft_rhash_update(struct nft_set * set,const u32 * key,struct nft_elem_priv * (* new)(struct nft_set *,const struct nft_expr *,struct nft_regs * regs),const struct nft_expr * expr,struct nft_regs * regs)125 nft_rhash_update(struct nft_set *set, const u32 *key,
126 struct nft_elem_priv *(*new)(struct nft_set *, const struct nft_expr *,
127 struct nft_regs *regs),
128 const struct nft_expr *expr, struct nft_regs *regs)
129 {
130 struct nft_rhash *priv = nft_set_priv(set);
131 struct nft_rhash_elem *he, *prev;
132 struct nft_elem_priv *elem_priv;
133 struct nft_rhash_cmp_arg arg = {
134 .genmask = NFT_GENMASK_ANY,
135 .set = set,
136 .key = key,
137 .tstamp = get_jiffies_64(),
138 };
139
140 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
141 if (he != NULL)
142 goto out;
143
144 elem_priv = new(set, expr, regs);
145 if (!elem_priv)
146 goto err1;
147
148 he = nft_elem_priv_cast(elem_priv);
149 prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
150 nft_rhash_params);
151 if (IS_ERR(prev))
152 goto err2;
153
154 /* Another cpu may race to insert the element with the same key */
155 if (prev) {
156 nft_set_elem_destroy(set, &he->priv, true);
157 atomic_dec(&set->nelems);
158 he = prev;
159 }
160
161 out:
162 return &he->ext;
163
164 err2:
165 nft_set_elem_destroy(set, &he->priv, true);
166 atomic_dec(&set->nelems);
167 err1:
168 return NULL;
169 }
170
nft_rhash_insert(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem,struct nft_elem_priv ** elem_priv)171 static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
172 const struct nft_set_elem *elem,
173 struct nft_elem_priv **elem_priv)
174 {
175 struct nft_rhash_elem *he = nft_elem_priv_cast(elem->priv);
176 struct nft_rhash *priv = nft_set_priv(set);
177 struct nft_rhash_cmp_arg arg = {
178 .genmask = nft_genmask_next(net),
179 .set = set,
180 .key = elem->key.val.data,
181 .tstamp = nft_net_tstamp(net),
182 };
183 struct nft_rhash_elem *prev;
184
185 prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
186 nft_rhash_params);
187 if (IS_ERR(prev))
188 return PTR_ERR(prev);
189 if (prev) {
190 *elem_priv = &prev->priv;
191 return -EEXIST;
192 }
193 return 0;
194 }
195
nft_rhash_activate(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)196 static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
197 struct nft_elem_priv *elem_priv)
198 {
199 struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
200
201 nft_clear(net, &he->ext);
202 }
203
nft_rhash_flush(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)204 static void nft_rhash_flush(const struct net *net,
205 const struct nft_set *set,
206 struct nft_elem_priv *elem_priv)
207 {
208 struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
209
210 nft_set_elem_change_active(net, set, &he->ext);
211 }
212
213 static struct nft_elem_priv *
nft_rhash_deactivate(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem)214 nft_rhash_deactivate(const struct net *net, const struct nft_set *set,
215 const struct nft_set_elem *elem)
216 {
217 struct nft_rhash *priv = nft_set_priv(set);
218 struct nft_rhash_elem *he;
219 struct nft_rhash_cmp_arg arg = {
220 .genmask = nft_genmask_next(net),
221 .set = set,
222 .key = elem->key.val.data,
223 .tstamp = nft_net_tstamp(net),
224 };
225
226 rcu_read_lock();
227 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
228 if (he)
229 nft_set_elem_change_active(net, set, &he->ext);
230
231 rcu_read_unlock();
232
233 return &he->priv;
234 }
235
nft_rhash_remove(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)236 static void nft_rhash_remove(const struct net *net,
237 const struct nft_set *set,
238 struct nft_elem_priv *elem_priv)
239 {
240 struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
241 struct nft_rhash *priv = nft_set_priv(set);
242
243 rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
244 }
245
nft_rhash_delete(const struct nft_set * set,const u32 * key)246 static bool nft_rhash_delete(const struct nft_set *set,
247 const u32 *key)
248 {
249 struct nft_rhash *priv = nft_set_priv(set);
250 struct nft_rhash_cmp_arg arg = {
251 .genmask = NFT_GENMASK_ANY,
252 .set = set,
253 .key = key,
254 };
255 struct nft_rhash_elem *he;
256
257 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
258 if (he == NULL)
259 return false;
260
261 nft_set_elem_dead(&he->ext);
262
263 return true;
264 }
265
nft_rhash_walk(const struct nft_ctx * ctx,struct nft_set * set,struct nft_set_iter * iter)266 static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
267 struct nft_set_iter *iter)
268 {
269 struct nft_rhash *priv = nft_set_priv(set);
270 struct nft_rhash_elem *he;
271 struct rhashtable_iter hti;
272
273 rhashtable_walk_enter(&priv->ht, &hti);
274 rhashtable_walk_start(&hti);
275
276 while ((he = rhashtable_walk_next(&hti))) {
277 if (IS_ERR(he)) {
278 if (PTR_ERR(he) != -EAGAIN) {
279 iter->err = PTR_ERR(he);
280 break;
281 }
282
283 continue;
284 }
285
286 if (iter->count < iter->skip)
287 goto cont;
288
289 iter->err = iter->fn(ctx, set, iter, &he->priv);
290 if (iter->err < 0)
291 break;
292
293 cont:
294 iter->count++;
295 }
296 rhashtable_walk_stop(&hti);
297 rhashtable_walk_exit(&hti);
298 }
299
nft_rhash_expr_needs_gc_run(const struct nft_set * set,struct nft_set_ext * ext)300 static bool nft_rhash_expr_needs_gc_run(const struct nft_set *set,
301 struct nft_set_ext *ext)
302 {
303 struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
304 struct nft_expr *expr;
305 u32 size;
306
307 nft_setelem_expr_foreach(expr, elem_expr, size) {
308 if (expr->ops->gc &&
309 expr->ops->gc(read_pnet(&set->net), expr) &&
310 set->flags & NFT_SET_EVAL)
311 return true;
312 }
313
314 return false;
315 }
316
nft_rhash_gc(struct work_struct * work)317 static void nft_rhash_gc(struct work_struct *work)
318 {
319 struct nftables_pernet *nft_net;
320 struct nft_set *set;
321 struct nft_rhash_elem *he;
322 struct nft_rhash *priv;
323 struct rhashtable_iter hti;
324 struct nft_trans_gc *gc;
325 struct net *net;
326 u32 gc_seq;
327
328 priv = container_of(work, struct nft_rhash, gc_work.work);
329 set = nft_set_container_of(priv);
330 net = read_pnet(&set->net);
331 nft_net = nft_pernet(net);
332 gc_seq = READ_ONCE(nft_net->gc_seq);
333
334 if (nft_set_gc_is_pending(set))
335 goto done;
336
337 gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL);
338 if (!gc)
339 goto done;
340
341 /* Elements never collected use a zero gc worker sequence number. */
342 if (unlikely(++priv->wq_gc_seq == 0))
343 priv->wq_gc_seq++;
344
345 rhashtable_walk_enter(&priv->ht, &hti);
346 rhashtable_walk_start(&hti);
347
348 while ((he = rhashtable_walk_next(&hti))) {
349 if (IS_ERR(he)) {
350 nft_trans_gc_destroy(gc);
351 gc = NULL;
352 goto try_later;
353 }
354
355 /* Ruleset has been updated, try later. */
356 if (READ_ONCE(nft_net->gc_seq) != gc_seq) {
357 nft_trans_gc_destroy(gc);
358 gc = NULL;
359 goto try_later;
360 }
361
362 /* rhashtable walk is unstable, already seen in this gc run?
363 * Then, skip this element. In case of (unlikely) sequence
364 * wraparound and stale element wq_gc_seq, next gc run will
365 * just find this expired element.
366 */
367 if (he->wq_gc_seq == priv->wq_gc_seq)
368 continue;
369
370 if (nft_set_elem_is_dead(&he->ext))
371 goto dead_elem;
372
373 if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPRESSIONS) &&
374 nft_rhash_expr_needs_gc_run(set, &he->ext))
375 goto needs_gc_run;
376
377 if (!nft_set_elem_expired(&he->ext))
378 continue;
379 needs_gc_run:
380 nft_set_elem_dead(&he->ext);
381 dead_elem:
382 gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
383 if (!gc)
384 goto try_later;
385
386 /* annotate gc sequence for this attempt. */
387 he->wq_gc_seq = priv->wq_gc_seq;
388 nft_trans_gc_elem_add(gc, he);
389 }
390
391 gc = nft_trans_gc_catchall_async(gc, gc_seq);
392
393 try_later:
394 /* catchall list iteration requires rcu read side lock. */
395 rhashtable_walk_stop(&hti);
396 rhashtable_walk_exit(&hti);
397
398 if (gc)
399 nft_trans_gc_queue_async_done(gc);
400
401 done:
402 queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
403 nft_set_gc_interval(set));
404 }
405
nft_rhash_privsize(const struct nlattr * const nla[],const struct nft_set_desc * desc)406 static u64 nft_rhash_privsize(const struct nlattr * const nla[],
407 const struct nft_set_desc *desc)
408 {
409 return sizeof(struct nft_rhash);
410 }
411
nft_rhash_gc_init(const struct nft_set * set)412 static void nft_rhash_gc_init(const struct nft_set *set)
413 {
414 struct nft_rhash *priv = nft_set_priv(set);
415
416 queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
417 nft_set_gc_interval(set));
418 }
419
nft_rhash_init(const struct nft_set * set,const struct nft_set_desc * desc,const struct nlattr * const tb[])420 static int nft_rhash_init(const struct nft_set *set,
421 const struct nft_set_desc *desc,
422 const struct nlattr * const tb[])
423 {
424 struct nft_rhash *priv = nft_set_priv(set);
425 struct rhashtable_params params = nft_rhash_params;
426 int err;
427
428 BUILD_BUG_ON(offsetof(struct nft_rhash_elem, priv) != 0);
429
430 params.nelem_hint = desc->size ?: NFT_RHASH_ELEMENT_HINT;
431 params.key_len = set->klen;
432
433 err = rhashtable_init(&priv->ht, ¶ms);
434 if (err < 0)
435 return err;
436
437 INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc);
438 if (set->flags & (NFT_SET_TIMEOUT | NFT_SET_EVAL))
439 nft_rhash_gc_init(set);
440
441 return 0;
442 }
443
444 struct nft_rhash_ctx {
445 const struct nft_ctx ctx;
446 const struct nft_set *set;
447 };
448
nft_rhash_elem_destroy(void * ptr,void * arg)449 static void nft_rhash_elem_destroy(void *ptr, void *arg)
450 {
451 struct nft_rhash_ctx *rhash_ctx = arg;
452 struct nft_rhash_elem *he = ptr;
453
454 nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, &he->priv);
455 }
456
nft_rhash_destroy(const struct nft_ctx * ctx,const struct nft_set * set)457 static void nft_rhash_destroy(const struct nft_ctx *ctx,
458 const struct nft_set *set)
459 {
460 struct nft_rhash *priv = nft_set_priv(set);
461 struct nft_rhash_ctx rhash_ctx = {
462 .ctx = *ctx,
463 .set = set,
464 };
465
466 cancel_delayed_work_sync(&priv->gc_work);
467 rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
468 (void *)&rhash_ctx);
469 }
470
471 /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
472 #define NFT_MAX_BUCKETS (1U << 31)
473
nft_hash_buckets(u32 size)474 static u32 nft_hash_buckets(u32 size)
475 {
476 u64 val = div_u64((u64)size * 4, 3);
477
478 if (val >= NFT_MAX_BUCKETS)
479 return NFT_MAX_BUCKETS;
480
481 return roundup_pow_of_two(val);
482 }
483
nft_rhash_estimate(const struct nft_set_desc * desc,u32 features,struct nft_set_estimate * est)484 static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
485 struct nft_set_estimate *est)
486 {
487 est->size = ~0;
488 est->lookup = NFT_SET_CLASS_O_1;
489 est->space = NFT_SET_CLASS_O_N;
490
491 return true;
492 }
493
494 struct nft_hash {
495 u32 seed;
496 u32 buckets;
497 struct hlist_head table[];
498 };
499
500 struct nft_hash_elem {
501 struct nft_elem_priv priv;
502 struct hlist_node node;
503 struct nft_set_ext ext;
504 };
505
506 INDIRECT_CALLABLE_SCOPE
507 const struct nft_set_ext *
nft_hash_lookup(const struct net * net,const struct nft_set * set,const u32 * key)508 nft_hash_lookup(const struct net *net, const struct nft_set *set,
509 const u32 *key)
510 {
511 struct nft_hash *priv = nft_set_priv(set);
512 u8 genmask = nft_genmask_cur(net);
513 const struct nft_hash_elem *he;
514 u32 hash;
515
516 hash = jhash(key, set->klen, priv->seed);
517 hash = reciprocal_scale(hash, priv->buckets);
518 hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
519 if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
520 nft_set_elem_active(&he->ext, genmask))
521 return &he->ext;
522 }
523 return NULL;
524 }
525
526 static struct nft_elem_priv *
nft_hash_get(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem,unsigned int flags)527 nft_hash_get(const struct net *net, const struct nft_set *set,
528 const struct nft_set_elem *elem, unsigned int flags)
529 {
530 struct nft_hash *priv = nft_set_priv(set);
531 u8 genmask = nft_genmask_cur(net);
532 struct nft_hash_elem *he;
533 u32 hash;
534
535 hash = jhash(elem->key.val.data, set->klen, priv->seed);
536 hash = reciprocal_scale(hash, priv->buckets);
537 hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
538 if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) &&
539 nft_set_elem_active(&he->ext, genmask))
540 return &he->priv;
541 }
542 return ERR_PTR(-ENOENT);
543 }
544
545 INDIRECT_CALLABLE_SCOPE
546 const struct nft_set_ext *
nft_hash_lookup_fast(const struct net * net,const struct nft_set * set,const u32 * key)547 nft_hash_lookup_fast(const struct net *net, const struct nft_set *set,
548 const u32 *key)
549 {
550 struct nft_hash *priv = nft_set_priv(set);
551 u8 genmask = nft_genmask_cur(net);
552 const struct nft_hash_elem *he;
553 u32 hash, k1, k2;
554
555 k1 = *key;
556 hash = jhash_1word(k1, priv->seed);
557 hash = reciprocal_scale(hash, priv->buckets);
558 hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
559 k2 = *(u32 *)nft_set_ext_key(&he->ext)->data;
560 if (k1 == k2 &&
561 nft_set_elem_active(&he->ext, genmask))
562 return &he->ext;
563 }
564 return NULL;
565 }
566
nft_jhash(const struct nft_set * set,const struct nft_hash * priv,const struct nft_set_ext * ext)567 static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv,
568 const struct nft_set_ext *ext)
569 {
570 const struct nft_data *key = nft_set_ext_key(ext);
571 u32 hash, k1;
572
573 if (set->klen == 4) {
574 k1 = *(u32 *)key;
575 hash = jhash_1word(k1, priv->seed);
576 } else {
577 hash = jhash(key, set->klen, priv->seed);
578 }
579 hash = reciprocal_scale(hash, priv->buckets);
580
581 return hash;
582 }
583
nft_hash_insert(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem,struct nft_elem_priv ** elem_priv)584 static int nft_hash_insert(const struct net *net, const struct nft_set *set,
585 const struct nft_set_elem *elem,
586 struct nft_elem_priv **elem_priv)
587 {
588 struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
589 struct nft_hash *priv = nft_set_priv(set);
590 u8 genmask = nft_genmask_next(net);
591 u32 hash;
592
593 hash = nft_jhash(set, priv, &this->ext);
594 hlist_for_each_entry(he, &priv->table[hash], node) {
595 if (!memcmp(nft_set_ext_key(&this->ext),
596 nft_set_ext_key(&he->ext), set->klen) &&
597 nft_set_elem_active(&he->ext, genmask)) {
598 *elem_priv = &he->priv;
599 return -EEXIST;
600 }
601 }
602 hlist_add_head_rcu(&this->node, &priv->table[hash]);
603 return 0;
604 }
605
nft_hash_activate(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)606 static void nft_hash_activate(const struct net *net, const struct nft_set *set,
607 struct nft_elem_priv *elem_priv)
608 {
609 struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
610
611 nft_clear(net, &he->ext);
612 }
613
nft_hash_flush(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)614 static void nft_hash_flush(const struct net *net,
615 const struct nft_set *set,
616 struct nft_elem_priv *elem_priv)
617 {
618 struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
619
620 nft_set_elem_change_active(net, set, &he->ext);
621 }
622
623 static struct nft_elem_priv *
nft_hash_deactivate(const struct net * net,const struct nft_set * set,const struct nft_set_elem * elem)624 nft_hash_deactivate(const struct net *net, const struct nft_set *set,
625 const struct nft_set_elem *elem)
626 {
627 struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
628 struct nft_hash *priv = nft_set_priv(set);
629 u8 genmask = nft_genmask_next(net);
630 u32 hash;
631
632 hash = nft_jhash(set, priv, &this->ext);
633 hlist_for_each_entry(he, &priv->table[hash], node) {
634 if (!memcmp(nft_set_ext_key(&he->ext), &elem->key.val,
635 set->klen) &&
636 nft_set_elem_active(&he->ext, genmask)) {
637 nft_set_elem_change_active(net, set, &he->ext);
638 return &he->priv;
639 }
640 }
641 return NULL;
642 }
643
nft_hash_remove(const struct net * net,const struct nft_set * set,struct nft_elem_priv * elem_priv)644 static void nft_hash_remove(const struct net *net,
645 const struct nft_set *set,
646 struct nft_elem_priv *elem_priv)
647 {
648 struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
649
650 hlist_del_rcu(&he->node);
651 }
652
nft_hash_walk(const struct nft_ctx * ctx,struct nft_set * set,struct nft_set_iter * iter)653 static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
654 struct nft_set_iter *iter)
655 {
656 struct nft_hash *priv = nft_set_priv(set);
657 struct nft_hash_elem *he;
658 int i;
659
660 for (i = 0; i < priv->buckets; i++) {
661 hlist_for_each_entry_rcu(he, &priv->table[i], node) {
662 if (iter->count < iter->skip)
663 goto cont;
664
665 iter->err = iter->fn(ctx, set, iter, &he->priv);
666 if (iter->err < 0)
667 return;
668 cont:
669 iter->count++;
670 }
671 }
672 }
673
nft_hash_privsize(const struct nlattr * const nla[],const struct nft_set_desc * desc)674 static u64 nft_hash_privsize(const struct nlattr * const nla[],
675 const struct nft_set_desc *desc)
676 {
677 return sizeof(struct nft_hash) +
678 (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
679 }
680
nft_hash_init(const struct nft_set * set,const struct nft_set_desc * desc,const struct nlattr * const tb[])681 static int nft_hash_init(const struct nft_set *set,
682 const struct nft_set_desc *desc,
683 const struct nlattr * const tb[])
684 {
685 struct nft_hash *priv = nft_set_priv(set);
686
687 priv->buckets = nft_hash_buckets(desc->size);
688 get_random_bytes(&priv->seed, sizeof(priv->seed));
689
690 return 0;
691 }
692
nft_hash_destroy(const struct nft_ctx * ctx,const struct nft_set * set)693 static void nft_hash_destroy(const struct nft_ctx *ctx,
694 const struct nft_set *set)
695 {
696 struct nft_hash *priv = nft_set_priv(set);
697 struct nft_hash_elem *he;
698 struct hlist_node *next;
699 int i;
700
701 for (i = 0; i < priv->buckets; i++) {
702 hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
703 hlist_del_rcu(&he->node);
704 nf_tables_set_elem_destroy(ctx, set, &he->priv);
705 }
706 }
707 }
708
nft_hash_estimate(const struct nft_set_desc * desc,u32 features,struct nft_set_estimate * est)709 static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
710 struct nft_set_estimate *est)
711 {
712 if (!desc->size)
713 return false;
714
715 if (desc->klen == 4)
716 return false;
717
718 est->size = sizeof(struct nft_hash) +
719 (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
720 (u64)desc->size * sizeof(struct nft_hash_elem);
721 est->lookup = NFT_SET_CLASS_O_1;
722 est->space = NFT_SET_CLASS_O_N;
723
724 return true;
725 }
726
nft_hash_fast_estimate(const struct nft_set_desc * desc,u32 features,struct nft_set_estimate * est)727 static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features,
728 struct nft_set_estimate *est)
729 {
730 if (!desc->size)
731 return false;
732
733 if (desc->klen != 4)
734 return false;
735
736 est->size = sizeof(struct nft_hash) +
737 (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
738 (u64)desc->size * sizeof(struct nft_hash_elem);
739 est->lookup = NFT_SET_CLASS_O_1;
740 est->space = NFT_SET_CLASS_O_N;
741
742 return true;
743 }
744
745 const struct nft_set_type nft_set_rhash_type = {
746 .features = NFT_SET_MAP | NFT_SET_OBJECT |
747 NFT_SET_TIMEOUT | NFT_SET_EVAL,
748 .ops = {
749 .privsize = nft_rhash_privsize,
750 .elemsize = offsetof(struct nft_rhash_elem, ext),
751 .estimate = nft_rhash_estimate,
752 .init = nft_rhash_init,
753 .gc_init = nft_rhash_gc_init,
754 .destroy = nft_rhash_destroy,
755 .insert = nft_rhash_insert,
756 .activate = nft_rhash_activate,
757 .deactivate = nft_rhash_deactivate,
758 .flush = nft_rhash_flush,
759 .remove = nft_rhash_remove,
760 .lookup = nft_rhash_lookup,
761 .update = nft_rhash_update,
762 .delete = nft_rhash_delete,
763 .walk = nft_rhash_walk,
764 .get = nft_rhash_get,
765 },
766 };
767
768 const struct nft_set_type nft_set_hash_type = {
769 .features = NFT_SET_MAP | NFT_SET_OBJECT,
770 .ops = {
771 .privsize = nft_hash_privsize,
772 .elemsize = offsetof(struct nft_hash_elem, ext),
773 .estimate = nft_hash_estimate,
774 .init = nft_hash_init,
775 .destroy = nft_hash_destroy,
776 .insert = nft_hash_insert,
777 .activate = nft_hash_activate,
778 .deactivate = nft_hash_deactivate,
779 .flush = nft_hash_flush,
780 .remove = nft_hash_remove,
781 .lookup = nft_hash_lookup,
782 .walk = nft_hash_walk,
783 .get = nft_hash_get,
784 },
785 };
786
787 const struct nft_set_type nft_set_hash_fast_type = {
788 .features = NFT_SET_MAP | NFT_SET_OBJECT,
789 .ops = {
790 .privsize = nft_hash_privsize,
791 .elemsize = offsetof(struct nft_hash_elem, ext),
792 .estimate = nft_hash_fast_estimate,
793 .init = nft_hash_init,
794 .destroy = nft_hash_destroy,
795 .insert = nft_hash_insert,
796 .activate = nft_hash_activate,
797 .deactivate = nft_hash_deactivate,
798 .flush = nft_hash_flush,
799 .remove = nft_hash_remove,
800 .lookup = nft_hash_lookup_fast,
801 .walk = nft_hash_walk,
802 .get = nft_hash_get,
803 },
804 };
805