[PATCH v3 12/13] conf: support manually specifying VFIO variant driver in <hostdev> XML

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch makes it possible to manually specify which VFIO variant
driver to use for PCI hostdev device assignment, so that, e.g. you
could force use of a VFIO "variant" driver, with e.g.

  <driver model='mlx5_vfio_pci'/>

or alternately to force use of the generic vfio-pci driver with

  <driver model='vfio-pci'/>

when libvirt would have normally (after applying a subsequent patch)
found a "better match" for a device in the active kernel's
modules.alias file. (The main potential use of this manual override
would probably be to work around a bug in a new VFIO variant driver by
temporarily not using that driver).

Signed-off-by: Laine Stump <laine@xxxxxxxxxx>
---

Change from V2: use new <driver model='blah'/> instead of repurposing
existing <driver name='blah'/>

 docs/formatdomain.rst                         | 54 +++++++++++++------
 docs/formatnetwork.rst                        | 21 ++++----
 src/conf/device_conf.c                        | 10 ++++
 src/conf/device_conf.h                        |  4 ++
 src/conf/domain_conf.c                        |  3 ++
 src/conf/network_conf.c                       |  2 +
 src/conf/schemas/basictypes.rng               | 21 +++++---
 src/conf/virnetworkportdef.c                  |  1 +
 src/network/bridge_driver.c                   |  1 +
 tests/networkxml2xmlin/hostdev-pf-old.xml     |  8 +++
 tests/networkxml2xmlout/hostdev-pf-old.xml    |  8 +++
 tests/networkxml2xmltest.c                    |  6 +++
 .../hostdev-vfio.x86_64-latest.args           |  5 +-
 tests/qemuxml2argvdata/hostdev-vfio.xml       | 18 +++++++
 .../hostdev-vfio.x86_64-latest.xml            | 23 +++++++-
 .../plug-hostdev-pci-unmanaged.xml            |  1 -
 .../plug-hostdev-pci.xml                      |  1 -
 17 files changed, 148 insertions(+), 39 deletions(-)
 create mode 100644 tests/networkxml2xmlin/hostdev-pf-old.xml
 create mode 100644 tests/networkxml2xmlout/hostdev-pf-old.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index c08033f940..36c74d9eae 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -4500,24 +4500,46 @@ or:
    an error. See the `Device Addresses`_ section for more details on the address
    element.
 ``driver``
