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@xxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list