gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/interfaces/builtin/kvm.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2017-2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package builtin 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "regexp" 26 "strings" 27 28 "github.com/snapcore/snapd/interfaces" 29 "github.com/snapcore/snapd/interfaces/kmod" 30 "github.com/snapcore/snapd/logger" 31 "github.com/snapcore/snapd/strutil" 32 ) 33 34 const kvmSummary = `allows access to the kvm device` 35 36 const kvmBaseDeclarationSlots = ` 37 kvm: 38 allow-installation: 39 slot-snap-type: 40 - core 41 deny-auto-connection: true 42 ` 43 44 const kvmConnectedPlugAppArmor = ` 45 # Description: Allow write access to kvm. 46 # See 'man kvm' for details. 47 48 /dev/kvm rw, 49 50 # Allow nested virtualization checks for different CPU models and architectures (where it is supported). 51 /sys/module/kvm_intel/parameters/nested r, 52 /sys/module/kvm_amd/parameters/nested r, 53 /sys/module/kvm_hv/parameters/nested r, # PPC64. 54 /sys/module/kvm/parameters/nested r, # S390. 55 ` 56 57 var kvmConnectedPlugUDev = []string{`KERNEL=="kvm"`} 58 59 type kvmInterface struct { 60 commonInterface 61 } 62 63 var procCpuinfo = "/proc/cpuinfo" 64 var flagsMatcher = regexp.MustCompile(`(?m)^flags\s+:\s+(.*)$`).FindSubmatch 65 66 func getCpuFlags() (flags []string, err error) { 67 buf, err := ioutil.ReadFile(procCpuinfo) 68 if err != nil { 69 // if we can't read cpuinfo, we want to know _why_ 70 return nil, fmt.Errorf("unable to read %v: %v", procCpuinfo, err) 71 } 72 73 // want to capture the text after 'flags:' entry 74 match := flagsMatcher(buf) 75 if len(match) == 0 { 76 return nil, fmt.Errorf("%v does not contain a 'flags:' entry", procCpuinfo) 77 } 78 79 // match[0] has whole matching line, match[1] must exist as it has the captured text after 'flags:' 80 cpu_flags := strings.Fields(string(match[1])) 81 return cpu_flags, nil 82 } 83 84 func (iface *kvmInterface) KModConnectedPlug(spec *kmod.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 85 // Check CPU capabilities to load suitable module 86 // NOTE: this only considers i386, x86_64 and amd64 CPUs, but some ARM, PPC and S390 CPUs also support KVM 87 m := "kvm" 88 cpu_flags, err := getCpuFlags() 89 if err != nil { 90 logger.Debugf("kvm: fetching cpu info failed: %v", err) 91 } 92 93 if strutil.ListContains(cpu_flags, "vmx") { 94 m = "kvm_intel" 95 } else if strutil.ListContains(cpu_flags, "svm") { 96 m = "kvm_amd" 97 } else { 98 // CPU appears not to support KVM extensions, fall back to bare kvm module as it appears 99 // sufficient for some architectures 100 logger.Noticef("kvm: failed to detect CPU specific KVM support, will attempt to modprobe generic KVM support") 101 } 102 103 if err := spec.AddModule(m); err != nil { 104 return nil 105 } 106 return nil 107 } 108 109 func init() { 110 registerIface(&kvmInterface{commonInterface{ 111 name: "kvm", 112 summary: kvmSummary, 113 implicitOnCore: true, 114 implicitOnClassic: true, 115 baseDeclarationSlots: kvmBaseDeclarationSlots, 116 connectedPlugAppArmor: kvmConnectedPlugAppArmor, 117 connectedPlugUDev: kvmConnectedPlugUDev, 118 }}) 119 }