]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: nf_conncount: increase the connection clean up limit to 64
authorFernando Fernandez Mancera <fmancera@suse.de>
Wed, 17 Dec 2025 14:46:41 +0000 (15:46 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 20 Jan 2026 15:23:37 +0000 (16:23 +0100)
After the optimization to only perform one GC per jiffy, a new problem
was introduced. If more than 8 new connections are tracked per jiffy the
list won't be cleaned up fast enough possibly reaching the limit
wrongly.

In order to prevent this issue, only skip the GC if it was already
triggered during the same jiffy and the increment is lower than the
clean up limit. In addition, increase the clean up limit to 64
connections to avoid triggering GC too often and do more effective GCs.

This has been tested using a HTTP server and several
performance tools while having nft_connlimit/xt_connlimit or OVS limit
configured.

Output of slowhttptest + OVS limit at 52000 connections:

 slow HTTP test status on 340th second:
 initializing:        0
 pending:             432
 connected:           51998
 error:               0
 closed:              0
 service available:   YES

Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC")
Reported-by: Aleksandra Rukomoinikova <ARukomoinikova@k2.cloud>
Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
include/net/netfilter/nf_conntrack_count.h
net/netfilter/nf_conncount.c

index 52a06de41aa0f9301e99e90e81845de0b455d455..cf0166520cf338c42d4fbded268d405c701f8020 100644 (file)
@@ -13,6 +13,7 @@ struct nf_conncount_list {
        u32 last_gc;            /* jiffies at most recent gc */
        struct list_head head;  /* connections with the same filtering key */
        unsigned int count;     /* length of list */
+       unsigned int last_gc_count; /* length of list at most recent gc */
 };
 
 struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen);
index 8487808c87614f56c1377af4e148e12b2dbf1a2f..288936f5c1bf927aa566db961cff2886469aab98 100644 (file)
@@ -34,8 +34,9 @@
 
 #define CONNCOUNT_SLOTS                256U
 
-#define CONNCOUNT_GC_MAX_NODES 8
-#define MAX_KEYLEN             5
+#define CONNCOUNT_GC_MAX_NODES         8
+#define CONNCOUNT_GC_MAX_COLLECT       64
+#define MAX_KEYLEN                     5
 
 /* we will save the tuples of all connections we care about */
 struct nf_conncount_tuple {
@@ -182,12 +183,13 @@ static int __nf_conncount_add(struct net *net,
                goto out_put;
        }
 
-       if ((u32)jiffies == list->last_gc)
+       if ((u32)jiffies == list->last_gc &&
+           (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT)
                goto add_new_node;
 
        /* check the saved connections */
        list_for_each_entry_safe(conn, conn_n, &list->head, node) {
-               if (collect > CONNCOUNT_GC_MAX_NODES)
+               if (collect > CONNCOUNT_GC_MAX_COLLECT)
                        break;
 
                found = find_or_evict(net, list, conn);
@@ -230,6 +232,7 @@ static int __nf_conncount_add(struct net *net,
                nf_ct_put(found_ct);
        }
        list->last_gc = (u32)jiffies;
+       list->last_gc_count = list->count;
 
 add_new_node:
        if (WARN_ON_ONCE(list->count > INT_MAX)) {
@@ -277,6 +280,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list)
        spin_lock_init(&list->list_lock);
        INIT_LIST_HEAD(&list->head);
        list->count = 0;
+       list->last_gc_count = 0;
        list->last_gc = (u32)jiffies;
 }
 EXPORT_SYMBOL_GPL(nf_conncount_list_init);
@@ -316,13 +320,14 @@ static bool __nf_conncount_gc_list(struct net *net,
                }
 
                nf_ct_put(found_ct);
-               if (collected > CONNCOUNT_GC_MAX_NODES)
+               if (collected > CONNCOUNT_GC_MAX_COLLECT)
                        break;
        }
 
        if (!list->count)
                ret = true;
        list->last_gc = (u32)jiffies;
+       list->last_gc_count = list->count;
 
        return ret;
 }