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 BC37B1FF0E3 for ; Tue, 27 Oct 2026 10:02:28 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 3C66221B46; Tue, 27 Oct 2026 09:57:11 +0100 (CET) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-container v3 43/45] lxc: update the microseg enforcement on a tag or hostname change Date: Tue, 27 Oct 2026 09:55:25 +0100 Message-ID: <20261027085527.702738-44-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261027085527.702738-1-h.laimer@proxmox.com> References: <20261027085527.702738-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: 1793091380424 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.357 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: KDZ6DBHTZSGFUSU4GGH3SE3VWF7Y4QKT X-Message-ID-Hash: KDZ6DBHTZSGFUSU4GGH3SE3VWF7Y4QKT 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 groups of a container's NICs depend on its tags and hostname, but a change of those took effect at the next start of the container or the next network reload of the node. Update the NICs of a running container once the new config is written, so the change applies right away. The update reads the config under the same lock as a network reload, so a reload running at the same time cannot leave the old groups in place. A failed update only warns, and the next reload or start catches up. Moving a container between groups is an SDN change like putting a NIC on a vnet, which needs SDN.Use on the vnet. So a tag or hostname change that can move the container also needs SDN.Use on /sdn/microseg, and so does creating a container with such a tag or hostname. Signed-off-by: Hannes Laimer --- src/PVE/API2/LXC/Config.pm | 3 +++ src/PVE/LXC.pm | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index 805eac0eac38..1ba8c5d865de 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -262,6 +262,9 @@ __PACKAGE__->register_method({ $conf = PVE::LXC::Config->load_config($vmid); PVE::LXC::update_lxc_config($vmid, $conf); + # reads the tags and hostname from pmxcfs, so after the write + PVE::LXC::update_nets_enforcement($conf, $vmid) + if $running && grep { $_ eq 'tags' || $_ eq 'hostname' } (keys %$param, @delete); raise_param_exc($errors) if scalar(keys %$errors); }; diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 44ae4fa69bef..0472d1b16bf5 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -25,6 +25,7 @@ use PVE::GuestHelpers qw(check_vnet_access safe_string_ne safe_num_ne safe_boole use PVE::INotify; use PVE::JSONSchema qw(get_standard_option); use PVE::Network; +use PVE::Network::SDN::Microseg; use PVE::Network::SDN::Vnets; use PVE::Network::SDN::Zones; use PVE::ProcFSTools; @@ -1122,6 +1123,21 @@ sub net_tap_plug : prototype($$) { PVE::Tools::run_command(['/sbin/ip', 'link', 'set', 'dev', $iface, 'up']); } +# the groups of a NIC depend on the container's tags and hostname +sub update_nets_enforcement { + my ($conf, $vmid) = @_; + + for my $opt (keys %$conf) { + next if $opt !~ m/^net(\d+)$/; + my $iface = "veth${vmid}i$1"; + next if !-d "/sys/class/net/$iface"; + my $net = PVE::LXC::Config->parse_lxc_network($conf->{$opt}); + next if ($net->{type} // '') ne 'veth'; + my $firewall = $net->{firewall} && PVE::Firewall::Helpers::needs_fwbr($net->{bridge}); + PVE::Network::SDN::Zones::tap_update($iface, $firewall); + } +} + sub update_net { my ($vmid, $conf, $opt, $newnet, $netid, $rootdir) = @_; @@ -1691,6 +1707,12 @@ sub check_ct_modify_config_perm { raise_perm_exc("configuring device passthrough is only allowed for root\@pam"); } elsif ($opt eq 'nameserver' || $opt eq 'searchdomain' || $opt eq 'hostname') { $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Network']); + PVE::Network::SDN::Microseg::check_name_access( + $rpcenv, + $authuser, + $oldconf->{$opt}, + $delete ? undef : $newconf->{$opt}, + ) if $opt eq 'hostname'; } elsif ($opt eq 'features') { raise_perm_exc( "changing feature flags for privileged container is only allowed for root\@pam") @@ -1744,6 +1766,12 @@ sub check_ct_modify_config_perm { my $old = $oldconf->{$opt}; my $new = $delete ? '' : $newconf->{$opt}; PVE::GuestHelpers::assert_tag_permissions($vmid, $old, $new, $rpcenv, $authuser); + PVE::Network::SDN::Microseg::check_tag_access( + $rpcenv, + $authuser, + $old, + PVE::GuestHelpers::get_unique_tags($new), + ); } else { $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Options']); } -- 2.47.3