• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
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