[libvirt] [RFC PATCH 2/5] conf: Parse and format ivshmem device XML

Maxime Leroy maxime.leroy at 6wind.com
Tue Aug 5 16:48:02 UTC 2014


This patch adds configuration support for the ivshmem 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   | 234 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h   |  40 ++++++++
 src/libvirt_private.syms |   4 +
 3 files changed, 277 insertions(+), 1 deletion(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index c25c74b..829f1bf 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",
+              "ivshmem")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -759,6 +760,15 @@ VIR_ENUM_DECL(virDomainBlockJob)
 VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
               "", "", "copy", "", "active-commit")
 
+VIR_ENUM_IMPL(virDomainIvshmemServer, VIR_DOMAIN_IVSHMEM_SERVER_LAST,
+              "yes",
+              "no");
+
+VIR_ENUM_IMPL(virDomainIvshmemRole, VIR_DOMAIN_IVSHMEM_ROLE_LAST,
+              "default",
+              "master",
+              "peer");
+
 #define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
 #define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE
 
@@ -1686,6 +1696,17 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainIvshmemDefFree(virDomainIvshmemDefPtr def)
+{
+    if (!def)
+        return;
+
+    virDomainDeviceInfoClear(&def->info);
+
+    VIR_FREE(def->file);
+    VIR_FREE(def);
+}
+
 void virDomainVideoDefFree(virDomainVideoDefPtr def)
 {
     if (!def)
@@ -1887,6 +1908,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_NVRAM:
         virDomainNVRAMDefFree(def->data.nvram);
         break;
+    case VIR_DOMAIN_DEVICE_IVSHMEM:
+        virDomainIvshmemDefFree(def->data.ivshmem);
+        break;
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -2128,6 +2152,10 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virDomainRedirFilterDefFree(def->redirfilter);
 
+    for (i = 0; i < def->nivshmems; i++)
+            virDomainIvshmemDefFree(def->ivshmems[i]);
+    VIR_FREE(def->ivshmems);
+
     if (def->namespaceData && def->ns.free)
         (def->ns.free)(def->namespaceData);
 
@@ -2562,6 +2590,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
         return &device->data.memballoon->info;
     case VIR_DOMAIN_DEVICE_NVRAM:
         return &device->data.nvram->info;
+    case VIR_DOMAIN_DEVICE_IVSHMEM:
+        return &device->data.ivshmem->info;
     case VIR_DOMAIN_DEVICE_RNG:
         return &device->data.rng->info;
 
@@ -2777,6 +2807,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
         if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
             return -1;
     }
