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