]> git.proxmox.com Git - qemu-server.git/blob - PVE/QemuServer/Machine.pm
d9429ed45fad878c6c67e7ff88539e779b3caa7f
[qemu-server.git] / PVE / QemuServer / Machine.pm
1 package PVE::QemuServer::Machine;
2
3 use strict;
4 use warnings;
5
6 use PVE::QemuServer::Helpers;
7 use PVE::QemuServer::Monitor;
8
9 # Bump this for VM HW layout changes during a release (where the QEMU machine
10 # version stays the same)
11 our $PVE_MACHINE_VERSION = {
12 '4.1' => 2,
13 };
14
15 sub machine_type_is_q35 {
16 my ($conf) = @_;
17
18 return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
19 }
20
21 sub current_from_query_machines {
22 my ($res) = @_;
23
24 my ($current, $pve_version, $default);
25 foreach my $e (@$res) {
26 $default = $e->{name} if $e->{'is-default'};
27 $current = $e->{name} if $e->{'is-current'};
28 $pve_version = $e->{'pve-version'} if $e->{'pve-version'};
29 }
30
31 $current .= "+$pve_version" if $current && $pve_version;
32
33 # fallback to the default machine if current is not supported by qemu
34 return $current || $default || 'pc';
35 }
36
37 # this only works if VM is running
38 sub get_current_qemu_machine {
39 my ($vmid) = @_;
40
41 my $res = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-machines');
42
43 return current_from_query_machines($res);
44 }
45
46 # returns a string with major.minor+pve<VERSION>, patch version-part is ignored
47 # as it's seldom ressembling a real QEMU machine type, so it would be '0' 99% of
48 # the time anyway.. This explicitly separates pveversion from the machine.
49 sub extract_version {
50 my ($machine_type, $kvmversion) = @_;
51
52 if (defined($machine_type) && $machine_type =~
53 m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/)
54 {
55 my $versionstr = "$1.$2";
56 $versionstr .= $4 if $4;
57 return $versionstr;
58 } elsif (defined($kvmversion)) {
59 if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
60 my $pvever = get_pve_version($kvmversion);
61 return "$1.$2+pve$pvever";
62 }
63 }
64
65 return;
66 }
67
68 sub machine_version {
69 my ($machine_type, $major, $minor, $pve) = @_;
70
71 return PVE::QemuServer::Helpers::min_version(
72 extract_version($machine_type), $major, $minor, $pve);
73 }
74
75 sub get_pve_version {
76 my ($verstr) = @_;
77
78 if ($verstr =~ m/^(\d+\.\d+)/) {
79 return $PVE_MACHINE_VERSION->{$1} // 0;
80 }
81
82 die "internal error: cannot get pve version for invalid string '$verstr'";
83 }
84
85 sub can_run_pve_machine_version {
86 my ($machine_version, $kvmversion) = @_;
87
88 $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))?(?:\.pxe)?$/;
89 my $major = $1;
90 my $minor = $2;
91 my $pvever = $3;
92
93 $kvmversion =~ m/(\d+)\.(\d+)/;
94 return 0 if PVE::QemuServer::Helpers::version_cmp($1, $major, $2, $minor) < 0;
95
96 # if $pvever is missing or 0, we definitely support it as long as we didn't
97 # fail the QEMU version check above
98 return 1 if !$pvever;
99
100 my $max_supported = get_pve_version("$major.$minor");
101 return 1 if $max_supported >= $pvever;
102
103 return 0;
104 }
105
106 # dies if a) VM not running or not exisiting b) Version query failed
107 # So, any defined return value is valid, any invalid state can be caught by eval
108 sub runs_at_least_qemu_version {
109 my ($vmid, $major, $minor, $extra) = @_;
110
111 my $v = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-version');
112 die "could not query currently running version for VM $vmid\n" if !defined($v);
113 $v = $v->{qemu};
114
115 return PVE::QemuServer::Helpers::version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
116 }
117
118 sub qemu_machine_pxe {
119 my ($vmid, $conf) = @_;
120
121 my $machine = get_current_qemu_machine($vmid);
122
123 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
124 $machine .= '.pxe';
125 }
126
127 return $machine;
128 }
129
130 1;