Add new 'kvm' domain feature and ability to hide KVM signature

QEMU 2.1 added support for the kvm=off option to the -cpu command,
allowing the KVM hypervisor signature to be hidden from the guest.
This enables disabling of some paravirualization features in the
guest as well as allowing certain drivers which test for the
hypervisor to load.  Domain XML syntax is as follows:

<domain type='kvm>
  ...
  <features>
    ...
    <kvm>
      <hidden state='on'/>
    </kvm>
  </features>
  ...

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Alex Williamson 2014-08-21 11:04:45 -06:00 committed by Ján Tomko
parent 4dfc34c301
commit d071164272
12 changed files with 240 additions and 2 deletions

View File

@ -1250,6 +1250,9 @@
&lt;vapic state='on'/&gt;
&lt;spinlocks state='on' retries='4096'/&gt;
&lt;/hyperv&gt;
&lt;kvm&gt;
&lt;hidden state='on'/&gt;
&lt;/kvm&gt;
&lt;pvspinlock/&gt;
&lt;/features&gt;
@ -1328,7 +1331,23 @@
can be explicitly disabled by using <code>state='off'</code>
attribute.
</dd>
<dt><code>kvm</code></dt>
<dd>Various features to change the behavior of the KVM hypervisor.
<table class="top_table">
<tr>
<th>Feature</th>
<th>Description</th>
<th>Value</th>
<th>Since</th>
</tr>
<tr>
<td>hidden</td>
<td>Hide the KVM hypervisor from standard MSR based discovery</td>
<td>on, off</td>
<td><span class="since">2.1.0 (QEMU only)</span></td>
</tr>
</table>
</dd>
</dl>
<h3><a name="elementsTime">Time keeping</a></h3>

View File

@ -3831,7 +3831,7 @@
</define>
<!--
A set of optional features: PAE, APIC, ACPI,
HyperV Enlightenment, paravirtual spinlocks and HAP support
HyperV Enlightenment, KVM features, paravirtual spinlocks and HAP support
-->
<define name="features">
<optional>
@ -3872,6 +3872,9 @@
<empty/>
</element>
</optional>
<optional>
<ref name="kvm"/>
</optional>
<optional>
<element name="privnet">
<empty/>
@ -4477,6 +4480,19 @@
</element>
</define>
<!-- Optional KVM features -->
<define name="kvm">
<element name="kvm">
<interleave>
<optional>
<element name="hidden">
<ref name="featurestate"/>
</element>
</optional>
</interleave>
</element>
</define>
<!-- Optional capabilities features -->
<define name="capabilities">
<element name="capabilities">

View File

