diff --git a/pkg/util/util.go b/pkg/util/util.go index a1265b2747d8..106fee893a92 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "os" "strings" v1 "kubevirt.io/client-go/api/v1" @@ -81,6 +82,23 @@ func NeedVirtioNetDevice(vmi *v1.VirtualMachineInstance, useEmulation bool) bool return false } +// UseSoftwareEmulationForDevice determines whether to fallback to software emulation for the given device. +// This happens when the given device doesn't exist, and software emulation is enabled. +func UseSoftwareEmulationForDevice(devicePath string, useEmulation bool) (bool, error) { + if !useEmulation { + return false, nil + } + + _, err := os.Stat(devicePath) + if err == nil { + return false, nil + } + if os.IsNotExist(err) { + return true, nil + } + return false, err +} + func ResourceNameToEnvVar(prefix string, resourceName string) string { varName := strings.ToUpper(resourceName) varName = strings.Replace(varName, "/", "_", -1) diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go index c821a77360ae..d8783006c3f3 100644 --- a/pkg/virt-handler/vm.go +++ b/pkg/virt-handler/vm.go @@ -2414,13 +2414,9 @@ func (d *VirtualMachineController) vmUpdateHelperMigrationTarget(origVMI *v1.Vir } - res, err := d.podIsolationDetector.Detect(vmi) + err = d.claimKVMDeviceOwnership(vmi) if err != nil { - return err - } - - if err := diskutils.DefaultOwnershipManager.SetFileOwnership(path.Join(res.MountRoot(), "dev", "kvm")); err != nil { - return err + return fmt.Errorf("failed to set up file ownership for /dev/kvm: %v", err) } if virtutil.IsNonRootVMI(vmi) { @@ -2504,12 +2500,9 @@ func (d *VirtualMachineController) vmUpdateHelperDefault(origVMI *v1.VirtualMach } - res, err := d.podIsolationDetector.Detect(vmi) + err = d.claimKVMDeviceOwnership(vmi) if err != nil { - return err - } - if err := diskutils.DefaultOwnershipManager.SetFileOwnership(path.Join(res.MountRoot(), "dev", "kvm")); err != nil { - return err + return fmt.Errorf("failed to set up file ownership for /dev/kvm: %v", err) } if virtutil.IsNonRootVMI(vmi) { @@ -2772,6 +2765,22 @@ func (d *VirtualMachineController) isHostModelMigratable(vmi *v1.VirtualMachineI return nil } +func (d *VirtualMachineController) claimKVMDeviceOwnership(vmi *v1.VirtualMachineInstance) error { + isolation, err := d.podIsolationDetector.Detect(vmi) + if err != nil { + return err + } + + kvmPath := path.Join(isolation.MountRoot(), "dev", "kvm") + + softwareEmulation, err := util.UseSoftwareEmulationForDevice(kvmPath, d.clusterConfig.IsUseEmulation()) + if err != nil || softwareEmulation { + return err + } + + return diskutils.DefaultOwnershipManager.SetFileOwnership(kvmPath) +} + func nodeHasHostModelLabel(node *k8sv1.Node) bool { for key, _ := range node.Labels { if strings.HasPrefix(key, v1.HostModelCPULabel) { diff --git a/pkg/virt-launcher/virtwrap/converter/converter.go b/pkg/virt-launcher/virtwrap/converter/converter.go index c2f475d00ea6..540235aa5aa5 100644 --- a/pkg/virt-launcher/virtwrap/converter/converter.go +++ b/pkg/virt-launcher/virtwrap/converter/converter.go @@ -1136,26 +1136,28 @@ func Convert_v1_VirtualMachineInstance_To_api_Domain(vmi *v1.VirtualMachineInsta CPUs: cpuCount, } - if _, err := os.Stat("/dev/kvm"); os.IsNotExist(err) { - if c.UseEmulation { - logger := log.DefaultLogger() - logger.Infof("Hardware emulation device '/dev/kvm' not present. Using software emulation.") - domain.Spec.Type = "qemu" - } else { - return fmt.Errorf("hardware emulation device '/dev/kvm' not present") - } + kvmPath := "/dev/kvm" + if softwareEmulation, err := util.UseSoftwareEmulationForDevice(kvmPath, c.UseEmulation); err != nil { + return err + } else if softwareEmulation { + logger := log.DefaultLogger() + logger.Infof("Hardware emulation device '%s' not present. Using software emulation.", kvmPath) + domain.Spec.Type = "qemu" + } else if _, err := os.Stat(kvmPath); os.IsNotExist(err) { + return fmt.Errorf("hardware emulation device '%s' not present", kvmPath) } else if err != nil { return err } virtioNetProhibited := false - if _, err := os.Stat("/dev/vhost-net"); os.IsNotExist(err) { - if c.UseEmulation { - logger := log.DefaultLogger() - logger.Infof("In-kernel virtio-net device emulation '/dev/vhost-net' not present. Falling back to QEMU userland emulation.") - } else { - virtioNetProhibited = true - } + vhostNetPath := "/dev/vhost-net" + if softwareEmulation, err := util.UseSoftwareEmulationForDevice(vhostNetPath, c.UseEmulation); err != nil { + return err + } else if softwareEmulation { + logger := log.DefaultLogger() + logger.Infof("In-kernel virtio-net device emulation '%s' not present. Falling back to QEMU userland emulation.", vhostNetPath) + } else if _, err := os.Stat(vhostNetPath); os.IsNotExist(err) { + virtioNetProhibited = true } else if err != nil { return err }