gitee.com/mysnapcore/mysnapd@v0.1.0/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 "gitee.com/mysnapcore/mysnapd/interfaces" 29 "gitee.com/mysnapcore/mysnapd/interfaces/kmod" 30 "gitee.com/mysnapcore/mysnapd/logger" 31 "gitee.com/mysnapcore/mysnapd/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 # Allow AMD SEV checks for AMD CPU's. 57 /sys/module/kvm_amd/parameters/sev r, 58 ` 59 60 var kvmConnectedPlugUDev = []string{`KERNEL=="kvm"`} 61 62 type kvmInterface struct { 63 commonInterface 64 } 65 66 var procCpuinfo = "/proc/cpuinfo" 67 var flagsMatcher = regexp.MustCompile(`(?m)^flags\s+:\s+(.*)$`).FindSubmatch 68 69 func getCpuFlags() (flags []string, err error) { 70 buf, err := ioutil.ReadFile(procCpuinfo) 71 if err != nil { 72 // if we can't read cpuinfo, we want to know _why_ 73 return nil, fmt.Errorf("unable to read %v: %v", procCpuinfo, err) 74 } 75 76 // want to capture the text after 'flags:' entry 77 match := flagsMatcher(buf) 78 if len(match) == 0 { 79 return nil, fmt.Errorf("%v does not contain a 'flags:' entry", procCpuinfo) 80 } 81 82 // match[0] has whole matching line, match[1] must exist as it has the captured text after 'flags:' 83 cpu_flags := strings.Fields(string(match[1])) 84 return cpu_flags, nil 85 } 86 87 func (iface *kvmInterface) KModConnectedPlug(spec *kmod.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 88 // Check CPU capabilities to load suitable module 89 // NOTE: this only considers i386, x86_64 and amd64 CPUs, but some ARM, PPC and S390 CPUs also support KVM 90 m := "kvm" 91 cpu_flags, err := getCpuFlags() 92 if err != nil { 93 logger.Debugf("kvm: fetching cpu info failed: %v", err) 94 } 95 96 if strutil.ListContains(cpu_flags, "vmx") { 97 m = "kvm_intel" 98 } else if strutil.ListContains(cpu_flags, "svm") { 99 m = "kvm_amd" 100 } else { 101 // CPU appears not to support KVM extensions, fall back to bare kvm module as it appears 102 // sufficient for some architectures 103 logger.Noticef("kvm: failed to detect CPU specific KVM support, will attempt to modprobe generic KVM support") 104 } 105 106 if err := spec.AddModule(m); err != nil { 107 return nil 108 } 109 return nil 110 } 111 112 func init() { 113 registerIface(&kvmInterface{commonInterface{ 114 name: "kvm", 115 summary: kvmSummary, 116 implicitOnCore: true, 117 implicitOnClassic: true, 118 baseDeclarationSlots: kvmBaseDeclarationSlots, 119 connectedPlugAppArmor: kvmConnectedPlugAppArmor, 120 connectedPlugUDev: kvmConnectedPlugUDev, 121 }}) 122 }