[pve-devel] [RFC qemu-server 5/6] Add support for 'cluster' CPU type

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


CPU type 'cluster' uses the default kvm64 (or qemu64) CPU model, but
appends as many feature flags as possible. The maximum set of flags is
determined by looking at the supported flags of each node in the cluster
(or the local machine in case its running standalone), and matching
those up with the flags that the local QEMU/KVM (and the host, via
/proc/cpuinfo) understands.

Manually specified flags (by the user or by other code) will *not* be
overwritten.

Some flags only work with a dash (-) seperating them (instead of an _),
and to support comparing with other flags, "lahf_lm" has been changed to
"lahf-lm" - this had to be reflected in tests too.

Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
 PVE/QemuServer.pm                      | 59 +++++++++++++++++++++++++-
 test/cfg2cmd/minimal-defaults.conf.cmd |  2 +-
 test/cfg2cmd/simple1.conf.cmd          |  2 +-
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 9ee9722..a95ec88 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -27,6 +27,7 @@ use PVE::Storage;
 use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Cluster;
 use PVE::INotify;
 use PVE::ProcFSTools;
 use PVE::QemuConfig;
@@ -165,6 +166,7 @@ my $cpu_vendor_list = {
     qemu32 => 'default',
     qemu64 => 'default',
     max => 'default',
+    cluster => 'default',
 };
 
 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb|md-clear)/;
@@ -3527,6 +3529,41 @@ sub query_supported_cpu_flags {
     return $flags;
 }
 
+sub get_cluster_cpu_options {
+    # We can retrieve the understood flags locally (no cluster sync needed),
+    # since they only depend on the QEMU/KVM version - and we can't migrate to
+    # older versions anyway
+    my $flag_arrays = [
+	query_understood_cpu_flags()
+    ];
+
+    my @cpuinfo_flags = split(m/\s+/, PVE::ProcFSTools::read_cpuinfo()->{flags});
+    for my $i (1 .. $#cpuinfo_flags) {
+	# tsc-deadline flag is named differently in /proc/cpuinfo
+	if ($cpuinfo_flags[$i] =~ m/tsc_deadline_timer/) {
+	    $cpuinfo_flags[$i] = 'tsc_deadline';
+	    last;
+	}
+    }
+    push(@$flag_arrays, \@cpuinfo_flags);
+
+    my $all_infos = PVE::Cluster::get_node_kv('cpuflags');
+
+    foreach my $node (keys %$all_infos) {
+	my $node_flags = $all_infos->{$node};
+	my @node_flag_array = split(m/\s+/, $node_flags);
+	push(@$flag_arrays, \@node_flag_array);
+    }
+
+    my $flags_intersect = PVE::Tools::array_intersect($flag_arrays);
+
+    return map {
+	# Some flags are only supported with dashes
+	(my $dashed = $_) =~ s/_/-/g;
+	'+' . $dashed;
+    } @$flags_intersect;
+}
+
 sub get_cpu_options {
     my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
 
@@ -3538,10 +3575,17 @@ sub get_cpu_options {
 	$cpu = 'cortex-a57';
     }
     my $hv_vendor_id;
+    my $cluster = 0;
     if (my $cputype = $conf->{cpu}) {
 	my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
 	    or die "Cannot parse cpu description: $cputype\n";
-	$cpu = $cpuconf->{cputype};
+
+	$cluster = $cpuconf->{cputype} eq 'cluster';
+	$cpu = $cpuconf->{cputype} if !$cluster;
+
+	die "CPU type 'cluster' only supported on native x86_64"
+	    if $cluster && (!is_native($arch) || $arch ne 'x86_64');
+
 	$kvm_off = 1 if $cpuconf->{hidden};
 	$hv_vendor_id = $cpuconf->{'hv-vendor-id'};
 
@@ -3550,7 +3594,7 @@ sub get_cpu_options {
 	}
     }
 
-    push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
+    push @$cpuFlags , '+lahf-lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
 
     push @$cpuFlags , '-x2apic'
 	if $conf->{ostype} && $conf->{ostype} eq 'solaris';
@@ -3571,6 +3615,17 @@ sub get_cpu_options {
 
     push @$cpuFlags, 'kvm=off' if $kvm_off;
 
+    if ($cluster) {
+	my @cluster_flags = get_cluster_cpu_options();
+
+	# append cluster flags, but don't overwrite existing ones
+	foreach my $flag (@cluster_flags) {
+	    (my $match_flag = $flag) =~ s/^[+-=]?(.*)$/$1/g;
+	    push(@$cpuFlags, $flag)
+		if !grep(m/[+-=]?\Q$match_flag/, @$cpuFlags);
+	}
+    }
+
     if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
 	push @$cpuFlags, "vendor=${cpu_vendor}"
 	    if $cpu_vendor ne 'default';
diff --git a/test/cfg2cmd/minimal-defaults.conf.cmd b/test/cfg2cmd/minimal-defaults.conf.cmd
index 5abebe9..34abac5 100644
--- a/test/cfg2cmd/minimal-defaults.conf.cmd
+++ b/test/cfg2cmd/minimal-defaults.conf.cmd
@@ -12,7 +12,7 @@
   -nodefaults \
   -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \
   -vnc unix:/var/run/qemu-server/8006.vnc,password \
-  -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
+  -cpu kvm64,+lahf-lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
   -m 512 \
   -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
   -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
diff --git a/test/cfg2cmd/simple1.conf.cmd b/test/cfg2cmd/simple1.conf.cmd
index b5c06cf..9c11e9f 100644
--- a/test/cfg2cmd/simple1.conf.cmd
+++ b/test/cfg2cmd/simple1.conf.cmd
@@ -12,7 +12,7 @@
   -nodefaults \
   -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \
   -vnc unix:/var/run/qemu-server/8006.vnc,password \
-  -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
+  -cpu kvm64,+lahf-lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \
   -m 768 \
   -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
   -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
-- 
2.20.1





More information about the pve-devel mailing list