[libvirt] [PATCH] Added QEMU support for IVSHMEM devices

Shawn Furrow sfurrow at vt.edu
Mon Sep 24 15:44:10 UTC 2012


*Created at Virginia Tech's Systems Software Research Group

This patch adds the XML schema and implementation for IVSHMEM device driver     
support. Currently it defaults to using interrupts. A sample IVSHMEM entry     
in the VM's XML file is:

<ivshmem id='nahanni' size='16834' path='/tmp/'/>

---
 docs/schemas/domaincommon.rng |   17 +++++
 src/conf/domain_conf.c        |  152 ++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h        |   16 ++++-
 src/qemu/qemu_command.c       |   75 ++++++++++++++++++++
 src/qemu/qemu_command.h       |    6 ++
 5 files changed, 264 insertions(+), 2 deletions(-)

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index f47fdad..ddf8eb1 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2576,6 +2576,23 @@
       </optional>
     </element>
   </define>
+  <define name="ivshmem">
+    <element name="ivshmem">
+      <attribute name="id">
+        <ref name="deviceName">
+      </attribute>
+      <optional>
+        <attribute name="size">
+          <ref name="memoryKB">
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="path">
+          <ref name="filePath">
+        </attribute>
+      </optional>
+    </element>
+  </define>
   <define name="parallel">
     <element name="parallel">
       <ref name="qemucdev"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 4aa08d0..0cd2f98 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -156,7 +156,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "redirdev",
               "smartcard",
               "chr",
-              "memballoon")
+              "memballoon",
+              "ivshmem")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -1374,6 +1375,16 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainIvshmemDefFree(virDomainIvshmemDefPtr def)
+{
+    if (!def)
+        return;
+
+    virDomainDeviceInfoClear(&def->info);
+
+    VIR_FREE(def);
+}
+
 void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
 {
     if (!def)
@@ -1707,6 +1718,8 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virDomainMemballoonDefFree(def->memballoon);
 
+    virDomainIvshmemDefFree(dev->ivshmem);
+
     for (i = 0; i < def->nseclabels; i++)
         virSecurityLabelDefFree(def->seclabels[i]);
     VIR_FREE(def->seclabels);
@@ -2136,6 +2149,12 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
         if (cb(def, &device, &def->memballoon->info, opaque) < 0)
             return -1;
     }
+    if (def->ivshmem) {
+        device.type = VIR_DOMAIN_DEVICE_IVSHMEM;
+        device.data.ivshmem = def->ivshmem;
+        if (cb(def, &device, &def->ivshmem->info, opaque) < 0)
+            return -1;
+    }
     device.type = VIR_DOMAIN_DEVICE_HUB;
     for (i = 0; i < def->nhubs ; i++) {
         device.data.hub = def->hubs[i];
@@ -6935,6 +6954,69 @@ error:
     goto cleanup;
 }
 
+static virDomainIvshmemDefPtr
+virDomainIvshmemDefParseXML(const xmlNodePtr node,
+                               unsigned int flags)
+{
+    char *id = NULL;
+    char *size = NULL;
+    char *path = NULL;
+    virDomainIvshmemDefPtr def;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    id = virXMLPropString(node, "id");
+    VIR_DEBUG("ivshmem: id = '%s'", id);
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("ivshmem id=' %s'"), id);
+    if (id == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("ERROR: ivshmem, id not defined' %s'"), id);
+        goto error;
+    }
+
+    def->id = id;
+    size = virXMLPropString(node, "size");
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("ivshmem size=' %s'"), size);
+
+    VIR_DEBUG("ivshmem: size = '%s'", size);
+    if (size) {
+        if (virStrToLong_i(size, NULL, 10, &def->size) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("cannot parse ivshmem size %s"), size);
+            VIR_FREE(size);
+            goto error;
+        }
+    } else {
+        def->size = 16834;
+    }
+
+    path = virXMLPropString(node, "path");
+    VIR_DEBUG("ivshmem: path = '%s'", path);
+    if (path == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("ERROR: ivshmem, path not defined' %s'"), path);
+        goto error;
+    }
+    def->path = path;
+
+    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+        goto error;
+
+cleanup:
+    VIR_FREE(size);
+    return def;
+
+error:
+    virDomainIvshmemDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
 static virSysinfoDefPtr
 virSysinfoParseXML(const xmlNodePtr node,
                   xmlXPathContextPtr ctxt)
