diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index e7b585cfed..8e50b8caac 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -5582,6 +5582,58 @@ qemu-kvm -net nic,model=? /dev/null +

Shared memory device

+ +

+ A shared memory device allows to share a memory region between + different virtual machines and the host. + Since 1.2.9, QEMU and KVM only +

+ +
+  ...
+  <devices>
+    <shmem name='my_shmem0'>
+      <size unit='M'>4</size>
+    </shmem>
+    <shmem name='shmem_server'>
+      <size unit='M'>2</size>
+      <server path='/tmp/socket-shmem'/>
+      <msi vectors='32' ioeventfd='on'/>
+    </shmem>
+  </devices>
+  ...
+
+ +
+
shmem
+
+ The shmem element has one mandatory attribute, + name to identify the shared memory. +
+
size
+
+ The optional size element specifies the size of the shared + memory. This must be power of 2 and greater than or equal to 1 MiB. +
+
server
+
+ The optional server element can be used to configure a server + socket the device is supposed to connect to. The optional + path attribute specifies the path to the unix socket and + defaults to /var/lib/libvirt/shmem/$shmem-$name-sock. +
+
msi
+
+ The optional msi element enables/disables (values "on"/"off", + respectively) MSI interrupts. This option can currently be used only + together with the server element. The vectors + attribute can be used to specify the number of interrupt + vectors. The ioeventd attribute enables/disables (values + "on"/"off", respectively) ioeventfd. +
+
+

