"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> ... <devices> - <memory mode='ivshmem'> + <memory'> + <model type='ivshmem'/> <source id='nahanni' path='/tmp/nahanni'/> <size unit='KiB'>10240</size> <ioeventfd/> @@ -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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list