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
next prev 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