public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Christoph Heiss <c.heiss@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH installer v4 16/30] install: network: set up vlan on management interface if requested
Date: Mon,  2 Nov 2026 13:45:22 +0100	[thread overview]
Message-ID: <20261102124539.1008075-17-c.heiss@proxmox.com> (raw)
In-Reply-To: <20261102124539.1008075-1-c.heiss@proxmox.com>

Adds the necessary configuration to /etc/network/interfaces when a VLAN
ID was configured by the user in the installation config.

Depending on the rest of the network configuration (bridged, bonded), a
separated (dotted) VLAN interface will be created and integrated in the
rest of the configuration as needed.

This follows our recommended approach for setting up such a
network configuration.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Had a discussion with @Stefan about this, and this way of configuring
this was the best / most user-friendly we plotted out.

Changes v3 -> v4:
  * no changes

Changes v2 -> v3:
  * new patch

 Proxmox/Install.pm                |  45 +++++++--
 test/generate-ifupdown2-config.pl | 159 ++++++++++++++++++++++++++----
 2 files changed, 175 insertions(+), 29 deletions(-)

diff --git a/Proxmox/Install.pm b/Proxmox/Install.pm
index 9e167d8..b39df6f 100644
--- a/Proxmox/Install.pm
+++ b/Proxmox/Install.pm
@@ -889,14 +889,40 @@ sub generate_ifupdown2_config {
             && ($_->{protocol} // '') eq 'ra';
     } $gateways6->@*;
 
-    if ($iso_env->{cfg}->{bridged_network}) {
-        if ($bond_enabled) {
-            $ifaces .= "auto $ethdev\n" #
-                . "iface $ethdev $ntype manual\n" #
-                . $bond_config;
-        } else {
-            $ifaces .= "iface $ethdev $ntype manual\n";
-        }
+    my $vlan_enabled = Proxmox::Install::Config::get_mngmt_vlan_enabled();
+    my $vlan_id = Proxmox::Install::Config::get_mngmt_vlan_opt('vid');
+
+    # the live environment is not on the management VLAN, so its routes say nothing about it
+    $is_gateway6_from_ra = 0 if $vlan_enabled;
+
+    my $link_config =
+        $bond_enabled
+        ? "auto $ethdev\niface $ethdev $ntype manual\n$bond_config"
+        : "iface $ethdev $ntype manual\n";
+
+    my $get_vlan_config = sub {
+        my ($raw_device) = @_;
+
+        return
+            "\nauto $raw_device.$vlan_id\niface $raw_device.$vlan_id $ntype static\n"
+            . "\taddress $cidr\n"
+            . "\tgateway $gateway\n";
+    };
+
+    if ($iso_env->{cfg}->{bridged_network} && $vlan_enabled) {
+        $ifaces .= $link_config;
+
+        $ifaces .=
+            "\nauto vmbr0\niface vmbr0 $ntype manual\n"
+            . "\tbridge-ports $ethdev\n"
+            . "\tbridge-stp off\n"
+            . "\tbridge-fd 0\n"
+            . "\tbridge-vlan-aware yes\n"
+            . "\tbridge-vids 2-4094\n";
+
+        $ifaces .= $get_vlan_config->('vmbr0');
+    } elsif ($iso_env->{cfg}->{bridged_network}) {
+        $ifaces .= $link_config;
 
         $ifaces .= "\nauto vmbr0\niface vmbr0 $ntype static\n";
 
@@ -908,6 +934,9 @@ sub generate_ifupdown2_config {
         $ifaces .= "\tbridge-ports $ethdev\n" #
             . "\tbridge-stp off\n" #
             . "\tbridge-fd 0\n";
+    } elsif ($vlan_enabled) {
+        $ifaces .= $bond_enabled ? $link_config : "auto $ethdev\n$link_config";
+        $ifaces .= $get_vlan_config->($ethdev);
     } else {
         # if bonding is enabled, this becomes the bond interface stanza
         # otherwise, it's the physical interface stanza
diff --git a/test/generate-ifupdown2-config.pl b/test/generate-ifupdown2-config.pl
index f40689c..9ac9b3d 100755
--- a/test/generate-ifupdown2-config.pl
+++ b/test/generate-ifupdown2-config.pl
@@ -34,6 +34,10 @@ my sub set_config {
 
     Proxmox::Install::Config::merge({
         mngmt_nic => $cfg{bond} ? 'bond0' : 'eno1',
+        mngmt_vlan => {
+            enabled => $cfg{vlan},
+            vid => $cfg{vlan} ? 5 : 0,
+        },
         mngmt_bond => {
             members => $cfg{bond} ? ['12:34:56:ab:cd:ef', 'ab:cd:ef:12:34:56'] : [],
             mode => 'active-backup',
@@ -54,7 +58,7 @@ $expected
 
 source /etc/network/interfaces.d/*
 EOT
-        "$msg (bridge:$current_cfg->{bridge} bond:$current_cfg->{bond})",
+        "$msg (bridge:$current_cfg->{bridge} bond:$current_cfg->{bond} vlan:$current_cfg->{vlan})",
     );
 }
 
@@ -84,7 +88,7 @@ $proxmox_install_runenv->redefine(
         };
     },
 );
-set_config(bridge => 0, bond => 0);
+set_config(bridge => 0, bond => 0, vlan => 0);
 Proxmox::Install::Config::merge({
     cidr => '192.168.0.10/24',
     gateway => '192.168.0.1',
@@ -93,18 +97,22 @@ Proxmox::Install::Config::merge({
 ###
 # There's essentially a matrix to test w.r.t the overall networking setup:
 #
-# +-------+--------+------+
-# | test# | bridge | bond |
-# +=======+========+======+
-# |   1   |    0   |  0   |
-# |   2   |    0   |  1   |
-# |   3   |    1   |  0   |
-# |   4   |    1   |  1   |
-# +-------+--------+------+
+# +-------+--------+------+------+
+# | test# | bridge | bond | vlan |
+# +=======+========+======+======+
+# |   1   |    0   |  0   |  0   |
+# |   2   |    0   |  0   |  1   |
+# |   3   |    0   |  1   |  0   |
+# |   4   |    0   |  1   |  1   |
+# |   5   |    1   |  0   |  0   |
+# |   6   |    1   |  0   |  1   |
+# |   7   |    1   |  1   |  0   |
+# |   8   |    1   |  1   |  1   |
+# +-------+--------+------+------+
 ###
 
 # 1.
-set_config(bridge => 0, bond => 0);
+set_config(bridge => 0, bond => 0, vlan => 0);
 is_generated(
     <<EOT
 auto eno1
@@ -118,7 +126,24 @@ EOT
 );
 
 # 2.
-set_config(bridge => 0, bond => 1);
+set_config(bridge => 0, bond => 0, vlan => 1);
+is_generated(
+    <<EOT
+auto eno1
+iface eno1 inet manual
+
+auto eno1.5
+iface eno1.5 inet static
+	address 192.168.0.10/24
+	gateway 192.168.0.1
+
+iface eno2 inet manual
+EOT
+    , 'host network setup',
+);
+
+# 3.
+set_config(bridge => 0, bond => 1, vlan => 0);
 is_generated(
     <<EOT
 auto bond0
@@ -138,8 +163,32 @@ EOT
     , 'host network setup',
 );
 
-# 3.
-set_config(bridge => 1, bond => 0);
+# 4.
+set_config(bridge => 0, bond => 1, vlan => 1);
+is_generated(
+    <<EOT
+auto bond0
+iface bond0 inet manual
+	bond-slaves eno1 eno2
+	bond-miimon 100
+	bond-mode active-backup
+
+auto bond0.5
+iface bond0.5 inet static
+	address 192.168.0.10/24
+	gateway 192.168.0.1
+
+auto eno1
+iface eno1 inet manual
+
+auto eno2
+iface eno2 inet manual
+EOT
+    , 'host network setup',
+);
+
+# 5.
+set_config(bridge => 1, bond => 0, vlan => 0);
 is_generated(
     <<EOT
 iface eno1 inet manual
@@ -157,8 +206,32 @@ EOT
     , 'host network setup',
 );
 
-# 4.
-set_config(bridge => 1, bond => 1);
+# 6.
+set_config(bridge => 1, bond => 0, vlan => 1);
+is_generated(
+    <<EOT
+iface eno1 inet manual
+
+auto vmbr0
+iface vmbr0 inet manual
+	bridge-ports eno1
+	bridge-stp off
+	bridge-fd 0
+	bridge-vlan-aware yes
+	bridge-vids 2-4094
+
+auto vmbr0.5
+iface vmbr0.5 inet static
+	address 192.168.0.10/24
+	gateway 192.168.0.1
+
+iface eno2 inet manual
+EOT
+    , 'host network setup',
+);
+
+# 7.
+set_config(bridge => 1, bond => 1, vlan => 0);
 is_generated(
     <<EOT
 auto bond0
@@ -184,12 +257,44 @@ EOT
     , 'host network setup',
 );
 
+# 8.
+set_config(bridge => 1, bond => 1, vlan => 1);
+is_generated(
+    <<EOT
+auto bond0
+iface bond0 inet manual
+	bond-slaves eno1 eno2
+	bond-miimon 100
+	bond-mode active-backup
+
+auto vmbr0
+iface vmbr0 inet manual
+	bridge-ports bond0
+	bridge-stp off
+	bridge-fd 0
+	bridge-vlan-aware yes
+	bridge-vids 2-4094
+
+auto vmbr0.5
+iface vmbr0.5 inet static
+	address 192.168.0.10/24
+	gateway 192.168.0.1
+
+auto eno1
+iface eno1 inet manual
+
+auto eno2
+iface eno2 inet manual
+EOT
+    , 'host network setup',
+);
+
 # interface name pinning test
 Proxmox::Install::Config::merge({
     mngmt_nic => 'eno1',
     network_interface_pin_map => $pin_map,
 });
-set_config(bridge => 1, bond => 0);
+set_config(bridge => 1, bond => 0, vlan => 0);
 is_generated(
     <<EOT
 iface nic0 inet manual
@@ -239,7 +344,7 @@ $proxmox_install_runenv->redefine(
         };
     },
 );
-set_config(bridge => 1, bond => 0);
+set_config(bridge => 1, bond => 0, vlan => 0);
 
 is_generated(
     <<EOT
@@ -263,7 +368,7 @@ Proxmox::Install::Config::merge({
     cidr => '2001:db8::1/64',
     gateway => 'fe80::1',
 });
-set_config(bridge => 0, bond => 1);
+set_config(bridge => 0, bond => 1, vlan => 0);
 
 is_generated(
     <<EOT
@@ -289,7 +394,7 @@ Proxmox::Install::Config::merge({
     cidr => '192.168.0.10/24',
     gateway => '192.168.0.1',
 });
-set_config(bridge => 0, bond => 0);
+set_config(bridge => 0, bond => 0, vlan => 0);
 $proxmox_install_runenv->redefine(
     get => sub {
         return {
@@ -330,7 +435,7 @@ EOT
     , 'unpinnable names keep their kernel name',
 );
 
-set_config(bridge => 1, bond => 1);
+set_config(bridge => 1, bond => 1, vlan => 0);
 Proxmox::Install::Config::merge({
     mngmt_nic => 'bond0',
     mngmt_bond => {
@@ -421,4 +526,16 @@ is(
     'unknown bond member is an error',
 );
 
+for my $id (0, 1, 4095, 'abc', '1.5') {
+    eval { Proxmox::Install::Config::set_mngmt_vlan_opt('vid', $id) };
+    like($@, qr/^invalid VLAN tag '\Q$id\E'/, "VLAN tag '$id' is rejected");
+}
+
+Proxmox::Install::Config::set_mngmt_vlan_opt('vid', '0005');
+is(
+    Proxmox::Install::Config::get_mngmt_vlan_opt('vid'),
+    5,
+    'VLAN tag with leading zeros is normalized',
+);
+
 done_testing();
-- 
2.55.0





  parent reply	other threads:[~2026-11-02 12:48 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02 12:45 [PATCH installer/proxmox v4 00/30] fix #2164: add bond setup across all installers Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 01/30] installer-types: clippy: use .is_multiple_of() instead of manual modulo Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 02/30] installer-types: use `MacAddress` type where applicable Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 03/30] installer-types: derive Display for RebootMode and FilterMatch Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 04/30] installer-types: answer: add options for configuring management bond Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 05/30] installer-types: answer: add options for configuring management vlan Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 06/30] installer-types: bump fetch schema for bond and VLAN answer options Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 07/30] installer-types: bump version to 0.3.0-1 Christoph Heiss
2026-11-02 12:45 ` [PATCH proxmox v4 08/30] network-api: derive Display and FromStr for network bond types Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 09/30] install: run make tidy Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 10/30] tree-wide: use `MacAddress` type instead of string for MAC addresses Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 11/30] install: factor out ifupdown2 config generation into own subroutine Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 12/30] install: do not rely on interface name map to be fully populated Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 13/30] install: config: add option for setting up bond on management interface Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 14/30] install: config: add option for setting up vlan " Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 15/30] install: network: set up management bond if requested Christoph Heiss
2026-11-02 12:45 ` Christoph Heiss [this message]
2026-11-02 12:45 ` [PATCH installer v4 17/30] gui: network: factor out name pinning into advanced options dialog Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 18/30] gui: network: add bond setup options to " Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 19/30] gui: network: add vlan setup options to advanced network dialog Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 20/30] auto: pass through management network bond options to low-level installer Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 21/30] auto: pass through management network vlan " Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 22/30] tui: drop long obsolete comment about logo formatting Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 23/30] tui: views: add widget for displaying a group of checkboxes Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 24/30] tui: network: factor out name pinning into advanced options dialog Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 25/30] tui: network: add bond setup options to advanced network dialog Christoph Heiss
2026-11-02 14:55   ` Lukas Sichert
2026-11-02 12:45 ` [PATCH installer v4 26/30] tui: network: add vlan " Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 27/30] gui: network: split advanced options dialog into tabs Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 28/30] tui: " Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 29/30] gui: network: list bond member candidates sharing a MAC address once Christoph Heiss
2026-11-02 12:45 ` [PATCH installer v4 30/30] tui: " Christoph Heiss

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261102124539.1008075-17-c.heiss@proxmox.com \
    --to=c.heiss@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal