*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