"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