+    device.type = VIR_DOMAIN_DEVICE_IVSHMEM;
+    for (i = 0; i < def->nivshmems; i++) {
+        device.data.ivshmem = def->ivshmems[i];
+        if (cb(def, &device, &def->ivshmems[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
@@ -2805,6 +2841,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_NVRAM:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
+    case VIR_DOMAIN_DEVICE_IVSHMEM:
         break;
     }
 
@@ -9354,6 +9391,124 @@ virDomainNVRAMDefParseXML(xmlNodePtr node,
     return NULL;
 }
 
+static virDomainIvshmemDefPtr
+virDomainIvshmemDefParseXML(xmlNodePtr node,
+                            xmlXPathContextPtr ctxt,
+                            unsigned int flags)
+{
+    virDomainIvshmemDefPtr def;
+    char *use_server = NULL;
+    char *role = NULL;
+    char *ioeventfd = NULL;
+    char *vectors = NULL;
+    xmlNodePtr cur;
+    xmlNodePtr save = ctxt->node;
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+
+    use_server = virXMLPropString(node, "use_server");
+    if (use_server !=  NULL) {
+        if ((def->use_server
+             = virDomainIvshmemServerTypeFromString(use_server)) < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unknown ivshmem use_server tyoe '%s'"), use_server);
+            goto error;
+        }
+    } else {
+        virReportError(VIR_ERR_XML_ERROR,
+                       "%s", _("missing use_server type"));
+        goto error;
+    }
+
+    role = virXMLPropString(node, "role");
+    if (role !=  NULL) {
+        if ((int)(def->role = virDomainIvshmemRoleTypeFromString(role)) < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unknown ivshmem role type '%s'"), role);
+            goto error;
+        }
+    } else
+        def->role = VIR_DOMAIN_IVSHMEM_ROLE_DEFAULT;
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+                    if (!(def->file = virXMLPropString(cur, "file"))) {
+                        virReportError(VIR_ERR_XML_ERROR, "%s",
+                                       _("cannot parse <source> 'file' 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",
+                                   _("size parsing failed"));
+                    goto error;
+                }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "msi")) {
+                if (def->use_server != VIR_DOMAIN_IVSHMEM_SERVER_ENABLED) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("msi <element> is only supported for server ivshmem"));
+                    goto error;
+                }
+                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 ivshmem vectors attribute '%s'"),
+                                   vectors);
+                    goto error;
+                }
+                if (ioeventfd) {
+                    if ((def->msi.ioeventfd =
+                         virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
+                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                       _("unknown ivshmem ioeventfd mode '%s'"),
+                                       ioeventfd);
+                        goto error;
+                    }
+                }
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (!def->file) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing <source> element in ivshmem device"));
+            goto error;
+    }
+
+    /* size should be a power of two */
+    if (def->size & (def->size-1)) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("ivshmem size should be a power of two"));
+      goto error;
+    }
+
+    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+        goto error;
+
+ cleanup:
+    ctxt->node = save;
+    VIR_FREE(use_server);
+    VIR_FREE(role);
+    VIR_FREE(ioeventfd);
+    VIR_FREE(vectors);
+    return def;
+
+ error:
+    virDomainIvshmemDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
 static virSysinfoDefPtr
 virSysinfoParseXML(xmlNodePtr node,
                   xmlXPathContextPtr ctxt,
@@ -10210,6 +10365,10 @@ virDomainDeviceDefParse(const char *xmlStr,
         if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
             goto error;
         break;
+    case VIR_DOMAIN_DEVICE_IVSHMEM:
+        if (!(dev->data.ivshmem = virDomainIvshmemDefParseXML(node, ctxt, flags)))
+            goto error;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -13102,6 +13261,25 @@ virDomainDefParseXML(xmlDocPtr xml,
         VIR_FREE(nodes);
     }
 
+    /* analysis of the ivshmem devices */
+    if ((n = virXPathNodeSet("./devices/ivshmem", ctxt, &nodes)) < 0) {
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->ivshmems, n) < 0)
+        goto error;
+
+    node = ctxt->node;
+    for (i = 0; i < n; i++) {
+        virDomainIvshmemDefPtr ivshmem;
+        ctxt->node = nodes[i];
+        ivshmem = virDomainIvshmemDefParseXML(nodes[i], ctxt, flags);
+        if (!ivshmem)
+            goto error;
+
+        def->ivshmems[def->nivshmems++] = ivshmem;
+    }
+    ctxt->node = node;
+    VIR_FREE(nodes);
 
     /* analysis of the user namespace mapping */
     if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
@@ -16701,6 +16879,55 @@ static int virDomainPanicDefFormat(virBufferPtr buf,
     return 0;
 }
 
+static int virDomainIvshmemDefFormat(virBufferPtr buf,
+                                     virDomainIvshmemDefPtr def,
+                                     unsigned int flags)
+{
+    const char *use_server = virDomainIvshmemServerTypeToString(def->use_server);
+    const char *role = virDomainIvshmemRoleTypeToString(def->role);
+
+    if (!use_server) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected ivshmem server %d"), def->use_server);
+        return -1;
+    }
+
+    if (!role) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected ivshmem role %d"), def->role);
+        return -1;
+    }
+
+    virBufferAsprintf(buf, "<ivshmem use_server='%s'", use_server);
+    if (def->role)
+        virBufferAsprintf(buf, " role='%s'", role);
+    virBufferAddLit(buf, ">\n");
+
+    virBufferAdjustIndent(buf, 2);
+    virBufferAsprintf(buf, "<source file='%s'/>\n", def->file);
+    if (def->size)
+        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n",
+                          def->size  / (1024 * 1024));
+
+    if (def->use_server == VIR_DOMAIN_IVSHMEM_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");
+    }
+
+    if (virDomainDeviceInfoIsSet(&def->info, flags) &&
+        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+        return -1;
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</ivshmem>\n");
+
+    return 0;
+}
+
 static int
 virDomainRNGDefFormat(virBufferPtr buf,
                       virDomainRNGDefPtr def,
@@ -18250,6 +18477,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         virDomainPanicDefFormat(buf, def->panic) < 0)
         goto error;
 
+    for (n = 0; n < def->nivshmems; n++)
+        if (virDomainIvshmemDefFormat(buf, def->ivshmems[n], flags) < 0)
+            goto error;
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</devices>\n");
 
