mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
Add support for <hostdev mode="capabilities">
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 assigning 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/input/event3</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@redhat.com>
This commit is contained in:
parent
347a712ab1
commit
aae0fc2a92
@ -2123,13 +2123,15 @@
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4><a name="elementsUSB">USB and PCI devices</a></h4>
|
||||
<h4><a name="elementsHostDev">Host device assignment</a></h4>
|
||||
|
||||
<h5><a href="elementsHostDevSubsys">USB / PCI devices</a></h5>
|
||||
|
||||
<p>
|
||||
USB and PCI devices attached to the host can be passed through
|
||||
to the guest using
|
||||
the <code>hostdev</code> element. <span class="since">since after
|
||||
0.4.4 for USB and 0.6.0 for PCI (KVM only)</span>:
|
||||
to the guest using the <code>hostdev</code> element.
|
||||
<span class="since">since after 0.4.4 for USB and 0.6.0 for PCI
|
||||
(KVM only)</span>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@ -2247,6 +2249,51 @@
|
||||
more details on the address element.
|
||||
</dl>
|
||||
|
||||
|
||||
<h5><a href="elementsHostDevCaps">Block / character devices</a></h5>
|
||||
|
||||
<p>
|
||||
Block / character devices from the host can be passed through
|
||||
to the guest using the <code>hostdev</code> element. This is
|
||||
only possible with container based virtualization.
|
||||
<span class="since">since after 1.0.1 for LXC</span>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
<hostdev mode='capabilities' type='storage'>
|
||||
<source>
|
||||
<block>/dev/sdf1</block>
|
||||
</source>
|
||||
</hostdev>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
...
|
||||
<hostdev mode='capabilities' type='misc'>
|
||||
<source>
|
||||
<char>/dev/input/event3</char>
|
||||
</source>
|
||||
</hostdev>
|
||||
...
|
||||
</pre>
|
||||
|
||||
<dl>
|
||||
<dt><code>hostdev</code></dt>
|
||||
<dd>The <code>hostdev</code> element is the main container for describing
|
||||
host devices. For block/character device passthrough <code>mode</code> is
|
||||
always "capabilities" and <code>type</code> is "block" for a block
|
||||
device and "char" for a character device.
|
||||
</dd>
|
||||
<dt><code>source</code></dt>
|
||||
<dd>The source element describes the device as seen from the host.
|
||||
For block devices, the path to the block device in the host
|
||||
OS is provided in the nested "block" element, while for character
|
||||
devices the "char" element is used
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4><a name="elementsRedir">Redirected devices</a></h4>
|
||||
|
||||
<p>
|
||||
|
@ -2834,63 +2834,123 @@
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="hostdev">
|
||||
<element name="hostdev">
|
||||
<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>
|
||||
</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>
|
||||
<choice>
|
||||
<group>
|
||||
<ref name="hostdevsubsys"/>
|
||||
</group>
|
||||
<group>
|
||||
<ref name="hostdevcaps"/>
|
||||
</group>
|
||||
</choice>
|
||||
<optional>
|
||||
<ref name="alias"/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="address"/>
|
||||
<ref name="deviceBoot"/>
|
||||
</optional>
|
||||
<optional>
|
||||
<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>
|
||||
<group>
|
||||
<ref name="hostdevcapsmisc"/>
|
||||
</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="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="hostdevcapsmisc">
|
||||
<attribute name="type">
|
||||
<value>misc</value>
|
||||
</attribute>
|
||||
<element name="source">
|
||||
<element name="char">
|
||||
<ref name="absFilePath"/>
|
||||
</element>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="usbproduct">
|
||||
<element name="vendor">
|
||||
<attribute name="id">
|
||||
|
@ -260,42 +260,84 @@ 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;
|
||||
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
||||
if (!(device = virAuditEncode("chardev",
|
||||
VIR_AUDIT_STR(hostdev->source.caps.u.misc.chardev)))) {
|
||||
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);
|
||||
VIR_WARN("Unexpected hostdev mode while encoding audit message: %d",
|
||||
hostdev->mode);
|
||||
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);
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(vmname);
|
||||
VIR_FREE(device);
|
||||
|
@ -536,6 +536,10 @@ 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",
|
||||
@ -1442,6 +1446,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)
|
||||
@ -3028,6 +3043,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).
|
||||
*/
|
||||
if (type) {
|
||||
if ((def->source.caps.type
|
||||
= virDomainHostdevCapsTypeFromString(type)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("unknown host device source address type '%s'"),
|
||||
type);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
"%s", _("missing source address type"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(sourcenode = virXPathNode("./source", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("Missing <source> element in hostdev device"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (def->source.caps.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
||||
if (!(def->source.caps.u.storage.block =
|
||||
virXPathString("string(./source/block[1])", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("Missing <block> element in hostdev storage device"));
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
||||
if (!(def->source.caps.u.misc.chardev =
|
||||
virXPathString("string(./source/char[1])", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("Missing <char> element in hostdev character device"));
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("address type='%s' not supported in hostdev interfaces"),
|
||||
virDomainHostdevCapsTypeToString(def->source.caps.type));
|
||||
goto error;
|
||||
}
|
||||
ret = 0;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
virDomainDiskFindControllerModel(virDomainDefPtr def,
|
||||
virDomainDiskDefPtr disk,
|
||||
@ -7384,6 +7464,11 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
|
||||
if (virDomainHostdevDefParseXMLSubsys(node, ctxt, type, def, flags) < 0)
|
||||
goto error;
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
||||
/* parse managed/mode/type, and the <source> element */
|
||||
if (virDomainHostdevDefParseXMLCaps(node, ctxt, type, def) < 0)
|
||||
goto error;
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unexpected hostdev mode %d"), def->mode);
|
||||
@ -7940,6 +8025,41 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainHostdevMatchCapsStorage(virDomainHostdevDefPtr a,
|
||||
virDomainHostdevDefPtr b)
|
||||
{
|
||||
return STREQ_NULLABLE(a->source.caps.u.storage.block,
|
||||
b->source.caps.u.storage.block);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainHostdevMatchCapsMisc(virDomainHostdevDefPtr a,
|
||||
virDomainHostdevDefPtr b)
|
||||
{
|
||||
return STREQ_NULLABLE(a->source.caps.u.misc.chardev,
|
||||
b->source.caps.u.misc.chardev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainHostdevMatchCaps(virDomainHostdevDefPtr a,
|
||||
virDomainHostdevDefPtr b)
|
||||
{
|
||||
if (a->source.caps.type != b->source.caps.type)
|
||||
return 0;
|
||||
|
||||
switch (a->source.caps.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
||||
return virDomainHostdevMatchCapsStorage(a, b);
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
||||
return virDomainHostdevMatchCapsMisc(a, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainHostdevMatch(virDomainHostdevDefPtr a,
|
||||
virDomainHostdevDefPtr b)
|
||||
@ -7950,6 +8070,8 @@ virDomainHostdevMatch(virDomainHostdevDefPtr a,
|
||||
switch (a->mode) {
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
|
||||
return virDomainHostdevMatchSubsys(a, b);
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
||||
return virDomainHostdevMatchCaps(a, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -12516,6 +12638,35 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainHostdevDefFormatCaps(virBufferPtr buf,
|
||||
virDomainHostdevDefPtr def)
|
||||
{
|
||||
virBufferAddLit(buf, "<source>\n");
|
||||
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
switch (def->source.caps.type)
|
||||
{
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
||||
virBufferEscapeString(buf, "<block>%s</block>\n",
|
||||
def->source.caps.u.storage.block);
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
|
||||
virBufferEscapeString(buf, "<char>%s</char>\n",
|
||||
def->source.caps.u.misc.chardev);
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unexpected hostdev type %d"),
|
||||
def->source.caps.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
virBufferAddLit(buf, "</source>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainActualNetDefFormat(virBufferPtr buf,
|
||||
virDomainActualNetDefPtr def,
|
||||
@ -13588,14 +13739,28 @@ virDomainHostdevDefFormat(virBufferPtr buf,
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
||||
type = virDomainHostdevCapsTypeToString(def->source.caps.type);
|
||||
if (!type) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unexpected hostdev type %d"),
|
||||
def->source.caps.type);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unexpected hostdev mode %d"), def->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n",
|
||||
mode, type, def->managed ? "yes" : "no");
|
||||
virBufferAsprintf(buf, " <hostdev mode='%s' type='%s'",
|
||||
mode, type);
|
||||
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
virBufferAsprintf(buf, " managed='%s'>\n",
|
||||
def->managed ? "yes" : "no");
|
||||
else
|
||||
virBufferAddLit(buf, ">\n");
|
||||
|
||||
virBufferAdjustIndent(buf, 6);
|
||||
switch (def->mode) {
|
||||
@ -13603,6 +13768,10 @@ virDomainHostdevDefFormat(virBufferPtr buf,
|
||||
if (virDomainHostdevDefFormatSubsys(buf, def, flags, false) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
||||
if (virDomainHostdevDefFormatCaps(buf, def) < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
virBufferAdjustIndent(buf, -6);
|
||||
|
||||
|
@ -383,6 +383,29 @@ struct _virDomainHostdevSubsys {
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
enum virDomainHostdevCapsType {
|
||||
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE,
|
||||
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC,
|
||||
|
||||
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST
|
||||
};
|
||||
|
||||
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
|
||||
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
|
||||
struct _virDomainHostdevCaps {
|
||||
int type; /* enum virDOmainHostdevCapsType */
|
||||
union {
|
||||
struct {
|
||||
char *block;
|
||||
} storage;
|
||||
struct {
|
||||
char *chardev;
|
||||
} misc;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/* basic device for direct passthrough */
|
||||
struct _virDomainHostdevDef {
|
||||
virDomainDeviceDef parent; /* higher level Def containing this */
|
||||
@ -392,12 +415,7 @@ struct _virDomainHostdevDef {
|
||||
unsigned int missing : 1;
|
||||
union {
|
||||
virDomainHostdevSubsys subsys;
|
||||
struct {
|
||||
/* TBD: struct capabilities see:
|
||||
* https://www.redhat.com/archives/libvir-list/2008-July/msg00429.html
|
||||
*/
|
||||
int dummy;
|
||||
} caps;
|
||||
virDomainHostdevCaps caps;
|
||||
} source;
|
||||
virDomainHostdevOrigStates origstates;
|
||||
virDomainDeviceInfoPtr info; /* Guest address */
|
||||
@ -2246,6 +2264,7 @@ VIR_ENUM_DECL(virDomainWatchdogAction)
|
||||
VIR_ENUM_DECL(virDomainVideo)
|
||||
VIR_ENUM_DECL(virDomainHostdevMode)
|
||||
VIR_ENUM_DECL(virDomainHostdevSubsys)
|
||||
VIR_ENUM_DECL(virDomainHostdevCaps)
|
||||
VIR_ENUM_DECL(virDomainPciRombarMode)
|
||||
VIR_ENUM_DECL(virDomainHub)
|
||||
VIR_ENUM_DECL(virDomainRedirdevBus)
|
||||
|
@ -412,6 +412,7 @@ virDomainGraphicsSpiceZlibCompressionTypeToString;
|
||||
virDomainGraphicsTypeFromString;
|
||||
virDomainGraphicsTypeToString;
|
||||
virDomainHasDiskMirror;
|
||||
virDomainHostdevCapsTypeToString;
|
||||
virDomainHostdevDefAlloc;
|
||||
virDomainHostdevDefClear;
|
||||
virDomainHostdevDefFree;
|
||||
|
34
tests/lxcxml2xmldata/lxc-hostdev.xml
Normal file
34
tests/lxcxml2xmldata/lxc-hostdev.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<domain type='lxc'>
|
||||
<name>demo</name>
|
||||
<uuid>8369f1ac-7e46-e869-4ca5-759d51478066</uuid>
|
||||
<memory unit='KiB'>500000</memory>
|
||||
<currentMemory unit='KiB'>500000</currentMemory>
|
||||
<vcpu placement='static'>1</vcpu>
|
||||
<os>
|
||||
<type arch='x86_64'>exe</type>
|
||||
<init>/bin/sh</init>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<filesystem type='mount' accessmode='passthrough'>
|
||||
<source dir='/root/container'/>
|
||||
<target dir='/'/>
|
||||
</filesystem>
|
||||
<console type='pty'>
|
||||
<target type='lxc' port='0'/>
|
||||
</console>
|
||||
<hostdev mode='capabilities' type='storage'>
|
||||
<source>
|
||||
<block>/dev/sdf1</block>
|
||||
</source>
|
||||
</hostdev>
|
||||
<hostdev mode='capabilities' type='misc'>
|
||||
<source>
|
||||
<char>/dev/tty0</char>
|
||||
</source>
|
||||
</hostdev>
|
||||
</devices>
|
||||
</domain>
|
@ -121,6 +121,7 @@ mymain(void)
|
||||
setenv("PATH", "/bin", 1);
|
||||
|
||||
DO_TEST("systemd");
|
||||
DO_TEST("hostdev");
|
||||
|
||||
virCapabilitiesFree(caps);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user