"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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to