@@ -19615,6 +19846,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
+    case VIR_DOMAIN_DEVICE_IVSHMEM:
     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 bffc0a5..af499b4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -136,6 +136,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
 typedef struct _virDomainChrSourceDef virDomainChrSourceDef;
 typedef virDomainChrSourceDef *virDomainChrSourceDefPtr;
 
+typedef struct _virDomainIvshmemDef virDomainIvshmemDef;
+typedef virDomainIvshmemDef *virDomainIvshmemDefPtr;
+
 /* Flags for the 'type' field in virDomainDeviceDef */
 typedef enum {
     VIR_DOMAIN_DEVICE_NONE = 0,
@@ -157,6 +160,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMBALLOON,
     VIR_DOMAIN_DEVICE_NVRAM,
     VIR_DOMAIN_DEVICE_RNG,
+    VIR_DOMAIN_DEVICE_IVSHMEM,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -184,6 +188,7 @@ struct _virDomainDeviceDef {
         virDomainMemballoonDefPtr memballoon;
         virDomainNVRAMDefPtr nvram;
         virDomainRNGDefPtr rng;
+        virDomainIvshmemDefPtr ivshmem;
     } data;
 };
 
@@ -598,6 +603,22 @@ typedef enum {
     VIR_DOMAIN_DISK_DISCARD_LAST
 } virDomainDiskDiscard;
 
+typedef enum {
+    VIR_DOMAIN_IVSHMEM_SERVER_ENABLED = 0,
+    VIR_DOMAIN_IVSHMEM_SERVER_DISABLED,
+
+    VIR_DOMAIN_IVSHMEM_SERVER_LAST,
+} virDomainIvshmemServer;
+
+
+typedef enum {
+    VIR_DOMAIN_IVSHMEM_ROLE_DEFAULT = 0,
+    VIR_DOMAIN_IVSHMEM_ROLE_MASTER,
+    VIR_DOMAIN_IVSHMEM_ROLE_PEER,
+
+    VIR_DOMAIN_IVSHMEM_ROLE_LAST,
+} virDomainIvshmemRole;
+
 typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
 struct _virDomainBlockIoTuneInfo {
     unsigned long long total_bytes_sec;
@@ -1485,6 +1506,19 @@ struct _virDomainNVRAMDef {
     virDomainDeviceInfo info;
 };
 
+struct _virDomainIvshmemDef {
+    int use_server; /* enum virDomainIvshmemServer */
+    int role; /* virDomainIvshmemRole */
+    unsigned long long size;
+    char *file;
+    struct {
+        bool enabled;
+        unsigned vectors;
+        virTristateSwitch ioeventfd;
+    } msi;
+    virDomainDeviceInfo info;
+};
+
 typedef enum {
     VIR_DOMAIN_SMBIOS_NONE = 0,
     VIR_DOMAIN_SMBIOS_EMULATE,
@@ -2006,6 +2040,9 @@ struct _virDomainDef {
     size_t nrngs;
     virDomainRNGDefPtr *rngs;
 
+    size_t nivshmems;
+    virDomainIvshmemDefPtr *ivshmems;
+
     /* Only 1 */
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
@@ -2203,6 +2240,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
 void virDomainHubDefFree(virDomainHubDefPtr def);
 void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
 void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def);
+void virDomainIvshmemDefFree(virDomainIvshmemDefPtr def);
 void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
 virDomainDeviceDefPtr virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
                                              const virDomainDef *def,
@@ -2629,6 +2667,8 @@ VIR_ENUM_DECL(virDomainRNGModel)
 VIR_ENUM_DECL(virDomainRNGBackend)
 VIR_ENUM_DECL(virDomainTPMModel)
 VIR_ENUM_DECL(virDomainTPMBackend)
+VIR_ENUM_DECL(virDomainIvshmemServer)
+VIR_ENUM_DECL(virDomainIvshmemRole)
 /* from libvirt.h */
 VIR_ENUM_DECL(virDomainState)
 VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 08111d4..794f3dd 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -300,6 +300,10 @@ virDomainHubTypeToString;
 virDomainHypervTypeFromString;
 virDomainHypervTypeToString;
 virDomainInputDefFree;
+virDomainIvshmemRoleTypeFromString;
+virDomainIvshmemRoleTypeToString;
+virDomainIvshmemServerTypeFromString;
+virDomainIvshmemServerTypeToString;
 virDomainLeaseDefFree;
 virDomainLeaseIndex;
 virDomainLeaseInsert;
-- 
1.9.3




More information about the libvir-list mailing list