hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/net/netfilter/nft_set_hash.c
....@@ -17,6 +17,9 @@
1717 #include <linux/netfilter.h>
1818 #include <linux/netfilter/nf_tables.h>
1919 #include <net/netfilter/nf_tables_core.h>
20
+#include <net/netns/generic.h>
21
+
22
+extern unsigned int nf_tables_net_id;
2023
2124 /* We target a hash table size of 4, element hint is 75% of final size */
2225 #define NFT_RHASH_ELEMENT_HINT 3
....@@ -58,6 +61,8 @@
5861 const struct nft_rhash_elem *he = ptr;
5962
6063 if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
64
+ return 1;
65
+ if (nft_set_elem_is_dead(&he->ext))
6166 return 1;
6267 if (nft_set_elem_expired(&he->ext))
6368 return 1;
....@@ -187,7 +192,6 @@
187192 struct nft_rhash_elem *he = elem->priv;
188193
189194 nft_set_elem_change_active(net, set, &he->ext);
190
- nft_set_elem_clear_busy(&he->ext);
191195 }
192196
193197 static bool nft_rhash_flush(const struct net *net,
....@@ -195,12 +199,9 @@
195199 {
196200 struct nft_rhash_elem *he = priv;
197201
198
- if (!nft_set_elem_mark_busy(&he->ext) ||
199
- !nft_is_active(net, &he->ext)) {
200
- nft_set_elem_change_active(net, set, &he->ext);
201
- return true;
202
- }
203
- return false;
202
+ nft_set_elem_change_active(net, set, &he->ext);
203
+
204
+ return true;
204205 }
205206
206207 static void *nft_rhash_deactivate(const struct net *net,
....@@ -217,9 +218,8 @@
217218
218219 rcu_read_lock();
219220 he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
220
- if (he != NULL &&
221
- !nft_rhash_flush(net, set, he))
222
- he = NULL;
221
+ if (he)
222
+ nft_set_elem_change_active(net, set, &he->ext);
223223
224224 rcu_read_unlock();
225225
....@@ -251,7 +251,9 @@
251251 if (he == NULL)
252252 return false;
253253
254
- return rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params) == 0;
254
+ nft_set_elem_dead(&he->ext);
255
+
256
+ return true;
255257 }
256258
257259 static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
....@@ -277,8 +279,6 @@
277279
278280 if (iter->count < iter->skip)
279281 goto cont;
280
- if (nft_set_elem_expired(&he->ext))
281
- goto cont;
282282 if (!nft_set_elem_active(&he->ext, iter->genmask))
283283 goto cont;
284284
....@@ -297,49 +297,75 @@
297297
298298 static void nft_rhash_gc(struct work_struct *work)
299299 {
300
+ struct nftables_pernet *nft_net;
300301 struct nft_set *set;
301302 struct nft_rhash_elem *he;
302303 struct nft_rhash *priv;
303
- struct nft_set_gc_batch *gcb = NULL;
304304 struct rhashtable_iter hti;
305
+ struct nft_trans_gc *gc;
306
+ struct net *net;
307
+ u32 gc_seq;
305308
306309 priv = container_of(work, struct nft_rhash, gc_work.work);
307310 set = nft_set_container_of(priv);
311
+ net = read_pnet(&set->net);
312
+ nft_net = net_generic(net, nf_tables_net_id);
313
+ gc_seq = READ_ONCE(nft_net->gc_seq);
314
+
315
+ if (nft_set_gc_is_pending(set))
316
+ goto done;
317
+
318
+ gc = nft_trans_gc_alloc(set, gc_seq, GFP_KERNEL);
319
+ if (!gc)
320
+ goto done;
308321
309322 rhashtable_walk_enter(&priv->ht, &hti);
310323 rhashtable_walk_start(&hti);
311324
312325 while ((he = rhashtable_walk_next(&hti))) {
313326 if (IS_ERR(he)) {
314
- if (PTR_ERR(he) != -EAGAIN)
315
- break;
316
- continue;
327
+ nft_trans_gc_destroy(gc);
328
+ gc = NULL;
329
+ goto try_later;
317330 }
331
+
332
+ /* Ruleset has been updated, try later. */
333
+ if (READ_ONCE(nft_net->gc_seq) != gc_seq) {
334
+ nft_trans_gc_destroy(gc);
335
+ gc = NULL;
336
+ goto try_later;
337
+ }
338
+
339
+ if (nft_set_elem_is_dead(&he->ext))
340
+ goto dead_elem;
318341
319342 if (nft_set_ext_exists(&he->ext, NFT_SET_EXT_EXPR)) {
320343 struct nft_expr *expr = nft_set_ext_expr(&he->ext);
321344
322345 if (expr->ops->gc &&
323346 expr->ops->gc(read_pnet(&set->net), expr))
324
- goto gc;
347
+ goto needs_gc_run;
325348 }
349
+
326350 if (!nft_set_elem_expired(&he->ext))
327351 continue;
328
-gc:
329
- if (nft_set_elem_mark_busy(&he->ext))
330
- continue;
352
+needs_gc_run:
353
+ nft_set_elem_dead(&he->ext);
354
+dead_elem:
355
+ gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
356
+ if (!gc)
357
+ goto try_later;
331358
332
- gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
333
- if (gcb == NULL)
334
- break;
335
- rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
336
- atomic_dec(&set->nelems);
337
- nft_set_gc_batch_add(gcb, he);
359
+ nft_trans_gc_elem_add(gc, he);
338360 }
361
+
362
+try_later:
339363 rhashtable_walk_stop(&hti);
340364 rhashtable_walk_exit(&hti);
341365
342
- nft_set_gc_batch_complete(gcb);
366
+ if (gc)
367
+ nft_trans_gc_queue_async_done(gc);
368
+done:
343369 queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
344370 nft_set_gc_interval(set));
345371 }
....@@ -374,25 +400,36 @@
374400 return err;
375401
376402 INIT_DEFERRABLE_WORK(&priv->gc_work, nft_rhash_gc);
377
- if (set->flags & NFT_SET_TIMEOUT)
403
+ if (set->flags & (NFT_SET_TIMEOUT | NFT_SET_EVAL))
378404 nft_rhash_gc_init(set);
379405
380406 return 0;
381407 }
382408
409
+struct nft_rhash_ctx {
410
+ const struct nft_ctx ctx;
411
+ const struct nft_set *set;
412
+};
413
+
383414 static void nft_rhash_elem_destroy(void *ptr, void *arg)
384415 {
385
- nft_set_elem_destroy(arg, ptr, true);
416
+ struct nft_rhash_ctx *rhash_ctx = arg;
417
+
418
+ nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, ptr);
386419 }
387420
388
-static void nft_rhash_destroy(const struct nft_set *set)
421
+static void nft_rhash_destroy(const struct nft_ctx *ctx,
422
+ const struct nft_set *set)
389423 {
390424 struct nft_rhash *priv = nft_set_priv(set);
425
+ struct nft_rhash_ctx rhash_ctx = {
426
+ .ctx = *ctx,
427
+ .set = set,
428
+ };
391429
392430 cancel_delayed_work_sync(&priv->gc_work);
393
- rcu_barrier();
394431 rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
395
- (void *)set);
432
+ (void *)&rhash_ctx);
396433 }
397434
398435 /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
....@@ -621,7 +658,8 @@
621658 return 0;
622659 }
623660
624
-static void nft_hash_destroy(const struct nft_set *set)
661
+static void nft_hash_destroy(const struct nft_ctx *ctx,
662
+ const struct nft_set *set)
625663 {
626664 struct nft_hash *priv = nft_set_priv(set);
627665 struct nft_hash_elem *he;
....@@ -631,7 +669,7 @@
631669 for (i = 0; i < priv->buckets; i++) {
632670 hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
633671 hlist_del_rcu(&he->node);
634
- nft_set_elem_destroy(set, he, true);
672
+ nf_tables_set_elem_destroy(ctx, set, he);
635673 }
636674 }
637675 }