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 F2E531FF0B4 for ; Tue, 08 Sep 2026 12:18:09 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 813882162D; Tue, 08 Sep 2026 12:17:39 +0200 (CEST) From: Christoph Heiss To: pve-devel@lists.proxmox.com Subject: [PATCH installer 07/15] install: config: add option for setting up bond on management interface Date: Tue, 8 Sep 2026 12:16:21 +0200 Message-ID: <20260908101647.1057780-8-c.heiss@proxmox.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260908101647.1057780-1-c.heiss@proxmox.com> References: <20260908101647.1057780-1-c.heiss@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1788862647126 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.384 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: NRSB7PQDK6Y2R7V3L2UNZAMOPNPWW5VZ X-Message-ID-Hash: NRSB7PQDK6Y2R7V3L2UNZAMOPNPWW5VZ X-MailFrom: c.heiss@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: Prerequisite for the rest of the installer to support setting up a bond as management interface during installations. Signed-off-by: Christoph Heiss --- Proxmox/Install/Config.pm | 44 +++++++++++++++++++++++++++++++++++++++ Proxmox/Sys/Net.pm | 30 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/Proxmox/Install/Config.pm b/Proxmox/Install/Config.pm index dba3692..946e642 100644 --- a/Proxmox/Install/Config.pm +++ b/Proxmox/Install/Config.pm @@ -103,6 +103,21 @@ my sub init_cfg { # network related mngmt_nic => undef, + # Options for creating a bond for the management interface with the given physical + # interfaces and mode. + # Enabled if `interfaces` is not empty. + mngmt_bond => { + # MAC addresses of member interfaces. If empty, bonding is disabled. + members => [], + # must be one of: 'balance-rr', 'active-backup', 'balance-xor', 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb' + mode => 'active-backup', # recommended by our docs + # hash policy, only used with '802.3ad' and 'balance-xor' mode + # must be one of 'layer2', 'layer2+3', 'layer3+4' + hash_policy => 'layer2', + # MAC address of primary bond interface, only used with 'active-backup' mode, optional + primary_interface => undef, + }, + # maps mac address -> custom name # if set to a hash, enables interface name pinning for all interfaces network_interface_pin_map => undef, @@ -257,6 +272,35 @@ sub get_subscription_key { return get('subscription_key'); } sub set_mngmt_nic { set_key('mngmt_nic', $_[0]); } sub get_mngmt_nic { return get('mngmt_nic'); } +sub set_mngmt_bond_opt { + my ($k, $v) = @_; + my $opts = get('mngmt_bond'); + + croak "unknown management bond option key '$k'\n" if !exists($opts->{$k}); + croak "unknown bond mode '$v'\n" + if $k eq 'mode' && !Proxmox::Sys::Net::is_valid_bond_mode($v); + croak "unknown bond hash policy '$v'\n" + if $k eq 'hash_policy' && !Proxmox::Sys::Net::is_valid_bond_hash_policy($v); + + # allow setting no interfaces (disabling bonding), or 2+ for enabling it + croak "at least 2 member interfaces are required for bond\n" + if $k eq 'members' && scalar($v->@*) == 1; + croak "primary interface '$v' is not a member of the bond\n" + if $k eq 'primary_interface' && !grep { $_ eq $v } $opts->{members}->@*; + + $opts->{$k} = $v; +} + +sub get_mngmt_bond_opt { + my ($k) = @_; + my $opts = get('mngmt_bond'); + return defined($k) ? $opts->{$k} : $opts; +} + +sub get_mngmt_bond_enabled { # virtual config + return scalar(get_mngmt_bond_opt('members')->@*) >= 2; +} + sub set_network_interface_pin_map { set_key('network_interface_pin_map', $_[0]); } sub get_network_interface_pin_map { return get('network_interface_pin_map'); } diff --git a/Proxmox/Sys/Net.pm b/Proxmox/Sys/Net.pm index c43311d..04bb782 100644 --- a/Proxmox/Sys/Net.pm +++ b/Proxmox/Sys/Net.pm @@ -15,6 +15,8 @@ our @EXPORT_OK = qw( parse_ip_mask parse_fqdn validate_link_pin_map + is_valid_bond_mode + is_valid_bond_hash_policy MIN_IFNAME_LEN MAX_IFNAME_LEN DEFAULT_PIN_PREFIX @@ -450,4 +452,32 @@ sub validate_link_pin_map : prototype($) { } } +sub is_valid_bond_mode { + my ($mode) = @_; + + my $valid = { + 'active-backup' => 1, + 'balance-alb' => 1, + 'balance-rr' => 1, + 'balance-tlb' => 1, + 'balance-xor' => 1, + 'broadcast' => 1, + '802.3ad' => 1, + }; + + return exists($valid->{$mode}); +} + +sub is_valid_bond_hash_policy { + my ($policy) = @_; + + my $valid = { + layer2 => 1, + 'layer2+3' => 1, + 'layer3+4' => 1, + }; + + return exists($valid->{$policy}); +} + 1; -- 2.55.0