Re: [PATCH RFC nf-next 12/12] netfilter: ipset: re-add forceadd support for rhashtable
Jozsef Kadlecsik <[email protected]> Thu, 16 Jul 2026 16:06:32 +0200 (CEST)
| Newsgroups | gmane.comp.security.firewalls.netfilter.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Florian, On Tue, 14 Jul 2026, Florian Westphal wrote: > The rhashtable conversion removed the SET_WITH_FORCEADD eviction logic. > Sets created with the forceadd flag got IPSET_ERR_HASH_FULL instead of > evicting an existing element to make room. > > Add mtype_remove_random() helper that walks the rhashtable to pick an > element to evict, and call it from mtype_add() when the set is full and > forceadd is enabled. I like it! This is a worst case scenario when we want to add a new entry by all means, so deleting a random entry is quite good. However, shouldn't mtype_remove_random() return success/failure? mtype_add() should add the new entry only if mtype_remove_random() succeeded. Best regards, Jozsef > Assisted-by: Claude:claude-opus-4-6 > Signed-off-by: Florian Westphal <[email protected]> > --- > net/netfilter/ipset/ip_set_hash_gen.h | 43 +++++++++++++++++++++++---- > 1 file changed, 38 insertions(+), 5 deletions(-) > > diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h > index 12d3bc5acc81..df73c1ebb3f0 100644 > --- a/net/netfilter/ipset/ip_set_hash_gen.h > +++ b/net/netfilter/ipset/ip_set_hash_gen.h > @@ -116,6 +116,7 @@ static const union nf_inet_addr zeromask = {}; > #undef mtype_bucket_size > #undef mtype_hash_size > > +#undef mtype_remove_random > #undef mtype_add > #undef mtype_del > #undef mtype_test_cidrs > @@ -165,6 +166,7 @@ static const union nf_inet_addr zeromask = {}; > #define mtype_bucket_size IPSET_TOKEN(MTYPE, _bucket_size) > #define mtype_hash_size IPSET_TOKEN(MTYPE, _hash_size) > > +#define mtype_remove_random IPSET_TOKEN(MTYPE, _remove_random) > #define mtype_add IPSET_TOKEN(MTYPE, _add) > #define mtype_del IPSET_TOKEN(MTYPE, _del) > #define mtype_test_cidrs IPSET_TOKEN(MTYPE, _test_cidrs) > @@ -511,6 +513,33 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size) > (offsetof(struct mtype_rht_elem, elem) + set->dsize); > } > > +/* Evict one element from the set to make room for a new one (forceadd) */ > +static void __maybe_unused > +mtype_remove_random(struct ip_set *set, struct htype *h) > +{ > + struct rhashtable_iter hti; > + struct mtype_rht_elem *e; > + bool removed = false; > + > + rhashtable_walk_enter(&h->ht, &hti); > + rhashtable_walk_start(&hti); > + e = rhashtable_walk_next(&hti); > + if (IS_ERR(e)) > + e = NULL; > + > + if (e && !rhashtable_remove_fast(&h->ht, &e->node, mtype_rht_params)) > + removed = true; > + > + rhashtable_walk_stop(&hti); > + rhashtable_walk_exit(&hti); > + > + if (removed) { > + mtype_del_cidr_all(set, h, &e->elem); > + ip_set_ext_destroy_slow(set, &e->elem); > + kfree_rcu(e, rcu); > + } > +} > + > /* Add an element to a hash and update the internal counters when succeeded, > * otherwise report the proper error code. > */ > @@ -573,11 +602,15 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, > rcu_read_unlock(); > > if (atomic_read(&h->ht.nelems) >= h->maxelem) { > - if (net_ratelimit()) > - pr_warn("Set %s is full, maxelem %u reached\n", > - set->name, h->maxelem); > - mtype_data_next(&h->next, d); > - return -IPSET_ERR_HASH_FULL; > + if (SET_WITH_FORCEADD(set)) { > + mtype_remove_random(set, h); > + } else { > + if (net_ratelimit()) > + pr_warn("Set %s is full, maxelem %u reached\n", > + set->name, h->maxelem); > + mtype_data_next(&h->next, d); > + return -IPSET_ERR_HASH_FULL; > + } > } > > e = kzalloc(offsetof(struct mtype_rht_elem, elem) + set->dsize, > -- > 2.54.0 > > >