"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)
---
src/conf/domain_conf.c | 184 +++++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 27 +++++++
src/libvirt_private.syms | 3 +
src/util/util.c | 5 +
src/util/util.h | 2 +
5 files changed, 220 insertions(+), 1 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index db6608e..dbcfcaf 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
@@ -1384,6 +1389,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)
@@ -1717,6 +1742,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);
@@ -7004,7 +7032,6 @@ error:
goto cleanup;
}
-
static virDomainMemballoonDefPtr
virDomainMemballoonDefParseXML(const xmlNodePtr node,
unsigned int flags)
@@ -7043,6 +7070,140 @@ 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 (!(model = virXMLPropString(node, "model"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Memory model 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 "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 model='%s'>\n",
+ virDomainMemoryModelTypeToString(def->model));
+
+ switch (def->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_IVSHMEM:
+ 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)
@@ -10017,6 +10178,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;
@@ -14179,6 +14356,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 c7c1ca6..f68b75f 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;
@@ -1352,6 +1355,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,
@@ -1780,6 +1803,9 @@ struct _virDomainDef {
size_t nseclabels;
virSecurityLabelDefPtr *seclabels;
+ size_t nmemorys;
+ virDomainMemoryDefPtr *memorys;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2250,6 +2276,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 e94b478..e4b6c49 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -434,6 +434,8 @@ virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainMemDumpTypeFromString;
virDomainMemDumpTypeToString;
+virDomainMemoryModelTypeFromString;
+virDomainMemoryModelTypeToString;
virDomainNetDefFree;
virDomainNetFind;
virDomainNetFindIdx;
@@ -1266,6 +1268,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