In Commit 4608fdfc07e1 ("netfilter: conntrack: collect all entries in one cycle") conntrack gc was changed to run periodically every 2 minutes. On systems handling many UDP connections, this leads to bursts of session termination handling. As suggested in the original commit, provide the ability to control the gc interval using a sysctl knob. Signed-off-by: Eyal Birger <eyal.birger@xxxxxxxxx> --- v2: fix compiler warning on max() macro usage --- Documentation/networking/nf_conntrack-sysctl.rst | 4 ++++ include/net/netfilter/nf_conntrack.h | 1 + net/netfilter/nf_conntrack_core.c | 6 +++++- net/netfilter/nf_conntrack_standalone.c | 9 +++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/nf_conntrack-sysctl.rst b/Documentation/networking/nf_conntrack-sysctl.rst index 311128abb768..7aaa5e26ed3f 100644 --- a/Documentation/networking/nf_conntrack-sysctl.rst +++ b/Documentation/networking/nf_conntrack-sysctl.rst @@ -207,3 +207,7 @@ nf_flowtable_udp_timeout - INTEGER (seconds) Control offload timeout for udp connections. UDP connections may be offloaded from nf conntrack to nf flow table. Once aged, the connection is returned to nf conntrack with udp pickup timeout. + +nf_conntrack_gc_scan_intervaL - INTEGER (seconds) + default 120 + minimum 1 diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index cc663c68ddc4..f4ed812936a8 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -314,6 +314,7 @@ extern struct hlist_nulls_head *nf_conntrack_hash; extern unsigned int nf_conntrack_htable_size; extern seqcount_spinlock_t nf_conntrack_generation; extern unsigned int nf_conntrack_max; +extern unsigned int nf_conntrack_gc_scan_interval; /* must be called with rcu read lock held */ static inline void diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 054ee9d25efe..76867baaf05c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -83,6 +83,8 @@ static DEFINE_MUTEX(nf_conntrack_mutex); #define MIN_CHAINLEN 8u #define MAX_CHAINLEN (32u - MIN_CHAINLEN) +__read_mostly unsigned int nf_conntrack_gc_scan_interval = GC_SCAN_INTERVAL; +EXPORT_SYMBOL_GPL(nf_conntrack_gc_scan_interval); static struct conntrack_gc_work conntrack_gc_work; void nf_conntrack_lock(spinlock_t *lock) __acquires(lock) @@ -1422,7 +1424,9 @@ static void gc_worker(struct work_struct *work) { unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION; unsigned int i, hashsz, nf_conntrack_max95 = 0; - unsigned long next_run = GC_SCAN_INTERVAL; + unsigned long next_run = max_t(unsigned int, + nf_conntrack_gc_scan_interval, + HZ); struct conntrack_gc_work *gc_work; gc_work = container_of(work, struct conntrack_gc_work, dwork.work); diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 80f675d884b2..436e37df70e5 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -565,6 +565,7 @@ enum nf_ct_sysctl_index { #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP NF_SYSCTL_CT_TIMESTAMP, #endif + NF_SYSCTL_CT_GC_SCAN_INTERVAL, NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC, NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_SENT, NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_RECV, @@ -707,6 +708,13 @@ static struct ctl_table nf_ct_sysctl_table[] = { .extra2 = SYSCTL_ONE, }, #endif + [NF_SYSCTL_CT_GC_SCAN_INTERVAL] = { + .procname = "nf_conntrack_gc_scan_interval", + .data = &nf_conntrack_gc_scan_interval, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, [NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC] = { .procname = "nf_conntrack_generic_timeout", .maxlen = sizeof(unsigned int), @@ -1123,6 +1131,7 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) table[NF_SYSCTL_CT_MAX].mode = 0444; table[NF_SYSCTL_CT_EXPECT_MAX].mode = 0444; table[NF_SYSCTL_CT_BUCKETS].mode = 0444; + table[NF_SYSCTL_CT_GC_SCAN_INTERVAL].mode = 0444; } cnet->sysctl_header = register_net_sysctl(net, "net/netfilter", table); -- 2.32.0