[pve-devel] [PATCH qemu-server v2 20/32] test: add tests for PCI reservations

Fiona Ebner f.ebner at proxmox.com
Wed Jun 18 15:01:57 CEST 2025


This is currently tested as part of the config-to-command tests, but
the plan is to make command generation for 'qm showcmd' not actually
reserve anything. The reserve_pci_usage() function also serves as
checking what already is reserved by other VMs at the same time.
Thus, the config-to-command test will not be able to test whether
reservations are actually respected after the above-mentioned change.
Add a dedicated test for this.

Signed-off-by: Fiona Ebner <f.ebner at proxmox.com>
---

New in v2.

 src/PVE/QemuServer/PCI.pm             |   2 +-
 src/test/Makefile                     |   5 +-
 src/test/run_pci_reservation_tests.pl | 175 ++++++++++++++++++++++++++
 3 files changed, 180 insertions(+), 2 deletions(-)
 create mode 100755 src/test/run_pci_reservation_tests.pl

diff --git a/src/PVE/QemuServer/PCI.pm b/src/PVE/QemuServer/PCI.pm
index 751f8a84..9b343115 100644
--- a/src/PVE/QemuServer/PCI.pm
+++ b/src/PVE/QemuServer/PCI.pm
@@ -576,7 +576,7 @@ my sub create_nvidia_device {
 #
 # mdev devices must be chosen later when we actually allocate it, but we
 # flatten the inner list since there can only be one device per alternative anyway
-my sub choose_hostpci_devices {
+sub choose_hostpci_devices {
     my ($devices, $vmid) = @_;
 
     # if the vm is running, we must be in 'showcmd', so don't actually reserve or create anything
diff --git a/src/test/Makefile b/src/test/Makefile
index f7372e2e..2ef9073a 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -1,6 +1,6 @@
 all: test
 
-test: test_snapshot test_cfg_to_cmd test_pci_addr_conflicts test_qemu_img_convert test_migration test_restore_config test_parse_config
+test: test_snapshot test_cfg_to_cmd test_pci_addr_conflicts test_pci_reservation test_qemu_img_convert test_migration test_restore_config test_parse_config
 
 test_snapshot: run_snapshot_tests.pl
 	./run_snapshot_tests.pl
@@ -15,6 +15,9 @@ test_qemu_img_convert: run_qemu_img_convert_tests.pl
 test_pci_addr_conflicts: run_pci_addr_checks.pl
 	./run_pci_addr_checks.pl
 
+test_pci_reservation: run_pci_reservation_tests.pl
+	./run_pci_reservation_tests.pl
+
 MIGRATION_TEST_TARGETS := $(addprefix test_migration_,$(shell perl -ne 'print "$$1 " if /^\s*name\s*=>\s*["'\'']([^\s"'\'']+)["'\'']\s*,\s*$$/; END { print "\n" }' run_qemu_migrate_tests.pl))
 
 test_migration: run_qemu_migrate_tests.pl MigrationTest/*.pm $(MIGRATION_TEST_TARGETS)
diff --git a/src/test/run_pci_reservation_tests.pl b/src/test/run_pci_reservation_tests.pl
new file mode 100755
index 00000000..bd428a80
--- /dev/null
+++ b/src/test/run_pci_reservation_tests.pl
@@ -0,0 +1,175 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use lib qw(..);
+
+my $vmid = 8006;
+
+use Test::MockModule;
+use Test::More;
+
+use PVE::Mapping::PCI;
+
+use PVE::QemuServer::PCI;
+
+my $pci_devs = [
+    "0000:00:43.1",
+    "0000:00:f4.0",
+    "0000:00:ff.1",
+    "0000:0f:f2.0",
+    "0000:d0:13.0",
+    "0000:d0:15.1",
+    "0000:d0:15.2",
+    "0000:d0:17.0",
+    "0000:f0:42.0",
+    "0000:f0:43.0",
+    "0000:f0:43.1",
+    "1234:f0:43.1",
+    "0000:01:00.4",
+    "0000:01:00.5",
+    "0000:01:00.6",
+    "0000:07:10.0",
+    "0000:07:10.1",
+    "0000:07:10.4",
+];
+
+my $pci_map_config = {
+    ids => {
+        someGpu => {
+            type => 'pci',
+            mdev => 1,
+            map => [
+                'node=localhost,path=0000:01:00.4,id=10de:2231,iommugroup=1',
+                'node=localhost,path=0000:01:00.5,id=10de:2231,iommugroup=1',
+                'node=localhost,path=0000:01:00.6,id=10de:2231,iommugroup=1',
+            ],
+        },
+        someNic => {
+            type => 'pci',
+            map => [
+                'node=localhost,path=0000:07:10.0,id=8086:1520,iommugroup=2',
+                'node=localhost,path=0000:07:10.1,id=8086:1520,iommugroup=2',
+                'node=localhost,path=0000:07:10.4,id=8086:1520,iommugroup=2',
+            ],
+        },
+    },
+};
+
+my $tests = [
+    {
+        name => 'reservation-is-respected',
+        conf => {
+            hostpci0 => 'mapping=someNic',
+            hostpci1 => 'mapping=someGpu,mdev=some-model',
+            hostpci2 => 'mapping=someNic',
+        },
+        expected => {
+            hostpci0 => { ids => [{ id => '0000:07:10.0' }] },
+            hostpci1 => {
+                ids => [
+                    { id => '0000:01:00.4' }, { id => '0000:01:00.5' },
+                    { id => '0000:01:00.6' },
+                ],
+                mdev => 'some-model',
+            },
+            hostpci2 => { ids => [{ id => '0000:07:10.4' }] },
+        },
+    },
+];
+
+plan tests => scalar($tests->@*);
+
+my $pve_common_inotify;
+$pve_common_inotify = Test::MockModule->new('PVE::INotify');
+$pve_common_inotify->mock(
+    nodename => sub {
+        return 'localhost';
+    },
+);
+
+my $pve_common_sysfstools;
+$pve_common_sysfstools = Test::MockModule->new('PVE::SysFSTools');
+$pve_common_sysfstools->mock(
+    lspci => sub {
+        my ($filter, $verbose) = @_;
+
+        return [
+            map { { id => $_ } }
+            grep {
+                !defined($filter)
+                    || (!ref($filter) && $_ =~ m/^(0000:)?\Q$filter\E/)
+                    || (ref($filter) eq 'CODE' && $filter->({ id => $_ }))
+            } sort @$pci_devs
+        ];
+    },
+    pci_device_info => sub {
+        my ($path, $noerr) = @_;
+
+        if ($path =~ m/^0000:01:00/) {
+            return {
+                mdev => 1,
+                iommugroup => 1,
+                mdev => 1,
+                vendor => "0x10de",
+                device => "0x2231",
+            };
+        } elsif ($path =~ m/^0000:07:10/) {
+            return {
+                iommugroup => 2,
+                vendor => "0x8086",
+                device => "0x1520",
+            };
+        } else {
+            return {};
+        }
+    },
+);
+
+my $mapping_pci_module = Test::MockModule->new("PVE::Mapping::PCI");
+$mapping_pci_module->mock(
+    config => sub {
+        return $pci_map_config;
+    },
+);
+
+my $pci_module = Test::MockModule->new("PVE::QemuServer::PCI");
+$pci_module->mock(
+    reserve_pci_usage => sub {
+        my ($ids, $vmid, $timeout, $pid, $dryrun) = @_;
+
+        $ids = [$ids] if !ref($ids);
+
+        for my $id (@$ids) {
+            if ($id eq "0000:07:10.1") {
+                die "reserved";
+            }
+        }
+
+        return undef;
+    },
+    create_nvidia_device => sub {
+        return 1;
+    },
+);
+
+for my $test ($tests->@*) {
+    my ($name, $conf, $expected) = $test->@{qw(name conf expected)};
+    my $pci_devices;
+    eval {
+        my $devices = PVE::QemuServer::PCI::parse_hostpci_devices($conf);
+        use JSON;
+        $pci_devices = PVE::QemuServer::PCI::choose_hostpci_devices($devices, $vmid);
+    };
+    if (my $err = $@) {
+        is($err, $expected, $name);
+    } elsif ($pci_devices) {
+        is_deeply($pci_devices, $expected, $name);
+    } else {
+        fail($name);
+        note("no result");
+    }
+}
+
+done_testing();
-- 
2.39.5





More information about the pve-devel mailing list