[libvirt] [PATCH v1 2/6] conf: Parse and format shmem device XML

Maxime Leroy maxime.leroy at 6wind.com
Fri Aug 22 10:47:01 UTC 2014


This patch adds configuration support for the shmem device
as described in the schema in the previous patch.

Signed-off-by: Maxime Leroy <maxime.leroy at 6wind.com>
---
 src/conf/domain_conf.c   | 249 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h   |  41 ++++++++
 src/libvirt_private.syms |   2 +
 3 files changed, 291 insertions(+), 1 deletion(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 9557020..08d653a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -234,7 +234,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "chr",
               "memballoon",
               "nvram",
-              "rng")
+              "rng",
+              "shmem")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -759,6 +760,9 @@ VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
               "abort",
               "pivot")
 
+VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST,
+              "ivshmem")
+
 /* Internal mapping: subset of block job types that can be present in
  * <mirror> XML (remaining types are not two-phase). */
 VIR_ENUM_DECL(virDomainBlockJob)
@@ -1692,6 +1696,26 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainShmemDefFree(virDomainShmemDefPtr def)
+{
+    if (!def)
+        return;
+
+    switch (def->model) {
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
+        VIR_FREE(def->data.ivshmem.server.path);
+        break;
+    default:
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unexpected shmem model %d"), def->model);
+    }
+
+    virDomainDeviceInfoClear(&def->info);
+
+    VIR_FREE(def->name);
+    VIR_FREE(def);
+}
+
 void virDomainVideoDefFree(virDomainVideoDefPtr def)
 {
     if (!def)
@@ -1893,6 +1917,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_NVRAM:
         virDomainNVRAMDefFree(def->data.nvram);
         break;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        virDomainShmemDefFree(def->data.shmem);
+        break;
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -2134,6 +2161,10 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virDomainRedirFilterDefFree(def->redirfilter);
 
+    for (i = 0; i < def->nshmems; i++)
+            virDomainShmemDefFree(def->shmems[i]);
+    VIR_FREE(def->shmems);
+
     if (def->namespaceData && def->ns.free)
         (def->ns.free)(def->namespaceData);
 
@@ -2568,6 +2599,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
         return &device->data.memballoon->info;
     case VIR_DOMAIN_DEVICE_NVRAM:
         return &device->data.nvram->info;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        return &device->data.shmem->info;
     case VIR_DOMAIN_DEVICE_RNG:
         return &device->data.rng->info;
 
@@ -2783,6 +2816,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
         if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
             return -1;
     }
