]>
Commit | Line | Data |
---|---|---|
3392d6ca SR |
1 | package PVE::QemuServer::Machine; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
2ea5fb7e | 6 | use PVE::QemuServer::Helpers; |
3392d6ca | 7 | use PVE::QemuServer::Monitor; |
43569a32 | 8 | use PVE::JSONSchema qw(get_standard_option parse_property_string print_property_string); |
3392d6ca | 9 | |
9471e48b TL |
10 | # Bump this for VM HW layout changes during a release (where the QEMU machine |
11 | # version stays the same) | |
ac0077cc | 12 | our $PVE_MACHINE_VERSION = { |
b8fb1c03 | 13 | '4.1' => 2, |
ac0077cc | 14 | }; |
9471e48b | 15 | |
8082eb8c MF |
16 | my $machine_fmt = { |
17 | type => { | |
18 | default_key => 1, | |
19 | description => "Specifies the QEMU machine type.", | |
20 | type => 'string', | |
21 | pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)', | |
22 | maxLength => 40, | |
23 | format_description => 'machine type', | |
24 | optional => 1, | |
25 | }, | |
2db4c272 MF |
26 | viommu => { |
27 | type => 'string', | |
28 | description => "Enable and set guest vIOMMU variant (Intel vIOMMU needs q35 to be set as" | |
29 | ." machine type).", | |
30 | enum => ['intel', 'virtio'], | |
31 | optional => 1, | |
32 | }, | |
8082eb8c MF |
33 | }; |
34 | ||
35 | PVE::JSONSchema::register_format('pve-qemu-machine-fmt', $machine_fmt); | |
36 | ||
37 | PVE::JSONSchema::register_standard_option('pve-qemu-machine', { | |
2db4c272 | 38 | description => "Specify the QEMU machine.", |
8082eb8c MF |
39 | type => 'string', |
40 | optional => 1, | |
41 | format => PVE::JSONSchema::get_format('pve-qemu-machine-fmt'), | |
42 | }); | |
43 | ||
44 | sub parse_machine { | |
45 | my ($value) = @_; | |
46 | ||
47 | return if !$value; | |
48 | ||
49 | my $res = parse_property_string($machine_fmt, $value); | |
50 | return $res; | |
51 | } | |
52 | ||
53 | sub print_machine { | |
54 | my ($machine_conf) = @_; | |
55 | return print_property_string($machine_conf, $machine_fmt); | |
56 | } | |
57 | ||
2db4c272 MF |
58 | sub assert_valid_machine_property { |
59 | my ($conf, $machine_conf) = @_; | |
60 | my $q35 = $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0; | |
61 | if ($machine_conf->{viommu} && $machine_conf->{viommu} eq "intel" && !$q35) { | |
62 | die "to use Intel vIOMMU please set the machine type to q35\n"; | |
63 | } | |
64 | } | |
65 | ||
3392d6ca SR |
66 | sub machine_type_is_q35 { |
67 | my ($conf) = @_; | |
68 | ||
8082eb8c MF |
69 | my $machine_conf = parse_machine($conf->{machine}); |
70 | return $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0; | |
3392d6ca SR |
71 | } |
72 | ||
da841554 | 73 | # In list context, also returns whether the current machine is deprecated or not. |
ea71be24 | 74 | sub current_from_query_machines { |
081eed3b | 75 | my ($machines) = @_; |
3392d6ca | 76 | |
7d6a6292 | 77 | my ($current, $default); |
081eed3b FE |
78 | for my $machine ($machines->@*) { |
79 | $default = $machine->{name} if $machine->{'is-default'}; | |
3392d6ca | 80 | |
7d6a6292 FE |
81 | if ($machine->{'is-current'}) { |
82 | $current = $machine->{name}; | |
83 | # pve-version only exists for the current machine | |
84 | $current .= "+$machine->{'pve-version'}" if $machine->{'pve-version'}; | |
da841554 | 85 | return wantarray ? ($current, $machine->{deprecated} ? 1 : 0) : $current; |
7d6a6292 FE |
86 | } |
87 | } | |
9471e48b | 88 | |
da841554 FE |
89 | # fallback to the default machine if current is not supported by qemu - assume never deprecated |
90 | my $fallback = $default || 'pc'; | |
91 | return wantarray ? ($fallback, 0) : $fallback; | |
3392d6ca SR |
92 | } |
93 | ||
da841554 FE |
94 | # This only works if VM is running. |
95 | # In list context, also returns whether the current machine is deprecated or not. | |
ea71be24 FE |
96 | sub get_current_qemu_machine { |
97 | my ($vmid) = @_; | |
98 | ||
99 | my $res = PVE::QemuServer::Monitor::mon_cmd($vmid, 'query-machines'); | |
100 | ||
101 | return current_from_query_machines($res); | |
102 | } | |
103 | ||
9471e48b TL |
104 | # returns a string with major.minor+pve<VERSION>, patch version-part is ignored |
105 | # as it's seldom ressembling a real QEMU machine type, so it would be '0' 99% of | |
106 | # the time anyway.. This explicitly separates pveversion from the machine. | |
2ea5fb7e | 107 | sub extract_version { |
9471e48b TL |
108 | my ($machine_type, $kvmversion) = @_; |
109 | ||
d4be7f31 SR |
110 | if (defined($machine_type) && $machine_type =~ |
111 | m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/) | |
112 | { | |
9471e48b TL |
113 | my $versionstr = "$1.$2"; |
114 | $versionstr .= $4 if $4; | |
115 | return $versionstr; | |
116 | } elsif (defined($kvmversion)) { | |
117 | if ($kvmversion =~ m/^(\d+)\.(\d+)/) { | |
ac0077cc SR |
118 | my $pvever = get_pve_version($kvmversion); |
119 | return "$1.$2+pve$pvever"; | |
9471e48b | 120 | } |
3392d6ca SR |
121 | } |
122 | ||
d1c1af4b | 123 | return; |
3392d6ca SR |
124 | } |
125 | ||
2ea5fb7e | 126 | sub machine_version { |
9471e48b | 127 | my ($machine_type, $major, $minor, $pve) = @_; |
3392d6ca | 128 | |
2ea5fb7e | 129 | return PVE::QemuServer::Helpers::min_version( |
9471e48b | 130 | extract_version($machine_type), $major, $minor, $pve); |
3392d6ca SR |
131 | } |
132 | ||
ac0077cc SR |
133 | sub get_pve_version { |
134 | my ($verstr) = @_; | |
135 | ||
136 | if ($verstr =~ m/^(\d+\.\d+)/) { | |
137 | return $PVE_MACHINE_VERSION->{$1} // 0; | |
138 | } | |
139 | ||
140 | die "internal error: cannot get pve version for invalid string '$verstr'"; | |
141 | } | |
142 | ||
143 | sub can_run_pve_machine_version { | |
144 | my ($machine_version, $kvmversion) = @_; | |
145 | ||
d4be7f31 | 146 | $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))?(?:\.pxe)?$/; |
ac0077cc SR |
147 | my $major = $1; |
148 | my $minor = $2; | |
149 | my $pvever = $3; | |
150 | ||
151 | $kvmversion =~ m/(\d+)\.(\d+)/; | |
152 | return 0 if PVE::QemuServer::Helpers::version_cmp($1, $major, $2, $minor) < 0; | |
153 | ||
154 | # if $pvever is missing or 0, we definitely support it as long as we didn't | |
155 | # fail the QEMU version check above | |
156 | return 1 if !$pvever; | |
157 | ||
158 | my $max_supported = get_pve_version("$major.$minor"); | |
159 | return 1 if $max_supported >= $pvever; | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
3392d6ca SR |
164 | sub qemu_machine_pxe { |
165 | my ($vmid, $conf) = @_; | |
166 | ||
167 | my $machine = get_current_qemu_machine($vmid); | |
168 | ||
8082eb8c MF |
169 | my $machine_conf = parse_machine($conf->{machine}); |
170 | if ($machine_conf->{type} && $machine_conf->{type} =~ m/\.pxe$/) { | |
3392d6ca SR |
171 | $machine .= '.pxe'; |
172 | } | |
173 | ||
174 | return $machine; | |
175 | } | |
176 | ||
177 | 1; |