[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 2/4] conf: Parse and format memory device XML



"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>
   ...
   &lt;devices&gt;
-    &lt;memory mode='ivshmem'&gt;
+    &lt;memory'&gt;
+      &lt;model type='ivshmem'/&gt;
       &lt;source id='nahanni' path='/tmp/nahanni'/&gt;
       &lt;size unit='KiB'&gt;10240&lt;/size&gt;
       &lt;ioeventfd/&gt;
@@ -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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]