use PVE::QemuServer::Helpers;
use PVE::QemuServer::Monitor;
+# Bump this for VM HW layout changes during a release (where the QEMU machine
+# version stays the same)
+our $PVE_MACHINE_VERSION = {
+ '4.1' => 2,
+};
+
sub machine_type_is_q35 {
my ($conf) = @_;
my $res = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-machines');
- my ($current, $default);
+ my ($current, $pve_version, $default);
foreach my $e (@$res) {
$default = $e->{name} if $e->{'is-default'};
$current = $e->{name} if $e->{'is-current'};
+ $pve_version = $e->{'pve-version'} if $e->{'pve-version'};
}
+ $current .= "+$pve_version" if $current && $pve_version;
+
# fallback to the default machine if current is not supported by qemu
return $current || $default || 'pc';
}
+# returns a string with major.minor+pve<VERSION>, patch version-part is ignored
+# as it's seldom ressembling a real QEMU machine type, so it would be '0' 99% of
+# the time anyway.. This explicitly separates pveversion from the machine.
sub extract_version {
- my ($machine_type) = @_;
-
- if ($machine_type && $machine_type =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
- return "$3.$4";
+ my ($machine_type, $kvmversion) = @_;
+
+ if (defined($machine_type) && $machine_type =~ m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?/) {
+ my $versionstr = "$1.$2";
+ $versionstr .= $4 if $4;
+ return $versionstr;
+ } elsif (defined($kvmversion)) {
+ if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
+ my $pvever = get_pve_version($kvmversion);
+ return "$1.$2+pve$pvever";
+ }
}
- return undef;
+ return;
}
sub machine_version {
- my ($machine_type, $version_major, $version_minor) = @_;
+ my ($machine_type, $major, $minor, $pve) = @_;
return PVE::QemuServer::Helpers::min_version(
- extract_version($machine_type), $version_major, $version_minor);
+ extract_version($machine_type), $major, $minor, $pve);
+}
+
+sub get_pve_version {
+ my ($verstr) = @_;
+
+ if ($verstr =~ m/^(\d+\.\d+)/) {
+ return $PVE_MACHINE_VERSION->{$1} // 0;
+ }
+
+ die "internal error: cannot get pve version for invalid string '$verstr'";
+}
+
+sub can_run_pve_machine_version {
+ my ($machine_version, $kvmversion) = @_;
+
+ $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))$/;
+ my $major = $1;
+ my $minor = $2;
+ my $pvever = $3;
+
+ $kvmversion =~ m/(\d+)\.(\d+)/;
+ return 0 if PVE::QemuServer::Helpers::version_cmp($1, $major, $2, $minor) < 0;
+
+ # if $pvever is missing or 0, we definitely support it as long as we didn't
+ # fail the QEMU version check above
+ return 1 if !$pvever;
+
+ my $max_supported = get_pve_version("$major.$minor");
+ return 1 if $max_supported >= $pvever;
+
+ return 0;
}
# dies if a) VM not running or not exisiting b) Version query failed
die "could not query currently running version for VM $vmid\n" if !defined($v);
$v = $v->{qemu};
- return version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
+ return PVE::QemuServer::Helpers::version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
}
sub qemu_machine_pxe {