The hardware UUID (hwuuid) element provides a mechanism to supply an external
UUID to the guest, as opposed to the libvirt domain UUID. This is to allow
for the scenario whereby a domain can be stopped, cloned and then started as
a new domain without altering the guest-visible UUID.
Add the element, documentation and core code for the hwuuid feature along
with an implementation for the QEMU driver.
Signed-off-by: Mark Cave-Ayland <mark.caveayland(a)nutanix.com>
---
docs/formatdomain.rst | 7 ++++++
src/conf/domain_conf.c | 38 ++++++++++++++++++++++++++++---
src/conf/domain_conf.h | 1 +
src/conf/schemas/domaincommon.rng | 5 ++++
src/qemu/qemu_command.c | 6 ++++-
5 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 9a2f065590..7b10dfa3da 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -54,6 +54,13 @@ General metadata
:since:`Since 0.8.7`, it is also possible to provide the UUID via a
`SMBIOS System Information`_ specification.
+``hwuuid``
+ The optional ``hwuuid`` element can be used to supply an alternative UUID for
+ identifying the virtual machine from the domain ``uuid`` above. The difference
+ between using the ``hwuuid`` element and simply providing an alternative UUID
+ via a `SMBIOS System Information`_ specification is that the ``hwuuid`` affects
+ all devices that expose the UUID to the guest.
+ :since:`Since 11.6.0 QEMU/KVM only`
``genid``
:since:`Since 4.4.0`, the ``genid`` element can be used to add a Virtual
Machine Generation ID which exposes a 128-bit, cryptographically random,
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index bfc62b6270..63603ca527 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -13098,6 +13098,7 @@ static int
virSysinfoSystemParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
virSysinfoSystemDef **sysdef,
+ unsigned char *hwUUID,
unsigned char *domUUID,
bool uuid_generated)
{
@@ -13122,11 +13123,18 @@ virSysinfoSystemParseXML(xmlNodePtr node,
}
if (uuid_generated) {
memcpy(domUUID, uuidbuf, VIR_UUID_BUFLEN);
- } else if (memcmp(domUUID, uuidbuf, VIR_UUID_BUFLEN) != 0) {
+ } else if (!virUUIDIsValid(hwUUID) &&
+ memcmp(domUUID, uuidbuf, VIR_UUID_BUFLEN) != 0) {
virReportError(VIR_ERR_XML_DETAIL, "%s",
_("UUID mismatch between <uuid> and
<sysinfo>"));
return -1;
}
+ if (virUUIDIsValid(hwUUID) &&
+ memcmp(hwUUID, uuidbuf, VIR_UUID_BUFLEN) != 0) {
+ virReportError(VIR_ERR_XML_DETAIL, "%s",
+ _("UUID mismatch between <hwuuid> and
<sysinfo>"));
+ return -1;
+ }
/* Although we've validated the UUID as good, virUUIDParse() is
* lax with respect to allowing extraneous "-" and " ", but
the
* underlying hypervisor may be less forgiving. Use virUUIDFormat()
@@ -13263,6 +13271,7 @@ virSysinfoChassisParseXML(xmlNodePtr node,
static int
virSysinfoParseSMBIOSDef(virSysinfoDef *def,
xmlXPathContextPtr ctxt,
+ unsigned char *hwUUID,
unsigned char *domUUID,
bool uuid_generated)
{
@@ -13276,7 +13285,7 @@ virSysinfoParseSMBIOSDef(virSysinfoDef *def,
/* Extract system related metadata */
if ((tmpnode = virXPathNode("./system[1]", ctxt)) != NULL) {
- if (virSysinfoSystemParseXML(tmpnode, ctxt, &def->system,
+ if (virSysinfoSystemParseXML(tmpnode, ctxt, &def->system, hwUUID,
domUUID, uuid_generated) < 0)
return -1;
}
@@ -13363,6 +13372,7 @@ virSysinfoParseFWCfgDef(virSysinfoDef *def,
static virSysinfoDef *
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
+ unsigned char *hwUUID,
unsigned char *domUUID,
bool uuid_generated)
{
@@ -13377,7 +13387,8 @@ virSysinfoParseXML(xmlNodePtr node,
switch (def->type) {
case VIR_SYSINFO_SMBIOS:
- if (virSysinfoParseSMBIOSDef(def, ctxt, domUUID, uuid_generated) < 0)
+ if (virSysinfoParseSMBIOSDef(def, ctxt, hwUUID, domUUID,
+ uuid_generated) < 0)
return NULL;
break;
@@ -18667,6 +18678,21 @@ virDomainDefParseIDs(virDomainDef *def,
VIR_FREE(tmp);
}
+ /* Extract hardware uuid (optional). For some use cases e.g. cloning a
+ * domain from a snapshot, the hardware uuid must remain constant and
+ * separate from the domain uuid. */
+ tmp = virXPathString("string(./hwuuid[1])", ctxt);
+ if (tmp) {
+ if (virUUIDParse(tmp, def->hw_uuid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed hwuuid element"));
+ return -1;
+ }
+ VIR_FREE(tmp);
+ } else {
+ memset(def->hw_uuid, 0, VIR_UUID_BUFLEN);
+ }
+
/* Extract domain genid - a genid can either be provided or generated */
if ((n = virXPathNodeSet("./genid", ctxt, &nodes)) < 0)
return -1;
@@ -20132,6 +20158,7 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
for (i = 0; i < n; i++) {
virSysinfoDef *sysinfo = virSysinfoParseXML(nodes[i], ctxt,
+ def->hw_uuid,
def->uuid, uuid_generated);
if (!sysinfo)
@@ -28903,6 +28930,11 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
virUUIDFormat(uuid, uuidstr);
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
+ if (virUUIDIsValid(def->hw_uuid)) {
+ virUUIDFormat(def->hw_uuid, uuidstr);
+ virBufferAsprintf(buf, "<hwuuid>%s</hwuuid>\n", uuidstr);
+ }
+
if (def->genidRequested) {
char genidstr[VIR_UUID_STRING_BUFLEN];
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6997cf7c09..a00ba729fd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3115,6 +3115,7 @@ struct _virDomainDef {
int virtType; /* enum virDomainVirtType */
int id;
unsigned char uuid[VIR_UUID_BUFLEN];
+ unsigned char hw_uuid[VIR_UUID_BUFLEN];
unsigned char genid[VIR_UUID_BUFLEN];
bool genidRequested;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 2d6e15f144..e39dacfff7 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -47,6 +47,11 @@
<ref name="UUID"/>
</element>
</optional>
+ <optional>
+ <element name="hwuuid">
+ <ref name="UUID"/>
+ </element>
+ </optional>
<optional>
<element name="genid">
<choice>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 7658cc4d39..c7fd2eb183 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -10713,7 +10713,11 @@ qemuBuildCommandLine(virDomainObj *vm,
qemuBuildNumaCommandLine(cfg, def, cmd, priv) < 0)
return NULL;
- virUUIDFormat(def->uuid, uuid);
+ if (virUUIDIsValid(def->hw_uuid)) {
+ virUUIDFormat(def->hw_uuid, uuid);
+ } else {
+ virUUIDFormat(def->uuid, uuid);
+ }
virCommandAddArgList(cmd, "-uuid", uuid, NULL);
if (qemuBuildSmbiosCommandLine(cmd, driver, def) < 0)
--
2.43.0