@@ -9742,6 +9824,28 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
         }
     }
 
+    /* analysis of the ivshmem devices */
+    def->ivshmem = NULL;
+    if ((n = virXPathNodeSet("./devices/ivshmem", ctxt, &nodes)) < 0) {
+        goto error;
+    }
+
+    if (n > 0) {
+        virDomainIvshmemDefPtr ivshmem =
+            virDomainIvshmemDefParseXML(nodes[0], flags);
+        if (!ivshmem)
+            goto error;
+
+        def->ivshmem = ivshmem;
+        VIR_FREE(nodes);
+    } else if (def->virtType != VIR_DOMAIN_VIRT_QEMU) {
+        /* TODO: currently ivshmem only on QEMU */
+            virDomainIvshmemDefPtr ivshmem;
+            if (VIR_ALLOC(ivshmem) < 0)
+                goto no_memory;
+            def->ivshmem = 0;
+    }
+
     /* analysis of the hub devices */
     if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
         goto error;
@@ -12673,6 +12777,49 @@ virDomainMemballoonDefFormat(virBufferPtr buf,
     return 0;
 }
 
+
+static int
+virDomainIvshmemDefFormat(virBufferPtr buf,
+                            virDomainIvshmemDefPtr def,
+                             unsigned int flags)
+{
+    const char *id = def->id;
+    const char *path = def->path;
+
+    if (!id) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected ivshmem id =  %s"), def->id);
+        return -1;
+    }
+    if (!def->size) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected ivshmem size =  %d"), def->size);
+        return -1;
+    }
+
+    if (!path) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected ivshmem id =  %s"), def->path);
+        return -1;
+    }
+
+    virBufferAsprintf(buf, "    <ivshmem id='%s'", id);
+    virBufferAsprintf(buf, " size='%d'", def->size);
+    virBufferAsprintf(buf, " path='%s'", path);
+
+    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
+        virBufferAddLit(buf, ">\n");
+        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+            return -1;
+        virBufferAddLit(buf, "    </ivshmem>\n");
+    } else {
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    return 0;
+}
+
+
 static int
 virDomainSysinfoDefFormat(virBufferPtr buf,
                           virSysinfoDefPtr def)
@@ -13828,6 +13975,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
     if (def->memballoon)
         virDomainMemballoonDefFormat(buf, def->memballoon, flags);
 
+    if (def->ivshmem)
+        virDomainIvshmemDefFormat(buf, def->ivshmem, flags);
+
     virBufferAddLit(buf, "  </devices>\n");
 
     virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1a61318..78bdf84 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -114,6 +114,9 @@ typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
 typedef struct _virDomainSnapshotObjList virDomainSnapshotObjList;
 typedef virDomainSnapshotObjList *virDomainSnapshotObjListPtr;
 
+typedef struct _virDomainIvshmemDef virDomainIvshmemDef;
+typedef virDomainIvshmemDef *virDomainIvshmemDefPtr;
+
 /* Flags for the 'type' field in virDomainDeviceDef */
 typedef enum {
     VIR_DOMAIN_DEVICE_NONE = 0,
@@ -133,6 +136,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_SMARTCARD,
     VIR_DOMAIN_DEVICE_CHR,
     VIR_DOMAIN_DEVICE_MEMBALLOON,
+    VIR_DOMAIN_DEVICE_IVSHMEM,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -157,7 +161,8 @@ struct _virDomainDeviceDef {
         virDomainRedirdevDefPtr redirdev;
         virDomainSmartcardDefPtr smartcard;
         virDomainChrDefPtr chr;
-        virDomainMemballoonDefPtr memballoon;
+        virDomainMemballoonDefPtr memballoon,
+        virDomainIvshmemDefPtr ivshmem;
     } data;
 };
 
@@ -1344,6 +1349,12 @@ struct _virDomainMemballoonDef {
     virDomainDeviceInfo info;
 };
 
