summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2023-07-26 17:41:31 +0200
committerSimon Rettberg2023-07-26 17:41:31 +0200
commitc1e793128dc53cfed7faec60edf0c5998f527097 (patch)
treed40c0504139b93932af4956f9dfbc37b1dbf8b32
parent[libvirt-python/libvirt-src] Bump libvirt version (diff)
downloadmltk-c1e793128dc53cfed7faec60edf0c5998f527097.tar.gz
mltk-c1e793128dc53cfed7faec60edf0c5998f527097.tar.xz
mltk-c1e793128dc53cfed7faec60edf0c5998f527097.zip
[qemu] java: Make pci passthrough generic, not just for nvidia
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java6
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java30
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuPciPassthrough.java (renamed from core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java)121
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java10
4 files changed, 98 insertions, 69 deletions
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
index 6a0dc9cb..0744c9b5 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
@@ -25,14 +25,14 @@ import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericInterf
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericMemory;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericName;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericParallelDevices;
-import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuSerialDevices;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericUuid;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericWrapperScript;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuArchitecture;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuFirmware;
-import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGpuPassthroughNvidia;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGraphics;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuMdevPassthroughIntel;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuPciPassthrough;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuSerialDevices;
import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu.QemuSessionType;
import org.openslx.runvirt.viewer.Viewer;
@@ -160,7 +160,7 @@ public class App
transformationManager.register( new TransformationSpecificQemuGraphics( hypervisorQemu ), true );
transformationManager.register( new TransformationSpecificQemuSerialDevices( hypervisorQemu ), true );
transformationManager.register( new TransformationSpecificQemuMdevPassthroughIntel( hypervisorQemu ), false );
- transformationManager.register( new TransformationSpecificQemuGpuPassthroughNvidia( hypervisorQemu ), false );
+ transformationManager.register( new TransformationSpecificQemuPciPassthrough( hypervisorQemu ), false );
}
// Needs to be last one since TransformationSpecificQemuArchitecture sets this too
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
index 21b11968..396c0d8c 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
@@ -13,6 +13,8 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.openslx.libvirt.domain.device.HostdevPciDeviceDescription;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuPciPassthrough;
import org.openslx.util.Util;
/**
@@ -453,13 +455,33 @@ public class CommandLineArgs
}
/**
- * Returns the state whether a passthrough of a NVIDIA GPU is required.
- *
- * @return state whether a passthrough of a NVIDIA GPU is required.
+ * Returns the state whether a passthrough of a NVIDIA GPU is requested.
+ * Do this by checking the vendor ID of each PCI device that's being passed
+ * through. If one of them is nvidia, assume we're running passthrough for
+ * an nvidia GPU.
*/
public boolean isNvidiaGpuPassthroughEnabled()
{
- return this.getVmNvGpuIds0().size() > 0;
+ List<String> pciIds = this.getVmNvGpuIds0();
+ // parse PCI device description and PCI device address
+ for ( int i = 0; i < pciIds.size() - 1; i += 2 ) {
+ // parse vendor and device ID
+ HostdevPciDeviceDescription deviceDescription = null;
+ try {
+ deviceDescription = HostdevPciDeviceDescription.valueOf( pciIds.get( i ) );
+ } catch ( IllegalArgumentException e ) {
+ continue;
+ }
+
+ // validate vendor ID
+ final int vendorId = deviceDescription.getVendorId();
+ if ( TransformationSpecificQemuPciPassthrough.NVIDIA_PCI_VENDOR_ID != vendorId )
+ continue;
+
+ // Have at least one device by nvidia, just assume it's a GPU for now
+ return true;
+ }
+ return false;
}
/**
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuPciPassthrough.java
index 23e5fe18..1a20448f 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuPciPassthrough.java
@@ -6,14 +6,14 @@ import java.util.List;
import org.openslx.libvirt.capabilities.Capabilities;
import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Device;
+import org.openslx.libvirt.domain.device.Graphics.ListenType;
import org.openslx.libvirt.domain.device.GraphicsSpice;
import org.openslx.libvirt.domain.device.HostdevPci;
import org.openslx.libvirt.domain.device.HostdevPciDeviceAddress;
import org.openslx.libvirt.domain.device.HostdevPciDeviceDescription;
import org.openslx.libvirt.domain.device.Shmem;
import org.openslx.libvirt.domain.device.Video;
-import org.openslx.libvirt.domain.device.Device;
-import org.openslx.libvirt.domain.device.Graphics.ListenType;
import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
@@ -26,7 +26,7 @@ import org.openslx.virtualization.configuration.transformation.TransformationSpe
* @author Manuel Bentele
* @version 1.0
*/
-public class TransformationSpecificQemuGpuPassthroughNvidia
+public class TransformationSpecificQemuPciPassthrough
extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu>
{
/**
@@ -37,7 +37,7 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
/**
* Vendor identifier of PCI devices from Nvidia.
*/
- private static final int NVIDIA_PCI_VENDOR_ID = 0x10de;
+ public static final int NVIDIA_PCI_VENDOR_ID = 0x10de;
/**
* Switch to turn patch for Nvidia GPU-Passthrough (enables Hyper-V enlightening) on or off to
@@ -71,9 +71,9 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
*
* @param hypervisor Libvirt/QEMU hypervisor.
*/
- public TransformationSpecificQemuGpuPassthroughNvidia( LibvirtHypervisorQemu hypervisor )
+ public TransformationSpecificQemuPciPassthrough( LibvirtHypervisorQemu hypervisor )
{
- super( TransformationSpecificQemuGpuPassthroughNvidia.NAME, hypervisor );
+ super( TransformationSpecificQemuPciPassthrough.NAME, hypervisor );
}
/**
@@ -115,13 +115,6 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
throw new TransformationException( "Invalid vendor or device ID of the PCI device description!" );
}
- // validate vendor ID
- final int vendorId = deviceDescription.getVendorId();
- if ( TransformationSpecificQemuGpuPassthroughNvidia.NVIDIA_PCI_VENDOR_ID != vendorId ) {
- final String errorMsg = "Vendor ID '" + vendorId + "' of the PCI device is not from Nvidia!";
- throw new TransformationException( errorMsg );
- }
-
// parse PCI domain, PCI bus, PCI device and PCI function
final HostdevPciDeviceAddress parsedPciAddress = HostdevPciDeviceAddress.valueOf( pciIds.get( i + 1 ) );
if ( parsedPciAddress != null ) {
@@ -146,7 +139,7 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
}
- TransformationSpecificQemuGpuPassthroughNvidia.validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
+ TransformationSpecificQemuPciPassthrough.validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
}
/**
@@ -202,58 +195,53 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
// validate configuration and input arguments
this.validateInputs( config, args );
- // check if passthrough of Nvidia GPU takes place
- if ( args.isNvidiaGpuPassthroughEnabled() ) {
- // validate submitted PCI IDs
- final List<HostdevPciDeviceAddress> pciDeviceAddresses = TransformationSpecificQemuGpuPassthroughNvidia
- .validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
-
- // check if IOMMU support is available on the host
- if ( !this.getCapabilities().hasHostIommuSupport() ) {
- final String errorMsg = "IOMMU support is not available on the hypervisor but required for GPU passthrough!";
- throw new TransformationException( errorMsg );
- }
- // Check config for PCI addresses already in use
- boolean inUse[] = new boolean[ 64 ];
- inUse[0] = true;
- inUse[1] = true;
- for ( Device dev : config.getDevices() ) {
- HostdevPciDeviceAddress target = dev.getPciTarget();
- if ( target == null )
- continue;
- if ( target.getPciDomain() != 0 || target.getPciBus() != 0 )
- continue; // Ignore non-primary bus
- if ( target.getPciDevice() >= inUse.length )
- continue;
- inUse[target.getPciDevice()] = true;
- }
- // Use first free one. Usually 00:02:00 is primary VGA
- int devAddr;
- for ( devAddr = 0; devAddr < inUse.length; ++devAddr ) {
- if ( !inUse[devAddr] )
- break;
- }
+ // validate submitted PCI IDs
+ final List<HostdevPciDeviceAddress> pciDeviceAddresses = TransformationSpecificQemuPciPassthrough
+ .validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
- // passthrough PCI devices of the GPU
- for ( final HostdevPciDeviceAddress pciDeviceAddress : pciDeviceAddresses ) {
- final HostdevPci pciDevice = config.addHostdevPciDevice();
- pciDevice.setManaged( true );
- pciDevice.setSource( pciDeviceAddress );
- if ( pciDeviceAddress.getPciFunction() == 0 && pciDeviceAddresses.size() > 1 ) {
- pciDevice.setMultifunction( true );
- }
- pciDevice.setPciTarget( new HostdevPciDeviceAddress( 0, devAddr, pciDeviceAddress.getPciFunction() ) );
+ // check if IOMMU support is available on the host
+ if ( !this.getCapabilities().hasHostIommuSupport() ) {
+ final String errorMsg = "IOMMU support is not available on the hypervisor but required for GPU passthrough!";
+ throw new TransformationException( errorMsg );
+ }
+ // Check config for PCI addresses already in use
+ int inUse[] = new int[ 64 ];
+ inUse[0] = Integer.MAX_VALUE;
+ inUse[1] = Integer.MAX_VALUE;
+ for ( Device dev : config.getDevices() ) {
+ HostdevPciDeviceAddress target = dev.getPciTarget();
+ if ( target == null )
+ continue;
+ if ( target.getPciDomain() != 0 || target.getPciBus() != 0 )
+ continue; // Ignore non-primary bus
+ if ( target.getPciDevice() >= inUse.length )
+ continue;
+ inUse[target.getPciDevice()] = Integer.MAX_VALUE;
+ }
+
+ // passthrough PCI devices of the GPU
+ for ( final HostdevPciDeviceAddress pciDeviceAddress : pciDeviceAddresses ) {
+ final HostdevPci pciDevice = config.addHostdevPciDevice();
+ pciDevice.setManaged( true );
+ pciDevice.setSource( pciDeviceAddress );
+ if ( pciDeviceAddress.getPciFunction() == 0 && pciDeviceAddresses.size() > 1 ) {
+ pciDevice.setMultifunction( true );
}
+ int devAddr = getFreeAddr( inUse, pciDeviceAddress );
+ pciDevice.setPciTarget( new HostdevPciDeviceAddress( 0, devAddr, pciDeviceAddress.getPciFunction() ) );
+ }
+ // check if passthrough of Nvidia GPU takes place
+ if ( args.isNvidiaGpuPassthroughEnabled() ) {
// add shared memory device for Looking Glass
final Shmem shmemDevice = config.addShmemDevice();
shmemDevice.setName( "looking-glass" );
shmemDevice.setModel( Shmem.Model.IVSHMEM_PLAIN );
- shmemDevice.setSize( TransformationSpecificQemuGpuPassthroughNvidia.calculateFramebufferSize() );
+ shmemDevice.setSize( TransformationSpecificQemuPciPassthrough.calculateFramebufferSize() );
// enable hypervisor shadowing to avoid error code 43 of Nvidia drivers in virtual machines
- if ( TransformationSpecificQemuGpuPassthroughNvidia.NVIDIA_PATCH ) {
- config.setFeatureHypervVendorIdValue( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID );
+ if ( TransformationSpecificQemuPciPassthrough.NVIDIA_PATCH ) {
+ config.setFeatureHypervVendorIdValue( TransformationSpecificQemuPciPassthrough.HYPERV_VENDOR_ID );
config.setFeatureHypervVendorIdState( true );
config.setFeatureKvmHiddenState( true );
}
@@ -274,4 +262,23 @@ public class TransformationSpecificQemuGpuPassthroughNvidia
}
}
}
+
+ private int getFreeAddr( int[] inUse, HostdevPciDeviceAddress pciDeviceAddress )
+ {
+ // Use first free one. Usually 00:02:00 is primary VGA
+ int devAddr;
+ int firstFree = -1;
+ int lookup = (pciDeviceAddress.getPciDomain() << 16)
+ | (pciDeviceAddress.getPciBus() << 8)
+ | (pciDeviceAddress.getPciDevice());
+ for ( devAddr = 0; devAddr < inUse.length; ++devAddr ) {
+ if ( firstFree == -1 && inUse[devAddr] == 0 ) {
+ firstFree = devAddr;
+ } else if ( inUse[devAddr] == lookup ) {
+ return devAddr;
+ }
+ }
+ inUse[firstFree] = lookup;
+ return firstFree;
+ }
}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java
index 4c021363..ae9f531b 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java
@@ -29,7 +29,7 @@ import org.openslx.libvirt.xml.LibvirtXmlValidationException;
import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
import org.openslx.virtualization.configuration.transformation.TransformationException;
-class TransformationSpecificQemuGpuPassthroughNvidiaStub extends TransformationSpecificQemuGpuPassthroughNvidia
+class TransformationSpecificQemuGpuPassthroughNvidiaStub extends TransformationSpecificQemuPciPassthrough
{
final String capabilityFileName;
@@ -87,13 +87,13 @@ public class TransformationSpecificQemuGpuPassthroughNvidiaTest
assertEquals( Shmem.Model.IVSHMEM_PLAIN, shmemDevice.getModel() );
assertEquals( BigInteger.valueOf( 67108864 ).toString(), shmemDevice.getSize().toString() );
- if ( TransformationSpecificQemuGpuPassthroughNvidia.NVIDIA_PATCH ) {
- assertEquals( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID,
+ if ( TransformationSpecificQemuPciPassthrough.NVIDIA_PATCH ) {
+ assertEquals( TransformationSpecificQemuPciPassthrough.HYPERV_VENDOR_ID,
config.getFeatureHypervVendorIdValue() );
assertTrue( config.isFeatureHypervVendorIdStateOn() );
assertTrue( config.isFeatureKvmHiddenStateOn() );
} else {
- assertNotEquals( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID,
+ assertNotEquals( TransformationSpecificQemuPciPassthrough.HYPERV_VENDOR_ID,
config.getFeatureHypervVendorIdValue() );
assertFalse( config.isFeatureHypervVendorIdStateOn() );
assertFalse( config.isFeatureKvmHiddenStateOn() );
@@ -136,7 +136,7 @@ public class TransformationSpecificQemuGpuPassthroughNvidiaTest
assertNotNull( shmemDevices );
assertEquals( 0, shmemDevices.size() );
- assertNotEquals( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID,
+ assertNotEquals( TransformationSpecificQemuPciPassthrough.HYPERV_VENDOR_ID,
config.getFeatureHypervVendorIdValue() );
assertFalse( config.isFeatureHypervVendorIdStateOn() );
assertFalse( config.isFeatureKvmHiddenStateOn() );