"source id" must be specified for 'ivshmem' memory device, and
the size must be power of 2 in bytes (required by QEMU ivshmem
device).
"ivshmem" device is exposed to guest as a PCI device, so device
address is necessary.
* src/conf/domain_conf.h (New data struct for memory devices)
* src/conf/domain_conf.c (Implement functions to parse, format
memory device XML).
* src/util/util.h (Declare helper virIsPowerOfTwo)
* src/util/util.c (Implement virIsPowerOfTwo)
* src/src/libvirt_private.syms (Export the private symbols)
---
docs/formatdomain.html.in | 7 +-
docs/schemas/domaincommon.rng | 8 +-
src/conf/domain_conf.c | 195 ++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 27 ++++++
src/libvirt_private.syms | 3 +
src/util/util.c | 5 +
src/util/util.h | 2 +
7 files changed, 240 insertions(+), 7 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index dedfa17..4e8b0db 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4099,7 +4099,8 @@ qemu-kvm -net nic,model=? /dev/null
<pre>
...
<devices>
- <memory mode='ivshmem'>
+ <memory'>
+ <model type='ivshmem'/>
<source id='nahanni' path='/tmp/nahanni'/>
<size unit='KiB'>10240</size>
<ioeventfd/>
@@ -4110,8 +4111,8 @@ qemu-kvm -net nic,model=? /dev/null
<dl>
<dt><code>memory</code></dt>
<dd>
- The <code>memory</code> element has one mandatory attribute,
- <code>model</code>, its value can only be 'ivshmem'
currently.
+ The mandatory element <code>model</code> has one attribute,
+ <code>type</code>, its value can only be 'ivshmem'
currently.
The optional element <code>source</code> has two attributes.
Attribute <code>id</code> is mandatory, to specify the name of
the memory device; Attribute <code>path</code> specifies the socket
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a99a1d4..838efe0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2791,9 +2791,11 @@
<define name="memory">
<element name="memory">
<group>
- <attribute name="model">
- <value>ivshmem</value>
- </attribute>
+ <element name="model">
+ <attribute name="type">
+ <value>ivshmem</value>
+ </attribute>
+ </element>
<interleave>
<element name="source">
<attribute name="id">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 99f03a9..828228e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -670,6 +670,11 @@ VIR_ENUM_IMPL(virDomainNumatuneMemPlacementMode,
"static",
"auto");
+VIR_ENUM_IMPL(virDomainMemoryModel,
+ VIR_DOMAIN_MEMORY_MODEL_LAST,
+ "ivshmem");
+
+
#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
@@ -1382,6 +1387,26 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
VIR_FREE(def);
}
+static void
+virDomainMemoryDefFree(virDomainMemoryDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_IVSHMEM:
+ VIR_FREE(def->data.ivshmem.id);
+ VIR_FREE(def->data.ivshmem.path);
+ virDomainDeviceInfoClear(&def->data.ivshmem.info);
+ break;
+
+ default:
+ break;
+ }
+
+ VIR_FREE(def);
+}
+
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
if (!def)
@@ -1715,6 +1740,9 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainMemballoonDefFree(def->memballoon);
+ for (i = 0; i < def->nmemorys; i++)
+ virDomainMemoryDefFree(def->memorys[i]);
+
for (i = 0; i < def->nseclabels; i++)
virSecurityLabelDefFree(def->seclabels[i]);
VIR_FREE(def->seclabels);
@@ -6974,7 +7002,6 @@ error:
goto cleanup;
}
-
static virDomainMemballoonDefPtr
virDomainMemballoonDefParseXML(const xmlNodePtr node,
unsigned int flags)
@@ -7013,6 +7040,151 @@ error:
goto cleanup;
}
+static virDomainMemoryDefPtr
+virDomainMemoryDefParseXML(const xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ virDomainMemoryDefPtr def = NULL;
+ xmlNodePtr cur = NULL;
+ char *model = NULL;
+
+ xmlNodePtr oldnode = ctxt->node;
+ ctxt->node = node;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (!virXPathNode("./model", ctxt)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("memory model must be specified"));
+ goto cleanup;
+ }
+
+ if (!(model = virXPathString("string(./model/@type)", ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Memory model type must be specified"));
+ goto cleanup;
+ }
+
+ if ((def->model == virDomainMemoryModelTypeFromString(model)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unknown memory model '%s'"), model);
+ goto cleanup;
+ }
+
+ if ((def->model == VIR_DOMAIN_MEMORY_MODEL_IVSHMEM) &&
+ !virXPathNode("./source", ctxt)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("memory source must be specified"));
+ goto cleanup;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (def->model == VIR_DOMAIN_MEMORY_MODEL_IVSHMEM) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "model")) {
+ cur = cur->next;
+ continue;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+ if (!(def->data.ivshmem.id = virXMLPropString(cur,
"id"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("memory source id must be
specified"));
+ goto cleanup;
+ }
+ def->data.ivshmem.path = virXMLPropString(cur, "path");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "size")) {
+ if (virDomainParseScaledValue("./size[1]", ctxt,
+ &def->data.ivshmem.size, 1,
+ ULLONG_MAX, true) < 0)
+ goto cleanup;
+
+ if (!virIsPowerOfTwo(def->data.ivshmem.size)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("size for memory device must be "
+ "power of 2 in bytes"));
+ goto cleanup;
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "vectors")) {
+ if (virXPathUInt("string(./vectors)", ctxt,
+ &def->data.ivshmem.vectors) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Malformed vectors for memory
device"));
+ goto cleanup;
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "ioeventfd")) {
+ def->data.ivshmem.ioeventfd = true;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
+ cur = cur->next;
+ continue;
+ } else {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unknown XML for memory device
'%s'"),
+ cur->name);
+ goto cleanup;
+ }
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (def->model == VIR_DOMAIN_MEMORY_MODEL_IVSHMEM)
+ if (virDomainDeviceInfoParseXML(node, NULL,
+ &def->data.ivshmem.info, flags) < 0)
+ goto cleanup;
+
+ ctxt->node = oldnode;
+ VIR_FREE(model);
+ return def;
+
+cleanup:
+ ctxt->node = oldnode;
+ virDomainMemoryDefFree(def);
+ VIR_FREE(model);
+ return NULL;
+}
+
+static int
+virDomainMemoryDefFormat(virBufferPtr buf,
+ virDomainMemoryDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, " <memory>\n");
+
+ switch (def->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_IVSHMEM:
+ virBufferAsprintf(buf, " <model type='%s'/>\n",
+ virDomainMemoryModelTypeToString(def->model));
+ virBufferAsprintf(buf, " <source id='%s'",
def->data.ivshmem.id);
+ virBufferEscapeString(buf, " path='%s'",
def->data.ivshmem.path);
+ virBufferAddLit(buf, "/>\n");
+
+ virBufferAsprintf(buf, " <size
unit='bytes'>%llu</size>\n",
+ def->data.ivshmem.size);
+
+ if (def->data.ivshmem.vectors)
+ virBufferAsprintf(buf, "
<vectors>%u</vectors>\n",
+ def->data.ivshmem.vectors);
+ if (def->data.ivshmem.ioeventfd)
+ virBufferAddLit(buf, " <ioeventfd/>\n");
+
+
+ if (virDomainDeviceInfoFormat(buf, &def->data.ivshmem.info, flags) <
0)
+ return -1;
+
+ virBufferAddLit(buf, " </memory>\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt)
@@ -9987,6 +10159,22 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
}
}
+ /* analysis of the memory devices */
+ if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0) {
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->memorys, n) < 0)
+ goto no_memory;
+ for (i = 0 ; i < n ; i++) {
+ virDomainMemoryDefPtr memory = virDomainMemoryDefParseXML(nodes[i],
+ ctxt,
+ flags);
+ if (!memory)
+ goto error;
+ def->memorys[def->nmemorys++] = memory;
+ }
+ VIR_FREE(nodes);
+
/* analysis of the hub devices */
if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
goto error;
@@ -14149,6 +14337,11 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->memballoon)
virDomainMemballoonDefFormat(buf, def->memballoon, flags);
+ for (n = 0; n < def->nmemorys; n++) {
+ if (virDomainMemoryDefFormat(buf, def->memorys[n], flags) < 0)
+ goto cleanup;
+ }
+
virBufferAddLit(buf, " </devices>\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6539281..c959757 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -109,6 +109,9 @@ typedef virDomainChrDef *virDomainChrDefPtr;
typedef struct _virDomainMemballoonDef virDomainMemballoonDef;
typedef virDomainMemballoonDef *virDomainMemballoonDefPtr;
+typedef struct _virDomainMemoryDef virDomainMemoryDef;
+typedef virDomainMemoryDef *virDomainMemoryDefPtr;
+
typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
@@ -1350,6 +1353,26 @@ struct _virDomainMemballoonDef {
virDomainDeviceInfo info;
};
+enum virDomainMemoryModel {
+ VIR_DOMAIN_MEMORY_MODEL_IVSHMEM,
+
+ VIR_DOMAIN_MEMORY_MODEL_LAST,
+};
+
+struct _virDomainMemoryDef {
+ int model;
+
+ union {
+ struct {
+ char *id;
+ char *path;
+ unsigned long long size;
+ unsigned int vectors;
+ bool ioeventfd;
+ virDomainDeviceInfo info;
+ } ivshmem;
+ } data;
+};
enum virDomainSmbiosMode {
VIR_DOMAIN_SMBIOS_NONE,
@@ -1778,6 +1801,9 @@ struct _virDomainDef {
size_t nseclabels;
virSecurityLabelDefPtr *seclabels;
+ size_t nmemorys;
+ virDomainMemoryDefPtr *memorys;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2248,6 +2274,7 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode)
VIR_ENUM_DECL(virDomainNumatuneMemMode)
VIR_ENUM_DECL(virDomainNumatuneMemPlacementMode)
VIR_ENUM_DECL(virDomainHyperv)
+VIR_ENUM_DECL(virDomainMemoryModel)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5a07139..e29af26 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -434,6 +434,8 @@ virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainMemDumpTypeFromString;
virDomainMemDumpTypeToString;
+virDomainMemoryModelTypeFromString;
+virDomainMemoryModelTypeToString;
virDomainNetDefFree;
virDomainNetFind;
virDomainNetFindIdx;
@@ -1267,6 +1269,7 @@ virGetUserName;
virHexToBin;
virIndexToDiskName;
virIsDevMapperDevice;
+virIsPowerOfTwo;
virParseNumber;
virParseVersionString;
virPipeReadUntilEOF;
diff --git a/src/util/util.c b/src/util/util.c
index 75b18c1..858d64e 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -3114,3 +3114,8 @@ virValidateWWN(const char *wwn) {
return true;
}
+
+bool
+virIsPowerOfTwo(unsigned long long n) {
+ return (n & (n - 1)) == 0;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 4316ab1..fd32b0c 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -280,4 +280,6 @@ bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1);
bool virValidateWWN(const char *wwn);
+bool virIsPowerOfTwo(unsigned long long n);
+
#endif /* __VIR_UTIL_H__ */
--
1.7.7.6