| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package sysutils
- import (
- "io/ioutil"
- "os"
- "path"
- "regexp"
- "strings"
- "yunion.io/x/log"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/onecloud/pkg/util/fileutils2"
- "yunion.io/x/onecloud/pkg/util/procutils"
- )
- const (
- KVM_MODULE_INTEL = "kvm-intel"
- KVM_MODULE_AMD = "kvm-amd"
- KVM_MODULE = "kvm"
- KVM_MODULE_UNSUPPORT = "unsupport"
- KVM_MODULE_BUILDIN = "buildin"
- HOST_NEST_UNSUPPORT = "0"
- HOST_NEST_SUPPORT = "1"
- HOST_NEST_ENABLE = "3"
- )
- var (
- kvmModuleSupport string
- nestStatus string
- )
- func GetKVMModuleSupport() string {
- if len(kvmModuleSupport) == 0 {
- kvmModuleSupport = detectKVMModuleSupport()
- }
- return kvmModuleSupport
- }
- func IsKvmSupport() bool {
- GetKVMModuleSupport()
- if kvmModuleSupport == KVM_MODULE_UNSUPPORT {
- return false
- }
- return true
- }
- func IsProcessorIntel() bool {
- GetKVMModuleSupport()
- if kvmModuleSupport == KVM_MODULE_INTEL {
- return true
- }
- return false
- }
- func IsProcessorAmd() bool {
- GetKVMModuleSupport()
- if kvmModuleSupport == KVM_MODULE_AMD {
- return true
- }
- return false
- }
- func isDevKVMExists() bool {
- return fileutils2.Exists("/dev/kvm")
- }
- func detectKVMModuleSupport() string {
- var km = KVM_MODULE_UNSUPPORT
- if isDevKVMExists() {
- if IsKernelModuleLoaded(KVM_MODULE_INTEL) {
- km = KVM_MODULE_INTEL
- } else if IsKernelModuleLoaded(KVM_MODULE_AMD) {
- km = KVM_MODULE_AMD
- } else if IsKernelModuleLoaded(KVM_MODULE) {
- km = KVM_MODULE
- } else {
- km = KVM_MODULE_BUILDIN
- }
- } else {
- if ModprobeKvmModule(KVM_MODULE_INTEL, false, false) {
- km = KVM_MODULE_INTEL
- } else if ModprobeKvmModule(KVM_MODULE_AMD, false, false) {
- km = KVM_MODULE_AMD
- } else if ModprobeKvmModule(KVM_MODULE, false, false) {
- if isDevKVMExists() {
- km = KVM_MODULE
- }
- }
- if km == KVM_MODULE_UNSUPPORT {
- if isDevKVMExists() {
- km = KVM_MODULE_BUILDIN
- }
- }
- }
- return km
- }
- func ModprobeKvmModule(name string, remove, nest bool) bool {
- var params = []string{"modprobe"}
- if remove {
- params = append(params, "-r")
- }
- params = append(params, name)
- if nest {
- params = append(params, "nested=1")
- }
- if err := procutils.NewRemoteCommandAsFarAsPossible(params[0], params[1:]...).Run(); err != nil {
- log.Errorf("Modprobe kvm %v failed: %s", params, err)
- return false
- }
- return true
- }
- func IsNestEnabled() bool {
- return GetNestSupport() == HOST_NEST_ENABLE
- }
- func GetNestSupport() string {
- if len(nestStatus) == 0 {
- nestStatus = detectNestSupport()
- }
- return nestStatus
- }
- func detectNestSupport() string {
- moduleName := GetKVMModuleSupport()
- nestStatus := HOST_NEST_UNSUPPORT
- if moduleName != KVM_MODULE_UNSUPPORT && isNestSupport(moduleName) {
- log.Infof("Host is support kvm nest ...")
- nestStatus = HOST_NEST_SUPPORT
- }
- if nestStatus == HOST_NEST_SUPPORT && loadKvmModuleWithNest(moduleName) {
- log.Infof("Host kvm nest is enabled ...")
- nestStatus = HOST_NEST_ENABLE
- }
- return nestStatus
- }
- func isNestSupport(name string) bool {
- output, err := procutils.NewRemoteCommandAsFarAsPossible("modinfo", name).Output()
- if err != nil {
- log.Errorln(err)
- return false
- }
- // TODO Test
- var re = regexp.MustCompile(`parm:\s*nested:`)
- for _, line := range strings.Split(string(output), "\n") {
- if re.MatchString(line) {
- return true
- }
- }
- return false
- }
- func loadKvmModuleWithNest(name string) bool {
- var notload = true
- if IsKernelModuleLoaded(name) {
- nest := GetKernelModuleParameter(name, "nested")
- if nest == "Y" {
- return true
- }
- notload = unloadKvmModule(name)
- }
- if notload {
- if ModprobeKvmModule(name, false, true) {
- return true
- }
- }
- return false
- }
- func unloadKvmModule(name string) bool {
- return ModprobeKvmModule(name, true, false)
- }
- func GetKernelModuleParameter(name, moduel string) string {
- pa := path.Join("/sys/module/", strings.Replace(name, "-", "_", -1), "/parameters/", moduel)
- return GetSysConfig(pa)
- }
- func getSysConfig(pa string, quiet bool) string {
- if f, err := os.Stat(pa); err == nil {
- if f.IsDir() {
- return ""
- }
- cont, err := fileutils2.FileGetContents(pa)
- if err != nil {
- if !quiet {
- log.Errorln(err)
- }
- return ""
- }
- return strings.TrimSpace(cont)
- }
- return ""
- }
- func GetSysConfig(pa string) string {
- return getSysConfig(pa, false)
- }
- func GetSysConfigQuiet(pa string) string {
- return getSysConfig(pa, true)
- }
- func IsKernelModuleLoaded(name string) bool {
- output, err := procutils.NewRemoteCommandAsFarAsPossible("lsmod").Output()
- if err != nil {
- log.Errorln(err)
- return false
- }
- for _, line := range strings.Split(string(output), "\n") {
- lm := strings.Split(line, " ")
- if len(lm) > 0 && utils.IsInStringArray(strings.Replace(name, "-", "_", -1), lm) {
- return true
- }
- }
- return false
- }
- func SetSysConfig(cpath, val string) bool {
- if fileutils2.Exists(cpath) {
- oval, err := ioutil.ReadFile(cpath)
- if err != nil {
- log.Errorln(err)
- return false
- }
- if strings.TrimSpace(string(oval)) != val {
- err = fileutils2.FilePutContents(cpath, val, false)
- if err == nil {
- return true
- }
- log.Errorln(err)
- }
- }
- return false
- }
- func IsHypervisor() bool {
- cont, _ := fileutils2.FileGetContents("/proc/cpuinfo")
- if strings.Index(cont, " hypervisor") > 0 {
- return true
- }
- return false
- }
|