From: "Daniel P. Berrange"<berrange@xxxxxxxxxx>
The<hostdev> device type has long had a redundant "mode"
attribute, which has always been "subsys". This finally
introduces a new mode "capabilities", which will be used
by the LXC driver for device assignment. Since container
based virtualization uses a single kernel, the idea of
assigning physical PCI devices doesn't make sense. It is
still reasonable to assign USB devices, but for assinging
arbitrary nodes in /dev, the new 'capabilities' mode is
to be used.
The first capability support is 'storage', which is for
assignment of block devices. Functionally this is really
pretty similar to the<disk> support. The only difference
is the device node name is identical in both host and
container namespaces.
<hostdev mode='capabilities' type='storage'>
<source>
<block>/dev/sdf1</block>
</source>
</hostdev>
The second capability support is 'misc', which is for
assignment of character devices. There is no existing
parallel to this. Again the device node is the same
inside& outside the container.
<hostdev mode='capabilities' type='misc'>
<source>
<char>/dev/sdf1</char>
</source>
</hostdev>
The reason for keeping the char& storage devices
separate in the domain XML, is to mirror the split
in the node device XML. NB the node device XML does
not yet report character devices, but that's another
new patch to come
Signed-off-by: Daniel P. Berrange<berrange@xxxxxxxxxx>
---
docs/schemas/domaincommon.rng | 128 +++++++++++++++++--------
src/conf/domain_audit.c | 80 +++++++++++-----
src/conf/domain_conf.c | 175 ++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 31 +++++--
src/libvirt_private.syms | 1 +
tests/lxcxml2xmldata/lxc-hostdev.xml | 34 +++++++
tests/lxcxml2xmltest.c | 1 +
7 files changed, 375 insertions(+), 75 deletions(-)
create mode 100644 tests/lxcxml2xmldata/lxc-hostdev.xml
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 0e85739..072e5cc 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2812,63 +2812,109 @@
</zeroOrMore>
</element>
</define>
+
<define name="hostdev">
<element name="hostdev">
+<choice>
+<group>
+<ref name="hostdevsubsys"/>
+</group>
+<group>
+<ref name="hostdevcaps"/>
+</group>
+</choice>
<optional>
-<attribute name="mode">
-<choice>
-<value>subsystem</value>
-<value>capabilities</value>
-</choice>
-</attribute>
-</optional>
-<attribute name="type">
-<choice>
-<value>usb</value>
-<value>pci</value>
-</choice>
-</attribute>
-<optional>
-<attribute name="managed">
-<choice>
-<value>yes</value>
-<value>no</value>
-</choice>
-</attribute>
+<ref name="alias"/>
</optional>
-<group>
-<element name="source">
-<optional>
-<ref name="startupPolicy"/>
-</optional>
-<choice>
-<group>
-<ref name="usbproduct"/>
-<optional>
-<ref name="usbaddress"/>
-</optional>
-</group>
-<ref name="usbaddress"/>
-<element name="address">
-<ref name="pciaddress"/>
-</element>
-</choice>
-</element>
-</group>
<optional>
<ref name="deviceBoot"/>
</optional>
<optional>
-<ref name="alias"/>
+<ref name="rom"/>
</optional>
<optional>
<ref name="address"/>
</optional>
+</element>
+</define>
+
+<define name="hostdevsubsys">
+<optional>
+<attribute name="mode">
+<value>subsystem</value>
+</attribute>
+</optional>
+<optional>
+<attribute name="managed">
+<choice>
+<value>yes</value>
+<value>no</value>
+</choice>
+</attribute>
+</optional>
+<choice>
+<ref name="hostdevsubsyspci"/>
+<ref name="hostdevsubsysusb"/>
+</choice>
+</define>
+
+<define name="hostdevcaps">
+<attribute name="mode">
+<value>capabilities</value>
+</attribute>
+<choice>
+<group>
+<ref name="hostdevcapsstorage"/>
+</group>
+</choice>
+</define>
+
+
+<define name="hostdevsubsyspci">
+<attribute name="type">
+<value>pci</value>
+</attribute>
+<element name="source">
+<optional>
+<ref name="startupPolicy"/>
+</optional>
+<element name="address">
+<ref name="pciaddress"/>
+</element>
+</element>
+</define>
+
+<define name="hostdevsubsysusb">
+<attribute name="type">
+<value>usb</value>
+</attribute>
+<element name="source">
<optional>
-<ref name="rom"/>
+<ref name="startupPolicy"/>
</optional>
+<choice>
+<group>
+<ref name="usbproduct"/>
+<optional>
+<ref name="usbaddress"/>
+</optional>
+</group>
+<ref name="usbaddress"/>
+</choice>
</element>
</define>
+
+<define name="hostdevcapsstorage">
+<attribute name="type">
+<value>storage</value>
+</attribute>
+<element name="source">
+<element name="block">
+<ref name="absFilePath"/>
+</element>
+</element>
+</define>
+
<define name="usbproduct">
<element name="vendor">
<attribute name="id">
diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index 939d213..e61eabe 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -260,42 +260,72 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev,
virt = "?";
}
- switch (hostdev->source.subsys.type) {
- case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
- if (virAsprintf(&address, "%.4x:%.2x:%.2x.%.1x",
- hostdev->source.subsys.u.pci.domain,
- hostdev->source.subsys.u.pci.bus,
- hostdev->source.subsys.u.pci.slot,
- hostdev->source.subsys.u.pci.function)< 0) {
+ switch (hostdev->mode) {
+ case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
+ switch (hostdev->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+ if (virAsprintf(&address, "%.4x:%.2x:%.2x.%.1x",
+ hostdev->source.subsys.u.pci.domain,
+ hostdev->source.subsys.u.pci.bus,
+ hostdev->source.subsys.u.pci.slot,
+ hostdev->source.subsys.u.pci.function)< 0) {
+ VIR_WARN("OOM while encoding audit message");
+ goto cleanup;
+ }
+ break;
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ if (virAsprintf(&address, "%.3d.%.3d",
+ hostdev->source.subsys.u.usb.bus,
+ hostdev->source.subsys.u.usb.device)< 0) {
+ VIR_WARN("OOM while encoding audit message");
+ goto cleanup;
+ }
+ break;
+ default:
+ VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
+ hostdev->source.subsys.type);
+ goto cleanup;
+ }
+
+ if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) {
VIR_WARN("OOM while encoding audit message");
goto cleanup;
}
+
+ VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
+ "virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s",
+ virt, reason, vmname, uuidstr,
+ virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type),
+ device);
break;
- case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- if (virAsprintf(&address, "%.3d.%.3d",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device)< 0) {
- VIR_WARN("OOM while encoding audit message");
+
+ case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
+ switch (hostdev->source.caps.type) {
+ case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+ if (!(device = virAuditEncode("disk",
+ VIR_AUDIT_STR(hostdev->source.caps.u.storage.block)))) {
+ VIR_WARN("OOM while encoding audit message");
+ goto cleanup;
+ }
+
+ VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
+ "virt=%s resrc=hostdev reason=%s %s uuid=%s %s",
+ virt, reason, vmname, uuidstr, device);
+ break;
+
+ default:
+ VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
+ hostdev->source.caps.type);
goto cleanup;
}
break;
- default:
- VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
- hostdev->source.subsys.type);
- goto cleanup;
- }
- if (!(device = virAuditEncode("device", VIR_AUDIT_STR(address)))) {
- VIR_WARN("OOM while encoding audit message");
+ default:
+ VIR_WARN("Unexpected hostdev mode while cndoing audit message: %d",
+ hostdev->mode);
goto cleanup;
}
- VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
- "virt=%s resrc=dev reason=%s %s uuid=%s bus=%s %s",
- virt, reason, vmname, uuidstr,
- virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type),
- device);
-
cleanup:
VIR_FREE(vmname);
VIR_FREE(device);
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index dd0e841..d97bbc8 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -530,12 +530,16 @@ VIR_ENUM_IMPL(virDomainGraphicsSpiceClipboardCopypaste,
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
"subsystem",
- "capabilities")
+ "capabilities");
VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
"usb",
"pci")
+VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
+ "storage",
+ "misc")
+
VIR_ENUM_IMPL(virDomainPciRombarMode,
VIR_DOMAIN_PCI_ROMBAR_LAST,
"default",
@@ -1440,6 +1444,17 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
*/
if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
virDomainDeviceInfoFree(def->info);
+
+ if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
+ switch (def->source.caps.type) {
+ case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
+ VIR_FREE(def->source.caps.u.storage.block);
+ break;
+ case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
+ VIR_FREE(def->source.caps.u.misc.chardev);
+ break;
+ }
+ }
}
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
@@ -3026,6 +3041,71 @@ error:
return ret;
}
+static int
+virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
+ xmlXPathContextPtr ctxt,
+ const char *type,
+ virDomainHostdevDefPtr def)
+{
+ xmlNodePtr sourcenode;
+ int ret = -1;
+
+ /* @type is passed in from the caller rather than read from the
+ * xml document, because it is specified in different places for
+ * different kinds of defs - it is an attribute of
+ *<source>/<address> for an intelligent hostdev (<interface>),
+ * but an attribute of the toplevel element for a standard
+ *<hostdev>. (the functions we're going to call expect address
+ * type to already be known).