Add VM Generation ID device XML schema, parse, format, and documentation.
Signed-off-by: John Ferlan <jferlan@redhat.com>
---
docs/formatdomain.html.in | 54 ++++++++++++++
docs/schemas/domaincommon.rng | 21 ++++++
src/conf/domain_conf.c | 112 +++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 11 +++
tests/qemuxml2argvdata/vmgenid-auto.xml | 32 +++++++++
tests/qemuxml2argvdata/vmgenid.xml | 32 +++++++++
tests/qemuxml2xmloutdata/vmgenid-auto.xml | 1 +
tests/qemuxml2xmloutdata/vmgenid.xml | 1 +
tests/qemuxml2xmltest.c | 3 +
9 files changed, 266 insertions(+), 1 deletion(-)
create mode 100644 tests/qemuxml2argvdata/vmgenid-auto.xml
create mode 100644 tests/qemuxml2argvdata/vmgenid.xml
create mode 120000 tests/qemuxml2xmloutdata/vmgenid-auto.xml
create mode 120000 tests/qemuxml2xmloutdata/vmgenid.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 6fd2189cd2..895e51b343 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -8027,6 +8027,60 @@ qemu-kvm -net nic,model=? /dev/null
</dd>
</dl>
+ <h4><a id="elementsVmgenid">VM Generation ID device</a></h4>
+
+ <p>
+ <span class="since">Since 4.2.0</span>, the <code>vmgenid</code>
+ element can be used to add a Virtual Machine Generation ID device.
+ A <code>vmgenid</code> device is an emulated device which exposes
+ a 128-bit, cryptographically random, integer value identifier,
+ referred to as a Globally Unique Identifier, or GUID. The value is
+ stored within the virtual machine's BIOS so that programs running in
+ the virtual machine can protect themselves from potential corruption
+ by checking that the Generation ID has not changed immediately prior
+ to committing a transaction.
+
+ The <code>vmgenid</code> device will update the BIOS entry each time
+ the virtual machine executes from a different configuration file such
+ as executing from a recovered snapshot or executing after restoring
+ from backup. Programs running in a virtual machine can protect themselves
+ from potential corruption by checking that the generation ID has not
+ changed immediately prior to committing a transaction, they can also
+ use the data provided in the 128-bit identifier as a high entropy
+ random data source.
+ </p>
+
+ <p>
+ Example:
+ </p>
+<pre>
+...
+<devices>
+ <vmgenid guid='3e3fce45-4f53-4fa7-bb32-11f34168b82b'/>
+</devices>
+...
+</pre>
+
+<pre>
+...
+<devices>
+ <vmgenid guid='auto'/>
+</devices>
+...
+</pre>
+
+ <dl>
+ <dt><code>guid</code></dt>
+ <dd>
+ <p>
+ The required <code>guid</code> attribute can be either a provided
+ (<a href="#elementsMetadata"><code>uuid</code></a>) formatted value
+ or the string 'auto' if the underlying hypervisor supports creating
+ its own value.
+ </p>
+ </dd>
+ </dl>
+
<h3><a id="seclabel">Security label</a></h3>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 8165e699d6..692cc8d5a0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4644,6 +4644,24 @@
</attribute>
</element>
</define>
+
+ <define name="vmgenid">
+ <element name="vmgenid">
+ <choice>
+ <group>
+ <attribute name="guid">
+ <ref name="UUID"/>
+ </attribute>
+ </group>
+ <group>
+ <attribute name="guid">
+ <value>auto</value>
+ </attribute>
+ </group>
+ </choice>
+ </element>
+ </define>
+
<define name="devices">
<element name="devices">
<interleave>
@@ -4691,6 +4709,9 @@
<optional>
<ref name="iommu"/>
</optional>
+ <optional>
+ <ref name="vmgenid"/>
+ </optional>
</interleave>
</element>
</define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2f07180faa..aaba2a47f7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2741,6 +2741,8 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
VIR_FREE(def->data.iommu);
break;
case VIR_DOMAIN_DEVICE_VMGENID:
+ VIR_FREE(def->data.vmgenid);
+ break;
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -15690,6 +15692,45 @@ virDomainIOMMUDefParseXML(xmlNodePtr node,
}
+static virDomainVMGenIDDefPtr
+virDomainVMGenIDDefParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ virDomainVMGenIDDefPtr vmgenid = NULL;
+ virDomainVMGenIDDefPtr ret = NULL;
+ xmlNodePtr save = ctxt->node;
+ char *guidxml = NULL;
+
+ ctxt->node = node;
+
+ if (VIR_ALLOC(vmgenid) < 0)
+ goto cleanup;
+
+ if (!(guidxml = virXMLPropString(node, "guid"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing required 'guid' attribute"));
+ goto cleanup;
+ }
+
+ if (STREQ(guidxml, "auto")) {
+ vmgenid->autogenerate = true;
+ } else {
+ if (virUUIDParse(guidxml, vmgenid->guidstr) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("malformed guid='%s' provided"), guidxml);
+ goto cleanup;
+ }
+ }
+
+ VIR_STEAL_PTR(ret, vmgenid);
+
+ cleanup:
+ VIR_FREE(vmgenid);
+ ctxt->node = save;
+ return ret;
+}
+
+
virDomainDeviceDefPtr
virDomainDeviceDefParse(const char *xmlStr,
const virDomainDef *def,
@@ -15846,6 +15887,9 @@ virDomainDeviceDefParse(const char *xmlStr,
goto error;
break;
case VIR_DOMAIN_DEVICE_VMGENID:
+ if (!(dev->data.vmgenid = virDomainVMGenIDDefParseXML(node, ctxt)))
+ goto error;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -20249,6 +20293,21 @@ virDomainDefParseXML(xmlDocPtr xml,
}
VIR_FREE(nodes);
+ if ((n = virXPathNodeSet("./devices/vmgenid", ctxt, &nodes)) < 0)
+ goto error;
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only a single vmgenid device is supported"));
+ goto error;
+ }
+
+ if (n > 0) {
+ if (!(def->vmgenid = virDomainVMGenIDDefParseXML(nodes[0], ctxt)))
+ goto error;
+ }
+ VIR_FREE(nodes);
+
/* analysis of the user namespace mapping */
if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
goto error;
@@ -21812,6 +21871,25 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src,
static bool
+virDomainVMGenIDDefCheckABIStability(virDomainVMGenIDDefPtr src,
+ virDomainVMGenIDDefPtr dst)
+{
+ if (memcmp(src->guidstr, dst->guidstr, VIR_UUID_BUFLEN) != 0) {
+ char guidsrc[VIR_UUID_STRING_BUFLEN];
+ char guiddst[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(src->guidstr, guidsrc);
+ virUUIDFormat(dst->guidstr, guiddst);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain vmgenid guid '%s' does not match "
+ "source '%s'"),
+ guiddst, guidsrc);
+ return false;
+ }
+ return true;
+}
+
+
+static bool
virDomainDefVcpuCheckAbiStability(virDomainDefPtr src,
virDomainDefPtr dst)
{
@@ -22256,6 +22334,17 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
!virDomainIOMMUDefCheckABIStability(src->iommu, dst->iommu))
goto error;
+ if (!!src->vmgenid != !!dst->vmgenid) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target domain vmgenid device count does not "
+ "match source"));
+ goto error;
+ }
+
+ if (src->vmgenid &&
+ !virDomainVMGenIDDefCheckABIStability(src->vmgenid, dst->vmgenid))
+ goto error;
+
if (xmlopt && xmlopt->abi.domain &&
!xmlopt->abi.domain(src, dst))
goto error;
@@ -26470,6 +26559,21 @@ virDomainIOMMUDefFormat(virBufferPtr buf,
}
+static void
+virDomainVMGenIDDefFormat(virBufferPtr buf,
+ const virDomainVMGenIDDef *vmgenid)
+{
+ char guidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (vmgenid->autogenerate) {
+ virBufferAddLit(buf, "<vmgenid guid='auto'/>\n");
+ } else {
+ virUUIDFormat(vmgenid->guidstr, guidstr);
+ virBufferAsprintf(buf, "<vmgenid guid='%s'/>\n", guidstr);
+ }
+}
+
+
/* This internal version appends to an existing buffer
* (possibly with auto-indent), rather than flattening
* to string.
@@ -27251,6 +27355,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainIOMMUDefFormat(buf, def->iommu) < 0)
goto error;
+ if (def->vmgenid)
+ virDomainVMGenIDDefFormat(buf, def->vmgenid);
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</devices>\n");
@@ -28371,13 +28478,16 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
case VIR_DOMAIN_DEVICE_SHMEM:
rc = virDomainShmemDefFormat(&buf, src->data.shmem, flags);
break;
+ case VIR_DOMAIN_DEVICE_VMGENID:
+ virDomainVMGenIDDefFormat(&buf, src->data.vmgenid);
+ rc = 0;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_IOMMU:
- case VIR_DOMAIN_DEVICE_VMGENID:
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 6e204d31fb..7805ad1819 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -157,6 +157,9 @@ typedef virDomainTPMDef *virDomainTPMDefPtr;
typedef struct _virDomainIOMMUDef virDomainIOMMUDef;
typedef virDomainIOMMUDef *virDomainIOMMUDefPtr;
+typedef struct _virDomainVMGenIDDef virDomainVMGenIDDef;
+typedef virDomainVMGenIDDef *virDomainVMGenIDDefPtr;
+
typedef struct _virDomainVirtioOptions virDomainVirtioOptions;
typedef virDomainVirtioOptions *virDomainVirtioOptionsPtr;
@@ -219,6 +222,7 @@ struct _virDomainDeviceDef {
virDomainPanicDefPtr panic;
virDomainMemoryDefPtr memory;
virDomainIOMMUDefPtr iommu;
+ virDomainVMGenIDDefPtr vmgenid;
} data;
};
@@ -2309,6 +2313,12 @@ struct _virDomainVirtioOptions {
virTristateSwitch ats;
};
+struct _virDomainVMGenIDDef {
+ bool autogenerate;
+ unsigned char guidstr[VIR_UUID_STRING_BUFLEN];
+};
+
+
/*
* Guest VM main configuration
*
@@ -2449,6 +2459,7 @@ struct _virDomainDef {
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
virDomainIOMMUDefPtr iommu;
+ virDomainVMGenIDDefPtr vmgenid;
void *namespaceData;
virDomainXMLNamespace ns;
diff --git a/tests/qemuxml2argvdata/vmgenid-auto.xml b/tests/qemuxml2argvdata/vmgenid-auto.xml
new file mode 100644
index 0000000000..d111dbec8e
--- /dev/null
+++ b/tests/qemuxml2argvdata/vmgenid-auto.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='none'/>
+ <vmgenid guid='auto'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/vmgenid.xml b/tests/qemuxml2argvdata/vmgenid.xml
new file mode 100644
index 0000000000..14c94706df
--- /dev/null
+++ b/tests/qemuxml2argvdata/vmgenid.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='none'/>
+ <vmgenid guid='e9392370-2917-565e-692b-d057f46512d6'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/vmgenid-auto.xml b/tests/qemuxml2xmloutdata/vmgenid-auto.xml
new file mode 120000
index 0000000000..498b582ddc
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/vmgenid-auto.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/vmgenid-auto.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmloutdata/vmgenid.xml b/tests/qemuxml2xmloutdata/vmgenid.xml
new file mode 120000
index 0000000000..37bb1c6b9c
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/vmgenid.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/vmgenid.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 28ba46efb2..868a774bbf 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1193,6 +1193,9 @@ mymain(void)
DO_TEST("intel-iommu-eim", NONE);
DO_TEST("intel-iommu-device-iotlb", NONE);
+ DO_TEST("vmgenid", NONE);
+ DO_TEST("vmgenid-auto", NONE);
+
DO_TEST("cpu-check-none", NONE);
DO_TEST("cpu-check-partial", NONE);
DO_TEST("cpu-check-full", NONE);
--
2.13.6
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Tue, Mar 20, 2018 at 18:55:44 -0400, John Ferlan wrote: > Add VM Generation ID device XML schema, parse, format, and documentation. > > Signed-off-by: John Ferlan <jferlan@redhat.com> > --- > docs/formatdomain.html.in | 54 ++++++++++++++ > docs/schemas/domaincommon.rng | 21 ++++++ > src/conf/domain_conf.c | 112 +++++++++++++++++++++++++++++- > src/conf/domain_conf.h | 11 +++ > tests/qemuxml2argvdata/vmgenid-auto.xml | 32 +++++++++ > tests/qemuxml2argvdata/vmgenid.xml | 32 +++++++++ > tests/qemuxml2xmloutdata/vmgenid-auto.xml | 1 + > tests/qemuxml2xmloutdata/vmgenid.xml | 1 + > tests/qemuxml2xmltest.c | 3 + > 9 files changed, 266 insertions(+), 1 deletion(-) > create mode 100644 tests/qemuxml2argvdata/vmgenid-auto.xml > create mode 100644 tests/qemuxml2argvdata/vmgenid.xml > create mode 120000 tests/qemuxml2xmloutdata/vmgenid-auto.xml > create mode 120000 tests/qemuxml2xmloutdata/vmgenid.xml > > diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in > index 6fd2189cd2..895e51b343 100644 > --- a/docs/formatdomain.html.in > +++ b/docs/formatdomain.html.in > @@ -8027,6 +8027,60 @@ qemu-kvm -net nic,model=? /dev/null > </dd> > </dl> > > + <h4><a id="elementsVmgenid">VM Generation ID device</a></h4> > + > + <p> > + <span class="since">Since 4.2.0</span>, the <code>vmgenid</code> > + element can be used to add a Virtual Machine Generation ID device. > + A <code>vmgenid</code> device is an emulated device which exposes > + a 128-bit, cryptographically random, integer value identifier, > + referred to as a Globally Unique Identifier, or GUID. The value is > + stored within the virtual machine's BIOS so that programs running in According to the qemu docs, it's stored in the ACPI table, so it does not depend on BIOS being used. EFI can be used as well. > + the virtual machine can protect themselves from potential corruption > + by checking that the Generation ID has not changed immediately prior > + to committing a transaction. This last sentence is weird. I'd refrain from giving examples and rather stick to describe which changes can be tracked by this. > + > + The <code>vmgenid</code> device will update the BIOS entry each time BIOS ... > + the virtual machine executes from a different configuration file such > + as executing from a recovered snapshot or executing after restoring Okay. From this it seems that the GUID should change where the VM state could be reverted to a point in history of the execution of the guest software. This basically means that it should be always left to autogenerating except in cases of migration where the new qemu process needs to continue to use the old GUID. This means that you'll need to query it if 'auto' is specified and qemu does not guarantee that it's properly transported in the migration stream. On the other hand, if it is transported in the migration stream, then save/restore and reversion of external snapshots with memory will be fun, since that uses the migration code. You'll need to figure out where qemu stores this and how it's handled on migration, since I did not see it in the doc. Also there is one other problem and that is reversion of internal snapshots, which in some cases does not require restarting the emulator in case of qemu. In such case you'll need to make sure that the condition is modified so that a VM with this device will always restart qemu. > + from backup. Programs running in a virtual machine can protect themselves > + from potential corruption by checking that the generation ID has not > + changed immediately prior to committing a transaction, they can also > + use the data provided in the 128-bit identifier as a high entropy > + random data source. Whoah. The qemu docs don't speak about entropy source. Is it described in the Microsoft documentation? In any case, if the GUID is going to be used as an entropy source, we need to approach it way more carefully. Especially don't report it to unauthorized eyes. I'd be very happy if will not have to keep it secret. This will get especially tricky since there will be cases where we'll need to put it on the command line (either on migration or on save/restore). > + </p> > + > + <p> > + Example: > + </p> > +<pre> > +... > +<devices> > + <vmgenid guid='3e3fce45-4f53-4fa7-bb32-11f34168b82b'/> So I think we should use a more generic element with 'vmgenid' as a model. It looks like this is one of possible implementations of such a thing and it's fully possible to emulate a PCI device or anything else with similar semantics. > +</devices> > +... > +</pre> > + > +<pre> > +... > +<devices> > + <vmgenid guid='auto'/> > +</devices> > +... > +</pre> > + > + <dl> > + <dt><code>guid</code></dt> > + <dd> > + <p> > + The required <code>guid</code> attribute can be either a provided > + (<a href="#elementsMetadata"><code>uuid</code></a>) formatted value > + or the string 'auto' if the underlying hypervisor supports creating So 'auto' in place of the guid is a qemuism according to the docs. You should go with a separate element for it in cases where you need to configure that the setting is automatic, but you also need to transfer the guid itself. Also the necessity to allow configuration of the GUID really depends on the questions I've asked above. It might be even unnecessary to allow configuration of the GUID itself depending on that. In cases where we'll need to preserve it accross migration, we'll really need a way to store it in the XML. > + its own value. > + </p> > + </dd> > + </dl> > + > <h3><a id="seclabel">Security label</a></h3> > > <p> > <interleave> [...] > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 2f07180faa..aaba2a47f7 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c [...] > @@ -15690,6 +15692,45 @@ virDomainIOMMUDefParseXML(xmlNodePtr node, > } > > > +static virDomainVMGenIDDefPtr > +virDomainVMGenIDDefParseXML(xmlNodePtr node, > + xmlXPathContextPtr ctxt) > +{ > + virDomainVMGenIDDefPtr vmgenid = NULL; > + virDomainVMGenIDDefPtr ret = NULL; > + xmlNodePtr save = ctxt->node; > + char *guidxml = NULL; > + > + ctxt->node = node; > + > + if (VIR_ALLOC(vmgenid) < 0) > + goto cleanup; > + > + if (!(guidxml = virXMLPropString(node, "guid"))) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("missing required 'guid' attribute")); > + goto cleanup; > + } > + > + if (STREQ(guidxml, "auto")) { > + vmgenid->autogenerate = true; > + } else { > + if (virUUIDParse(guidxml, vmgenid->guidstr) < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("malformed guid='%s' provided"), guidxml); > + goto cleanup; > + } > + } > + > + VIR_STEAL_PTR(ret, vmgenid); > + > + cleanup: 'guidxml' is leaked > + VIR_FREE(vmgenid); > + ctxt->node = save; > + return ret; > +} > + > + > virDomainDeviceDefPtr > virDomainDeviceDefParse(const char *xmlStr, > const virDomainDef *def, [...] > @@ -21812,6 +21871,25 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src, > > > static bool > +virDomainVMGenIDDefCheckABIStability(virDomainVMGenIDDefPtr src, > + virDomainVMGenIDDefPtr dst) > +{ > + if (memcmp(src->guidstr, dst->guidstr, VIR_UUID_BUFLEN) != 0) { This does not check 'auto' separately. It will not be able to differentiate between 'auto' and an UUID of '00000-000...'. Also it will report weird error message in that case. Also given that the GUID is to be changed during lifetime of the VM I'm not sure whether checking it is necessary at all. > + char guidsrc[VIR_UUID_STRING_BUFLEN]; > + char guiddst[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(src->guidstr, guidsrc); > + virUUIDFormat(dst->guidstr, guiddst); > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Target domain vmgenid guid '%s' does not match " > + "source '%s'"), > + guiddst, guidsrc); -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
On 03/21/2018 03:19 AM, Peter Krempa wrote: > On Tue, Mar 20, 2018 at 18:55:44 -0400, John Ferlan wrote: >> Add VM Generation ID device XML schema, parse, format, and documentation. >> >> Signed-off-by: John Ferlan <jferlan@redhat.com> >> --- >> docs/formatdomain.html.in | 54 ++++++++++++++ >> docs/schemas/domaincommon.rng | 21 ++++++ >> src/conf/domain_conf.c | 112 +++++++++++++++++++++++++++++- >> src/conf/domain_conf.h | 11 +++ >> tests/qemuxml2argvdata/vmgenid-auto.xml | 32 +++++++++ >> tests/qemuxml2argvdata/vmgenid.xml | 32 +++++++++ >> tests/qemuxml2xmloutdata/vmgenid-auto.xml | 1 + >> tests/qemuxml2xmloutdata/vmgenid.xml | 1 + >> tests/qemuxml2xmltest.c | 3 + >> 9 files changed, 266 insertions(+), 1 deletion(-) >> create mode 100644 tests/qemuxml2argvdata/vmgenid-auto.xml >> create mode 100644 tests/qemuxml2argvdata/vmgenid.xml >> create mode 120000 tests/qemuxml2xmloutdata/vmgenid-auto.xml >> create mode 120000 tests/qemuxml2xmloutdata/vmgenid.xml >> >> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in >> index 6fd2189cd2..895e51b343 100644 >> --- a/docs/formatdomain.html.in >> +++ b/docs/formatdomain.html.in >> @@ -8027,6 +8027,60 @@ qemu-kvm -net nic,model=? /dev/null >> </dd> >> </dl> >> >> + <h4><a id="elementsVmgenid">VM Generation ID device</a></h4> >> + >> + <p> >> + <span class="since">Since 4.2.0</span>, the <code>vmgenid</code> >> + element can be used to add a Virtual Machine Generation ID device. >> + A <code>vmgenid</code> device is an emulated device which exposes >> + a 128-bit, cryptographically random, integer value identifier, >> + referred to as a Globally Unique Identifier, or GUID. The value is >> + stored within the virtual machine's BIOS so that programs running in > > According to the qemu docs, it's stored in the ACPI table, so it does > not depend on BIOS being used. EFI can be used as well. > >> + the virtual machine can protect themselves from potential corruption >> + by checking that the Generation ID has not changed immediately prior >> + to committing a transaction. > > This last sentence is weird. I'd refrain from giving examples and rather > stick to describe which changes can be tracked by this. > > >> + >> + The <code>vmgenid</code> device will update the BIOS entry each time > > BIOS ... > >> + the virtual machine executes from a different configuration file such >> + as executing from a recovered snapshot or executing after restoring > > Okay. From this it seems that the GUID should change where the VM state > could be reverted to a point in history of the execution of the guest > software. This basically means that it should be always left to > autogenerating except in cases of migration where the new qemu process > needs to continue to use the old GUID. > > This means that you'll need to query it if 'auto' is specified and qemu > does not guarantee that it's properly transported in the migration > stream. On the other hand, if it is transported in the migration stream, > then save/restore and reversion of external snapshots with memory will > be fun, since that uses the migration code. > > You'll need to figure out where qemu stores this and how it's handled on > migration, since I did not see it in the doc. I read something along the way during the review of the patch series where the migration part of this was handled properly. The v8 is here: http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg03774.html and within the pile of responses for patch 4 this was discussed. I'll certainly go through that again once the XML pieces are agreed upon. > > Also there is one other problem and that is reversion of internal > snapshots, which in some cases does not require restarting the emulator > in case of qemu. In such case you'll need to make sure that the > condition is modified so that a VM with this device will always restart > qemu. > Perhaps this is what danpb was alluding to in his comment in bz 1149445. I hadn't yet begun the process of thinking through the various transitions - I do know I can add the vmgenid device to a "new" guest (either either a static guid or an 'auto' guid). But that just POC for me that it's possible to do the simple thing. One "issue" is that there's currently no way to update/provide the guid value for a transaction that QEMU isn't restarted. However, there is code upstream for qemu to add that, see: http://lists.nongnu.org/archive/html/qemu-devel/2018-03/msg00551.html >> + from backup. Programs running in a virtual machine can protect themselves >> + from potential corruption by checking that the generation ID has not >> + changed immediately prior to committing a transaction, they can also >> + use the data provided in the 128-bit identifier as a high entropy >> + random data source. > > Whoah. The qemu docs don't speak about entropy source. Is it described > in the Microsoft documentation? In any case, if the GUID is going to be > used as an entropy source, we need to approach it way more carefully. > Especially don't report it to unauthorized eyes. I'd be very happy if > will not have to keep it secret. This will get especially tricky since > there will be cases where we'll need to put it on the command line > (either on migration or on save/restore). > Yes, that's all from the MS docs. I toyed with keeping the QEMU wording only, but since this is "currently" essentially a Windows guest feature, I went with the MS wording even though yes, it's a bit more onerous. And based on the Aug 1, 2012 date of the MS document and the target OS (Windows Server 2012 or Windows 8), I'd say they weren't thinking anything beyond BIOS. In any case, I can reword things to be a bit more vague as this moves forward. If we avoid the capability to "supply" a guid and only allowed an 'auto' guid, then being able to fetch the guid after the creation of the device and save it in the qemu private data would be possible. Although saving that does open the question again about being able to 'see' it. It is possible to fetch the value and display by a new virsh command too, but based on this perhaps it's best that code never sees the light of day. >> + </p> >> + >> + <p> >> + Example: >> + </p> >> +<pre> >> +... >> +<devices> >> + <vmgenid guid='3e3fce45-4f53-4fa7-bb32-11f34168b82b'/> > > So I think we should use a more generic element with 'vmgenid' as a > model. It looks like this is one of possible implementations of such a > thing and it's fully possible to emulate a PCI device or anything else > with similar semantics. > Oh interesting implementation idea. Wish you'd provided generic example XML as well. <devices> <generic model='vmgenid'> <params guid='auto'/> </generic> </devices> Could make for some awful RNG code that I'll dislike writing. I prefer to keep things a bit more simple and not try to over engineer this, but I'm willing to work through an example. >> +</devices> >> +... >> +</pre> >> + >> +<pre> >> +... >> +<devices> >> + <vmgenid guid='auto'/> >> +</devices> >> +... >> +</pre> >> + >> + <dl> >> + <dt><code>guid</code></dt> >> + <dd> >> + <p> >> + The required <code>guid</code> attribute can be either a provided >> + (<a href="#elementsMetadata"><code>uuid</code></a>) formatted value >> + or the string 'auto' if the underlying hypervisor supports creating > > So 'auto' in place of the guid is a qemuism according to the docs. You > should go with a separate element for it in cases where you need to > configure that the setting is automatic, but you also need to transfer > the guid itself. > > Also the necessity to allow configuration of the GUID really depends on > the questions I've asked above. It might be even unnecessary to allow > configuration of the GUID itself depending on that. In cases where we'll > need to preserve it accross migration, we'll really need a way to store > it in the XML. > Now that you've brought it up, I can certainly see the downsides of providing a static guid and enforcing that it's always autogenerated. >> + its own value. >> + </p> >> + </dd> >> + </dl> >> + >> <h3><a id="seclabel">Security label</a></h3> >> >> <p> >> <interleave> > > [...] > >> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c >> index 2f07180faa..aaba2a47f7 100644 >> --- a/src/conf/domain_conf.c >> +++ b/src/conf/domain_conf.c > > [...] > >> @@ -15690,6 +15692,45 @@ virDomainIOMMUDefParseXML(xmlNodePtr node, >> } >> >> >> +static virDomainVMGenIDDefPtr >> +virDomainVMGenIDDefParseXML(xmlNodePtr node, >> + xmlXPathContextPtr ctxt) >> +{ >> + virDomainVMGenIDDefPtr vmgenid = NULL; >> + virDomainVMGenIDDefPtr ret = NULL; >> + xmlNodePtr save = ctxt->node; >> + char *guidxml = NULL; >> + >> + ctxt->node = node; >> + >> + if (VIR_ALLOC(vmgenid) < 0) >> + goto cleanup; >> + >> + if (!(guidxml = virXMLPropString(node, "guid"))) { >> + virReportError(VIR_ERR_XML_ERROR, "%s", >> + _("missing required 'guid' attribute")); >> + goto cleanup; >> + } >> + >> + if (STREQ(guidxml, "auto")) { >> + vmgenid->autogenerate = true; >> + } else { >> + if (virUUIDParse(guidxml, vmgenid->guidstr) < 0) { >> + virReportError(VIR_ERR_XML_ERROR, >> + _("malformed guid='%s' provided"), guidxml); >> + goto cleanup; >> + } >> + } >> + >> + VIR_STEAL_PTR(ret, vmgenid); >> + >> + cleanup: > > 'guidxml' is leaked > oh right... >> + VIR_FREE(vmgenid); >> + ctxt->node = save; >> + return ret; >> +} >> + >> + >> virDomainDeviceDefPtr >> virDomainDeviceDefParse(const char *xmlStr, >> const virDomainDef *def, > > [...] > >> @@ -21812,6 +21871,25 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src, >> >> >> static bool >> +virDomainVMGenIDDefCheckABIStability(virDomainVMGenIDDefPtr src, >> + virDomainVMGenIDDefPtr dst) >> +{ >> + if (memcmp(src->guidstr, dst->guidstr, VIR_UUID_BUFLEN) != 0) { > > This does not check 'auto' separately. It will not be able to > differentiate between 'auto' and an UUID of '00000-000...'. Also it will > report weird error message in that case. > > Also given that the GUID is to be changed during lifetime of the VM I'm > not sure whether checking it is necessary at all. > Hmmm... true, ironically my first pass at this was to compare src/dst autogenerated values. I hedged my bets in case there was a "desire" to fetch the QEMU generated GUID value and save it while the domain was running - although I suppose that would go in the domain private ... Of course then I wondered why even bother with this other than some reviewer asking - is there an ABI concerns. John >> + char guidsrc[VIR_UUID_STRING_BUFLEN]; >> + char guiddst[VIR_UUID_STRING_BUFLEN]; >> + virUUIDFormat(src->guidstr, guidsrc); >> + virUUIDFormat(dst->guidstr, guiddst); >> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, >> + _("Target domain vmgenid guid '%s' does not match " >> + "source '%s'"), >> + guiddst, guidsrc); -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
On Wed, Mar 21, 2018 at 08:19:46AM +0100, Peter Krempa wrote: > On Tue, Mar 20, 2018 at 18:55:44 -0400, John Ferlan wrote: > > Add VM Generation ID device XML schema, parse, format, and documentation. > > > > Signed-off-by: John Ferlan <jferlan@redhat.com> > > --- > > docs/formatdomain.html.in | 54 ++++++++++++++ > > docs/schemas/domaincommon.rng | 21 ++++++ > > src/conf/domain_conf.c | 112 +++++++++++++++++++++++++++++- > > src/conf/domain_conf.h | 11 +++ > > tests/qemuxml2argvdata/vmgenid-auto.xml | 32 +++++++++ > > tests/qemuxml2argvdata/vmgenid.xml | 32 +++++++++ > > tests/qemuxml2xmloutdata/vmgenid-auto.xml | 1 + > > tests/qemuxml2xmloutdata/vmgenid.xml | 1 + > > tests/qemuxml2xmltest.c | 3 + > > 9 files changed, 266 insertions(+), 1 deletion(-) > > create mode 100644 tests/qemuxml2argvdata/vmgenid-auto.xml > > create mode 100644 tests/qemuxml2argvdata/vmgenid.xml > > create mode 120000 tests/qemuxml2xmloutdata/vmgenid-auto.xml > > create mode 120000 tests/qemuxml2xmloutdata/vmgenid.xml > > > > diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in > > index 6fd2189cd2..895e51b343 100644 > > --- a/docs/formatdomain.html.in > > +++ b/docs/formatdomain.html.in > > @@ -8027,6 +8027,60 @@ qemu-kvm -net nic,model=? /dev/null > > </dd> > > </dl> > > > > + <h4><a id="elementsVmgenid">VM Generation ID device</a></h4> > > + > > + <p> > > + <span class="since">Since 4.2.0</span>, the <code>vmgenid</code> > > + element can be used to add a Virtual Machine Generation ID device. > > + A <code>vmgenid</code> device is an emulated device which exposes > > + a 128-bit, cryptographically random, integer value identifier, > > + referred to as a Globally Unique Identifier, or GUID. The value is > > + stored within the virtual machine's BIOS so that programs running in > > According to the qemu docs, it's stored in the ACPI table, so it does > not depend on BIOS being used. EFI can be used as well. Yes, it is part of ACPI blob exposed to the guest > > + the virtual machine executes from a different configuration file such > > + as executing from a recovered snapshot or executing after restoring > > Okay. From this it seems that the GUID should change where the VM state > could be reverted to a point in history of the execution of the guest > software. This basically means that it should be always left to > autogenerating except in cases of migration where the new qemu process > needs to continue to use the old GUID. > > This means that you'll need to query it if 'auto' is specified and qemu > does not guarantee that it's properly transported in the migration > stream. On the other hand, if it is transported in the migration stream, > then save/restore and reversion of external snapshots with memory will > be fun, since that uses the migration code. All ACPI state is maintained by QEMU across migration - so regardless of what CLI args are given, the vmgenid won't change during migration. For sanity sake though, we should likely make sure the CLI args given the matching version on target, otherwise we'll get seriously confused when debugging. > > + from backup. Programs running in a virtual machine can protect themselves > > + from potential corruption by checking that the generation ID has not > > + changed immediately prior to committing a transaction, they can also > > + use the data provided in the 128-bit identifier as a high entropy > > + random data source. > > Whoah. The qemu docs don't speak about entropy source. Is it described > in the Microsoft documentation? In any case, if the GUID is going to be > used as an entropy source, we need to approach it way more carefully. > Especially don't report it to unauthorized eyes. I'd be very happy if > will not have to keep it secret. This will get especially tricky since > there will be cases where we'll need to put it on the command line > (either on migration or on save/restore). > > > + </p> > > + > > + <p> > > + Example: > > + </p> > > +<pre> > > +... > > +<devices> > > + <vmgenid guid='3e3fce45-4f53-4fa7-bb32-11f34168b82b'/> > > So I think we should use a more generic element with 'vmgenid' as a > model. It looks like this is one of possible implementations of such a > thing and it's fully possible to emulate a PCI device or anything else > with similar semantics. I tend to thing we should *not* represent this as a device at all. This is essentially equivalent to the global <uuid> field we have already, except that in a handful of situations it can change. IOW I think we should just have <genid>.....</genid> in the XML alongside the <uuid>. An empty <genid/> element can be used to request that the feature be enabled, and we should automatically replace the previous value when required - I don't see a compelling reason to use a magic string "auto" - it should always be automatic. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2025 Red Hat, Inc.