From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 8CA4E1FF0AA for ; Fri, 21 Aug 2026 16:05:28 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id C874C2175D; Fri, 21 Aug 2026 16:04:26 +0200 (CEST) From: Gabriel Goller To: pve-devel@lists.proxmox.com Subject: [PATCH pve-network 09/15] sdn: add optional VRFs for simple zones Date: Fri, 21 Aug 2026 16:03:53 +0200 Message-ID: <20260821140404.322081-10-g.goller@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260821140404.322081-1-g.goller@proxmox.com> References: <20260821140404.322081-1-g.goller@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1787321023353 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.661 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: T5AI3DZRCGHQFV2VR7T2HS3M2N2NC7S6 X-Message-ID-Hash: T5AI3DZRCGHQFV2VR7T2HS3M2N2NC7S6 X-MailFrom: g.goller@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: Add a default-vrf option to simple zones. It defaults to true to keep backwards-compat. When disabled, create one VRF device for the zone and attach all of its VNets to it. Generate the zone device independently of its VNets. This also creates the VRF for an empty zone, so other users (e.g. fabrics) can rely on the VRF being present. Add tests for zones with and without VNets. Signed-off-by: Gabriel Goller --- src/PVE/API2/Network/SDN/Zones.pm | 6 ++++++ src/PVE/Network/SDN/Zones.pm | 19 +++++++++++++++--- src/PVE/Network/SDN/Zones/SimplePlugin.pm | 20 ++++++++++++++++++- .../simple/vrf-empty/expected_sdn_interfaces | 5 +++++ src/test/zones/simple/vrf-empty/interfaces | 2 ++ src/test/zones/simple/vrf-empty/sdn_config | 12 +++++++++++ .../zones/simple/vrf/expected_sdn_interfaces | 12 +++++++++++ src/test/zones/simple/vrf/interfaces | 2 ++ src/test/zones/simple/vrf/sdn_config | 17 ++++++++++++++++ 9 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/test/zones/simple/vrf-empty/expected_sdn_interfaces create mode 100644 src/test/zones/simple/vrf-empty/interfaces create mode 100644 src/test/zones/simple/vrf-empty/sdn_config create mode 100644 src/test/zones/simple/vrf/expected_sdn_interfaces create mode 100644 src/test/zones/simple/vrf/interfaces create mode 100644 src/test/zones/simple/vrf/sdn_config diff --git a/src/PVE/API2/Network/SDN/Zones.pm b/src/PVE/API2/Network/SDN/Zones.pm index b897cbdff973..95192497fb9e 100644 --- a/src/PVE/API2/Network/SDN/Zones.pm +++ b/src/PVE/API2/Network/SDN/Zones.pm @@ -94,6 +94,12 @@ my $ZONE_PROPERTIES = { optional => 1, description => 'Name of DHCP server backend for this zone.', }, + 'default-vrf' => { + type => 'boolean', + default => 1, + optional => 1, + description => 'Create a simple zone in the default VRF.', + }, 'rt-import' => { type => 'string', optional => 1, diff --git a/src/PVE/Network/SDN/Zones.pm b/src/PVE/Network/SDN/Zones.pm index f66830324766..893ec436d536 100644 --- a/src/PVE/Network/SDN/Zones.pm +++ b/src/PVE/Network/SDN/Zones.pm @@ -116,14 +116,27 @@ sub generate_etc_network_config { my $controller_cfg = $cfg->{controllers}; return if !$vnet_cfg && !$zone_cfg; + my $vnet_ids = $vnet_cfg ? ($vnet_cfg->{ids} // {}) : {}; + my $zone_ids = $zone_cfg ? ($zone_cfg->{ids} // {}) : {}; + my $interfaces_config = PVE::INotify::read_file('interfaces'); #generate configuration my $config = {}; my $nodename = PVE::INotify::nodename(); - for my $id (sort keys %{ $vnet_cfg->{ids} }) { - my $vnet = $vnet_cfg->{ids}->{$id}; + for my $zone_id (sort keys %$zone_ids) { + my $plugin_config = $zone_ids->{$zone_id}; + next if $plugin_config->{type} ne 'simple'; + next if defined($plugin_config->{nodes}) && !$plugin_config->{nodes}->{$nodename}; + + PVE::Network::SDN::Zones::SimplePlugin->generate_zone_config( + $plugin_config, $zone_id, $config, + ); + } + + for my $id (sort keys %$vnet_ids) { + my $vnet = $vnet_ids->{$id}; my $zone = $vnet->{zone}; if (!$zone) { @@ -131,7 +144,7 @@ sub generate_etc_network_config { next; } - my $plugin_config = $zone_cfg->{ids}->{$zone}; + my $plugin_config = $zone_ids->{$zone}; if (!defined($plugin_config)) { warn "can't generate vnet '$id': zone $zone don't exist\n"; diff --git a/src/PVE/Network/SDN/Zones/SimplePlugin.pm b/src/PVE/Network/SDN/Zones/SimplePlugin.pm index 347eee9a46ba..681d4396d4e4 100644 --- a/src/PVE/Network/SDN/Zones/SimplePlugin.pm +++ b/src/PVE/Network/SDN/Zones/SimplePlugin.pm @@ -35,6 +35,11 @@ sub properties { type => 'string', enum => PVE::Network::SDN::Dhcp->plugin_types(), }, + 'default-vrf' => { + description => 'Create the zone in the default VRF.', + type => 'boolean', + default => 1, + }, }; } @@ -47,15 +52,27 @@ sub options { dnszone => { optional => 1 }, ipam => { optional => 1 }, dhcp => { optional => 1 }, + 'default-vrf' => { optional => 1 }, }; } +sub generate_zone_config { + my ($class, $plugin_config, $zone_id, $config) = @_; + + if (!($plugin_config->{'default-vrf'} // 1)) { + my $vrf_iface = "vrf_$zone_id"; + $config->{$vrf_iface} = ['vrf-table auto'] if !defined($config->{$vrf_iface}); + } + + return $config; +} + # Plugin implementation sub generate_sdn_config { my ( $class, $plugin_config, - $zoneid, + $zone_id, $vnetid, $vnet, $controller, @@ -150,6 +167,7 @@ sub generate_sdn_config { push @iface_config, "alias $alias" if $alias; push @iface_config, "ip-forward on" if $enable_forward_v4; push @iface_config, "ip6-forward on" if $enable_forward_v6; + push @iface_config, "vrf vrf_$zone_id" if !($plugin_config->{'default-vrf'} // 1); push @{ $config->{$vnetid} }, @iface_config; diff --git a/src/test/zones/simple/vrf-empty/expected_sdn_interfaces b/src/test/zones/simple/vrf-empty/expected_sdn_interfaces new file mode 100644 index 000000000000..27150761a60d --- /dev/null +++ b/src/test/zones/simple/vrf-empty/expected_sdn_interfaces @@ -0,0 +1,5 @@ +#version:1 + +auto vrf_myzone +iface vrf_myzone + vrf-table auto diff --git a/src/test/zones/simple/vrf-empty/interfaces b/src/test/zones/simple/vrf-empty/interfaces new file mode 100644 index 000000000000..f1bd92ed2b43 --- /dev/null +++ b/src/test/zones/simple/vrf-empty/interfaces @@ -0,0 +1,2 @@ +auto lo +iface lo inet loopback diff --git a/src/test/zones/simple/vrf-empty/sdn_config b/src/test/zones/simple/vrf-empty/sdn_config new file mode 100644 index 000000000000..663c251349e3 --- /dev/null +++ b/src/test/zones/simple/vrf-empty/sdn_config @@ -0,0 +1,12 @@ +{ + version => 1, + vnets => { ids => {} }, + zones => { + ids => { + myzone => { + type => "simple", + "default-vrf" => 0, + }, + }, + }, +} diff --git a/src/test/zones/simple/vrf/expected_sdn_interfaces b/src/test/zones/simple/vrf/expected_sdn_interfaces new file mode 100644 index 000000000000..3cb20f15f133 --- /dev/null +++ b/src/test/zones/simple/vrf/expected_sdn_interfaces @@ -0,0 +1,12 @@ +#version:1 + +auto myvnet +iface myvnet + bridge_ports none + bridge_stp off + bridge_fd 0 + vrf vrf_myzone + +auto vrf_myzone +iface vrf_myzone + vrf-table auto diff --git a/src/test/zones/simple/vrf/interfaces b/src/test/zones/simple/vrf/interfaces new file mode 100644 index 000000000000..f1bd92ed2b43 --- /dev/null +++ b/src/test/zones/simple/vrf/interfaces @@ -0,0 +1,2 @@ +auto lo +iface lo inet loopback diff --git a/src/test/zones/simple/vrf/sdn_config b/src/test/zones/simple/vrf/sdn_config new file mode 100644 index 000000000000..de7fc5c8596c --- /dev/null +++ b/src/test/zones/simple/vrf/sdn_config @@ -0,0 +1,17 @@ +{ + version => 1, + vnets => { + ids => { + myvnet => { type => "vnet", zone => "myzone" }, + }, + }, + zones => { + ids => { + myzone => { + ipam => "pve", + type => "simple", + "default-vrf" => 0, + }, + }, + }, +} -- 2.47.3