File Index
Files and directories
Sign in
FILE

nft_set_hash.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_set_hash.c C
  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
 24struct nft_rhash {
 25	struct rhashtable		ht;
 26	struct delayed_work		gc_work;
 27	u32				wq_gc_seq;
 28};
 29
 30struct nft_rhash_elem {
 31	struct nft_elem_priv		priv;
 32	struct rhash_head		node;
 33	struct llist_node		walk_node;
 34	u32				wq_gc_seq;
 35	struct nft_set_ext		ext;
 36};
 37
 38struct nft_rhash_cmp_arg {
 39	const struct nft_set		*set;
 40	const u32			*key;
 41	u8				genmask;
 42	u64				tstamp;
 43};
 44
 45static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
 46{
 47	const struct nft_rhash_cmp_arg *arg = data;
 48
 49	return jhash(arg->key, len, seed);
 50}
 51
 52static inline u32 nft_rhash_obj(const void *data, u32 len, u32 seed)
 53{
 54	const struct nft_rhash_elem *he = data;
 55
 56	return jhash(nft_set_ext_key(&he->ext), len, seed);
 57}
 58
 59static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg,
 60				const void *ptr)
 61{
 62	const struct nft_rhash_cmp_arg *x = arg->key;
 63	const struct nft_rhash_elem *he = ptr;
 64
 65	if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
 66		return 1;
 67	if (nft_set_elem_is_dead(&he->ext))
 68		return 1;
 69	if (__nft_set_elem_expired(&he->ext, x->tstamp))
 70		return 1;
 71	if (!nft_set_elem_active(&he->ext, x->genmask))
 72		return 1;
 73	return 0;
 74}
 75
 76static const struct rhashtable_params nft_rhash_params = {
 77	.head_offset		= offsetof(struct nft_rhash_elem, node),
 78	.hashfn			= nft_rhash_key,
 79	.obj_hashfn		= nft_rhash_obj,
 80	.obj_cmpfn		= nft_rhash_cmp,
 81	.automatic_shrinking	= true,
 82};
 83
 84INDIRECT_CALLABLE_SCOPE
 85const struct nft_set_ext *
 86nft_rhash_lookup(const struct net *net, const struct nft_set *set,
 87		 const u32 *key)
 88{
 89	struct nft_rhash *priv = nft_set_priv(set);
 90	const struct nft_rhash_elem *he;
 91	struct nft_rhash_cmp_arg arg = {
 92		.genmask = nft_genmask_cur(net),
 93		.set	 = set,
 94		.key	 = key,
 95		.tstamp  = get_jiffies_64(),
 96	};
 97
 98	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
 99	if (he != NULL)
100		return &he->ext;
101
102	return NULL;
103}
104
105static struct nft_elem_priv *
106nft_rhash_get(const struct net *net, const struct nft_set *set,
107	      const struct nft_set_elem *elem, unsigned int flags)
108{
109	struct nft_rhash *priv = nft_set_priv(set);
110	struct nft_rhash_elem *he;
111	struct nft_rhash_cmp_arg arg = {
112		.genmask = nft_genmask_cur(net),
113		.set	 = set,
114		.key	 = elem->key.val.data,
115		.tstamp  = get_jiffies_64(),
116	};
117
118	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
119	if (he != NULL)
120		return &he->priv;
121
122	return ERR_PTR(-ENOENT);
123}
124
125static const struct nft_set_ext *
126nft_rhash_update(struct nft_set *set, const u32 *key,
127		 const struct nft_expr *expr, struct nft_regs *regs)
128{
129	struct nft_rhash *priv = nft_set_priv(set);
130	struct nft_rhash_elem *he, *prev;
131	struct nft_elem_priv *elem_priv;
132	struct nft_rhash_cmp_arg arg = {
133		.genmask = NFT_GENMASK_ANY,
134		.set	 = set,
135		.key	 = key,
136		.tstamp  = get_jiffies_64(),
137	};
138
139	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
140	if (he != NULL)
141		goto out;
142
143	elem_priv = nft_dynset_new(set, expr, regs);
144	if (!elem_priv)
145		goto err1;
146
147	he = nft_elem_priv_cast(elem_priv);
148	init_llist_node(&he->walk_node);
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
161out:
162	return &he->ext;
163
164err2:
165	nft_set_elem_destroy(set, &he->priv, true);
166	atomic_dec(&set->nelems);
167err1:
168	return NULL;
169}
170
171static 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	init_llist_node(&he->walk_node);
186	prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
187						nft_rhash_params);
188	if (IS_ERR(prev))
189		return PTR_ERR(prev);
190	if (prev) {
191		*elem_priv = &prev->priv;
192		return -EEXIST;
193	}
194	return 0;
195}
196
197static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
198			       struct nft_elem_priv *elem_priv)
199{
200	struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
201
202	nft_clear(net, &he->ext);
203}
204
205static void nft_rhash_flush(const struct net *net,
206			    const struct nft_set *set,
207			    struct nft_elem_priv *elem_priv)
208{
209	struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
210
211	nft_set_elem_change_active(net, set, &he->ext);
212}
213
214static struct nft_elem_priv *
215nft_rhash_deactivate(const struct net *net, const struct nft_set *set,
216		     const struct nft_set_elem *elem)
217{
218	struct nft_rhash *priv = nft_set_priv(set);
219	struct nft_rhash_elem *he;
220	struct nft_rhash_cmp_arg arg = {
221		.genmask = nft_genmask_next(net),
222		.set	 = set,
223		.key	 = elem->key.val.data,
224		.tstamp	 = nft_net_tstamp(net),
225	};
226
227	rcu_read_lock();
228	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
229	if (he)
230		nft_set_elem_change_active(net, set, &he->ext);
231
232	rcu_read_unlock();
233
234	return &he->priv;
235}
236
237static void nft_rhash_remove(const struct net *net,
238			     const struct nft_set *set,
239			     struct nft_elem_priv *elem_priv)
240{
241	struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);
242	struct nft_rhash *priv = nft_set_priv(set);
243
244	rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
245}
246
247static bool nft_rhash_delete(const struct nft_set *set,
248			     const u32 *key)
249{
250	struct nft_rhash *priv = nft_set_priv(set);
251	struct nft_rhash_cmp_arg arg = {
252		.genmask = NFT_GENMASK_ANY,
253		.set = set,
254		.key = key,
255	};
256	struct nft_rhash_elem *he;
257
258	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
259	if (he == NULL)
260		return false;
261
262	nft_set_elem_dead(&he->ext);
263
264	return true;
265}
266
267static void nft_rhash_walk_ro(const struct nft_ctx *ctx, struct nft_set *set,
268			      struct nft_set_iter *iter)
269{
270	struct nft_rhash *priv = nft_set_priv(set);
271	struct rhashtable_iter hti;
272	struct nft_rhash_elem *he;
273
274	rhashtable_walk_enter(&priv->ht, &hti);
275	rhashtable_walk_start(&hti);
276
277	while ((he = rhashtable_walk_next(&hti))) {
278		if (IS_ERR(he)) {
279			if (PTR_ERR(he) != -EAGAIN) {
280				iter->err = PTR_ERR(he);
281				break;
282			}
283
284			continue;
285		}
286
287		if (iter->count < iter->skip)
288			goto cont;
289
290		iter->err = iter->fn(ctx, set, iter, &he->priv);
291		if (iter->err < 0)
292			break;
293
294cont:
295		iter->count++;
296	}
297	rhashtable_walk_stop(&hti);
298	rhashtable_walk_exit(&hti);
299}
300
301static void nft_rhash_walk_update(const struct nft_ctx *ctx,
302				  struct nft_set *set,
303				  struct nft_set_iter *iter)
304{
305	struct nft_rhash *priv = nft_set_priv(set);
306	struct nft_rhash_elem *he, *tmp;
307	struct llist_node *first_node;
308	struct rhashtable_iter hti;
309	LLIST_HEAD(walk_list);
310
311	lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex);
312
313	if (set->in_update_walk) {
314		/* This can happen with bogus rulesets during ruleset validation
315		 * when a verdict map causes a jump back to the same map.
316		 *
317		 * Without this extra check the walk_next loop below will see
318		 * elems on the callers walk_list and skip (not validate) them.
319		 */
320		iter->err = -EMLINK;
321		return;
322	}
323
324	/* walk happens under RCU.
325	 *
326	 * We create a snapshot list so ->iter callback can sleep.
327	 * commit_mutex is held, elements can ...
328	 * .. be added in parallel from dataplane (dynset)
329	 * .. be marked as dead in parallel from dataplane (dynset).
330	 * .. be queued for removal in parallel (gc timeout).
331	 * .. not be freed: transaction mutex is held.
332	 */
333	rhashtable_walk_enter(&priv->ht, &hti);
334	rhashtable_walk_start(&hti);
335
336	while ((he = rhashtable_walk_next(&hti))) {
337		if (IS_ERR(he)) {
338			if (PTR_ERR(he) != -EAGAIN) {
339				iter->err = PTR_ERR(he);
340				break;
341			}
342
343			continue;
344		}
345
346		/* rhashtable resized during walk, skip */
347		if (llist_on_list(&he->walk_node))
348			continue;
349
350		llist_add(&he->walk_node, &walk_list);
351	}
352	rhashtable_walk_stop(&hti);
353	rhashtable_walk_exit(&hti);
354
355	first_node = __llist_del_all(&walk_list);
356	set->in_update_walk = true;
357	llist_for_each_entry_safe(he, tmp, first_node, walk_node) {
358		if (iter->err == 0) {
359			iter->err = iter->fn(ctx, set, iter, &he->priv);
360			if (iter->err == 0)
361				iter->count++;
362		}
363
364		/* all entries must be cleared again, else next ->walk iteration
365		 * will skip entries.
366		 */
367		init_llist_node(&he->walk_node);
368	}
369	set->in_update_walk = false;
370}
371
372static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
373			   struct nft_set_iter *iter)
374{
375	switch (iter->type) {
376	case NFT_ITER_UPDATE:
377	case NFT_ITER_UPDATE_CLONE:
378		/* only relevant for netlink dumps which use READ type */
379		WARN_ON_ONCE(iter->skip != 0);
380
381		nft_rhash_walk_update(ctx, set, iter);
382		break;
383	case NFT_ITER_READ:
384		nft_rhash_walk_ro(ctx, set, iter);
385		break;
386	default:
387		iter->err = -EINVAL;
388		WARN_ON_ONCE(1);
389		break;
390	}
391}
392
393static bool nft_rhash_expr_needs_gc_run(const struct nft_set *set,
394					struct nft_set_ext *ext)
395{
396	struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
397	struct nft_expr *expr;
398	u32 size;
399
400	nft_setelem_expr_foreach(expr, elem_expr, size) {
401		if (expr->ops->gc &&
402		    expr->ops->gc(read_pnet(&set->net), expr) &&
403		    set->flags & NFT_SET_EVAL)
404			return true;
405	}
406
407	return false;
408}
409
410static void nft_rhash_gc(struct work_struct *work)
411{
412	struct nftables_pernet *nft_net;
413	struct nft_set *set;
414	struct nft_rhash_elem *he;
415	struct nft_rhash *priv;
416	struct rhashtable_iter hti;
417	struct nft_trans_gc *gc;
418	struct net *net;
419	u32 gc_seq;
420
421	priv = container_of(work, struct nft_rhash, gc_work.work);
422	set  = nft_set_container_of(priv);
423	net  = read_pnet(&set->net);
424	nft_net = nft_pernet(net);
425	gc_seq = READ_ONCE(nft_net->gc_seq);
426
427	if (nft_set_gc_is_pending(set))
428		goto done;
429
430	gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL);
431	if (!gc)
432		goto done;
433
434	/* Elements never collected use a zero gc worker sequence number. */
435	if (unlikely(++priv->wq_gc_seq == 0))
436		priv->wq_gc_seq++;
437
438	rhashtable_walk_enter(&priv->ht, &hti);
439	rhashtable_walk_start(&hti);
440
441	while ((he = rhashtable_walk_next(&hti))) {
442		if (IS_ERR(he)) {
443			nft_trans_gc_destroy(gc);
444			gc = NULL;
445			goto try_later;
446		}
447
448		/* Ruleset has been updated, try later. */
449		if (READ_ONCE(nft_net->gc_seq) != gc_seq) {
450			nft_trans_gc_destroy(gc);
451			gc = NULL;
452			goto try_later;
453		}
454
455		/* rhashtable walk is unstable, already seen in this gc run?
456		 * Then, skip this element. In case of (unlikely) sequence
457		 * wraparound and stale element wq_gc_seq, next gc run will
458		 * just find this expired element.
459		 */
460		if (he->wq_gc_seq == priv->wq_gc_seq)
461			continue;
462
463		if (nft_set_elem_is_dead(&he->ext))
464			goto dead_elem;
465
466		if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPRESSIONS) &&
467		    nft_rhash_expr_needs_gc_run(set, &he->ext))
468			goto needs_gc_run;
469
470		if (!nft_set_elem_expired(&he->ext))
471			continue;
472needs_gc_run:
473		nft_set_elem_dead(&he->ext);
474dead_elem:
475		gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
476		if (!gc)
477			goto try_later;
478
479		/* annotate gc sequence for this attempt. */
480		he->wq_gc_seq = priv->wq_gc_seq;
481		nft_trans_gc_elem_add(gc, he);
482	}
483
484	gc = nft_trans_gc_catchall_async(gc, gc_seq);
485
486try_later:
487	/* catchall list iteration requires rcu read side lock. */
488	rhashtable_walk_stop(&hti);
489	rhashtable_walk_exit(&hti);
490
491	if (gc)
492		nft_trans_gc_queue_async_done(gc);
493
494done:
495	queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
496			   nft_set_gc_interval(set));
497}
498
499static u64 nft_rhash_privsize(const struct nlattr * const nla[],
500			      const struct nft_set_desc *desc)
501{
502	return sizeof(struct nft_rhash);
503}
504
505static void nft_rhash_gc_init(const struct nft_set *set)
506{
507	struct nft_rhash *priv = nft_set_priv(set);
508
509	queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
510			   nft_set_gc_interval(set));
511}
512
513static int nft_rhash_init(const struct nft_set *set,
514			  const struct nft_set_desc *desc,
515			  const struct nlattr * const tb[])
516{
517	struct nft_rhash *priv = nft_set_priv(set);
518	struct rhashtable_params params = nft_rhash_params;
519	int err;
520
521	BUILD_BUG_ON(offsetof(struct nft_rhash_elem, priv) != 0);
522
523	params.nelem_hint = desc->size ?: NFT_RHASH_ELEMENT_HINT;
524	params.key_len	  = set->klen;
525
526	err = rhashtable_init(&priv->ht, &params);
527	if (err < 0)
528		return err;
529
530	INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc);
531	if (set->flags & (NFT_SET_TIMEOUT | NFT_SET_EVAL))
532		nft_rhash_gc_init(set);
533
534	return 0;
535}
536
537struct nft_rhash_ctx {
538	const struct nft_ctx	ctx;
539	const struct nft_set	*set;
540};
541
542static void nft_rhash_elem_destroy(void *ptr, void *arg)
543{
544	struct nft_rhash_ctx *rhash_ctx = arg;
545	struct nft_rhash_elem *he = ptr;
546
547	nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, &he->priv);
548}
549
550static void nft_rhash_destroy(const struct nft_ctx *ctx,
551			      const struct nft_set *set)
552{
553	struct nft_rhash *priv = nft_set_priv(set);
554	struct nft_rhash_ctx rhash_ctx = {
555		.ctx	= *ctx,
556		.set	= set,
557	};
558
559	cancel_delayed_work_sync(&priv->gc_work);
560	rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
561				    (void *)&rhash_ctx);
562}
563
564/* Number of buckets is stored in u32, so cap our result to 1U<<31 */
565#define NFT_MAX_BUCKETS (1U << 31)
566
567static u32 nft_hash_buckets(u32 size)
568{
569	u64 val = div_u64((u64)size * 4, 3);
570
571	if (val >= NFT_MAX_BUCKETS)
572		return NFT_MAX_BUCKETS;
573
574	return roundup_pow_of_two(val);
575}
576
577static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
578			       struct nft_set_estimate *est)
579{
580	est->size   = ~0;
581	est->lookup = NFT_SET_CLASS_O_1;
582	est->space  = NFT_SET_CLASS_O_N;
583
584	return true;
585}
586
587struct nft_hash {
588	u32				seed;
589	u32				buckets;
590	struct hlist_head		table[];
591};
592
593struct nft_hash_elem {
594	struct nft_elem_priv		priv;
595	struct hlist_node		node;
596	struct nft_set_ext		ext;
597};
598
599INDIRECT_CALLABLE_SCOPE
600const struct nft_set_ext *
601nft_hash_lookup(const struct net *net, const struct nft_set *set,
602		const u32 *key)
603{
604	struct nft_hash *priv = nft_set_priv(set);
605	u8 genmask = nft_genmask_cur(net);
606	const struct nft_hash_elem *he;
607	u32 hash;
608
609	hash = jhash(key, set->klen, priv->seed);
610	hash = reciprocal_scale(hash, priv->buckets);
611	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
612		if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
613		    nft_set_elem_active(&he->ext, genmask))
614			return &he->ext;
615	}
616	return NULL;
617}
618
619static struct nft_elem_priv *
620nft_hash_get(const struct net *net, const struct nft_set *set,
621	     const struct nft_set_elem *elem, unsigned int flags)
622{
623	const u32 *key = (const u32 *)&elem->key.val;
624	struct nft_hash *priv = nft_set_priv(set);
625	u8 genmask = nft_genmask_cur(net);
626	struct nft_hash_elem *he;
627	u32 hash;
628
629	if (set->klen == 4)
630		hash = jhash_1word(*key, priv->seed);
631	else
632		hash = jhash(key, set->klen, priv->seed);
633
634	hash = reciprocal_scale(hash, priv->buckets);
635	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
636		if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
637		    nft_set_elem_active(&he->ext, genmask))
638			return &he->priv;
639	}
640	return ERR_PTR(-ENOENT);
641}
642
643INDIRECT_CALLABLE_SCOPE
644const struct nft_set_ext *
645nft_hash_lookup_fast(const struct net *net, const struct nft_set *set,
646		     const u32 *key)
647{
648	struct nft_hash *priv = nft_set_priv(set);
649	u8 genmask = nft_genmask_cur(net);
650	const struct nft_hash_elem *he;
651	u32 hash, k1, k2;
652
653	k1 = *key;
654	hash = jhash_1word(k1, priv->seed);
655	hash = reciprocal_scale(hash, priv->buckets);
656	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
657		k2 = *(u32 *)nft_set_ext_key(&he->ext)->data;
658		if (k1 == k2 &&
659		    nft_set_elem_active(&he->ext, genmask))
660			return &he->ext;
661	}
662	return NULL;
663}
664
665static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv,
666		     const struct nft_set_ext *ext)
667{
668	const struct nft_data *key = nft_set_ext_key(ext);
669	u32 hash, k1;
670
671	if (set->klen == 4) {
672		k1 = *(u32 *)key;
673		hash = jhash_1word(k1, priv->seed);
674	} else {
675		hash = jhash(key, set->klen, priv->seed);
676	}
677	hash = reciprocal_scale(hash, priv->buckets);
678
679	return hash;
680}
681
682static int nft_hash_insert(const struct net *net, const struct nft_set *set,
683			   const struct nft_set_elem *elem,
684			   struct nft_elem_priv **elem_priv)
685{
686	struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
687	struct nft_hash *priv = nft_set_priv(set);
688	u8 genmask = nft_genmask_next(net);
689	u32 hash;
690
691	hash = nft_jhash(set, priv, &this->ext);
692	hlist_for_each_entry(he, &priv->table[hash], node) {
693		if (!memcmp(nft_set_ext_key(&this->ext),
694			    nft_set_ext_key(&he->ext), set->klen) &&
695		    nft_set_elem_active(&he->ext, genmask)) {
696			*elem_priv = &he->priv;
697			return -EEXIST;
698		}
699	}
700	hlist_add_head_rcu(&this->node, &priv->table[hash]);
701	return 0;
702}
703
704static void nft_hash_activate(const struct net *net, const struct nft_set *set,
705			      struct nft_elem_priv *elem_priv)
706{
707	struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
708
709	nft_clear(net, &he->ext);
710}
711
712static void nft_hash_flush(const struct net *net,
713			   const struct nft_set *set,
714			   struct nft_elem_priv *elem_priv)
715{
716	struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
717
718	nft_set_elem_change_active(net, set, &he->ext);
719}
720
721static struct nft_elem_priv *
722nft_hash_deactivate(const struct net *net, const struct nft_set *set,
723		    const struct nft_set_elem *elem)
724{
725	struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
726	struct nft_hash *priv = nft_set_priv(set);
727	u8 genmask = nft_genmask_next(net);
728	u32 hash;
729
730	hash = nft_jhash(set, priv, &this->ext);
731	hlist_for_each_entry(he, &priv->table[hash], node) {
732		if (!memcmp(nft_set_ext_key(&he->ext), &elem->key.val,
733			    set->klen) &&
734		    nft_set_elem_active(&he->ext, genmask)) {
735			nft_set_elem_change_active(net, set, &he->ext);
736			return &he->priv;
737		}
738	}
739	return NULL;
740}
741
742static void nft_hash_remove(const struct net *net,
743			    const struct nft_set *set,
744			    struct nft_elem_priv *elem_priv)
745{
746	struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);
747
748	hlist_del_rcu(&he->node);
749}
750
751static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
752			  struct nft_set_iter *iter)
753{
754	struct nft_hash *priv = nft_set_priv(set);
755	struct nft_hash_elem *he;
756	int i;
757
758	for (i = 0; i < priv->buckets; i++) {
759		hlist_for_each_entry_rcu(he, &priv->table[i], node,
760					 lockdep_is_held(&nft_pernet(ctx->net)->commit_mutex)) {
761			if (iter->count < iter->skip)
762				goto cont;
763
764			iter->err = iter->fn(ctx, set, iter, &he->priv);
765			if (iter->err < 0)
766				return;
767cont:
768			iter->count++;
769		}
770	}
771}
772
773static u64 nft_hash_privsize(const struct nlattr * const nla[],
774			     const struct nft_set_desc *desc)
775{
776	return sizeof(struct nft_hash) +
777	       (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
778}
779
780static int nft_hash_init(const struct nft_set *set,
781			 const struct nft_set_desc *desc,
782			 const struct nlattr * const tb[])
783{
784	struct nft_hash *priv = nft_set_priv(set);
785
786	priv->buckets = nft_hash_buckets(desc->size);
787	get_random_bytes(&priv->seed, sizeof(priv->seed));
788
789	return 0;
790}
791
792static void nft_hash_destroy(const struct nft_ctx *ctx,
793			     const struct nft_set *set)
794{
795	struct nft_hash *priv = nft_set_priv(set);
796	struct nft_hash_elem *he;
797	struct hlist_node *next;
798	int i;
799
800	for (i = 0; i < priv->buckets; i++) {
801		hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
802			hlist_del_rcu(&he->node);
803			nf_tables_set_elem_destroy(ctx, set, &he->priv);
804		}
805	}
806}
807
808static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
809			      struct nft_set_estimate *est)
810{
811	if (!desc->size)
812		return false;
813
814	if (desc->klen == 4)
815		return false;
816
817	est->size   = sizeof(struct nft_hash) +
818		      (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
819		      (u64)desc->size * sizeof(struct nft_hash_elem);
820	est->lookup = NFT_SET_CLASS_O_1;
821	est->space  = NFT_SET_CLASS_O_N;
822
823	return true;
824}
825
826static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features,
827				   struct nft_set_estimate *est)
828{
829	if (!desc->size)
830		return false;
831
832	if (desc->klen != 4)
833		return false;
834
835	est->size   = sizeof(struct nft_hash) +
836		      (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
837		      (u64)desc->size * sizeof(struct nft_hash_elem);
838	est->lookup = NFT_SET_CLASS_O_1;
839	est->space  = NFT_SET_CLASS_O_N;
840
841	return true;
842}
843
844const struct nft_set_type nft_set_rhash_type = {
845	.features	= NFT_SET_MAP | NFT_SET_OBJECT |
846			  NFT_SET_TIMEOUT | NFT_SET_EVAL,
847	.ops		= {
848		.privsize       = nft_rhash_privsize,
849		.elemsize	= offsetof(struct nft_rhash_elem, ext),
850		.estimate	= nft_rhash_estimate,
851		.init		= nft_rhash_init,
852		.gc_init	= nft_rhash_gc_init,
853		.destroy	= nft_rhash_destroy,
854		.insert		= nft_rhash_insert,
855		.activate	= nft_rhash_activate,
856		.deactivate	= nft_rhash_deactivate,
857		.flush		= nft_rhash_flush,
858		.remove		= nft_rhash_remove,
859		.lookup		= nft_rhash_lookup,
860		.update		= nft_rhash_update,
861		.delete		= nft_rhash_delete,
862		.walk		= nft_rhash_walk,
863		.get		= nft_rhash_get,
864	},
865};
866
867const struct nft_set_type nft_set_hash_type = {
868	.features	= NFT_SET_MAP | NFT_SET_OBJECT,
869	.ops		= {
870		.privsize       = nft_hash_privsize,
871		.elemsize	= offsetof(struct nft_hash_elem, ext),
872		.estimate	= nft_hash_estimate,
873		.init		= nft_hash_init,
874		.destroy	= nft_hash_destroy,
875		.insert		= nft_hash_insert,
876		.activate	= nft_hash_activate,
877		.deactivate	= nft_hash_deactivate,
878		.flush		= nft_hash_flush,
879		.remove		= nft_hash_remove,
880		.lookup		= nft_hash_lookup,
881		.walk		= nft_hash_walk,
882		.get		= nft_hash_get,
883	},
884};
885
886const struct nft_set_type nft_set_hash_fast_type = {
887	.features	= NFT_SET_MAP | NFT_SET_OBJECT,
888	.ops		= {
889		.privsize       = nft_hash_privsize,
890		.elemsize	= offsetof(struct nft_hash_elem, ext),
891		.estimate	= nft_hash_fast_estimate,
892		.init		= nft_hash_init,
893		.destroy	= nft_hash_destroy,
894		.insert		= nft_hash_insert,
895		.activate	= nft_hash_activate,
896		.deactivate	= nft_hash_deactivate,
897		.flush		= nft_hash_flush,
898		.remove		= nft_hash_remove,
899		.lookup		= nft_hash_lookup_fast,
900		.walk		= nft_hash_walk,
901		.get		= nft_hash_get,
902	},
903};
~/ Read-only file preview.