From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id DAC111FF0A7 for ; Wed, 02 Sep 2026 14:48:13 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 8BF5D215C4; Wed, 02 Sep 2026 14:47:51 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-network 04/12] sdn: ipam: do not cache negative per-MAC answers, lock the write Date: Wed, 2 Sep 2026 14:47:31 +0200 Message-ID: <20260902124739.750853-5-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260902124739.750853-1-h.laimer@proxmox.com> References: <20260902124739.750853-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1788353260709 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.690 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: AYBHIUFB5YUETQPJZ7IUR7NJ34MLCGW7 X-Message-ID-Hash: AYBHIUFB5YUETQPJZ7IUR7NJ34MLCGW7 X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The lookup cache wrote an entry even when the plugin returned nothing, and that entry short-circuits every later lookup, so a record created after the first miss was never seen again. The read-modify-write also ran without the cluster lock the other cache writers take, allowing concurrent lookups to drop each other's entries. Only cache actual answers and take the lock for the write, keeping the common cache-hit path lock-free. Signed-off-by: Hannes Laimer --- src/PVE/Network/SDN/Ipams.pm | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/PVE/Network/SDN/Ipams.pm b/src/PVE/Network/SDN/Ipams.pm index 179bdf7..9292386 100644 --- a/src/PVE/Network/SDN/Ipams.pm +++ b/src/PVE/Network/SDN/Ipams.pm @@ -140,12 +140,24 @@ sub get_ips_from_mac { my $plugin_config = get_plugin_config($zone); my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); - ($macdb->{macs}->{$mac}->{ip4}, $macdb->{macs}->{$mac}->{ip6}) = - $plugin->get_ips_from_mac($plugin_config, $mac, $zoneid); + my ($ip4, $ip6) = $plugin->get_ips_from_mac($plugin_config, $mac, $zoneid); - write_macdb($macdb); + # an empty answer is not cached, the record may simply not exist yet + return if !defined($ip4) && !defined($ip6); - return ($macdb->{macs}->{$mac}->{ip4}, $macdb->{macs}->{$mac}->{ip6}); + cfs_lock_file( + $macdb_filename, + undef, + sub { + my $db = read_macdb(); + $db->{macs}->{$mac}->{ip4} = $ip4 if defined($ip4); + $db->{macs}->{$mac}->{ip6} = $ip6 if defined($ip6); + write_macdb($db); + }, + ); + warn "$@" if $@; + + return ($ip4, $ip6); } 1; -- 2.47.3