[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH]: hostdev passthrough support take #3



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]