[pve-devel] [PATCH qemu-server 2/3] cfg2cmd: hostpci: move code to PCI.pm

Stefan Reiter s.reiter at proxmox.com
Thu Jun 18 16:36:53 CEST 2020


To avoid further cluttering config_to_command with subsequent changes.

Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
 PVE/QemuServer.pm     | 170 ++----------------------------------------
 PVE/QemuServer/PCI.pm | 170 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 163 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index fa71b25..1c08222 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -48,7 +48,7 @@ use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdr
 use PVE::QemuServer::Machine;
 use PVE::QemuServer::Memory;
 use PVE::QemuServer::Monitor qw(mon_cmd);
-use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port);
+use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
 use PVE::QemuServer::USB qw(parse_usb_device);
 
 my $have_sdn;
@@ -768,7 +768,6 @@ while (my ($k, $v) = each %$confdesc) {
 
 my $MAX_USB_DEVICES = 5;
 my $MAX_NETS = 32;
-my $MAX_HOSTPCI_DEVICES = 16;
 my $MAX_SERIAL_PORTS = 4;
 my $MAX_PARALLEL_PORTS = 3;
 my $MAX_NUMA = 8;
@@ -1011,76 +1010,6 @@ my $usbdesc = {
 };
 PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
 
-my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
-my $hostpci_fmt = {
-    host => {
-	default_key => 1,
-	type => 'string',
-	pattern => qr/$PCIRE(;$PCIRE)*/,
-	format_description => 'HOSTPCIID[;HOSTPCIID2...]',
-	description => <<EODESCR,
-Host PCI device pass through. The PCI ID of a host's PCI device or a list
-of PCI virtual functions of the host. HOSTPCIID syntax is:
-
-'bus:dev.func' (hexadecimal numbers)
-
-You can us the 'lspci' command to list existing PCI devices.
-EODESCR
-    },
-    rombar => {
-	type => 'boolean',
-        description =>  "Specify whether or not the device's ROM will be visible in the guest's memory map.",
-	optional => 1,
-	default => 1,
-    },
-    romfile => {
-        type => 'string',
-        pattern => '[^,;]+',
-        format_description => 'string',
-        description => "Custom pci device rom filename (must be located in /usr/share/kvm/).",
-        optional => 1,
-    },
-    pcie => {
-	type => 'boolean',
-        description =>  "Choose the PCI-express bus (needs the 'q35' machine model).",
-	optional => 1,
-	default => 0,
-    },
-    'x-vga' => {
-	type => 'boolean',
-        description =>  "Enable vfio-vga device support.",
-	optional => 1,
-	default => 0,
-    },
-    'mdev' => {
-	type => 'string',
-        format_description => 'string',
-	pattern => '[^/\.:]+',
-	optional => 1,
-	description => <<EODESCR
-The type of mediated device to use.
-An instance of this type will be created on startup of the VM and
-will be cleaned up when the VM stops.
-EODESCR
-    }
-};
-PVE::JSONSchema::register_format('pve-qm-hostpci', $hostpci_fmt);
-
-my $hostpcidesc = {
-        optional => 1,
-        type => 'string', format => 'pve-qm-hostpci',
-        description => "Map host PCI devices into guest.",
-	verbose_description =>  <<EODESCR,
-Map host PCI devices into guest.
-
-NOTE: This option allows direct access to host hardware. So it is no longer
-possible to migrate such machines - use with special care.
-
-CAUTION: Experimental! User reported problems with this option.
-EODESCR
-};
-PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
-
 my $serialdesc = {
 	optional => 1,
 	type => 'string',
@@ -1119,8 +1048,8 @@ for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
     $confdesc->{"serial$i"} = $serialdesc;
 }
 
-for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
-    $confdesc->{"hostpci$i"} = $hostpcidesc;
+for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++)  {
+    $confdesc->{"hostpci$i"} = $PVE::QemuServer::PCI::hostpcidesc;
 }
 
 for my $key (keys %{$PVE::QemuServer::Drive::drivedesc_hash}) {
@@ -1756,23 +1685,6 @@ sub parse_numa {
     return $res;
 }
 
-sub parse_hostpci {
-    my ($value) = @_;
-
-    return undef if !$value;
-
-    my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
-
-    my @idlist = split(/;/, $res->{host});
-    delete $res->{host};
-    foreach my $id (@idlist) {
-	my $devs = PVE::SysFSTools::lspci($id);
-	die "no PCI device found for '$id'\n" if !scalar(@$devs);
-	push @{$res->{pciid}}, @$devs;
-    }
-    return $res;
-}
-
 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
 sub parse_net {
     my ($data) = @_;
@@ -3189,77 +3101,9 @@ sub config_to_command {
 	push @$devices, '-device', $kbd if defined($kbd);
     }
 
-    my $kvm_off = 0;
-    my $gpu_passthrough;
-
-    # host pci devices
-    for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
-	my $id = "hostpci$i";
-	my $d = parse_hostpci($conf->{$id});
-	next if !$d;
-
-	if (my $pcie = $d->{pcie}) {
-	    die "q35 machine model is not enabled" if !$q35;
-	    # win7 wants to have the pcie devices directly on the pcie bus
-	    # instead of in the root port
-	    if ($winversion == 7) {
-		$pciaddr = print_pcie_addr("${id}bus0");
-	    } else {
-		# add more root ports if needed, 4 are present by default
-		# by pve-q35 cfgs, rest added here on demand.
-		if ($i > 3) {
-		    push @$devices, '-device', print_pcie_root_port($i);
-		}
-		$pciaddr = print_pcie_addr($id);
-	    }
-	} else {
-	    $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
-	}
-
-	my $xvga = '';
-	if ($d->{'x-vga'}) {
-	    $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf');
-	    $kvm_off = 1;
-	    $vga->{type} = 'none' if !defined($conf->{vga});
-	    $gpu_passthrough = 1;
-	}
-
-	my $pcidevices = $d->{pciid};
-	my $multifunction = 1 if @$pcidevices > 1;
-
-	my $sysfspath;
-	if ($d->{mdev} && scalar(@$pcidevices) == 1) {
-	    my $pci_id = $pcidevices->[0]->{id};
-	    my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
-	    $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
-	} elsif ($d->{mdev}) {
-	    warn "ignoring mediated device '$id' with multifunction device\n";
-	}
-
-	my $j=0;
-	foreach my $pcidevice (@$pcidevices) {
-	    my $devicestr = "vfio-pci";
-
-	    if ($sysfspath) {
-		$devicestr .= ",sysfsdev=$sysfspath";
-	    } else {
-		$devicestr .= ",host=$pcidevice->{id}";
-	    }
-
-	    my $mf_addr = $multifunction ? ".$j" : '';
-	    $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
-
-	    if ($j == 0) {
-		$devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
-		$devicestr .= "$xvga";
-		$devicestr .= ",multifunction=on" if $multifunction;
-		$devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
-	    }
-
-	    push @$devices, '-device', $devicestr;
-	    $j++;
-	}
-    }
+    # host pci device passthrough
+    my ($kvm_off, $gpu_passthrough) = PVE::QemuServer::PCI::print_hostpci_devices(
+	$conf, $devices, $winversion, $q35, $bridges, $arch, $machine_type);
 
     # usb devices
     my $usb_dev_features = {};
@@ -5092,7 +4936,7 @@ sub vm_start_nolock {
     }
 
     # host pci devices
-    for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
+    for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++)  {
       my $d = parse_hostpci($conf->{"hostpci$i"});
       next if !$d;
       my $pcidevices = $d->{pciid};
diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm
index 4d9ce26..39f9970 100644
--- a/PVE/QemuServer/PCI.pm
+++ b/PVE/QemuServer/PCI.pm
@@ -1,13 +1,89 @@
 package PVE::QemuServer::PCI;
 
+use PVE::JSONSchema;
+use PVE::SysFSTools;
+
 use base 'Exporter';
 
 our @EXPORT_OK = qw(
 print_pci_addr
 print_pcie_addr
 print_pcie_root_port
+parse_hostpci
 );
 
+our $MAX_HOSTPCI_DEVICES = 16;
+
+my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
+my $hostpci_fmt = {
+    host => {
+	default_key => 1,
+	type => 'string',
+	pattern => qr/$PCIRE(;$PCIRE)*/,
+	format_description => 'HOSTPCIID[;HOSTPCIID2...]',
+	description => <<EODESCR,
+Host PCI device pass through. The PCI ID of a host's PCI device or a list
+of PCI virtual functions of the host. HOSTPCIID syntax is:
+
+'bus:dev.func' (hexadecimal numbers)
+
+You can us the 'lspci' command to list existing PCI devices.
+EODESCR
+    },
+    rombar => {
+	type => 'boolean',
+        description =>  "Specify whether or not the device's ROM will be visible in the guest's memory map.",
+	optional => 1,
+	default => 1,
+    },
+    romfile => {
+        type => 'string',
+        pattern => '[^,;]+',
+        format_description => 'string',
+        description => "Custom pci device rom filename (must be located in /usr/share/kvm/).",
+        optional => 1,
+    },
+    pcie => {
+	type => 'boolean',
+        description =>  "Choose the PCI-express bus (needs the 'q35' machine model).",
+	optional => 1,
+	default => 0,
+    },
+    'x-vga' => {
+	type => 'boolean',
+        description =>  "Enable vfio-vga device support.",
+	optional => 1,
+	default => 0,
+    },
+    'mdev' => {
+	type => 'string',
+        format_description => 'string',
+	pattern => '[^/\.:]+',
+	optional => 1,
+	description => <<EODESCR
+The type of mediated device to use.
+An instance of this type will be created on startup of the VM and
+will be cleaned up when the VM stops.
+EODESCR
+    }
+};
+PVE::JSONSchema::register_format('pve-qm-hostpci', $hostpci_fmt);
+
+our $hostpcidesc = {
+        optional => 1,
+        type => 'string', format => 'pve-qm-hostpci',
+        description => "Map host PCI devices into guest.",
+	verbose_description =>  <<EODESCR,
+Map host PCI devices into guest.
+
+NOTE: This option allows direct access to host hardware. So it is no longer
+possible to migrate such machines - use with special care.
+
+CAUTION: Experimental! User reported problems with this option.
+EODESCR
+};
+PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
+
 my $pci_addr_map;
 sub get_pci_addr_map {
     $pci_addr_map = {
@@ -253,4 +329,98 @@ sub print_pcie_root_port {
     return $res;
 }
 
+sub parse_hostpci {
+    my ($value) = @_;
+
+    return undef if !$value;
+
+    my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
+
+    my @idlist = split(/;/, $res->{host});
+    delete $res->{host};
+    foreach my $id (@idlist) {
+	my $devs = PVE::SysFSTools::lspci($id);
+	die "no PCI device found for '$id'\n" if !scalar(@$devs);
+	push @{$res->{pciid}}, @$devs;
+    }
+    return $res;
+}
+
+sub print_hostpci_devices {
+    my ($conf, $devices, $winversion, $q35, $bridges, $arch, $machine_type) = @_;
+
+    my $kvm_off = 0;
+    my $gpu_passthrough = 0;
+
+    for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
+	my $id = "hostpci$i";
+	my $d = parse_hostpci($conf->{$id});
+	next if !$d;
+
+	if (my $pcie = $d->{pcie}) {
+	    die "q35 machine model is not enabled" if !$q35;
+	    # win7 wants to have the pcie devices directly on the pcie bus
+	    # instead of in the root port
+	    if ($winversion == 7) {
+		$pciaddr = print_pcie_addr("${id}bus0");
+	    } else {
+		# add more root ports if needed, 4 are present by default
+		# by pve-q35 cfgs, rest added here on demand.
+		if ($i > 3) {
+		    push @$devices, '-device', print_pcie_root_port($i);
+		}
+		$pciaddr = print_pcie_addr($id);
+	    }
+	} else {
+	    $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
+	}
+
+	my $xvga = '';
+	if ($d->{'x-vga'}) {
+	    $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf');
+	    $kvm_off = 1;
+	    $vga->{type} = 'none' if !defined($conf->{vga});
+	    $gpu_passthrough = 1;
+	}
+
+	my $pcidevices = $d->{pciid};
+	my $multifunction = 1 if @$pcidevices > 1;
+
+	my $sysfspath;
+	if ($d->{mdev} && scalar(@$pcidevices) == 1) {
+	    my $pci_id = $pcidevices->[0]->{id};
+	    my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
+	    $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
+	} elsif ($d->{mdev}) {
+	    warn "ignoring mediated device '$id' with multifunction device\n";
+	}
+
+	my $j=0;
+	foreach my $pcidevice (@$pcidevices) {
+	    my $devicestr = "vfio-pci";
+
+	    if ($sysfspath) {
+		$devicestr .= ",sysfsdev=$sysfspath";
+	    } else {
+		$devicestr .= ",host=$pcidevice->{id}";
+	    }
+
+	    my $mf_addr = $multifunction ? ".$j" : '';
+	    $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
+
+	    if ($j == 0) {
+		$devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
+		$devicestr .= "$xvga";
+		$devicestr .= ",multifunction=on" if $multifunction;
+		$devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
+	    }
+
+	    push @$devices, '-device', $devicestr;
+	    $j++;
+	}
+    }
+
+    return ($kvm_off, $gpu_passthrough);
+}
+
 1;
-- 
2.20.1





More information about the pve-devel mailing list