]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer/Machine.pm
fix #3784: config: Parameter for guest vIOMMU + test-cases
[qemu-server.git] / PVE / QemuServer / Machine.pm
index d9429ed45fad878c6c67e7ff88539e779b3caa7f..3d92c96da4e13eb39b89525521f3b8654597dd91 100644 (file)
@@ -5,6 +5,7 @@ use warnings;
 
 use PVE::QemuServer::Helpers;
 use PVE::QemuServer::Monitor;
+use PVE::JSONSchema qw(get_standard_option parse_property_string);
 
 # Bump this for VM HW layout changes during a release (where the QEMU machine
 # version stays the same)
@@ -12,29 +13,86 @@ our $PVE_MACHINE_VERSION = {
     '4.1' => 2,
 };
 
+my $machine_fmt = {
+    type => {
+       default_key => 1,
+       description => "Specifies the QEMU machine type.",
+       type => 'string',
+       pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
+       maxLength => 40,
+       format_description => 'machine type',
+       optional => 1,
+    },
+    viommu => {
+       type => 'string',
+       description => "Enable and set guest vIOMMU variant (Intel vIOMMU needs q35 to be set as"
+           ." machine type).",
+       enum => ['intel', 'virtio'],
+       optional => 1,
+    },
+};
+
+PVE::JSONSchema::register_format('pve-qemu-machine-fmt', $machine_fmt);
+
+PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
+    description => "Specify the QEMU machine.",
+    type => 'string',
+    optional => 1,
+    format => PVE::JSONSchema::get_format('pve-qemu-machine-fmt'),
+});
+
+sub parse_machine {
+    my ($value) = @_;
+
+    return if !$value;
+
+    my $res = parse_property_string($machine_fmt, $value);
+    return $res;
+}
+
+sub print_machine {
+    my ($machine_conf) = @_;
+    return print_property_string($machine_conf, $machine_fmt);
+}
+
+sub assert_valid_machine_property {
+    my ($conf, $machine_conf) = @_;
+    my $q35 = $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0;
+    if ($machine_conf->{viommu} && $machine_conf->{viommu} eq "intel" && !$q35) {
+       die "to use Intel vIOMMU please set the machine type to q35\n";
+    }
+}
+
 sub machine_type_is_q35 {
     my ($conf) = @_;
 
-    return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
+    my $machine_conf = parse_machine($conf->{machine});
+    return $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0;
 }
 
+# In list context, also returns whether the current machine is deprecated or not.
 sub current_from_query_machines {
-    my ($res) = @_;
+    my ($machines) = @_;
 
-    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'};
-    }
+    my ($current, $default);
+    for my $machine ($machines->@*) {
+       $default = $machine->{name} if $machine->{'is-default'};
 
-    $current .= "+$pve_version" if $current && $pve_version;
+       if ($machine->{'is-current'}) {
+           $current = $machine->{name};
+           # pve-version only exists for the current machine
+           $current .= "+$machine->{'pve-version'}" if $machine->{'pve-version'};
+           return wantarray ? ($current, $machine->{deprecated} ? 1 : 0) : $current;
+       }
+    }
 
-    # fallback to the default machine if current is not supported by qemu
-    return $current || $default || 'pc';
+    # fallback to the default machine if current is not supported by qemu - assume never deprecated
+    my $fallback = $default || 'pc';
+    return wantarray ? ($fallback, 0) : $fallback;
 }
 
-# this only works if VM is running
+# This only works if VM is running.
+# In list context, also returns whether the current machine is deprecated or not.
 sub get_current_qemu_machine {
     my ($vmid) = @_;
 
@@ -120,7 +178,8 @@ sub qemu_machine_pxe {
 
     my $machine =  get_current_qemu_machine($vmid);
 
-    if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
+    my $machine_conf = parse_machine($conf->{machine});
+    if ($machine_conf->{type} && $machine_conf->{type} =~ m/\.pxe$/) {
        $machine .= '.pxe';
     }