+    device.type = VIR_DOMAIN_DEVICE_SHMEM;
+    for (i = 0; i < def->nshmems; i++) {
+        device.data.shmem = def->shmems[i];
+        if (cb(def, &device, &def->shmems[i]->info, opaque) < 0)
+            return -1;
+    }
 
     /* This switch statement is here to trigger compiler warning when adding
      * a new device type. When you are adding a new field to the switch you
@@ -2809,6 +2848,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_CHR:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
+    case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
         break;
@@ -9462,6 +9502,135 @@ virDomainNVRAMDefParseXML(xmlNodePtr node,
     return NULL;
 }
 
+static int
+virDomainIvshmemDefParseXML(xmlNodePtr node,
+                            xmlXPathContextPtr ctxt,
+                            virDomainIvshmemDefPtr def)
+{
+    char *ioeventfd = NULL;
+    char *vectors = NULL;
+    xmlNodePtr cur;
+    xmlNodePtr save = ctxt->node;
+    int ret;
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(cur->name, BAD_CAST "server")) {
+                def->server.enabled = true;
+                if (!(def->server.path = virXMLPropString(cur, "path"))) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("cannot parse <server> 'path' attribute"));
+                    goto error;
+                }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "size")) {
+                if (virDomainParseScaledValue("./size[1]", ctxt,
+                                              &def->size, 1,
+                                              ULLONG_MAX, true) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("cannot parse <size> attribute"));
+                    goto error;
+                }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "msi")) {
+                def->msi.enabled = true;
+                vectors = virXMLPropString(cur, "vectors");
+                ioeventfd = virXMLPropString(cur, "ioeventfd");
+
+                if (vectors &&
+                    virStrToLong_ui(vectors, NULL, 10, &def->msi.vectors) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR,
+                                   _("cannot parse <msi> 'vectors' attribute '%s'"),
+                                   vectors);
+                    goto error;
+                }
+                if (ioeventfd &&
+                    (def->msi.ioeventfd =
+                     virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                   _("cannot parse <msi> 'ioeventfd' mode '%s'"),
+                                   ioeventfd);
+                    goto error;
+                }
+            }
+        }
+        cur = cur->next;
+    }
+
+    /* msi option is only relevant with a server */
+    if (def->msi.enabled && !def->server.enabled) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("msi option is only supported with an ivshmem server"));
+        goto error;
+    }
+
+    /* size should be a power of two */
+    if (def->size & (def->size-1)) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("shmem size should be a power of two for ivshmem model"));
+      goto error;
+    }
+
+    ret = 0;
+ cleanup:
+    ctxt->node = save;
+    VIR_FREE(ioeventfd);
+    VIR_FREE(vectors);
+    return ret;
+
+ error:
+    ret = -1;
+    goto cleanup;
+}
+
+static virDomainShmemDefPtr
+virDomainShmemDefParseXML(xmlNodePtr node,
+                          xmlXPathContextPtr ctxt,
+                          unsigned int flags)
+{
+    char *model = virXMLPropString(node, "model");
+    virDomainShmemDefPtr def;
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+
+    if (model) {
+        if ((def->model == virDomainShmemModelTypeFromString(model)) < 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Unknown <shmem> model '%s'"), model);
+            goto error;
+        }
+    } else
+        def->model = VIR_DOMAIN_SHMEM_MODEL_IVSHMEM;
+
+    if (!(def->name = virXMLPropString(node, "name"))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("<shmem> must contain 'name' attribute"));
+        goto error;
+    }
+
+    switch (def->model) {
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
+        if (virDomainIvshmemDefParseXML(node, ctxt, &def->data.ivshmem) < 0)
+            goto error;
+        break;
+    default:
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unexpected <shmem> model %d"), def->model);
+        goto error;
+    }
+
+    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+        goto error;
+
+ cleanup:
+    VIR_FREE(model);
+    return def;
+ error:
+    virDomainShmemDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
 static virSysinfoDefPtr
 virSysinfoParseXML(xmlNodePtr node,
                   xmlXPathContextPtr ctxt,
@@ -10318,6 +10487,10 @@ virDomainDeviceDefParse(const char *xmlStr,
         if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
             goto error;
         break;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
+            goto error;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -13200,6 +13373,25 @@ virDomainDefParseXML(xmlDocPtr xml,
         VIR_FREE(nodes);
     }
 
+    /* analysis of the shmem devices */
+    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0) {
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->shmems, n) < 0)
+        goto error;
+
+    node = ctxt->node;
+    for (i = 0; i < n; i++) {
+        virDomainShmemDefPtr shmem;
+        ctxt->node = nodes[i];
+        shmem = virDomainShmemDefParseXML(nodes[i], ctxt, flags);
+        if (!shmem)
+            goto error;
+
+        def->shmems[def->nshmems++] = shmem;
+    }
+    ctxt->node = node;
+    VIR_FREE(nodes);
 
     /* analysis of the user namespace mapping */
     if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
@@ -16828,6 +17020,56 @@ static int virDomainPanicDefFormat(virBufferPtr buf,
     return 0;
 }
 