@ -142,6 +142,7 @@ VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
"viridian",
"privnet",
"hyperv",
"kvm",
"pvspinlock",
"capabilities")
@ -155,6 +156,9 @@ VIR_ENUM_IMPL(virDomainHyperv, VIR_DOMAIN_HYPERV_LAST,
"vapic",
"spinlocks")
VIR_ENUM_IMPL(virDomainKVM, VIR_DOMAIN_KVM_LAST,
"hidden")
VIR_ENUM_IMPL(virDomainCapsFeature, VIR_DOMAIN_CAPS_FEATURE_LAST,
"audit_control",
"audit_write",
@ -12203,6 +12207,7 @@ virDomainDefParseXML(xmlDocPtr xml,
case VIR_DOMAIN_FEATURE_VIRIDIAN:
case VIR_DOMAIN_FEATURE_PRIVNET:
case VIR_DOMAIN_FEATURE_HYPERV:
case VIR_DOMAIN_FEATURE_KVM:
def->features[val] = VIR_TRISTATE_SWITCH_ON;
break;
@ -12330,6 +12335,54 @@ virDomainDefParseXML(xmlDocPtr xml,
ctxt->node = node;
}
if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
int feature;
int value;
node = ctxt->node;
if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0)
goto error;
for (i = 0; i < n; i++) {
feature = virDomainKVMTypeFromString((const char *)nodes[i]->name);
if (feature < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported KVM feature: %s"),
nodes[i]->name);
goto error;
}
ctxt->node = nodes[i];
switch ((virDomainKVM) feature) {
case VIR_DOMAIN_KVM_HIDDEN:
if (!(tmp = virXPathString("string(./@state)", ctxt))) {
virReportError(VIR_ERR_XML_ERROR,
_("missing 'state' attribute for "
"KVM feature '%s'"),
nodes[i]->name);
goto error;
}
if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid value of state argument "
"for KVM feature '%s'"),
nodes[i]->name);
goto error;
}
VIR_FREE(tmp);
def->kvm_features[feature] = value;
break;
case VIR_DOMAIN_KVM_LAST:
break;
}
}
VIR_FREE(nodes);
ctxt->node = node;
}
if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
goto error;
@ -14338,6 +14391,29 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
}
}
/* kvm */
if (src->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
switch ((virDomainKVM) i) {
case VIR_DOMAIN_KVM_HIDDEN:
if (src->kvm_features[i] != dst->kvm_features[i]) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("State of KVM feature '%s' differs: "
"source: '%s', destination: '%s'"),
virDomainKVMTypeToString(i),
virTristateSwitchTypeToString(src->kvm_features[i]),
virTristateSwitchTypeToString(dst->kvm_features[i]));
return false;
}
break;
case VIR_DOMAIN_KVM_LAST:
break;
}
}
}
return true;
}
@ -18172,6 +18248,30 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virBufferAddLit(buf, "</hyperv>\n");
break;
case VIR_DOMAIN_FEATURE_KVM:
if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
break;
virBufferAddLit(buf, "<kvm>\n");
virBufferAdjustIndent(buf, 2);
for (j = 0; j < VIR_DOMAIN_KVM_LAST; j++) {
switch ((virDomainKVM) j) {
case VIR_DOMAIN_KVM_HIDDEN:
if (def->kvm_features[j])
virBufferAsprintf(buf, "<%s state='%s'/>\n",
virDomainKVMTypeToString(j),
virTristateSwitchTypeToString(
def->kvm_features[j]));
break;
case VIR_DOMAIN_KVM_LAST:
break;
}
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</kvm>\n");
break;
case VIR_DOMAIN_FEATURE_CAPABILITIES:
if (def->features[i] == VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT &&
!virDomainDefHasCapabilitiesFeatures(def))

View File

@ -1515,6 +1515,7 @@ typedef enum {
VIR_DOMAIN_FEATURE_VIRIDIAN,
VIR_DOMAIN_FEATURE_PRIVNET,
VIR_DOMAIN_FEATURE_HYPERV,
VIR_DOMAIN_FEATURE_KVM,
VIR_DOMAIN_FEATURE_PVSPINLOCK,
VIR_DOMAIN_FEATURE_CAPABILITIES,
@ -1529,6 +1530,12 @@ typedef enum {
VIR_DOMAIN_HYPERV_LAST
} virDomainHyperv;
typedef enum {
VIR_DOMAIN_KVM_HIDDEN = 0,
VIR_DOMAIN_KVM_LAST
} virDomainKVM;
typedef enum {
VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT = 0,
VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW,
@ -1945,6 +1952,7 @@ struct _virDomainDef {
int features[VIR_DOMAIN_FEATURE_LAST];
int apic_eoi;
int hyperv_features[VIR_DOMAIN_HYPERV_LAST];
int kvm_features[VIR_DOMAIN_KVM_LAST];
unsigned int hyperv_spinlocks;
/* These options are of type virTristateSwitch: ON = keep, OFF = drop */
@ -2628,6 +2636,7 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceStreamingMode)
VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode)
VIR_ENUM_DECL(virDomainGraphicsVNCSharePolicy)
VIR_ENUM_DECL(virDomainHyperv)
VIR_ENUM_DECL(virDomainKVM)
VIR_ENUM_DECL(virDomainRNGModel)
VIR_ENUM_DECL(virDomainRNGBackend)
VIR_ENUM_DECL(virDomainTPMModel)

View File

@ -6230,6 +6230,25 @@ qemuBuildCpuArgStr(virQEMUDriverPtr driver,
}
}
if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
if (!have_cpu) {
virBufferAdd(&buf, default_model, -1);
have_cpu = true;
}
for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
switch ((virDomainKVM) i) {
case VIR_DOMAIN_KVM_HIDDEN:
if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON)
virBufferAddLit(&buf, ",kvm=off");
break;
case VIR_DOMAIN_KVM_LAST:
break;
}
}
}
if (virBufferCheckError(&buf) < 0)
goto cleanup;
@ -10712,6 +10731,9 @@ qemuParseCommandLineCPU(virDomainDefPtr dom,
}
virStringFreeList(hv_tokens);
hv_tokens = NULL;
} else if (STREQ(tokens[i], "kvm=off")) {
dom->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON;
dom->kvm_features[VIR_DOMAIN_KVM_HIDDEN] = VIR_TRISTATE_SWITCH_ON;
}
}

View File

@ -284,6 +284,8 @@ mymain(void)
DO_TEST("hyperv");
DO_TEST("kvm-features");
DO_TEST("pseries-nvram");
DO_TEST("pseries-disk");

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
/usr/bin/qemu \
-S -M pc -cpu qemu32 -m 214 -smp 6 -nographic \
-monitor unix:/tmp/test-monitor,server,nowait \
-boot n -usb -net none -serial none -parallel none

View File

@ -0,0 +1,27 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
<vcpu placement='static'>6</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='network'/>
</os>
<features>
<acpi/>
<kvm>
<hidden state='off'/>
</kvm>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<controller type='usb' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
/usr/bin/qemu -S -M pc \
-cpu qemu32,kvm=off -m 214 -smp 6 -nographic -monitor \
unix:/tmp/test-monitor,server,nowait -boot n -usb -net none -serial none \
-parallel none

View File

@ -0,0 +1,27 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
<vcpu placement='static'>6</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='network'/>
</os>
<features>
<acpi/>
<kvm>
<hidden state='on'/>
</kvm>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<controller type='usb' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<memballoon model='none'/>
</devices>
</domain>

View File

@ -672,6 +672,9 @@ mymain(void)
DO_TEST("hyperv", NONE);
DO_TEST("hyperv-off", NONE);
DO_TEST("kvm-features", NONE);
DO_TEST("kvm-features-off", NONE);
DO_TEST("hugepages", QEMU_CAPS_MEM_PATH);
DO_TEST("hugepages-pages", QEMU_CAPS_MEM_PATH, QEMU_CAPS_OBJECT_MEMORY_RAM,
QEMU_CAPS_OBJECT_MEMORY_FILE);

View File

@ -198,6 +198,9 @@ mymain(void)
DO_TEST("hyperv");
DO_TEST("hyperv-off");
DO_TEST("kvm-features");
DO_TEST("kvm-features-off");
DO_TEST("hugepages");
DO_TEST("hugepages-pages");
DO_TEST("hugepages-pages2");