[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[libvirt] [PATCH]: hostdev passthrough support take #3
- From: Guido Günther <agx sigxcpu org>
- To: "Daniel P. Berrange" <berrange redhat com>
- Cc: libvir-list redhat com
- Subject: [libvirt] [PATCH]: hostdev passthrough support take #3
- Date: Thu, 7 Aug 2008 18:25:56 +0200
Hi,
attached is version three of the hostdev passthrough patch. It adds:
* code to format the XML for output
* RelaxNG schema update
* testcases
Cheers,
-- Guido
>From cfcfc85accdcc7be7a5fbfd2c8dde435646d5ab2 Mon Sep 17 00:00:00 2001
From: Guido Guenther <agx sigxcpu org>
Date: Fri, 25 Jul 2008 15:18:16 -0400
Subject: [PATCH] hostdev: pass host devices to the guest
current implementation allows to pass on usb devices to qemu/kvm
---
src/domain_conf.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/domain_conf.h | 51 ++++++++++
src/qemu_conf.c | 29 ++++++
src/qemu_driver.c | 110 ++++++++++++++++------
4 files changed, 430 insertions(+), 28 deletions(-)
diff --git a/src/domain_conf.c b/src/domain_conf.c
index 4998a7d..922cf76 100644
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -131,6 +131,13 @@ VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
"sdl",
"vnc")
+VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
+ "subsystem",
+ "capabilities")
+
+VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
+ "usb",
+ "pci")
static void virDomainReportError(virConnectPtr conn,
int code, const char *fmt, ...)
@@ -332,6 +339,16 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
VIR_FREE(def);
}
+void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->target);
+ virDomainHostdevDefFree(def->next);
+ VIR_FREE(def);
+}
+
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
if (!def)
@@ -350,6 +367,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_SOUND:
virDomainSoundDefFree(def->data.sound);
break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ virDomainHostdevDefFree(def->data.hostdev);
+ break;
}
VIR_FREE(def);
@@ -369,7 +389,7 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainChrDefFree(def->parallels);
virDomainChrDefFree(def->console);
virDomainSoundDefFree(def->sounds);
-
+ virDomainHostdevDefFree(def->hostdevs);
VIR_FREE(def->os.type);
VIR_FREE(def->os.arch);
@@ -1400,6 +1420,180 @@ error:
goto cleanup;
}
+static int
+virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
+ const xmlNodePtr node,
+ virDomainHostdevDefPtr def) {
+
+ int ret = -1;
+ xmlNodePtr cur;
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "vendor")) {
+ char *vendor = virXMLPropString(cur, "id");
+
+ if (vendor) {
+ if (virStrToLong_ui(vendor, NULL, 0,
+ &def->source.subsys.usb.vendor) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse vendor id %s"), vendor);
+ VIR_FREE(vendor);
+ goto out;
+ }
+ VIR_FREE(vendor);
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb vendor needs id"));
+ goto out;
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
+ char* product = virXMLPropString(cur, "id");
+
+ if (product) {
+ if (virStrToLong_ui(product, NULL, 0,
+ &def->source.subsys.usb.product) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse product %s"), product);
+ VIR_FREE(product);
+ goto out;
+ }
+ VIR_FREE(product);
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb product needs id"));
+ goto out;
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
+ char *bus, *device;
+
+ bus = virXMLPropString(cur, "bus");
+ if (bus) {
+ if (virStrToLong_ui(bus, NULL, 0,
+ &def->source.subsys.usb.bus) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse bus %s"), bus);
+ VIR_FREE(bus);
+ goto out;
+ }
+ VIR_FREE(bus);
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb address needs bus id"));
+ goto out;
+ }
+
+ device = virXMLPropString(cur, "device");
+ if (device) {
+ if (virStrToLong_ui(device, NULL, 0,
+ &def->source.subsys.usb.device) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse device %s"),
+ device);
+ VIR_FREE(device);
+ goto out;
+ }
+ VIR_FREE(device);
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb address needs device id"));
+ goto out;
+ }
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown usb source type '%s'"), cur->name);
+ goto out;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (def->source.subsys.usb.vendor == 0 &&
+ def->source.subsys.usb.product != 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing vendor"));
+ goto out;
+ }
+ if (def->source.subsys.usb.vendor != 0 &&
+ def->source.subsys.usb.product == 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing product"));
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+static virDomainHostdevDefPtr
+virDomainHostdevDefParseXML(virConnectPtr conn,
+ const xmlNodePtr node) {
+
+ xmlNodePtr cur;
+ virDomainHostdevDefPtr def;
+ char *mode, *type = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+ def->target = NULL;
+
+ mode = virXMLPropString(node, "mode");
+ if (mode) {
+ if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown hostdev mode '%s'"), mode);
+ goto error;
+ }
+ } else {
+ def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type) {
+ if ((def->source.subsys.type = virDomainHostdevSubsysTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown host device type '%s'"), type);
+ goto error;
+ }
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing type in hostdev"));
+ goto error;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+ if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ if (virDomainHostdevSubsysUsbDefParseXML(conn, cur, def) < 0)
+ goto error;
+ }
+ } else {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("uknown node %s"), cur->name);
+ }
+ }
+ cur = cur->next;
+ }
+
+cleanup:
+ VIR_FREE(type);
+ VIR_FREE(mode);
+ return def;
+
+error:
+ virDomainHostdevDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
static int virDomainLifecycleParseXML(virConnectPtr conn,
xmlXPathContextPtr ctxt,
@@ -1471,6 +1665,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
dev->type = VIR_DOMAIN_DEVICE_SOUND;
if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node)))
goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
+ dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
+ if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node)))
+ goto error;
} else {
virDomainReportError(conn, VIR_ERR_XML_ERROR,
"%s", _("unknown device type"));
@@ -1965,6 +2163,22 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
}
VIR_FREE(nodes);
+ /* analysis of the host devices */
+ if ((n = virXPathNodeSet(conn, "./devices/hostdev", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract host devices"));
+ goto error;
+ }
+ for (i = 0 ; i < n ; i++) {
+ virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(conn, nodes[i]);
+ if (!hostdev)
+ goto error;
+
+ hostdev->next = def->hostdevs;
+ def->hostdevs = hostdev;
+ }
+ VIR_FREE(nodes);
+
return def;
error:
@@ -2706,6 +2920,50 @@ virDomainGraphicsDefFormat(virConnectPtr conn,
return 0;
}
+
+static int
+virDomainHostdevDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainHostdevDefPtr def)
+{
+ const char *mode = virDomainHostdevModeTypeToString(def->mode);
+ const char *type;
+
+ if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected hostdev mode %d"), def->mode);
+ return -1;
+ }
+
+ type = virDomainHostdevSubsysTypeToString(def->source.subsys.type);
+ if (!type || def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected hostdev type %d"),
+ def->source.subsys.type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <hostdev mode='%s' type='%s'>\n", mode, type);
+ virBufferAddLit(buf, " <source>\n");
+
+ if (def->source.subsys.usb.vendor) {
+ virBufferVSprintf(buf, " <vendor id='0x%.4x'/>\n",
+ def->source.subsys.usb.vendor);
+ virBufferVSprintf(buf, " <product id='0x%.4x'/>\n",
+ def->source.subsys.usb.product);
+ } else {
+ virBufferVSprintf(buf, " <address bus='%d' device='%d'/>\n",
+ def->source.subsys.usb.bus,
+ def->source.subsys.usb.device);
+ }
+
+ virBufferAddLit(buf, " </source>\n");
+ virBufferAddLit(buf, " </hostdev>\n");
+
+ return 0;
+}
+
+
char *virDomainDefFormat(virConnectPtr conn,
virDomainDefPtr def,
int flags)
@@ -2719,6 +2977,7 @@ char *virDomainDefFormat(virConnectPtr conn,
virDomainSoundDefPtr sound;
virDomainInputDefPtr input;
virDomainChrDefPtr chr;
+ virDomainHostdevDefPtr hostdev;
const char *type = NULL, *tmp;
int n, allones = 1;
@@ -2931,6 +3190,13 @@ char *virDomainDefFormat(virConnectPtr conn,
sound = sound->next;
}
+ hostdev = def->hostdevs;
+ while (hostdev) {
+ if (virDomainHostdevDefFormat(conn, &buf, hostdev) < 0)
+ goto cleanup;
+ hostdev = hostdev->next;
+ }
+
virBufferAddLit(&buf, " </devices>\n");
virBufferAddLit(&buf, "</domain>\n");
diff --git a/src/domain_conf.h b/src/domain_conf.h
index 527dc71..8a9d1db 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -279,7 +279,52 @@ struct _virDomainGraphicsDef {
} data;
};
+enum virDomainHostdevMode {
+ VIR_DOMAIN_HOSTDEV_MODE_SUBSYS,
+ VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES,
+ VIR_DOMAIN_HOSTDEV_MODE_LAST,
+};
+
+enum virDomainHostdevSubsysType {
+ VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB,
+ VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI,
+
+ VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
+};
+
+typedef struct _virDomainHostdevDef virDomainHostdevDef;
+typedef virDomainHostdevDef *virDomainHostdevDefPtr;
+struct _virDomainHostdevDef {
+ int mode; /* enum virDomainHostdevMode */
+ union {
+ struct {
+ int type; /* enum virDomainHostdevBusType */
+ union {
+ struct {
+ unsigned bus;
+ unsigned device;
+
+ unsigned vendor;
+ unsigned product;
+ } usb;
+ struct {
+ unsigned domain;
+ unsigned bus;
+ unsigned slot;
+ unsigned function;
+ } pci;
+ };
+ } subsys;
+ struct {
+ /* TBD: struct capabilities see:
+ * https://www.redhat.com/archives/libvir-list/2008-July/msg00429.html
+ */
+ } caps;
+ } source;
+ char* target;
+ virDomainHostdevDefPtr next;
+};
/* Flags for the 'type' field in next struct */
enum virDomainDeviceType {
@@ -288,6 +333,7 @@ enum virDomainDeviceType {
VIR_DOMAIN_DEVICE_NET,
VIR_DOMAIN_DEVICE_INPUT,
VIR_DOMAIN_DEVICE_SOUND,
+ VIR_DOMAIN_DEVICE_HOSTDEV,
};
typedef struct _virDomainDeviceDef virDomainDeviceDef;
@@ -300,6 +346,7 @@ struct _virDomainDeviceDef {
virDomainNetDefPtr net;
virDomainInputDefPtr input;
virDomainSoundDefPtr sound;
+ virDomainHostdevDefPtr hostdev;
} data;
};
@@ -386,6 +433,7 @@ struct _virDomainDef {
virDomainNetDefPtr nets;
virDomainInputDefPtr inputs;
virDomainSoundDefPtr sounds;
+ virDomainHostdevDefPtr hostdevs;
virDomainChrDefPtr serials;
virDomainChrDefPtr parallels;
virDomainChrDefPtr console;
@@ -441,6 +489,7 @@ void virDomainFSDefFree(virDomainFSDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
+void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
void virDomainDefFree(virDomainDefPtr vm);
void virDomainObjFree(virDomainObjPtr vm);
@@ -515,6 +564,8 @@ VIR_ENUM_DECL(virDomainFS)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainHostdevMode)
+VIR_ENUM_DECL(virDomainHostdevSubsys)
VIR_ENUM_DECL(virDomainInput)
VIR_ENUM_DECL(virDomainInputBus)
VIR_ENUM_DECL(virDomainGraphics)
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index f5d12c7..46bb9f4 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -723,6 +723,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
virDomainNetDefPtr net = vm->def->nets;
virDomainInputDefPtr input = vm->def->inputs;
virDomainSoundDefPtr sound = vm->def->sounds;
+ virDomainHostdevDefPtr hostdev = vm->def->hostdevs;
virDomainChrDefPtr serial = vm->def->serials;
virDomainChrDefPtr parallel = vm->def->parallels;
struct utsname ut;
@@ -1152,6 +1153,34 @@ int qemudBuildCommandLine(virConnectPtr conn,
ADD_ARG(modstr);
}
+ /* Add host passthrough hardware */
+ while (hostdev) {
+ int ret;
+ char* usbdev;
+
+ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ if(hostdev->source.subsys.usb.vendor) {
+ ret = asprintf(&usbdev, "host:%.4x:%.4x",
+ hostdev->source.subsys.usb.vendor,
+ hostdev->source.subsys.usb.product);
+
+ } else {
+ ret = asprintf(&usbdev, "host:%.3d.%.3d",
+ hostdev->source.subsys.usb.bus,
+ hostdev->source.subsys.usb.device);
+ }
+ if (ret < 0) {
+ usbdev = NULL;
+ goto error;
+ }
+ ADD_ARG_LIT("-usbdevice");
+ ADD_ARG_LIT(usbdev);
+ VIR_FREE(usbdev);
+ }
+ hostdev = hostdev->next;
+ }
+
if (migrateFrom) {
ADD_ARG_LIT("-incoming");
ADD_ARG_LIT(migrateFrom);
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 7fe3903..ef4e158 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -2951,12 +2951,83 @@ static int qemudDomainChangeCDROM(virDomainPtr dom,
return 0;
}
+static int qemudDomainAttachCdromDevice(virDomainPtr dom,
+ virDomainDeviceDefPtr dev)
+{
+ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+ virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid);
+ virDomainDiskDefPtr disk;
+
+ disk = vm->def->disks;
+ while (disk) {
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ STREQ(disk->dst, dev->data.disk->dst))
+ break;
+ disk = disk->next;
+ }
+
+ if (!disk) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ "%s", _("CDROM not attached, cannot change media"));
+ return -1;
+ }
+
+ if (qemudDomainChangeCDROM(dom, vm, disk, dev->data.disk) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static int qemudDomainAttachHostDevice(virDomainPtr dom, virDomainDeviceDefPtr dev)
+{
+ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+ virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid);
+ int ret;
+ char *cmd, *reply;
+
+ if (dev->data.hostdev->source.subsys.usb.vendor) {
+ ret = asprintf(&cmd, "usb_add host:%.4x:%.4x",
+ dev->data.hostdev->source.subsys.usb.vendor,
+ dev->data.hostdev->source.subsys.usb.product);
+ } else {
+ ret = asprintf(&cmd, "usb_add host:%.3d.%.3d",
+ dev->data.hostdev->source.subsys.usb.bus,
+ dev->data.hostdev->source.subsys.usb.device);
+ }
+ if (ret == -1) {
+ qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+ return -1;
+ }
+
+ if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s", _("cannot attach usb device"));
+ VIR_FREE(cmd);
+ return -1;
+ }
+
+ DEBUG ("attach_usb reply: %s", reply);
+ /* If the command failed qemu prints:
+ * Could not add ... */
+ if (strstr(reply, "Could not add ")) {
+ qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s",
+ _("adding usb device failed"));
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+ return -1;
+ }
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+ return 0;
+}
+
static int qemudDomainAttachDevice(virDomainPtr dom,
const char *xml) {
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid);
virDomainDeviceDefPtr dev;
- virDomainDiskDefPtr disk;
+ int ret = 0;
if (!vm) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
@@ -2975,36 +3046,21 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
return -1;
}
- if (dev->type != VIR_DOMAIN_DEVICE_DISK ||
- dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
- qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
- "%s", _("only CDROM disk devices can be attached"));
- VIR_FREE(dev);
- return -1;
- }
-
- disk = vm->def->disks;
- while (disk) {
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
- STREQ(disk->dst, dev->data.disk->dst))
- break;
- disk = disk->next;
- }
-
- if (!disk) {
+ if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
+ dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+ ret = qemudDomainAttachCdromDevice(dom, dev);
+ } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
+ dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+ ret = qemudDomainAttachHostDevice(dom, dev);
+ } else {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
- "%s", _("CDROM not attached, cannot change media"));
- VIR_FREE(dev);
- return -1;
- }
-
- if (qemudDomainChangeCDROM(dom, vm, disk, dev->data.disk) < 0) {
- VIR_FREE(dev);
- return -1;
+ "%s", _("this devicetype cannnot be attached"));
+ ret = -1;
}
VIR_FREE(dev);
- return 0;
+ return ret;
}
static int qemudDomainGetAutostart(virDomainPtr dom,
--
1.5.6.3
>From 5e54098602f4585f60c1a2543189f08bd70c02c1 Mon Sep 17 00:00:00 2001
From: Guido Guenther <agx sigxcpu org>
Date: Thu, 7 Aug 2008 12:46:55 +0200
Subject: [PATCH] hostdev: add RNG schema
---
docs/libvirt.rng | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/docs/libvirt.rng b/docs/libvirt.rng
index cd5d798..60e181f 100644
--- a/docs/libvirt.rng
+++ b/docs/libvirt.rng
@@ -848,6 +848,57 @@
</element>
</define>
+ <define name='hostdev'>
+ <element name='hostdev'>
+ <optional>
+ <attribute name='mode'>
+ <choice>
+ <value>subsystem</value>
+ <value>capabilities</value>
+ </choice>
+ </attribute>
+ <attribute name='type'>
+ <choice>
+ <value>usb</value>
+ <value>pci</value>
+ </choice>
+ </attribute>
+ </optional>
+ <group>
+ <element name='source'>
+ <choice>
+ <ref name="usbproduct"/>
+ <ref name="usbaddress"/>
+ </choice>
+ </element>
+ </group>
+ </element>
+ </define>
+
+ <define name="usbproduct">
+ <element name="vendor">
+ <attribute name="id">
+ <ref name="usbId"/>
+ </attribute>
+ </element>
+ <element name="product">
+ <attribute name="id">
+ <ref name="usbId"/>
+ </attribute>
+ </element>
+ </define>
+
+ <define name="usbaddress">
+ <element name="address">
+ <attribute name="bus">
+ <ref name="usbAddr"/>
+ </attribute>
+ <attribute name="device">
+ <ref name="usbAddr"/>
+ </attribute>
+ </element>
+ </define>
+
<!--
Devices attached to a domain.
-->
@@ -868,6 +919,7 @@
<ref name='parallel'/>
<ref name='serial'/>
<ref name='input'/>
+ <ref name='hostdev'/>
</choice>
</zeroOrMore>
</interleave>
@@ -986,4 +1038,14 @@
<param name="pattern">([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9]</param>
</data>
</define>
+ <define name='usbId'>
+ <data type='string'>
+ <param name="pattern">(0x)?[0-9a-fA-F]{1,4}</param>
+ </data>
+ </define>
+ <define name='usbAddr'>
+ <data type='string'>
+ <param name="pattern">(0x)?[0-9a-fA-F]{1,3}</param>
+ </data>
+ </define>
</grammar>
--
1.5.6.3
>From 6fd13e2faa49eadf2db4a7e4a3a28192b4c61622 Mon Sep 17 00:00:00 2001
From: Guido Guenther <agx sigxcpu org>
Date: Thu, 7 Aug 2008 14:25:50 +0200
Subject: [PATCH] hostdev: add testcases
---
.../qemuxml2argv-hostdev-usb-address.args | 1 +
.../qemuxml2argv-hostdev-usb-address.xml | 27 +++++++++++++++++++
.../qemuxml2argv-hostdev-usb-product.args | 1 +
.../qemuxml2argv-hostdev-usb-product.xml | 28 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 3 ++
tests/qemuxml2xmltest.c | 3 ++
6 files changed, 63 insertions(+), 0 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args
new file mode 100644
index 0000000..0b89999
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.args
@@ -0,0 +1 @@
+/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice host:014.006
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml
new file mode 100644
index 0000000..0c044e1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-address.xml
@@ -0,0 +1,27 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219200</memory>
+ <currentMemory>219200</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ </disk>
+ <hostdev mode='subsystem' type='usb'>
+ <source>
+ <address bus='14' device='6'/>
+ </source>
+ </hostdev>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args
new file mode 100644
index 0000000..b993ae5
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.args
@@ -0,0 +1 @@
+/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice host:0204:6025
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml
new file mode 100644
index 0000000..aecad4c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-usb-product.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219200</memory>
+ <currentMemory>219200</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ </disk>
+ <hostdev mode='subsystem' type='usb'>
+ <source>
+ <vendor id='0x0204'/>
+ <product id='0x6025'/>
+ </source>
+ </hostdev>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index d136a13..458201b 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -179,6 +179,9 @@ mymain(int argc, char **argv)
DO_TEST("console-compat", 0);
DO_TEST("sound", 0);
+ DO_TEST("hostdev-usb-product", 0);
+ DO_TEST("hostdev-usb-address", 0);
+
virCapabilitiesFree(driver.caps);
return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 9e380e4..536c9bd 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -118,6 +118,9 @@ mymain(int argc, char **argv)
DO_TEST("parallel-tcp");
DO_TEST("console-compat");
+ DO_TEST("hostdev-usb-product");
+ DO_TEST("hostdev-usb-address");
+
virCapabilitiesFree(driver.caps);
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
--
1.5.6.3
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]