From 63b74c5089e0d0917fb078c173020cfc5f31bbfd Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 14 Dec 2023 10:09:48 +0100 Subject: [PATCH 01/16] expose SYS_prctl Signed-off-by: Wolfgang Bumiller --- src/PVE/Syscall.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/Syscall.pm b/src/PVE/Syscall.pm index 2a423e8..9ef3d5d 100644 --- a/src/PVE/Syscall.pm +++ b/src/PVE/Syscall.pm @@ -32,6 +32,7 @@ BEGIN { setxattr => &SYS_setxattr, fgetxattr => &SYS_fgetxattr, fsetxattr => &SYS_fsetxattr, + prctl => &SYS_prctl, # Below aren't yet in perl's syscall.ph but use asm-generic, so the same across (sane) archs # -> none unknown currently, yay -- 2.39.2 From e8c1bbfca212e0f5273945cea5444263aca38e02 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 21 Dec 2023 16:30:22 +0100 Subject: [PATCH 02/16] network tests: switch to ifupdown2 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit adapt allow-* to auto, and drop the one test where behaviour is not testable anymore. Signed-off-by: Fabian Grünbichler --- test/etc_network_interfaces/runtest.pl | 2 +- .../t.bridge_eth_remove_auto.pl | 24 ------------------- .../t.create_network.pl | 6 ++--- .../t.ovs_bridge_allow.pl | 12 +++++----- 4 files changed, 10 insertions(+), 34 deletions(-) delete mode 100644 test/etc_network_interfaces/t.bridge_eth_remove_auto.pl diff --git a/test/etc_network_interfaces/runtest.pl b/test/etc_network_interfaces/runtest.pl index f92f5ae..10fafae 100755 --- a/test/etc_network_interfaces/runtest.pl +++ b/test/etc_network_interfaces/runtest.pl @@ -78,7 +78,7 @@ sub r($;$$) { sub w() { # write shouldn't be able to change a previously parsed config my $config_clone = dclone($config); - return PVE::INotify::__write_etc_network_interfaces($config_clone); + return PVE::INotify::__write_etc_network_interfaces($config_clone, 1); } ## diff --git a/test/etc_network_interfaces/t.bridge_eth_remove_auto.pl b/test/etc_network_interfaces/t.bridge_eth_remove_auto.pl deleted file mode 100644 index 98f5df8..0000000 --- a/test/etc_network_interfaces/t.bridge_eth_remove_auto.pl +++ /dev/null @@ -1,24 +0,0 @@ -use strict; - -# access to the current config -our $config; - -# replace proc_net_dev with one with a bunch of interfaces -save('proc_net_dev', <<'/proc/net/dev'); -eth0: -eth1: -/proc/net/dev - -r(''); -update_iface('eth0', [], autostart => 1); -update_iface('eth1', [], autostart => 1); -r(w()); -die "autostart lost" if !$config->{ifaces}->{eth0}->{autostart}; -die "autostart lost" if !$config->{ifaces}->{eth1}->{autostart}; -new_iface("vmbr0", 'bridge', [{ family => 'inet' }], bridge_ports => 'eth0'); -new_iface("vmbr1", 'OVSBridge', [{ family => 'inet' }], ovs_ports => 'eth1'); -r(w()); -die "autostart wrongly removed for linux bridge port" if !$config->{ifaces}->{eth0}->{autostart}; -die "autostart not removed for ovs bridge port" if $config->{ifaces}->{eth1}->{autostart}; - -1; diff --git a/test/etc_network_interfaces/t.create_network.pl b/test/etc_network_interfaces/t.create_network.pl index b8da513..6aad74c 100644 --- a/test/etc_network_interfaces/t.create_network.pl +++ b/test/etc_network_interfaces/t.create_network.pl @@ -420,7 +420,7 @@ auto eth1.100 iface eth1.100 inet manual mtu 1400 -allow-vmbr6 ovsintvlan +auto ovsintvlan iface ovsintvlan inet manual ovs_type OVSIntPort ovs_bridge vmbr6 @@ -429,7 +429,7 @@ iface ovsintvlan inet manual $bond0_part -allow-vmbr6 bond1 +auto bond1 iface bond1 inet manual ovs_bonds eth4 eth5 ovs_type OVSBond @@ -464,7 +464,7 @@ iface vmbr5 inet manual bridge-fd 0 mtu 1100 -allow-ovs vmbr6 +auto vmbr6 iface vmbr6 inet manual ovs_type OVSBridge ovs_ports bond1 ovsintvlan diff --git a/test/etc_network_interfaces/t.ovs_bridge_allow.pl b/test/etc_network_interfaces/t.ovs_bridge_allow.pl index 9479ff5..742c9ef 100644 --- a/test/etc_network_interfaces/t.ovs_bridge_allow.pl +++ b/test/etc_network_interfaces/t.ovs_bridge_allow.pl @@ -37,7 +37,7 @@ iface eth2 inet manual iface eth3 inet manual -allow-ovs vmbr0 +auto vmbr0 iface vmbr0 inet static address $ip gateway $gw @@ -52,19 +52,19 @@ expect load('loopback') . <<"/etc/network/interfaces"; auto eth0 iface eth0 inet manual -allow-vmbr0 eth1 +auto eth1 iface eth1 inet manual ovs_type OVSPort ovs_bridge vmbr0 -allow-vmbr0 eth2 +auto eth2 iface eth2 inet manual ovs_type OVSPort ovs_bridge vmbr0 iface eth3 inet manual -allow-ovs vmbr0 +auto vmbr0 iface vmbr0 inet static address $ip gateway $gw @@ -89,7 +89,7 @@ expect load('loopback') . <<"/etc/network/interfaces"; auto eth0 iface eth0 inet manual -allow-vmbr0 eth1 +auto eth1 iface eth1 inet manual ovs_type OVSPort ovs_bridge vmbr0 @@ -98,7 +98,7 @@ iface eth3 inet manual iface eth2 inet manual -allow-ovs vmbr0 +auto vmbr0 iface vmbr0 inet static address $ip gateway $gw -- 2.39.2 From fcc97ec96da813460f73ff928f9ee5843375d744 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 21 Dec 2023 16:30:23 +0100 Subject: [PATCH 03/16] network parser: iterate deterministically MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit makes the behaviour easier to analyze, and also helps when testing since it allows constructing test cases that trigger certain order of parsing. Signed-off-by: Fabian Grünbichler --- src/PVE/INotify.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index bc33a8f..601e651 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -1030,7 +1030,7 @@ sub __read_etc_network_interfaces { }; } - foreach my $iface (keys %$ifaces) { + foreach my $iface (sort keys %$ifaces) { my $d = $ifaces->{$iface}; $d->{type} = 'unknown'; if ($iface =~ m/^bond\d+$/) { -- 2.39.2 From 80ed66dc17a5beb3606f8d4801852df434d723c0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 21 Dec 2023 16:30:24 +0100 Subject: [PATCH 04/16] fix #5141: network parser: fix accidental RE result re-use MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit $1 and friends are not cleared if a RE fails to match, in which case they will contain the captured values from a previous successful match in the same scope. deduplicate the two branches to avoid accidental re-introduction. Signed-off-by: Fabian Grünbichler --- src/PVE/INotify.pm | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index 601e651..6432295 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -1073,16 +1073,27 @@ sub __read_etc_network_interfaces { $ifaces->{$1}->{exists} = 0; $d->{exists} = 0; } - } elsif ($iface =~ m/^(\S+)\.(\d+)$/ || $d->{'vlan-raw-device'}) { + } elsif ($iface =~ m/^(\S+)\.(\d+)$/) { $d->{type} = 'vlan'; my ($dev, $id) = ($1, $2); $d->{'vlan-raw-device'} = $dev if defined($dev) && !$d->{'vlan-raw-device'}; + $d->{'vlan-id'} = $id if $id; # VLAN id 0 is not valid, so truthy check it is - if (!$id && $iface =~ m/^vlan(\d+)$/) { # VLAN id 0 is not valid, so truthy check it is - $id = $1; + my $raw_iface = $d->{'vlan-raw-device'}; + + if (defined ($ifaces->{$raw_iface})) { + $d->{exists} = $ifaces->{$raw_iface}->{exists}; + } else { + $ifaces->{$raw_iface}->{exists} = 0; + $d->{exists} = 0; + } + } elsif ($d->{'vlan-raw-device'}) { + $d->{type} = 'vlan'; + + if ($iface =~ m/^vlan(\d+)$/) { + $d->{'vlan-id'} = $1 if $1; # VLAN id 0 is not valid, so truthy check it is } - $d->{'vlan-id'} = $id if $id; my $raw_iface = $d->{'vlan-raw-device'}; -- 2.39.2 From f869c96a947b913eec3bb646de12d0ce6481519f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 21 Dec 2023 16:30:25 +0100 Subject: [PATCH 05/16] network tests: test #5141 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Fabian Grünbichler --- test/etc_network_interfaces/t.vlan-parsing.pl | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/etc_network_interfaces/t.vlan-parsing.pl diff --git a/test/etc_network_interfaces/t.vlan-parsing.pl b/test/etc_network_interfaces/t.vlan-parsing.pl new file mode 100644 index 0000000..6646683 --- /dev/null +++ b/test/etc_network_interfaces/t.vlan-parsing.pl @@ -0,0 +1,54 @@ +save('proc_net_dev', <<'/proc/net/dev'); +eth0: +eth1: +/proc/net/dev + +# Check for dropped or duplicated options + +my $ip = '192.168.0.2'; +my $nm = '255.255.255.0'; +my $gw = '192.168.0.1'; +my $ip6 = 'fc05::2'; +my $nm6 = '112'; +my $gw6 = 'fc05::1'; + +# Load +my $cfg = load('base') . <<"CHECK"; +iface eth1 inet manual + +auto vmbr0 +iface vmbr0 inet static + address 10.0.0.2/24 + gateway 10.0.0.1 + bridge-ports eth0 + bridge-stp off + bridge-fd 0 + bridge-vlan-aware yes + bridge-vids 2-4094 + +auto vmbr0.10 +iface vmbr0.10 inet static + +auto vmbr0.20 +iface vmbr0.20 inet static + +auto vmbr0.30 +iface vmbr0.30 inet static + +auto vmbr0.40 +iface vmbr0.40 inet static + +auto vmbr0.100 +iface vmbr0.100 inet static + +auto zmgmt +iface zmgmt inet static + vlan-id 1 + vlan-raw-device vmbr0 + +CHECK + +r $cfg; +expect $cfg; + +1; -- 2.39.2 From c6ec71d846001dea6b923bc3b95682caf6a25c16 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 22 Jan 2024 12:52:41 +0100 Subject: [PATCH 06/16] schema: fixup description vs format_description in remote_format Signed-off-by: Wolfgang Bumiller --- src/PVE/JSONSchema.pm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm index 6e1cd11..7be0595 100644 --- a/src/PVE/JSONSchema.pm +++ b/src/PVE/JSONSchema.pm @@ -685,21 +685,26 @@ register_standard_option('bwlimit', { my $remote_format = { host => { type => 'string', - format_description => 'Remote Proxmox hostname or IP', + description => 'Remote Proxmox hostname or IP', + format_description => 'ADDRESS', }, port => { type => 'integer', optional => 1, + description => 'Port to connect to', + format_description => 'PORT', }, apitoken => { type => 'string', - format_description => 'A full Proxmox API token including the secret value.', + description => 'A full Proxmox API token including the secret value.', + format_description => 'user@realm!token=SECRET', }, fingerprint => get_standard_option( 'fingerprint-sha256', { optional => 1, - format_description => 'Remote host\'s certificate fingerprint, if not trusted by system store.', + description => 'Remote host\'s certificate fingerprint, if not trusted by system store.', + format_description => 'FINGERPRINT', } ), }; -- 2.39.2 From 68b234f35efb3c6b672036bd0434a7e71f8c3b3a Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 15 Feb 2024 13:30:18 +0100 Subject: [PATCH 07/16] add PVE::Systemd::is_unit_active Signed-off-by: Wolfgang Bumiller --- src/PVE/Systemd.pm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/PVE/Systemd.pm b/src/PVE/Systemd.pm index 2517d31..07c912e 100644 --- a/src/PVE/Systemd.pm +++ b/src/PVE/Systemd.pm @@ -167,6 +167,23 @@ sub wait_for_unit_removed($;$) { }, $timeout); } +sub is_unit_active($;$) { + my ($unit) = @_; + + my $bus = Net::DBus->system(); + my $reactor = Net::DBus::Reactor->main(); + + my $service = $bus->get_service('org.freedesktop.systemd1'); + my $if = $service->get_object('/org/freedesktop/systemd1', 'org.freedesktop.systemd1.Manager'); + + my $unit_path = eval { $if->GetUnit($unit) } + or return 0; + $if = $service->get_object($unit_path, 'org.freedesktop.systemd1.Unit') + or return 0; + my $state = $if->ActiveState; + return defined($state) && $state eq 'active'; +} + sub read_ini { my ($filename) = @_; -- 2.39.2 From ff39327769ff51c1b48adc5d80f65df8f3d5cc21 Mon Sep 17 00:00:00 2001 From: Max Carrara Date: Tue, 20 Feb 2024 16:08:36 +0100 Subject: [PATCH 08/16] ticket: remove fallback for SHA1-base64 CSRF prevention tokens Signed-off-by: Max Carrara --- src/PVE/Ticket.pm | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/PVE/Ticket.pm b/src/PVE/Ticket.pm index ce8d5c8..c5508ed 100644 --- a/src/PVE/Ticket.pm +++ b/src/PVE/Ticket.pm @@ -34,13 +34,7 @@ sub verify_csrf_prevention_token { my $timestamp = $1; my $ttime = hex($timestamp); - my $digest; - if (length($sig) == 27) { - # detected sha1 csrf token from older proxy, fallback. FIXME: remove with 7.0 - $digest = Digest::SHA::sha1_base64("$timestamp:$username", $secret); - } else { - $digest = Digest::SHA::hmac_sha256_base64("$timestamp:$username", $secret); - } + my $digest = Digest::SHA::hmac_sha256_base64("$timestamp:$username", $secret); my $age = time() - $ttime; return 1 if ($digest eq $sig) && ($age > $min_age) && -- 2.39.2 From 10349969ccb92380c89a3e0d526a3da4a7d1cf52 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 6 Mar 2024 12:02:31 +0100 Subject: [PATCH 09/16] bump version to 8.1.1 Signed-off-by: Wolfgang Bumiller --- debian/changelog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/debian/changelog b/debian/changelog index 2649678..bd41b71 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,21 @@ +libpve-common-perl (8.1.1) bookworm; urgency=medium + + * fix #5141: network parser: fix accidental RE result re-use and add tests + + * network tests: switch to ifupdown2 + + * network parser: iterate deterministically + + * schema: fixup description vs format_description in remote_format + + * add PVE::Systemd::is_unit_active + + * ticket: remove fallback for SHA1-base64 CSRF prevention tokens + + * expose SYS_prctl + + -- Proxmox Support Team Wed, 06 Mar 2024 12:03:00 +0100 + libpve-common-perl (8.1.0) bookworm; urgency=medium * tools: Add mknod syscall -- 2.39.2 From a656f674c246732768cc250606ec71080d928df9 Mon Sep 17 00:00:00 2001 From: Folke Gleumes Date: Wed, 27 Mar 2024 14:09:22 +0100 Subject: [PATCH 10/16] docs: add missing prefix include 'PVEAPIToken=' prefix in the example for target-endpoint which is mainly used for remote migrations. Signed-off-by: Folke Gleumes --- src/PVE/JSONSchema.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm index 7be0595..4bf0e78 100644 --- a/src/PVE/JSONSchema.pm +++ b/src/PVE/JSONSchema.pm @@ -697,7 +697,7 @@ my $remote_format = { apitoken => { type => 'string', description => 'A full Proxmox API token including the secret value.', - format_description => 'user@realm!token=SECRET', + format_description => 'PVEAPIToken=user@realm!token=SECRET', }, fingerprint => get_standard_option( 'fingerprint-sha256', -- 2.39.2 From c302a28a21e17da6b3ed05945a553d2ed4576be8 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 11 Apr 2024 11:29:29 +0200 Subject: [PATCH 11/16] json schema: add format description for pve-storage-id standard option so that the option can be used as part of a property string. Signed-off-by: Fiona Ebner --- src/PVE/JSONSchema.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm index 4bf0e78..115f811 100644 --- a/src/PVE/JSONSchema.pm +++ b/src/PVE/JSONSchema.pm @@ -84,6 +84,7 @@ register_standard_option('pve-iface', { register_standard_option('pve-storage-id', { description => "The storage identifier.", type => 'string', format => 'pve-storage-id', + format_description => 'storage ID', }); register_standard_option('pve-bridge-id', { -- 2.39.2 From 55ba8536f00197b961a232e49f1b2867340a79aa Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Wed, 17 Apr 2024 21:10:39 +0200 Subject: [PATCH 12/16] bump version to 8.1.2 Signed-off-by: Thomas Lamprecht --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index bd41b71..749b319 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +libpve-common-perl (8.1.2) bookworm; urgency=medium + + * remote format: improve documentation of expected API-token format + + * json schema: add format description for pve-storage-id standard option + + -- Proxmox Support Team Wed, 17 Apr 2024 21:10:32 +0200 + libpve-common-perl (8.1.1) bookworm; urgency=medium * fix #5141: network parser: fix accidental RE result re-use and add tests -- 2.39.2 From e68ebda4f1097e825d69e4c3e986bd529f874d0d Mon Sep 17 00:00:00 2001 From: Stefan Hanreich Date: Fri, 12 Apr 2024 10:07:32 +0200 Subject: [PATCH 13/16] fix #545: interfaces: allow arbitrary bridge names in network config MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Similar to other interface types, we can detect a bridge by the presence of its bridge_ports attribute, rather than solely relying on the "vmbr" ifname prefix heuristic. For OVS bridges we need to examine the OVS type instead. The check needs to be moved up since other prefixes could theoretically be included in a bridge name and then would otherwise get picked up wrongly. Also added a warning for interfaces named vmbrX that are not bridges to catch possible misconfigurations. Originally-by: Jillian Morgan Reviewed-by: Fabian Grünbichler Signed-off-by: Stefan Hanreich --- src/PVE/INotify.pm | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index 6432295..4568593 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -22,6 +22,7 @@ use PVE::Network; use PVE::ProcFSTools; use PVE::SafeSyslog; use PVE::Tools; +use PVE::RESTEnvironment qw(log_warn); use base 'Exporter'; @@ -1033,7 +1034,17 @@ sub __read_etc_network_interfaces { foreach my $iface (sort keys %$ifaces) { my $d = $ifaces->{$iface}; $d->{type} = 'unknown'; - if ($iface =~ m/^bond\d+$/) { + if (defined $d->{'bridge_ports'}) { + $d->{type} = 'bridge'; + if (!defined ($d->{bridge_stp})) { + $d->{bridge_stp} = 'off'; + } + if (!defined($d->{bridge_fd}) && $d->{bridge_stp} eq 'off') { + $d->{bridge_fd} = 0; + } + } elsif ($d->{ovs_type} && $d->{ovs_type} eq 'OVSBridge') { + $d->{type} = $d->{ovs_type}; + } elsif ($iface =~ m/^bond\d+$/) { if (!$d->{ovs_type}) { $d->{type} = 'bond'; } elsif ($d->{ovs_type} eq 'OVSBond') { @@ -1053,18 +1064,6 @@ sub __read_etc_network_interfaces { my $tag = &$extract_ovs_option($d, 'tag'); $d->{ovs_tag} = $tag if defined($tag); } - } elsif ($iface =~ m/^vmbr\d+$/) { - if (!$d->{ovs_type}) { - $d->{type} = 'bridge'; - if (!defined ($d->{bridge_stp})) { - $d->{bridge_stp} = 'off'; - } - if (!defined($d->{bridge_fd}) && $d->{bridge_stp} eq 'off') { - $d->{bridge_fd} = 0; - } - } elsif ($d->{ovs_type} eq 'OVSBridge') { - $d->{type} = $d->{ovs_type}; - } } elsif ($iface =~ m/^(\S+):\d+$/) { $d->{type} = 'alias'; if (defined ($ifaces->{$1})) { @@ -1127,6 +1126,9 @@ sub __read_etc_network_interfaces { } } + log_warn("detected a interface $iface that is not a bridge!") + if !($d->{type} eq 'OVSBridge' || $d->{type} eq 'bridge') && $iface =~ m/^vmbr\d+$/; + # map address and netmask to cidr if (my $addr = $d->{address}) { if (_address_is_cidr($addr)) { -- 2.39.2 From a061517cdd60dceec14af449fff26a7a5349a6c6 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Sun, 21 Apr 2024 11:51:17 +0200 Subject: [PATCH 14/16] bump version to 8.2.0 Signed-off-by: Thomas Lamprecht --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 749b319..5b28346 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +libpve-common-perl (8.2.0) bookworm; urgency=medium + + * fix #545: interfaces: allow arbitrary bridge names in network config + + -- Proxmox Support Team Sun, 21 Apr 2024 11:50:54 +0200 + libpve-common-perl (8.1.2) bookworm; urgency=medium * remote format: improve documentation of expected API-token format -- 2.39.2 From b518bbd5f9a256b883a8da34d4af31ec2d04e6f4 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 23 Apr 2024 15:03:17 +0200 Subject: [PATCH 15/16] interfaces: support stanzas without types/methods This is allowed in ifupdown2 and previously interfaces named 'vmbr\d+' were recognized as bridges even if they used this mode. With commit e68ebda4f109 this is no longer the case. Fixes: e68ebda4f109 ("fix #545: interfaces: allow arbitrary bridge names in network config") Signed-off-by: Wolfgang Bumiller --- src/PVE/INotify.pm | 97 +++++++++++++------ .../t.ifupdown2-typeless.pl | 47 +++++++++ 2 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 test/etc_network_interfaces/t.ifupdown2-typeless.pl diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm index 4568593..8a4a810 100644 --- a/src/PVE/INotify.pm +++ b/src/PVE/INotify.pm @@ -912,23 +912,29 @@ sub __read_etc_network_interfaces { # FIXME: handle those differently? auto makes it required on-boot, vs. best-effort $ifaces->{$_}->{autostart} = 1 for split (/\s+/, $2); - } elsif ($line =~ m/^\s*iface\s+(\S+)\s+(inet6?)\s+(\S+)\s*$/) { + } elsif ($line =~ m/^\s*iface\s+(\S+)(?:\s+(inet6?)\s+(\S+))?\s*$/) { my $i = $1; my $family = $2; my $f = { method => $3 }; # by family, merged to $d with a $suffix - (my $suffix = $family) =~ s/^inet//; + my $suffix = $family; + $suffix =~ s/^inet// if defined $suffix; my $d = $ifaces->{$i} ||= {}; $d->{priority} = $priority++ if !$d->{priority}; + + # $family may be undef, an undef family means we have a stanza + # without an `inet` or `inet6` section push @{$d->{families}}, $family; + while (defined ($line = <$fh>)) { $line =~ s/\s+$//; # drop trailing whitespaces if ($line =~ m/^\s*#(.*?)\s*$/) { - $f->{comments} = '' if !$f->{comments}; + my $pushto = defined($suffix) ? $f : $d; + $pushto->{comments} = '' if !$pushto->{comments}; my $comment = decode('UTF-8', $1); - $f->{comments} .= "$comment\n"; + $pushto->{comments} .= "$comment\n"; } elsif ($line =~ m/^\s*(?:(?:iface|mapping|auto|source|source-directory)\s|allow-)/) { last; } elsif ($line =~ m/^\s*((\S+)\s+(.+))$/) { @@ -967,7 +973,17 @@ sub __read_etc_network_interfaces { }; if ($id eq 'address' || $id eq 'netmask' || $id eq 'broadcast' || $id eq 'gateway') { - $f->{$id} = $value; + if (defined($suffix)) { + $d->{$id.$suffix} = $value; + } elsif ($id ne 'netmask') { + if ($value =~ /:/) { + $d->{$id.'6'} = $value; + } else { + $d->{$id} = $value; + } + } else { + $d->{$id} = $value; + } } elsif ($simple_options->{$id}) { $d->{$id} = $value; } elsif ($id eq 'slaves' || $id eq 'bridge_ports') { @@ -1002,13 +1018,16 @@ sub __read_etc_network_interfaces { } elsif ($id eq 'vxlan-remoteip') { push @{$d->{$id}}, $value; } else { - push @{$f->{options}}, $option; + my $pushto = defined($suffix) ? $f : $d; + push @{$pushto->{options}}, $option; } } else { last; } } - $d->{"$_$suffix"} = $f->{$_} for keys $f->%*; + if (defined($suffix)) { + $d->{"$_$suffix"} = $f->{$_} for keys $f->%*; + } last SECTION if !defined($line); redo SECTION; } elsif ($line =~ /\w/) { @@ -1227,24 +1246,37 @@ sub _get_cidr { sub __interface_to_string { my ($iface, $d, $family, $first_block, $ifupdown2) = @_; - (my $suffix = $family) =~ s/^inet//; + my $suffix = $family; + $suffix =~ s/^inet// if defined($suffix); - return '' if !($d && $d->{"method$suffix"}); + return '' if $family && !($d && $d->{"method$suffix"}); - my $raw = "iface $iface $family " . $d->{"method$suffix"} . "\n"; + my $raw = "iface $iface"; + $raw .= " $family " . $d->{"method$suffix"} if defined $family; + $raw .= "\n"; - if (my $addr = $d->{"address$suffix"}) { - if ($addr !~ /\/\d+$/ && $d->{"netmask$suffix"}) { - if ($d->{"netmask$suffix"} =~ m/^\d+$/) { - $addr .= "/" . $d->{"netmask$suffix"}; - } elsif (my $mask = PVE::JSONSchema::get_netmask_bits($d->{"netmask$suffix"})) { - $addr .= "/" . $mask; + my $add_addr = sub { + my ($suffix) = @_; + if (my $addr = $d->{"address$suffix"}) { + if ($addr !~ /\/\d+$/ && $d->{"netmask$suffix"}) { + if ($d->{"netmask$suffix"} =~ m/^\d+$/) { + $addr .= "/" . $d->{"netmask$suffix"}; + } elsif (my $mask = PVE::JSONSchema::get_netmask_bits($d->{"netmask$suffix"})) { + $addr .= "/" . $mask; + } } + $raw .= "\taddress ${addr}\n"; } - $raw .= "\taddress ${addr}\n"; - } - $raw .= "\tgateway " . $d->{"gateway$suffix"} . "\n" if $d->{"gateway$suffix"}; + $raw .= "\tgateway " . $d->{"gateway$suffix"} . "\n" if $d->{"gateway$suffix"}; + }; + + if ($family) { + $add_addr->($suffix); + } else { + $add_addr->(''); + $add_addr->('6'); + } my $done = { type => 1, priority => 1, method => 1, active => 1, exists => 1, comments => 1, @@ -1413,14 +1445,25 @@ sub __interface_to_string { } } - foreach my $option (@{$d->{"options$suffix"}}) { - $raw .= "\t$option\n"; - } + my $add_options_comments = sub { + my ($suffix) = @_; + + foreach my $option (@{$d->{"options$suffix"}}) { + $raw .= "\t$option\n"; + } - # add comments - my $comments = $d->{"comments$suffix"} || ''; - foreach my $cl (split(/\n/, $comments)) { - $raw .= "#$cl\n"; + # add comments + my $comments = $d->{"comments$suffix"} || ''; + foreach my $cl (split(/\n/, $comments)) { + $raw .= "#$cl\n"; + } + }; + + if ($family) { + $add_options_comments->($suffix); + } else { + $add_options_comments->(''); + $add_options_comments->('6'); } $raw .= "\n"; @@ -1750,7 +1793,7 @@ NETWORKDOC } # if 'inet6' is the only family - if (scalar($d->{families}->@*) == 1 && $d->{families}[0] eq 'inet6') { + if (scalar($d->{families}->@*) == 1 && defined($d->{families}->[0]) && $d->{families}->[0] eq 'inet6') { $d->{comments6} = delete $d->{comments}; } diff --git a/test/etc_network_interfaces/t.ifupdown2-typeless.pl b/test/etc_network_interfaces/t.ifupdown2-typeless.pl new file mode 100644 index 0000000..d0ec5e6 --- /dev/null +++ b/test/etc_network_interfaces/t.ifupdown2-typeless.pl @@ -0,0 +1,47 @@ +my $ip = '10.0.0.2/24'; +my $gw = '10.0.0.1'; +my $ip6 = 'fc05::1:2/112'; +my $gw6 = 'fc05::1:1'; + +r(load('base') . <<"EOF"); +auto vmbr1 +iface vmbr1 + address 1.2.3.4/24 + address fccc::a:1/64 + gateway 1.2.3.1 + gateway fccc::1 + bridge-ports eth0 + bridge-stp off + bridge-fd 0 +# Comment + +EOF + +my $run = 'first'; +my $ifaces = $config->{ifaces}; + +my $ck = sub { + my ($i, $v, $e) = @_; + $ifaces->{$i}->{$v} eq $e + or die "$run run: $i variable $v: got \"$ifaces->{$i}->{$v}\", expected: $e\n"; +}; + +my $check_config = sub { + $ck->('vmbr1', type => 'bridge'); + $ck->('vmbr1', cidr => '1.2.3.4/24'); + $ck->('vmbr1', gateway => '1.2.3.1'); + $ck->('vmbr1', cidr6 => 'fccc::a:1/64'); + $ck->('vmbr1', gateway6 => 'fccc::1'); +}; + +$check_config->(); + +# idempotency +save('idem', w()); +r(load('idem')); +expect load('idem'); + +$run = 'second'; +$check_config->(); + +1; -- 2.39.2 From 1a6005ad2377b6586e084b3840ac622752b666b8 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Tue, 23 Apr 2024 15:43:01 +0200 Subject: [PATCH 16/16] bump version to 8.2.1 Signed-off-by: Thomas Lamprecht --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 5b28346..1b7ddcf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +libpve-common-perl (8.2.1) bookworm; urgency=medium + + * interfaces: support stanzas without types/methods, like ifupdown2 supports + + -- Proxmox Support Team Tue, 23 Apr 2024 15:42:55 +0200 + libpve-common-perl (8.2.0) bookworm; urgency=medium * fix #545: interfaces: allow arbitrary bridge names in network config -- 2.39.2