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