On Fri, Aug 08, 2008 at 02:30:15PM +0200, Jim Meyering wrote: > Guido Günther <agx@xxxxxxxxxxx> wrote: [..snip..] > > +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; > > Check for vm == NULL before dereferencing it. > > ... > > +static int qemudDomainAttachHostDevice(virDomainPtr dom, virDomainDeviceDefPtr dev) > > +{ > > + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; > > + virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); > ... > > + if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) { > > Likewise. The same applies here: qemudDomainAttachDevice checked that already, but again - better safe than sorry. Updated patches attached. -- Guido
>From 137b82948a680a68c619ac2ccdb1afedecc046b4 Mon Sep 17 00:00:00 2001 From: Guido Guenther <agx@xxxxxxxxxxx> 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 | 118 ++++++++++++++++++----- 4 files changed, 440 insertions(+), 26 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..3c6d7c0 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2951,11 +2951,11 @@ static int qemudDomainChangeCDROM(virDomainPtr dom, return 0; } -static int qemudDomainAttachDevice(virDomainPtr dom, - const char *xml) { +static int qemudDomainAttachCdromDevice(virDomainPtr dom, + virDomainDeviceDefPtr dev) +{ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); - virDomainDeviceDefPtr dev; virDomainDiskDefPtr disk; if (!vm) { @@ -2964,25 +2964,6 @@ static int qemudDomainAttachDevice(virDomainPtr dom, return -1; } - if (!virDomainIsActive(vm)) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot attach device on inactive domain")); - return -1; - } - - dev = virDomainDeviceDefParse(dom->conn, vm->def, xml); - if (dev == NULL) { - 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 && @@ -2994,19 +2975,106 @@ static int qemudDomainAttachDevice(virDomainPtr dom, if (!disk) { 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; } + return 0; +} - VIR_FREE(dev); +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 (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "%s", _("no domain with matching uuid")); + return -1; + } + + 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; + int ret = 0; + + if (!vm) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + "%s", _("no domain with matching uuid")); + return -1; + } + + if (!virDomainIsActive(vm)) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot attach device on inactive domain")); + return -1; + } + + dev = virDomainDeviceDefParse(dom->conn, vm->def, xml); + if (dev == NULL) { + return -1; + } + + 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", _("this devicetype cannnot be attached")); + ret = -1; + } + + VIR_FREE(dev); + return ret; +} + static int qemudDomainGetAutostart(virDomainPtr dom, int *autostart) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; -- 1.5.6.3
>From 9e42a0b002e61f8d8beab0f9c44b200d788bca2c Mon Sep 17 00:00:00 2001 From: Guido Guenther <agx@xxxxxxxxxxx> 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 99b8d6ff1bef43ea6cacd544fa6158cdfb301a27 Mon Sep 17 00:00:00 2001 From: Guido Guenther <agx@xxxxxxxxxxx> 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
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list