+struct _virDomainIvshmemDef {
+    char *id;
+    int size;
+    char *path;
+    virDomainDeviceInfo info;
+};
 
 enum virDomainSmbiosMode {
     VIR_DOMAIN_SMBIOS_NONE,
@@ -1752,6 +1763,7 @@ struct _virDomainDef {
     /* Only 1 */
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
+    virDomainIvshmemDefPtr ivshmem;
     virCPUDefPtr cpu;
     virSysinfoDefPtr sysinfo;
     virDomainRedirFilterDefPtr redirfilter;
@@ -1859,6 +1871,7 @@ int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src,
 void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
 void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
+void virDomainIvshmemDefFree(virDomainIvshmemDefPtr def);
 void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
 void virDomainVideoDefFree(virDomainVideoDefPtr def);
 virDomainHostdevDefPtr virDomainHostdevDefAlloc(void);
@@ -2194,6 +2207,7 @@ VIR_ENUM_DECL(virDomainSoundCodec)
 VIR_ENUM_DECL(virDomainSoundModel)
 VIR_ENUM_DECL(virDomainMemDump)
 VIR_ENUM_DECL(virDomainMemballoonModel)
+VIR_ENUM_DECL(virDomainIvshmemModel)
 VIR_ENUM_DECL(virDomainSmbiosMode)
 VIR_ENUM_DECL(virDomainWatchdogModel)
 VIR_ENUM_DECL(virDomainWatchdogAction)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index e7bb88e..6c66075 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -770,6 +770,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, qemuCapsPtr caps)
         if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0)
             goto no_memory;
     }
+    if (def->ivshmem) {
+        if (virAsprintf(&def->ivshmem->info.alias, "ivshmem%d", 0) < 0)
+            goto no_memory;
+    }
 
     return 0;
 
@@ -3245,6 +3249,58 @@ error:
     return NULL;
 }
 
+//adds the options for the "-device" portion of QEMU command line for ivshmem
+char *
+qemuBuildIvshmemDevStr(virDomainIvshmemDefPtr dev,
+                       qemuCapsPtr caps)
+{
+virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "ivshmem");
+    virBufferAsprintf(&buf, ",chardev=%s", dev->id);
+    virBufferAsprintf(&buf, ",size=%dm", dev->size/1024);
+    virBufferAsprintf(&buf, ",ioeventfd=on");
+    virBufferAsprintf(&buf, ",vectors=8");
+    //virBufferAsprintf(&buf, ",shm=%s", dev->id);
+    if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+//adds the options for the "-chardev" portion of QEMU command line for ivshmem
+char *
+qemuBuildIvshmemCharDevStr(virDomainIvshmemDefPtr dev,
+                           qemuCapsPtr caps)
+{
+virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "socket");
+    virBufferAsprintf(&buf, ",id=%s", dev->id);
+    virBufferAsprintf(&buf, ",path=%s%s", dev->path,dev->id);
+    if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
 
 char *
 qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
@@ -6582,6 +6638,25 @@ qemuBuildCommandLine(virConnectPtr conn,
         }
     }
 
+    // adds ivshmem QEMU command line entries
+    if ((def->ivshmem) && (def->ivshmem->id != NULL)) {
+        char *optstr;
+        virCommandAddArg(cmd, "-chardev");
+        optstr = qemuBuildIvshmemCharDevStr(def->ivshmem, caps);
+        if (!optstr)
+            goto error;
+        virCommandAddArg(cmd, optstr);
+
+        optstr = NULL;
+
+        virCommandAddArg(cmd, "-device");
+        optstr = qemuBuildIvshmemDevStr(def->ivshmem, caps);
+        if (!optstr)
+            goto error;
+        virCommandAddArg(cmd, optstr);
+        VIR_FREE(optstr);
+    }
+
     if (snapshot)
         virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
 
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 939833d..80e7565 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -118,6 +118,12 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
 char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
                                  qemuCapsPtr caps);
 
+char * qemuBuildIvshmemDevStr(virDomainIvshmemDefPtr dev,
+                              qemuCapsPtr caps);
+
+char * qemuBuildIvshmemCharDevStr(virDomainIvshmemDefPtr dev,
+                                  qemuCapsPtr caps);
+
 char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
                                qemuCapsPtr caps);
 
-- 
1.7.0.4




More information about the libvir-list mailing list