Security label

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 1a266e571c..6b69fd1bac 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3278,6 +3278,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3864,6 +3902,7 @@ + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ea25df401..b74782f42f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -255,7 +255,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", @@ -1720,6 +1721,17 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def) VIR_FREE(def); } +void virDomainShmemDefFree(virDomainShmemDefPtr def) +{ + if (!def) + return; + + virDomainDeviceInfoClear(&def->info); + VIR_FREE(def->server.path); + VIR_FREE(def->name); + VIR_FREE(def); +} + void virDomainVideoDefFree(virDomainVideoDefPtr def) { if (!def) @@ -1921,6 +1933,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; @@ -2181,6 +2196,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); @@ -2613,6 +2632,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; @@ -2828,6 +2849,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; + } /* Coverity is not very happy with this - all dead_error_condition */ #if !STATIC_ANALYSIS @@ -2856,6 +2883,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; @@ -9702,6 +9730,84 @@ virDomainNVRAMDefParseXML(xmlNodePtr node, return NULL; } +static virDomainShmemDefPtr +virDomainShmemDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + char *tmp = NULL; + virDomainShmemDefPtr def = NULL; + virDomainShmemDefPtr ret = NULL; + xmlNodePtr msi = NULL; + xmlNodePtr save = ctxt->node; + xmlNodePtr server = NULL; + + + if (VIR_ALLOC(def) < 0) + return NULL; + + ctxt->node = node; + + if (!(def->name = virXMLPropString(node, "name"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem element must contain 'name' attribute")); + goto cleanup; + } + + if (virDomainParseScaledValue("./size[1]", ctxt, &def->size, + 1, ULLONG_MAX, false) < 0) + goto cleanup; + + if ((server = virXPathNode("./server", ctxt))) { + def->server.enabled = true; + + if ((tmp = virXMLPropString(server, "path"))) + def->server.path = virFileSanitizePath(tmp); + VIR_FREE(tmp); + } + + if ((msi = virXPathNode("./msi", ctxt))) { + def->msi.enabled = true; + + if ((tmp = virXMLPropString(msi, "vectors")) && + virStrToLong_uip(tmp, NULL, 0, &def->msi.vectors) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid number of vectors for shmem: '%s'"), + tmp); + goto cleanup; + } + VIR_FREE(tmp); + + if ((tmp = virXMLPropString(msi, "ioeventfd")) && + (def->msi.ioeventfd = virTristateSwitchTypeFromString(tmp)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid msi ioeventfd setting for shmem: '%s'"), + tmp); + goto cleanup; + } + VIR_FREE(tmp); + } + + /* 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 a server")); + goto cleanup; + } + + if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) + goto cleanup; + + + ret = def; + def = NULL; + cleanup: + ctxt->node = save; + VIR_FREE(tmp); + virDomainShmemDefFree(def); + return ret; +} + static virSysinfoDefPtr virSysinfoParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, @@ -10558,6 +10664,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; @@ -13686,6 +13796,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) @@ -17469,6 +17598,54 @@ static int virDomainPanicDefFormat(virBufferPtr buf, return 0; } +static int +virDomainShmemDefFormat(virBufferPtr buf, + virDomainShmemDefPtr def, + unsigned int flags) +{ + virBufferAsprintf(buf, "name); + + if (!def->size && + !def->server.enabled && + !def->msi.enabled && + !virDomainDeviceInfoIsSet(&def->info, flags)) { + virBufferAddLit(buf, "/>\n"); + return 0; + } else { + virBufferAddLit(buf, ">\n"); + } + + virBufferAdjustIndent(buf, 2); + + if (def->size) + virBufferAsprintf(buf, "%llu\n", + VIR_DIV_UP(def->size, 1024 * 1024)); + + if (def->server.enabled) { + virBufferAddLit(buf, "server.path); + virBufferAddLit(buf, "/>\n"); + } + + if (def->msi.enabled) { + virBufferAddLit(buf, "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 (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) + return -1; + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + + return 0; +} + static int virDomainRNGDefFormat(virBufferPtr buf, virDomainRNGDefPtr def, @@ -19089,6 +19266,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, "\n"); @@ -20454,6 +20635,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 ea201b3a33..d73d654282 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 _virDomainShmemDef virDomainShmemDef; +typedef virDomainShmemDef *virDomainShmemDefPtr; + /* 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_SHMEM, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -184,6 +188,7 @@ struct _virDomainDeviceDef { virDomainMemballoonDefPtr memballoon; virDomainNVRAMDefPtr nvram; virDomainRNGDefPtr rng; + virDomainShmemDefPtr shmem; } data; }; @@ -1506,6 +1511,21 @@ struct _virDomainNVRAMDef { virDomainDeviceInfo info; }; +struct _virDomainShmemDef { + char *name; + unsigned long long size; + struct { + bool enabled; + char *path; + } server; + struct { + bool enabled; + unsigned vectors; + virTristateSwitch ioeventfd; + } msi; + virDomainDeviceInfo info; +}; + typedef enum { VIR_DOMAIN_SMBIOS_NONE = 0, VIR_DOMAIN_SMBIOS_EMULATE, @@ -2082,6 +2102,9 @@ struct _virDomainDef { size_t nrngs; virDomainRNGDefPtr *rngs; + size_t nshmems; + virDomainShmemDefPtr *shmems; + /* Only 1 */ virDomainWatchdogDefPtr watchdog; virDomainMemballoonDefPtr memballoon; @@ -2279,6 +2302,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, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index d63188749c..3a654e436f 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2859,6 +2859,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver, case VIR_DOMAIN_DEVICE_MEMBALLOON: case VIR_DOMAIN_DEVICE_NVRAM: case VIR_DOMAIN_DEVICE_RNG: + case VIR_DOMAIN_DEVICE_SHMEM: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("don't know how to remove a %s device"), diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml new file mode 100644 index 0000000000..d70279c21f --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml @@ -0,0 +1,24 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml new file mode 100644 index 0000000000..fd79c89c1a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml @@ -0,0 +1,51 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + + 128 + + + 256 + + + 512 + + + + 1024 + + + + 2048 + + + + + 4096 + + + + + 8192 + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 483ca90324..58153db0df 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1466,6 +1466,8 @@ mymain(void) DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS); + DO_TEST_PARSE_ERROR("shmem-msi-only", NONE); + virObjectUnref(driver.config); virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 9a568806d7..978e5f1c6a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -404,6 +404,7 @@ mymain(void) DO_TEST("bios-nvram"); DO_TEST("tap-vhost"); + DO_TEST("shmem"); virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt);