A domain's <interface> or <hostdev>, as well as a <network>'s
<forward>, can now have an optional <driver name='kvm|vfio'/>
element. As of this patch, there is no functionality behind this new
knob - this patch adds support to the domain and network
formatter/parser, and to the RNG and documentation.
When then backend is added, legacy KVM PCI device assignment will
continue to be used when no driver name is specified (or if <driver
name='kvm'/> is specified), but if driver name is 'vfio', the new UEFI
Secure Boot compatible VFIO device assignment will be used.
Note that the parser doesn't automatically insert the current default
value of this setting. This is done on purpose because the two
possibilities are functionally equivalent from the guest's point of
view, and we want to be able to automatically start using vfio as the
default (even for existing domains) at some time in the future. This
is similar to what was done with the "vhost" driver option in
<interface>.
---
docs/formatdomain.html.in | 42 ++++++++++++++++++++++-
docs/formatnetwork.html.in | 15 ++++++++
docs/schemas/domaincommon.rng | 79 ++++++++++++++++++++++++++++---------------
docs/schemas/network.rng | 11 ++++++
src/conf/domain_conf.c | 36 ++++++++++++++++++++
src/conf/domain_conf.h | 11 ++++++
6 files changed, 166 insertions(+), 28 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 888c005..0e5b00c 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2340,7 +2340,22 @@
the device as can be found with the <code>lspci</code> or
with <code>virsh
nodedev-list</code>. <a href="#elementsAddress">See
above</a> for
- more details on the address element.
+ more details on the address element.</dd>
+ <dt><code>driver</code></dt>
+ <dd>
+ PCI devices can have an optional <code>driver</code>
+ subelement that specifies which backend driver to use for PCI
+ device assignment. Use the <code>name</code> attribute to
+ select either "vfio" (for the new VFIO device assignment
+ backend, which is compatible with UEFI SecureBoot) or "kvm"
+ (for the legacy device assignment handled directly by the KVM
+ kernel module)<span class="since">Since 1.0.5 (QEMU and KVM
+ only, requires kernel 3.6 or newer)</span>. Currently, "kvm"
+ is the default used by libvirt when not explicitly provided,
+ but since the two are functionally equivalent, this default
+ could be changed in the future with no impact to domains that
+ don't specify anything.
+ </dd>
</dl>
@@ -2947,6 +2962,18 @@
</p>
<p>
+ To use VFIO device assignment rather than traditional/legacy KVM
+ device assignment (VFIO is a new method of device assignment
+ that is compatible with UEFI Secure Boot), a type='hostdev'
+ interface can have an optional <code>driver</code> sub-element
+ with a <code>name</code> attribute set to "vfio". To use
legacy
+ KVM device assignment you can set <code>name</code> to "kvm"
(or
+ simply omit the <code><driver></code> element, since
"kvm"
+ is currently the default).
+ <span class="since">Since 1.0.5 (QEMU and KVM only, requires kernel
3.6 or newer)</span>
+ </p>
+
+ <p>
Note that this "intelligent passthrough" of network devices is
very similar to the functionality of a standard <hostdev>
device, the difference being that this method allows specifying
@@ -2964,6 +2991,7 @@
...
<devices>
<interface type='hostdev'>
+ <driver name='vfio'/>
<source>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x07' function='0x0'/>
</source>
@@ -3095,6 +3123,18 @@ qemu-kvm -net nic,model=? /dev/null
to 'qemu' without error.
<span class="since">Since 0.8.8 (QEMU and KVM only)</span>
</dd>
+ <dd>
+ For interfaces of type='hostdev' (PCI passthrough devices)
+ the <code>name</code> attribute can optionally be set to
+ "vfio" or "kvm". "vfio" tells libvirt to use VFIO
device
+ assignment rather than traditional KVM device assignment (VFIO
+ is a new method of device assignment that is compatible with
+ UEFI Secure Boot), and "kvm" tells libvirt to use the legacy
+ device assignment performed directly by the kvm kernel module
+ (the default is currently "kvm", but is subject to change).
+ <span class="since">Since 1.0.5 (QEMU and KVM only, requires
kernel 3.6 or newer)</span>
+ </dd>
+
<dt><code>txmode</code></dt>
<dd>
The <code>txmode</code> attribute specifies how to handle
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 4dd0415..b188896 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -279,6 +279,20 @@
use the traditional <code>< hostdev></code> device
definition. <span class="since"> Since 0.10.0</span>
+ <p>
+ To use VFIO device assignment rather than
+ traditional/legacy KVM device assignment (VFIO is a new
+ method of device assignment that is compatible with UEFI
+ Secure Boot), a <forward type='hostdev'> interface
+ can have an optional <code>driver</code> sub-element
+ with a <code>name</code> attribute set to "vfio". To
use
+ legacy KVM device assignment you can
+ set <code>name</code> to "kvm" (or simply omit the
+ <driver> element, since "kvm" is currently the
+ default).
+ <span class="since">Since 1.0.5 (QEMU and KVM only,
requires kernel 3.6 or newer)</span>
+ </p>
+
<p>Note that this "intelligent passthrough" of network
devices is very similar to the functionality of a
standard <code>< hostdev></code> device, the
@@ -360,6 +374,7 @@
<pre>
...
<forward mode='hostdev' managed='yes'>
+ <driver name='vfio'/>
<address type='pci' domain='0' bus='4'
slot='0' function='1'/>
<address type='pci' domain='0' bus='4'
slot='0' function='2'/>
<address type='pci' domain='0' bus='4'
slot='0' function='3'/>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 3976b82..0bab37b 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1923,28 +1923,40 @@
</optional>
<optional>
<element name="driver">
- <optional>
- <attribute name="name">
- <choice>
- <value>qemu</value>
- <value>vhost</value>
- </choice>
- </attribute>
- </optional>
- <optional>
- <attribute name="txmode">
- <choice>
- <value>iothread</value>
- <value>timer</value>
- </choice>
- </attribute>
- </optional>
- <optional>
- <ref name="ioeventfd"/>
- </optional>
- <optional>
- <ref name="event_idx"/>
- </optional>
+ <choice>
+ <group>
+ <attribute name="name">
+ <choice>
+ <value>kvm</value>
+ <value>vfio</value>
+ </choice>
+ </attribute>
+ </group>
+ <group>
+ <optional>
+ <attribute name="name">
+ <choice>
+ <value>qemu</value>
+ <value>vhost</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="txmode">
+ <choice>
+ <value>iothread</value>
+ <value>timer</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
+ <optional>
+ <ref name="event_idx"/>
+ </optional>
+ </group>
+ </choice>
<empty/>
</element>
</optional>
@@ -3084,14 +3096,27 @@
<attribute name="type">
<value>pci</value>
</attribute>
- <element name="source">
+ <interleave>
<optional>
- <ref name="startupPolicy"/>
+ <element name="driver">
+ <attribute name="name">
+ <choice>
+ <value>kvm</value>
+ <value>vfio</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
</optional>
- <element name="address">
- <ref name="pciaddress"/>
+ <element name="source">
+ <optional>
+ <ref name="startupPolicy"/>
+ </optional>
+ <element name="address">
+ <ref name="pciaddress"/>
+ </element>
</element>
- </element>
+ </interleave>
</define>
<define name="hostdevsubsysusb">
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 6c3fae2..493edae 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -149,6 +149,17 @@
</attribute>
</element>
</optional>
+ <optional>
+ <element name="driver">
+ <attribute name="name">
+ <choice>
+ <value>kvm</value>
+ <value>vfio</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </optional>
</interleave>
</element>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b7fea36..ae1f6e2 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -581,6 +581,12 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
"usb",
"pci")
+VIR_ENUM_IMPL(virDomainHostdevSubsysPciBackend,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
+ "default",
+ "kvm",
+ "vfio")
+
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
"storage",
"misc",
@@ -3599,6 +3605,8 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
{
xmlNodePtr sourcenode;
char *managed = NULL;
+ char *backendStr = NULL;
+ int backend;
int ret = -1;
/* @managed can be read from the xml document - it is always an
@@ -3651,7 +3659,20 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
if (virDomainHostdevSubsysPciDefParseXML(sourcenode, def, flags) < 0)
goto error;
+
+ backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_DEFAULT;
+ if ((backendStr = virXPathString("string(./driver/@name)", ctxt))
&&
+ (((backend = virDomainHostdevSubsysPciBackendTypeFromString(backendStr)) <
0) ||
+ backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_DEFAULT)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown PCI device <driver name='%s'/>
"
+ "has been specified"), backendStr);
+ goto error;
+ }
+ def->source.subsys.u.pci.backend = backend;
+
break;
+
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
if (virDomainHostdevSubsysUsbDefParseXML(sourcenode, def) < 0)
goto error;
@@ -3662,9 +3683,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
virDomainHostdevSubsysTypeToString(def->source.subsys.type));
goto error;
}
+
ret = 0;
error:
VIR_FREE(managed);
+ VIR_FREE(backendStr);
return ret;
}
@@ -13665,6 +13688,19 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
unsigned int flags,
bool includeTypeInAddr)
{
+ if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+ def->source.subsys.u.pci.backend !=
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_DEFAULT) {
+ const char *backend =
virDomainHostdevSubsysPciBackendTypeToString(def->source.subsys.u.pci.backend);
+
+ if (!backend) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected pci hostdev driver name type %d"),
+ def->source.subsys.u.pci.backend);
+ return -1;
+ }
+ virBufferAsprintf(buf, "<driver name='%s'/>\n",
backend);
+ }
+
virBufferAddLit(buf, "<source");
if (def->startupPolicy) {
const char *policy;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a9f86c0..bb75da8 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -384,6 +384,16 @@ enum virDomainHostdevSubsysType {
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
};
+/* the backend driver used for PCI hostdev devices */
+typedef enum {
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_DEFAULT, /* currently kvm, could change */
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_KVM, /* force legacy kvm style */
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_VFIO, /* force vfio */
+
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST
+} virDomainHostdevSubsysPciBackendType;
+
+VIR_ENUM_DECL(virDomainHostdevSubsysPciBackend)
typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys;
typedef virDomainHostdevSubsys *virDomainHostdevSubsysPtr;
@@ -401,6 +411,7 @@ struct _virDomainHostdevSubsys {
} usb;
struct {
virDevicePCIAddress addr; /* host address */
+ int backend; /* enum virDomainHostdevSubsysPciBackendType */
} pci;
} u;
};
--
1.7.11.7