[pve-devel] [RFC qemu-server 4/6] Add QEMU CPU flag querying helpers

Stefan Reiter s.reiter at proxmox.com
Wed Jul 17 15:03:46 CEST 2019


* query_understood_cpu_flags returns all flags that QEMU/KVM knows about
* query_supported_cpu_flags returns all flags that QEMU/KVM can use on
  this particular host.

To get supported flags, a temporary VM is started with QEMU, so we can
issue the "query-cpu-model-expansion" QMP command. This is how libvirt
queries supported flags for its "host-passthrough" CPU type.

query_supported_cpu_flags is thus rather slow and shouldn't be called
unnecessarily.

Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
 PVE/QemuServer.pm | 79 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 9f29927..9ee9722 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -3448,6 +3448,85 @@ sub get_command_for_arch($) {
     return $cmd;
 }
 
+sub query_understood_cpu_flags {
+    my $flags = [];
+    my $flag_section = 0;
+
+    run_command(
+	[get_command_for_arch('x86_64'), '-cpu', 'help'],
+	noerr => 1,
+	quiet => 1,
+	outfunc => sub {
+	    my ($line) = @_;
+
+	    if ($flag_section) {
+		return if $line =~ m/^\s*$/;
+		$line =~ m/^\s*(.+?)\s*$/;
+		($line = $1) =~ s/-|\./_/g;
+		my @flags_line = split(m/\s+/, $line);
+		@$flags = (@$flags, @flags_line);
+	    } elsif ($line =~ m/^\s*Recognized CPUID flags:\s*$/) {
+		$flag_section = 1;
+	}
+    });
+
+    return $flags;
+}
+
+sub query_supported_cpu_flags {
+    my $flags = [];
+
+    my $pidfile = '/var/run/qemu-server/-1.pid';
+
+    # We start a temporary (frozen) VM with vmid -1 to allow us to send a QMP command
+    my $rc = run_command([
+	get_command_for_arch('x86_64'),
+	'-cpu', 'kvm64',
+	'-display', 'none',
+	'-chardev', 'socket,id=qmp,path=/var/run/qemu-server/-1.qmp,server,nowait',
+	'-mon', 'chardev=qmp,mode=control',
+	'-pidfile', $pidfile,
+	'-S',
+	'-daemonize'
+    ], noerr => 1, quiet => 1);
+    return [] if $rc;
+
+    my $qmpclient = PVE::QMPClient->new();
+    $qmpclient->queue_cmd(
+	-1,
+	sub {
+	    my ($vmid, $response) = @_;
+
+	    return if %{$response->{error}};
+
+	    my $props = $response->{return}->{model}->{props};
+	    return if !%$props;
+
+	    foreach my $prop_raw (keys %$props) {
+		(my $prop = $prop_raw) =~ s/-|\./_/g;
+		push @$flags, $prop if "$props->{$prop_raw}" eq '1';
+	    }
+	},
+	'query-cpu-model-expansion',
+	type => 'full',
+	model => { name => 'host' });
+    $qmpclient->queue_cmd(-1, undef, 'quit');
+    $qmpclient->queue_execute(3, 2);
+
+    # Wait for QEMU to terminate
+    sleep 1;
+
+    if (-e $pidfile) {
+	$rc = run_command([
+	    'pkill', '-F', $pidfile
+	], noerr => 1, quiet => 1);
+
+	warn 'QEMU instance used for host CPU flag detection could not be killed\n' if $rc;
+    }
+
+    return $flags;
+}
+
 sub get_cpu_options {
     my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
 
-- 
2.20.1





More information about the pve-devel mailing list