-   PCI devices can have an optional ``driver`` subelement that specifies which
-   backend driver to use for PCI device assignment. Use the ``name`` attribute
-   to select either "vfio" (for the new VFIO device assignment backend, which is
-   compatible with UEFI SecureBoot) or "kvm" (the legacy device assignment
-   handled directly by the KVM kernel module) :since:`Since 1.0.5 (QEMU and KVM
-   only, requires kernel 3.6 or newer)` . When specified, device assignment will
-   fail if the requested method of device assignment isn't available on the
-   host. When not specified, the default is "vfio" on systems where the VFIO
-   driver is available and loaded, and "kvm" on older systems, or those where
-   the VFIO driver hasn't been loaded :since:`Since 1.1.3` (prior to that the
-   default was always "kvm").
+   PCI hostdev devices can have an optional ``driver`` subelement that
+   specifies which host driver to bind to the device when preparing it
+   for assignment to a guest. :since:`Since 10.0.0 (useful for QEMU and
+   KVM only)`. This is done by setting the ``<driver>`` element's ``model``
+   attribute, for example::
+
+     ...
+       <hostdev mode='subsystem' type='pci' managed='yes'>
+         <driver model='vfio-pci-igb'/>
+     ...
+
+   tells libvirt to bind the driver "vfio-pci-igb" to the device on
+   the host before handing it off to QEMU for assignment to the
+   guest. Normally libvirt will bind the device to the "best match"
+   VFIO-type driver that it finds in the kernel's modules.alias file
+   (based on matching the corresponding fields of the device's
+   modalias file in sysfs) or to the generic "vfio-pci" driver if no
+   better match is found (vfio-pci is always used prior to libvirt
+   10.0.0), but in cases when the correct driver isn't listed in
+   modules.alias then the desired device-specific driver can be forced
+   by setting driver name, or if the device-specific driver that is
+   found is "problematic" in some way, the generic vfio-pci driver
+   similarly be forced.
+
+   (Note: :since:`Since 1.0.5, the ``name`` attribute has been
+   described to be used to select the type of PCI device assignment
+   ("vfio", "kvm", or "xen"), but those values have been mostly
+   useless, since the type of device assignment is actually determined
+   by which hypservisor is in use. This means that you may
+   occasionally see ``<driver name='vfio'/>`` or ``<driver
+   name='xen'/>`` in a domain's status XML, or more rarely in config,
+   but those specific values are essentially ignored.)
+
 ``readonly``
-   Indicates that the device is readonly, only supported by SCSI host device
-   now. :since:`Since 1.0.6 (QEMU and KVM only)`
+   Indicates that the device is readonly, only supported by SCSI host
+   device now. :since:`Since 1.0.6 (QEMU and KVM only)`
 ``shareable``
-   If present, this indicates the device is expected to be shared between
-   domains (assuming the hypervisor and OS support this). Only supported by SCSI
-   host device. :since:`Since 1.0.6`
+   If present, this indicates the device is expected to be shared
+   between domains (assuming the hypervisor and OS support this). Only
+   supported by SCSI host device. :since:`Since 1.0.6`
 
    Note: Although ``shareable`` was introduced :since:`in 1.0.6` , it did not
    work as as expected until :since:`1.2.2` .
diff --git a/docs/formatnetwork.rst b/docs/formatnetwork.rst
index 5d300a035e..d4181ac029 100644
--- a/docs/formatnetwork.rst
+++ b/docs/formatnetwork.rst
@@ -315,17 +315,14 @@ to the physical LAN (if at all).
       guest, use the traditional ``<hostdev>`` device definition. :since:` Since
       0.10.0`
 
-      To force use of a particular type of device assignment, a <forward
-      type='hostdev'> interface can have an optional ``driver`` sub-element with
-      a ``name`` attribute set to either "vfio" (VFIO is a new method of device
-      assignment that is compatible with UEFI Secure Boot) or "kvm" (the legacy
-      device assignment handled directly by the KVM kernel module) :since:`Since
-      1.0.5 (QEMU and KVM only, requires kernel 3.6 or newer)` . When specified,
-      device assignment will fail if the requested method of device assignment
-      isn't available on the host. When not specified, the default is "vfio" on
-      systems where the VFIO driver is available and loaded, and "kvm" on older
-      systems, or those where the VFIO driver hasn't been loaded :since:`Since
-      1.1.3` (prior to that the default was always "kvm").
+      To force use of a particular device-specific VFIO driver when
+      assigning the devices to a guest, a <forward type='hostdev'>
+      interface can have an optional ``driver`` sub-element with a
+      ``model`` attribute set to the name of the driver to use
+      :since:`Since 10.0.0 (QEMU only)`. When not specified, libvirt
+      will attempt to find a suitable VFIO variant driver for the
+      device, and if not found it will use the generic driver
+      "vfio-pci".
 
       Note that this "intelligent passthrough" of network devices is very
       similar to the functionality of a standard ``<hostdev>`` device, the
@@ -337,7 +334,7 @@ to the physical LAN (if at all).
       to the guest domain), or if you are using a version of libvirt older than
       0.10.0, you should use a standard ``<hostdev>`` device definition in the
       domain's configuration to assign the device to the guest instead of
-      defining an ``<interface             type='network'>`` pointing to a
+      defining an ``<interface type='network'>`` pointing to a
       network with ``<forward mode='hostdev'/>``.
 
    As mentioned above, a ``<forward>`` element can have multiple ``<interface>``
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c
index 68a8c7690a..f840efc1b5 100644
--- a/src/conf/device_conf.c
+++ b/src/conf/device_conf.c
@@ -67,6 +67,7 @@ virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node,
         return -1;
     }
 
+    driver->model = virXMLPropString(node, "model");
     return 0;
 }
 
@@ -90,11 +91,20 @@ virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf,
         virBufferAsprintf(&driverAttrBuf, " name='%s'", driverName);
     }
 
+    virBufferEscapeString(&driverAttrBuf, " model='%s'", driver->model);
+
     virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL);
     return 0;
 }
 
 
+void
+virDeviceHostdevPCIDriverInfoClear(virDeviceHostdevPCIDriverInfo *driver)
+{
+    VIR_FREE(driver->model);
+}
+
+
 static int
 virZPCIDeviceAddressParseXML(xmlNodePtr node,
                              virPCIDeviceAddress *addr)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index 0b3f17a3aa..2d674ecd85 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -46,6 +46,7 @@ VIR_ENUM_DECL(virDeviceHostdevPCIDriverName);
 
 struct _virDeviceHostdevPCIDriverInfo {
     virDeviceHostdevPCIDriverName name;
+    char *model;
 };
 
 typedef enum {
@@ -192,6 +193,9 @@ int virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node,
 int virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf,
                                         const virDeviceHostdevPCIDriverInfo *driver);
 
+void virDeviceHostdevPCIDriverInfoPostParse(virDeviceHostdevPCIDriverInfo *driver);
+void virDeviceHostdevPCIDriverInfoClear(virDeviceHostdevPCIDriverInfo *driver);
+
 void virDomainDeviceInfoClear(virDomainDeviceInfo *info);
 void virDomainDeviceInfoFree(virDomainDeviceInfo *info);
 
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0f137543e0..02fd5815cc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2636,6 +2636,7 @@ virDomainHostdevDefClear(virDomainHostdevDef *def)
             VIR_FREE(def->source.subsys.u.scsi_host.wwpn);
             break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+            virDeviceHostdevPCIDriverInfoClear(&def->source.subsys.u.pci.driver);
             g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree);
             break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
@@ -29898,6 +29899,7 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface,
         actual->data.hostdev.def.source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
         actual->data.hostdev.def.source.subsys.u.pci.addr = port->plug.hostdevpci.addr;
         actual->data.hostdev.def.source.subsys.u.pci.driver.name = port->plug.hostdevpci.driver.name;
+        actual->data.hostdev.def.source.subsys.u.pci.driver.model = g_strdup(port->plug.hostdevpci.driver.model);
         break;
 
     case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
@@ -29999,6 +30001,7 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom,
         port->plug.hostdevpci.managed = virTristateBoolFromBool(actual->data.hostdev.def.managed);
         port->plug.hostdevpci.addr = actual->data.hostdev.def.source.subsys.u.pci.addr;
         port->plug.hostdevpci.driver.name = actual->data.hostdev.def.source.subsys.u.pci.driver.name;
+        port->plug.hostdevpci.driver.model = g_strdup(actual->data.hostdev.def.source.subsys.u.pci.driver.model);
         break;
 
     case VIR_DOMAIN_NET_TYPE_CLIENT:
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 890c16b3b1..5c781d06af 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -229,6 +229,8 @@ virNetworkForwardDefClear(virNetworkForwardDef *def)
 {
     size_t i;
 
+    virDeviceHostdevPCIDriverInfoClear(&def->driver);
+
     for (i = 0; i < def->npfs && def->pfs; i++)
         virNetworkForwardPfDefClear(&def->pfs[i]);
     VIR_FREE(def->pfs);
diff --git a/src/conf/schemas/basictypes.rng b/src/conf/schemas/basictypes.rng
index 8d5f4475ca..b65d210091 100644
--- a/src/conf/schemas/basictypes.rng
+++ b/src/conf/schemas/basictypes.rng
@@ -658,13 +658,20 @@
 
   <define name="hostdevDriver">
     <element name="driver">
-      <attribute name="name">
-        <choice>
-          <value>kvm</value>
-          <value>vfio</value>
-          <value>xen</value>
-        </choice>
-      </attribute>
+      <optional>
+        <attribute name="name">
+          <choice>
+            <value>kvm</value>
+            <value>vfio</value>
+            <value>xen</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="model">
+          <ref name="genericName"/>
+        </attribute>
+      </optional>
       <empty/>
     </element>
   </define>
diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c
index 49d00b2ea6..64db63ae66 100644
--- a/src/conf/virnetworkportdef.c
+++ b/src/conf/virnetworkportdef.c
@@ -64,6 +64,7 @@ virNetworkPortDefFree(virNetworkPortDef *def)
         break;
 
     case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
+        virDeviceHostdevPCIDriverInfoClear(&def->plug.hostdevpci.driver);
         break;
 
     case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index d156333626..9921c7cd14 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -3931,6 +3931,7 @@ networkAllocatePort(virNetworkObj *obj,
         }
         port->plug.hostdevpci.addr = dev->device.pci;
         port->plug.hostdevpci.driver.name = netdef->forward.driver.name;
+        port->plug.hostdevpci.driver.model = g_strdup(netdef->forward.driver.model);
         port->plug.hostdevpci.managed = virTristateBoolFromBool(netdef->forward.managed);
 
         if (port->virtPortProfile) {
diff --git a/tests/networkxml2xmlin/hostdev-pf-old.xml b/tests/networkxml2xmlin/hostdev-pf-old.xml
new file mode 100644
index 0000000000..5b8f59858c
--- /dev/null
+++ b/tests/networkxml2xmlin/hostdev-pf-old.xml
@@ -0,0 +1,8 @@
+<network>
+  <name>hostdev</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward mode='hostdev' managed='yes'>
+    <driver name='vfio'/>
+    <pf dev='eth2'/>
+  </forward>
+</network>
diff --git a/tests/networkxml2xmlout/hostdev-pf-old.xml b/tests/networkxml2xmlout/hostdev-pf-old.xml
new file mode 100644
index 0000000000..5b8f59858c
--- /dev/null
+++ b/tests/networkxml2xmlout/hostdev-pf-old.xml
@@ -0,0 +1,8 @@
+<network>
+  <name>hostdev</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward mode='hostdev' managed='yes'>
+    <driver name='vfio'/>
+    <pf dev='eth2'/>
+  </forward>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index b0814c7529..928f28b579 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -146,6 +146,12 @@ mymain(void)
     DO_TEST_FLAGS("passthrough-pf", VIR_NETWORK_XML_INACTIVE);
     DO_TEST("hostdev");
     DO_TEST_FLAGS("hostdev-pf", VIR_NETWORK_XML_INACTIVE);
+
+    /* libvirt pre-9.9.0 used "name='vfio'" which should be
+     * automatically translated to "type='vfio'" by new parser
+     */
+    DO_TEST_FLAGS("hostdev-pf-old", VIR_NETWORK_XML_INACTIVE);
+
     DO_TEST("passthrough-address-crash");
     DO_TEST("nat-network-explicit-flood");
     DO_TEST("host-bridge-no-flood");
diff --git a/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args b/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args
index c1f9258844..8529cde269 100644
--- a/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args
+++ b/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args
@@ -32,6 +32,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.config \
 -device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-format","id":"ide0-0-0","bootindex":1}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
 -device '{"driver":"vfio-pci","host":"0000:06:12.1","id":"hostdev0","bus":"pci.0","addr":"0x2"}' \
--device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x3"}' \
+-device '{"driver":"vfio-pci","host":"0000:06:12.2","id":"hostdev1","bus":"pci.0","addr":"0x3"}' \
+-device '{"driver":"vfio-pci","host":"0000:06:12.3","id":"hostdev2","bus":"pci.0","addr":"0x4"}' \
+-device '{"driver":"vfio-pci","host":"0000:06:12.4","id":"hostdev3","bus":"pci.0","addr":"0x5"}' \
+-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x6"}' \
 -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
 -msg timestamp=on
diff --git a/tests/qemuxml2argvdata/hostdev-vfio.xml b/tests/qemuxml2argvdata/hostdev-vfio.xml
index a03870f6e0..812bac2cfd 100644
--- a/tests/qemuxml2argvdata/hostdev-vfio.xml
+++ b/tests/qemuxml2argvdata/hostdev-vfio.xml
@@ -29,6 +29,24 @@
         <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/>
       </source>
     </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/>
+      </source>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver model='vfio-pci-igb'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x3'/>
+      </source>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio' model='vfio-pci-igb'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x4'/>
+      </source>
+    </hostdev>
     <memballoon model='virtio'/>
   </devices>
 </domain>
diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml
index 3915b515f2..2042ba6c16 100644
--- a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml
@@ -39,8 +39,29 @@
       </source>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
     </hostdev>
-    <memballoon model='virtio'>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/>
+      </source>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver model='vfio-pci-igb'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x3'/>
+      </source>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </hostdev>
+    <hostdev mode='subsystem' type='pci' managed='yes'>
+      <driver name='vfio' model='vfio-pci-igb'/>
+      <source>
+        <address domain='0x0000' bus='0x06' slot='0x12' function='0x4'/>
+      </source>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </hostdev>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
     </memballoon>
   </devices>
 </domain>
diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml
index da5f568031..fa974affee 100644
--- a/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml
+++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml
@@ -6,7 +6,6 @@
   </owner>
   <mac address='52:54:00:7b:35:93'/>
   <plug type='hostdev-pci' managed='no'>
-    <driver name='vfio'/>
     <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/>
   </plug>
 </networkport>
diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
index cc4419f3fd..7354e1d48c 100644
--- a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
+++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
@@ -6,7 +6,6 @@
   </owner>
   <mac address='52:54:00:7b:35:93'/>
   <plug type='hostdev-pci' managed='yes'>
-    <driver name='vfio'/>
     <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/>
   </plug>
 </networkport>
-- 
2.43.0
_______________________________________________
Devel mailing list -- devel@xxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux