]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nf_conncount: use per-rule hash initval
authorFlorian Westphal <fw@strlen.de>
Wed, 29 Apr 2026 06:30:00 +0000 (08:30 +0200)
committerFlorian Westphal <fw@strlen.de>
Sun, 24 May 2026 20:55:47 +0000 (22:55 +0200)
As-is, different netns will use same slots if the key is the same.
OVS uses this infrastructure to limit conntrack counts per zones.
Those can easily overlap. Make them hash to different slots internally.

Signed-off-by: Florian Westphal <fw@strlen.de>
net/netfilter/nf_conncount.c

index 00eed5b4d1b12a659ca89f2ec7ff05aa1f1ac4b5..ab28b47395bd254f5f7c7728d2c6050133904ad8 100644 (file)
@@ -58,6 +58,7 @@ static spinlock_t nf_conncount_locks[CONNCOUNT_SLOTS] __cacheline_aligned_in_smp
 
 struct nf_conncount_data {
        unsigned int keylen;
+       u32 initval;
        struct rb_root root[CONNCOUNT_SLOTS];
        struct net *net;
        struct work_struct gc_work;
@@ -65,7 +66,6 @@ struct nf_conncount_data {
        unsigned int gc_tree;
 };
 
-static u_int32_t conncount_rnd __read_mostly;
 static struct kmem_cache *conncount_rb_cachep __read_mostly;
 static struct kmem_cache *conncount_conn_cachep __read_mostly;
 
@@ -496,7 +496,7 @@ count_tree(struct net *net,
        struct nf_conncount_rb *rbconn;
        unsigned int hash;
 
-       hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS;
+       hash = jhash2(key, data->keylen, data->initval) % CONNCOUNT_SLOTS;
        root = &data->root[hash];
 
        parent = rcu_dereference_raw(root->rb_node);
@@ -630,8 +630,6 @@ struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen
            keylen == 0)
                return ERR_PTR(-EINVAL);
 
-       net_get_random_once(&conncount_rnd, sizeof(conncount_rnd));
-
        data = kmalloc_obj(*data);
        if (!data)
                return ERR_PTR(-ENOMEM);
@@ -641,6 +639,7 @@ struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen
 
        data->keylen = keylen / sizeof(u32);
        data->net = net;
+       data->initval = get_random_u32();
        INIT_WORK(&data->gc_work, tree_gc_worker);
 
        return data;