1 package PVE
::QemuServer
::Machine
;
6 use PVE
::QemuServer
::Helpers
;
7 use PVE
::QemuServer
::Monitor
;
8 use PVE
::JSONSchema
qw(get_standard_option parse_property_string);
10 # Bump this for VM HW layout changes during a release (where the QEMU machine
11 # version stays the same)
12 our $PVE_MACHINE_VERSION = {
19 description
=> "Specifies the QEMU machine type.",
21 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
23 format_description
=> 'machine type',
28 description
=> "Enable and set guest vIOMMU variant (Intel vIOMMU needs q35 to be set as"
30 enum
=> ['intel', 'virtio'],
35 PVE
::JSONSchema
::register_format
('pve-qemu-machine-fmt', $machine_fmt);
37 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
38 description
=> "Specify the QEMU machine.",
41 format
=> PVE
::JSONSchema
::get_format
('pve-qemu-machine-fmt'),
49 my $res = parse_property_string
($machine_fmt, $value);
54 my ($machine_conf) = @_;
55 return print_property_string
($machine_conf, $machine_fmt);
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";
66 sub machine_type_is_q35
{
69 my $machine_conf = parse_machine
($conf->{machine
});
70 return $machine_conf->{type
} && ($machine_conf->{type
} =~ m/q35/) ?
1 : 0;
73 # In list context, also returns whether the current machine is deprecated or not.
74 sub current_from_query_machines
{
77 my ($current, $default);
78 for my $machine ($machines->@*) {
79 $default = $machine->{name
} if $machine->{'is-default'};
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'};
85 return wantarray ?
($current, $machine->{deprecated
} ?
1 : 0) : $current;
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;
94 # This only works if VM is running.
95 # In list context, also returns whether the current machine is deprecated or not.
96 sub get_current_qemu_machine
{
99 my $res = PVE
::QemuServer
::Monitor
::mon_cmd
($vmid, 'query-machines');
101 return current_from_query_machines
($res);
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.
107 sub extract_version
{
108 my ($machine_type, $kvmversion) = @_;
110 if (defined($machine_type) && $machine_type =~
111 m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/)
113 my $versionstr = "$1.$2";
114 $versionstr .= $4 if $4;
116 } elsif (defined($kvmversion)) {
117 if ($kvmversion =~ m/^(\d+)\.(\d+)/) {
118 my $pvever = get_pve_version
($kvmversion);
119 return "$1.$2+pve$pvever";
126 sub machine_version
{
127 my ($machine_type, $major, $minor, $pve) = @_;
129 return PVE
::QemuServer
::Helpers
::min_version
(
130 extract_version
($machine_type), $major, $minor, $pve);
133 sub get_pve_version
{
136 if ($verstr =~ m/^(\d+\.\d+)/) {
137 return $PVE_MACHINE_VERSION->{$1} // 0;
140 die "internal error: cannot get pve version for invalid string '$verstr'";
143 sub can_run_pve_machine_version
{
144 my ($machine_version, $kvmversion) = @_;
146 $machine_version =~ m/^(\d+)\.(\d+)(?:\+pve(\d+))?(?:\.pxe)?$/;
151 $kvmversion =~ m/(\d+)\.(\d+)/;
152 return 0 if PVE
::QemuServer
::Helpers
::version_cmp
($1, $major, $2, $minor) < 0;
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;
158 my $max_supported = get_pve_version
("$major.$minor");
159 return 1 if $max_supported >= $pvever;
164 # dies if a) VM not running or not exisiting b) Version query failed
165 # So, any defined return value is valid, any invalid state can be caught by eval
166 sub runs_at_least_qemu_version
{
167 my ($vmid, $major, $minor, $extra) = @_;
169 my $v = PVE
::QemuServer
::Monitor
::mon_cmd
($vmid, 'query-version');
170 die "could not query currently running version for VM $vmid\n" if !defined($v);
173 return PVE
::QemuServer
::Helpers
::version_cmp
($v->{major
}, $major, $v->{minor
}, $minor, $v->{micro
}, $extra) >= 0;
176 sub qemu_machine_pxe
{
177 my ($vmid, $conf) = @_;
179 my $machine = get_current_qemu_machine
($vmid);
181 my $machine_conf = parse_machine
($conf->{machine
});
182 if ($machine_conf->{type
} && $machine_conf->{type
} =~ m/\.pxe$/) {