+static int virDomainIvshmemDefFormat(virBufferPtr buf,
+                                     virDomainIvshmemDefPtr def)
+{
+    if (def->server.enabled)
+        virBufferAsprintf(buf, "<server path='%s'/>\n",
+                          def->server.path);
+    if (def->size)
+        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n",
+                          def->size  / (1024 * 1024));
+
+    if (def->server.enabled && def->msi.enabled) {
+            virBufferAddLit(buf, "<msi");
+            if (def->msi.vectors)
+                virBufferAsprintf(buf, " vectors='%u'", def->msi.vectors);
+            if (def->msi.ioeventfd)
+                virBufferAsprintf(buf, " ioeventfd='%s'",
+                                  virTristateSwitchTypeToString(def->msi.ioeventfd));
+            virBufferAddLit(buf, "/>\n");
+    }
+
+    return 0;
+}
+
+static int virDomainShmemDefFormat(virBufferPtr buf,
+                                   virDomainShmemDefPtr def,
+                                   unsigned int flags)
+{
+    virBufferAsprintf(buf, "<shmem name='%s' model='%s'>\n",
+                      def->name, virDomainShmemModelTypeToString(def->model));
+
+    virBufferAdjustIndent(buf, 2);
+    switch (def->model) {
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
+        virDomainIvshmemDefFormat(buf, &def->data.ivshmem);
+        break;
+    default:
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unexpected shem model %d"), def->model);
+    }
+
+    if (virDomainDeviceInfoIsSet(&def->info, flags) &&
+        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+        return -1;
+
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</shmem>\n");
+
+    return 0;
+}
+
 static int
 virDomainRNGDefFormat(virBufferPtr buf,
                       virDomainRNGDefPtr def,
@@ -18377,6 +18619,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         virDomainPanicDefFormat(buf, def->panic) < 0)
         goto error;
 
+    for (n = 0; n < def->nshmems; n++)
+        if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
+            goto error;
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</devices>\n");
 
@@ -19742,6 +19988,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
+    case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f2df4eb..0c6aa21 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -136,6 +136,12 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
 typedef struct _virDomainChrSourceDef virDomainChrSourceDef;
 typedef virDomainChrSourceDef *virDomainChrSourceDefPtr;
 
+typedef struct _virDomainIvshmemDef virDomainIvshmemDef;
+typedef virDomainIvshmemDef *virDomainIvshmemDefPtr;
+
+typedef struct _virDomainShmemDef virDomainShmemDef;
+typedef virDomainShmemDef *virDomainShmemDefPtr;
+
 /* Flags for the 'type' field in virDomainDeviceDef */
 typedef enum {
     VIR_DOMAIN_DEVICE_NONE = 0,
@@ -157,6 +163,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMBALLOON,
     VIR_DOMAIN_DEVICE_NVRAM,
     VIR_DOMAIN_DEVICE_RNG,
+    VIR_DOMAIN_DEVICE_SHMEM,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -184,6 +191,7 @@ struct _virDomainDeviceDef {
         virDomainMemballoonDefPtr memballoon;
         virDomainNVRAMDefPtr nvram;
         virDomainRNGDefPtr rng;
+        virDomainShmemDefPtr shmem;
     } data;
 };
 
@@ -1370,6 +1378,12 @@ typedef enum {
     VIR_DOMAIN_HUB_TYPE_LAST
 } virDomainHubType;
 
+typedef enum {
+    VIR_DOMAIN_SHMEM_MODEL_IVSHMEM,
+
+    VIR_DOMAIN_SHMEM_MODEL_LAST
+} virDomainShmemModel;
+
 typedef struct _virDomainGraphicsListenDef virDomainGraphicsListenDef;
 typedef virDomainGraphicsListenDef *virDomainGraphicsListenDefPtr;
 struct _virDomainGraphicsListenDef {
@@ -1486,6 +1500,28 @@ struct _virDomainNVRAMDef {
     virDomainDeviceInfo info;
 };
 
+struct _virDomainIvshmemDef {
+    unsigned long long size;
+    struct {
+        bool enabled;
+        char *path;
+    } server;
+    struct {
+        bool enabled;
+        unsigned vectors;
+        virTristateSwitch ioeventfd;
+    } msi;
+};
+
+struct _virDomainShmemDef {
+    int model; /* enum virDomainShmemModel */
+    char *name;
+    union {
+        virDomainIvshmemDef ivshmem;
+    } data;
+    virDomainDeviceInfo info;
+};
+
 typedef enum {
     VIR_DOMAIN_SMBIOS_NONE = 0,
     VIR_DOMAIN_SMBIOS_EMULATE,
@@ -2007,6 +2043,9 @@ struct _virDomainDef {
     size_t nrngs;
     virDomainRNGDefPtr *rngs;
 
+    size_t nshmems;
+    virDomainShmemDefPtr *shmems;
+
     /* Only 1 */
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
@@ -2204,6 +2243,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
 void virDomainHubDefFree(virDomainHubDefPtr def);
 void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
 void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def);
+void virDomainShmemDefFree(virDomainShmemDefPtr def);
 void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
 virDomainDeviceDefPtr virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
                                              const virDomainDef *def,
@@ -2628,6 +2668,7 @@ VIR_ENUM_DECL(virDomainGraphicsVNCSharePolicy)
 VIR_ENUM_DECL(virDomainHyperv)
 VIR_ENUM_DECL(virDomainRNGModel)
 VIR_ENUM_DECL(virDomainRNGBackend)
+VIR_ENUM_DECL(virDomainShmemModel)
 VIR_ENUM_DECL(virDomainTPMModel)
 VIR_ENUM_DECL(virDomainTPMBackend)
 /* from libvirt.h */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e09ddd5..f86926e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -373,6 +373,8 @@ virDomainSaveStatus;
 virDomainSaveXML;
 virDomainSeclabelTypeFromString;
 virDomainSeclabelTypeToString;
+virDomainShmemModelTypeFromString;
+virDomainShmemModelTypeToString;
 virDomainShutdownReasonTypeFromString;
 virDomainShutdownReasonTypeToString;
 virDomainShutoffReasonTypeFromString;
-- 
1.9.3




More information about the libvir-list mailing list