// Copyright (c) 2018 IBM // // SPDX-License-Identifier: Apache-2.0 // package main import ( "fmt" "os/exec" "strings" "github.com/kata-containers/runtime/pkg/katautils" "github.com/sirupsen/logrus" "regexp" "strconv" ) const ( cpuFlagsTag = genericCPUFlagsTag archCPUVendorField = "" archCPUModelField = "model" ) var ( ppc64CpuCmd = "ppc64_cpu" smtStatusOption = "--smt" _ = genericCPUVendorField _ = genericCPUModelField ) // archRequiredCPUFlags maps a CPU flag value to search for and a // human-readable description of that value. var archRequiredCPUFlags = map[string]string{} // archRequiredCPUAttribs maps a CPU (non-CPU flag) attribute value to search for // and a human-readable description of that value. var archRequiredCPUAttribs = map[string]string{} // archRequiredKernelModules maps a required module name to a human-readable // description of the modules functionality and an optional list of // required module parameters. var archRequiredKernelModules = map[string]kernelModule{ "kvm": { desc: "Kernel-based Virtual Machine", }, "kvm_hv": { desc: "Kernel-based Virtual Machine hardware virtualization", }, } func setCPUtype() error { return nil } func archHostCanCreateVMContainer() error { return kvmIsUsable() } // hostIsVMContainerCapable checks to see if the host is theoretically capable // of creating a VM container. func hostIsVMContainerCapable(details vmContainerCapableDetails) error { _, err := getCPUInfo(details.cpuInfoFile) if err != nil { return err } text, err := katautils.GetFileContents(details.cpuInfoFile) if err != nil { return err } ae := regexp.MustCompile("[0-9]+") re := regexp.MustCompile("POWER[0-9]") powerProcessor, err := strconv.Atoi(ae.FindString(re.FindString(text))) if err != nil { kataLog.WithError(err).Error("Failed to find Power Processor number from ", details.cpuInfoFile) } if powerProcessor <= 8 { if !isSMTOff() { return fmt.Errorf("SMT is not Off. %s", failMessage) } } count, err := checkKernelModules(details.requiredKernelModules, archKernelParamHandler) if err != nil { return err } if count == 0 { return nil } return fmt.Errorf("ERROR: %s", failMessage) } // kvmIsUsable determines if it will be possible to create a full virtual machine // by creating a minimal VM and then deleting it. func kvmIsUsable() error { return genericKvmIsUsable() } func archKernelParamHandler(onVMM bool, fields logrus.Fields, msg string) bool { return genericArchKernelParamHandler(onVMM, fields, msg) } func getPPC64leCPUInfo(cpuInfoFile string) (string, error) { text, err := katautils.GetFileContents(cpuInfoFile) if err != nil { return "", err } if len(strings.TrimSpace(text)) == 0 { return "", fmt.Errorf("Cannot determine CPU details") } return text, nil } func getCPUDetails() (vendor, model string, err error) { if vendor, model, err := genericGetCPUDetails(); err == nil { return vendor, model, nil } cpuinfo, err := getPPC64leCPUInfo(procCPUInfo) if err != nil { return "", "", err } lines := strings.Split(cpuinfo, "\n") for _, line := range lines { if archCPUVendorField != "" { if strings.HasPrefix(line, archCPUVendorField) { fields := strings.Split(line, ":") if len(fields) > 1 { vendor = strings.TrimSpace(fields[1]) } } } if archCPUModelField != "" { if strings.HasPrefix(line, archCPUModelField) { fields := strings.Split(line, ":") if len(fields) > 1 { model = strings.TrimSpace(fields[1]) } } } } if archCPUVendorField != "" && vendor == "" { return "", "", fmt.Errorf("cannot find vendor field in file %v", procCPUInfo) } if archCPUModelField != "" && model == "" { return "", "", fmt.Errorf("cannot find model field in file %v", procCPUInfo) } return vendor, model, nil } func isSMTOff() bool { // Check if the SMT is available and off cmd := exec.Command(ppc64CpuCmd, smtStatusOption) additionalEnv := "LANG=C" cmd.Env = append(cmd.Env, additionalEnv) out, err := cmd.Output() if err == nil && strings.TrimRight(string(out), "\n") == "SMT is off" { return true } else if err != nil { kataLog.Warn("ppc64_cpu isn't installed, can't detect SMT") return true } return false }