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 2A0231FF0A5 for ; Fri, 04 Sep 2026 11:39:13 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 0664C21611; Fri, 04 Sep 2026 11:38:47 +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: Fri, 4 Sep 2026 11:38:27 +0200 Message-ID: <20260904093835.1050030-5-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260904093835.1050030-1-h.laimer@proxmox.com> References: <20260904093835.1050030-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: 1788514718464 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.635 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: CKOUA6W3ARR7BYJKOHDOJQA4QKHQZ4PD X-Message-ID-Hash: CKOUA6W3ARR7BYJKOHDOJQA4QKHQZ4PD 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