Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp764018pxb; Mon, 16 Aug 2021 17:38:01 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwo+QkQtGg1w1NuEqDan6r39LStPAZBYUOGUPVvuaUVGwBqf/U7auH50LcJkgA+vffa7K9+ X-Received: by 2002:a05:6402:1157:: with SMTP id g23mr990135edw.90.1629160681484; Mon, 16 Aug 2021 17:38:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629160681; cv=none; d=google.com; s=arc-20160816; b=JZCvcXsb+Rsi1UBAANlucZmVZsfe74uAGuZodqKcLZXu/Mo9b1dIn7ZhZAbJX4eMBC IKiHaLevjSl91o5EiZo/gv/5+uUi3Stu5vRhF4UJPeypFkac8OxjpdMvko9qZ8kpDPFY lO6EP/h3SOL64qKBL6gk+H5nb6H4J0fekMKY4PDSxQo30lNBj0qFUaG58Fad22/DVyNJ jVY7zMVuCY3jr21cje6Rl71KdVXAIHlgMWeYzJ8Eh9Cbq3eywKtQ9YfwwAllmt06iXMn 7ZjtJrju072uYf4ywlYNRaV/Ymcx/f3eZplhfk9yGbBskHIqkjUptGekizTRqLrh/8NH OVpw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=sgPonolEard4YLl/PFg3J8OSsSxN21PwbM+8Os+uRNs=; b=DBy3B6+fzALgqNvZ+ylwWoNTh7l/GUF83lMBmw+nr448LjD94xebY4goSzObahwMRs YWImBzSWzRuPrRBOD4KReAzYJ+6YHFsFeLH2j8vUOIAWLEGaLGzE7ARhIO013ysGQMjB vuOnrkHxD0Spq+AyHi4BGEwKrrn5Vylnv9wyHvIdhlPkj2rJJRzb0aKtNQ24lnPv1ER/ 96SfF0sxE2Zh0iCGYYohF8salmCJa+/icoHWR8vATqUmfJV0Z0+K0KHcHsj9jyxWHvn2 Vgj8ZaewyUboeXpvHHGCdbJHlKgNy1XO+mhZ4wSpaIMY+4kL3pmH51QjP1iLorRVBe1l saDQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=dmQOCvk3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f6si499756edr.59.2021.08.16.17.37.39; Mon, 16 Aug 2021 17:38:01 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=dmQOCvk3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235931AbhHQAg3 (ORCPT + 99 others); Mon, 16 Aug 2021 20:36:29 -0400 Received: from mail.kernel.org ([198.145.29.99]:35170 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235652AbhHQAgT (ORCPT ); Mon, 16 Aug 2021 20:36:19 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 71DB760F5C; Tue, 17 Aug 2021 00:35:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1629160547; bh=TtcO+EvDa1OC4f0tX5LYwIZIn5H1tbWPF0jp/AEMpiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dmQOCvk3zKoFaWALI3DmHM/Xk4dn8XEpeCNd7Q7P3ySpHmvDy1NTt0hVYELxg6QfH EApPJ6hcbzJ/dPJ6IwopMChZNovgsQfG59QZ2wBNqNqup7N/iJFbLqiaOKcoc9JDev zhUzh//ZGbuY5YOjhA9UIZXOiSIjYspKHTqUYhyBS9ltxPX2p3fZgePCJPQp+4VYm4 np8ESr8vqJ/uMrJat+6mG6JIQMi1Xvorqvk+cYMuLyURWANw94Nf9ceA1PlJpTUlRD WHH+fiGJHv3dmoCCdffrd4npc+er+/DF2uJlwrO7wJIadQjRQLQQhrjkaBGPrfIa8b vpSOIvNLOVmGw== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Florian Westphal , Michal Kubecek , Pablo Neira Ayuso , Sasha Levin , netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org Subject: [PATCH AUTOSEL 5.13 07/12] netfilter: conntrack: collect all entries in one cycle Date: Mon, 16 Aug 2021 20:35:31 -0400 Message-Id: <20210817003536.83063-7-sashal@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210817003536.83063-1-sashal@kernel.org> References: <20210817003536.83063-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Florian Westphal [ Upstream commit 4608fdfc07e116f9fc0895beb40abad7cdb5ee3d ] Michal Kubecek reports that conntrack gc is responsible for frequent wakeups (every 125ms) on idle systems. On busy systems, timed out entries are evicted during lookup. The gc worker is only needed to remove entries after system becomes idle after a busy period. To resolve this, always scan the entire table. If the scan is taking too long, reschedule so other work_structs can run and resume from next bucket. After a completed scan, wait for 2 minutes before the next cycle. Heuristics for faster re-schedule are removed. GC_SCAN_INTERVAL could be exposed as a sysctl in the future to allow tuning this as-needed or even turn the gc worker off. Reported-by: Michal Kubecek Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_core.c | 71 ++++++++++--------------------- 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 69079a382d3a..6ba9f4b8d145 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -68,22 +68,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_hash); struct conntrack_gc_work { struct delayed_work dwork; - u32 last_bucket; + u32 next_bucket; bool exiting; bool early_drop; - long next_gc_run; }; static __read_mostly struct kmem_cache *nf_conntrack_cachep; static DEFINE_SPINLOCK(nf_conntrack_locks_all_lock); static __read_mostly bool nf_conntrack_locks_all; -/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */ -#define GC_MAX_BUCKETS_DIV 128u -/* upper bound of full table scan */ -#define GC_MAX_SCAN_JIFFIES (16u * HZ) -/* desired ratio of entries found to be expired */ -#define GC_EVICT_RATIO 50u +#define GC_SCAN_INTERVAL (120u * HZ) +#define GC_SCAN_MAX_DURATION msecs_to_jiffies(10) static struct conntrack_gc_work conntrack_gc_work; @@ -1359,17 +1354,13 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct) static void gc_worker(struct work_struct *work) { - unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u); - unsigned int i, goal, buckets = 0, expired_count = 0; - unsigned int nf_conntrack_max95 = 0; + unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION; + unsigned int i, hashsz, nf_conntrack_max95 = 0; + unsigned long next_run = GC_SCAN_INTERVAL; struct conntrack_gc_work *gc_work; - unsigned int ratio, scanned = 0; - unsigned long next_run; - gc_work = container_of(work, struct conntrack_gc_work, dwork.work); - goal = nf_conntrack_htable_size / GC_MAX_BUCKETS_DIV; - i = gc_work->last_bucket; + i = gc_work->next_bucket; if (gc_work->early_drop) nf_conntrack_max95 = nf_conntrack_max / 100u * 95u; @@ -1377,15 +1368,15 @@ static void gc_worker(struct work_struct *work) struct nf_conntrack_tuple_hash *h; struct hlist_nulls_head *ct_hash; struct hlist_nulls_node *n; - unsigned int hashsz; struct nf_conn *tmp; - i++; rcu_read_lock(); nf_conntrack_get_ht(&ct_hash, &hashsz); - if (i >= hashsz) - i = 0; + if (i >= hashsz) { + rcu_read_unlock(); + break; + } hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[i], hnnode) { struct nf_conntrack_net *cnet; @@ -1393,7 +1384,6 @@ static void gc_worker(struct work_struct *work) tmp = nf_ct_tuplehash_to_ctrack(h); - scanned++; if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) { nf_ct_offload_timeout(tmp); continue; @@ -1401,7 +1391,6 @@ static void gc_worker(struct work_struct *work) if (nf_ct_is_expired(tmp)) { nf_ct_gc_expired(tmp); - expired_count++; continue; } @@ -1434,7 +1423,14 @@ static void gc_worker(struct work_struct *work) */ rcu_read_unlock(); cond_resched(); - } while (++buckets < goal); + i++; + + if (time_after(jiffies, end_time) && i < hashsz) { + gc_work->next_bucket = i; + next_run = 0; + break; + } + } while (i < hashsz); if (gc_work->exiting) return; @@ -1445,40 +1441,17 @@ static void gc_worker(struct work_struct *work) * * This worker is only here to reap expired entries when system went * idle after a busy period. - * - * The heuristics below are supposed to balance conflicting goals: - * - * 1. Minimize time until we notice a stale entry - * 2. Maximize scan intervals to not waste cycles - * - * Normally, expire ratio will be close to 0. - * - * As soon as a sizeable fraction of the entries have expired - * increase scan frequency. */ - ratio = scanned ? expired_count * 100 / scanned : 0; - if (ratio > GC_EVICT_RATIO) { - gc_work->next_gc_run = min_interval; - } else { - unsigned int max = GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV; - - BUILD_BUG_ON((GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV) == 0); - - gc_work->next_gc_run += min_interval; - if (gc_work->next_gc_run > max) - gc_work->next_gc_run = max; + if (next_run) { + gc_work->early_drop = false; + gc_work->next_bucket = 0; } - - next_run = gc_work->next_gc_run; - gc_work->last_bucket = i; - gc_work->early_drop = false; queue_delayed_work(system_power_efficient_wq, &gc_work->dwork, next_run); } static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work) { INIT_DEFERRABLE_WORK(&gc_work->dwork, gc_worker); - gc_work->next_gc_run = HZ; gc_work->exiting = false; } -- 2.30.2