Merge pull request #286 from nitkon/master

Enable Kata container on ppc64le arch
This commit is contained in:
James O. D. Hunt 2018-06-01 09:58:37 +01:00 committed by GitHub
commit 2400978f6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 645 additions and 141 deletions

View File

@ -61,6 +61,12 @@ ifeq (,$(installing))
EXTRA_DEPS = clean
endif
ifeq (uncompressed,$(KERNELTYPE))
KERNEL_NAME = vmlinux.container
else
KERNEL_NAME = vmlinuz.container
endif
LIBEXECDIR := $(PREFIX)/libexec
SHAREDIR := $(PREFIX)/share
DEFAULTSDIR := $(SHAREDIR)/defaults
@ -77,7 +83,7 @@ PKGLIBDIR := $(LOCALSTATEDIR)/lib/$(PROJECT_DIR)
PKGRUNDIR := $(LOCALSTATEDIR)/run/$(PROJECT_DIR)
PKGLIBEXECDIR := $(LIBEXECDIR)/$(PROJECT_DIR)
KERNELPATH := $(PKGDATADIR)/vmlinuz.container
KERNELPATH := $(PKGDATADIR)/$(KERNEL_NAME)
INITRDPATH := $(PKGDATADIR)/$(INITRDNAME)
IMAGEPATH := $(PKGDATADIR)/$(IMAGENAME)
FIRMWAREPATH :=
@ -150,6 +156,7 @@ USER_VARS += INITRDNAME
USER_VARS += INITRDPATH
USER_VARS += MACHINETYPE
USER_VARS += KERNELPATH
USER_VARS += KERNELTYPE
USER_VARS += FIRMWAREPATH
USER_VARS += MACHINEACCELERATORS
USER_VARS += KERNELPARAMS

12
arch/ppc64le-options.mk Normal file
View File

@ -0,0 +1,12 @@
# Copyright (c) 2018 IBM
#
# SPDX-License-Identifier: Apache-2.0
#
# Power ppc64le settings
MACHINETYPE := pseries
KERNELPARAMS :=
MACHINEACCELERATORS :=
KERNELTYPE := uncompressed #This architecture must use an uncompressed kernel.
QEMUCMD := qemu-system-ppc64le

View File

@ -7,6 +7,13 @@
package main
/*
#include <linux/kvm.h>
const int ioctl_KVM_CREATE_VM = KVM_CREATE_VM;
*/
import "C"
import (
"fmt"
"os"
@ -14,6 +21,7 @@ import (
"path/filepath"
"regexp"
"strings"
"syscall"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/sirupsen/logrus"
@ -51,6 +59,11 @@ var (
modInfoCmd = "modinfo"
)
// variables rather than consts to allow tests to modify them
var (
kvmDevice = "/dev/kvm"
)
// getCPUInfo returns details of the first CPU read from the specified cpuinfo file
func getCPUInfo(cpuInfoFile string) (string, error) {
text, err := getFileContents(cpuInfoFile)
@ -222,9 +235,9 @@ func checkKernelModules(modules map[string]kernelModule, handler kernelParamHand
return count, nil
}
// hostIsVMContainerCapable checks to see if the host is theoretically capable
// genericHostIsVMContainerCapable checks to see if the host is theoretically capable
// of creating a VM container.
func hostIsVMContainerCapable(details vmContainerCapableDetails) error {
func genericHostIsVMContainerCapable(details vmContainerCapableDetails) error {
cpuinfo, err := getCPUInfo(details.cpuInfoFile)
if err != nil {
return err
@ -293,3 +306,58 @@ var kataCheckCLICommand = cli.Command{
return nil
},
}
func genericArchKernelParamHandler(onVMM bool, fields logrus.Fields, msg string) bool {
param, ok := fields["parameter"].(string)
if !ok {
return false
}
// This option is not required when
// already running under a hypervisor.
if param == "unrestricted_guest" && onVMM {
kataLog.WithFields(fields).Warn(kernelPropertyCorrect)
return true
}
if param == "nested" {
kataLog.WithFields(fields).Warn(msg)
return true
}
// don't ignore the error
return false
}
// genericKvmIsUsable determines if it will be possible to create a full virtual machine
// by creating a minimal VM and then deleting it.
func genericKvmIsUsable() error {
flags := syscall.O_RDWR | syscall.O_CLOEXEC
f, err := syscall.Open(kvmDevice, flags, 0)
if err != nil {
return err
}
defer syscall.Close(f)
fieldLogger := kataLog.WithField("check-type", "full")
fieldLogger.WithField("device", kvmDevice).Info("device available")
vm, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(f),
uintptr(C.ioctl_KVM_CREATE_VM),
0)
if errno != 0 {
if errno == syscall.EBUSY {
fieldLogger.WithField("reason", "another hypervisor running").Error("cannot create VM")
}
return errno
}
defer syscall.Close(int(vm))
fieldLogger.WithField("feature", "create-vm").Info("feature available")
return nil
}

View File

@ -5,24 +5,10 @@
package main
/*
#include <linux/kvm.h>
const int ioctl_KVM_CREATE_VM = KVM_CREATE_VM;
*/
import "C"
import (
"syscall"
"github.com/sirupsen/logrus"
)
// variables rather than consts to allow tests to modify them
var (
kvmDevice = "/dev/kvm"
)
// archRequiredCPUFlags maps a CPU flag value to search for and a
// human-readable description of that value.
var archRequiredCPUFlags = map[string]string{
@ -66,58 +52,19 @@ var archRequiredKernelModules = map[string]kernelModule{
// 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 {
flags := syscall.O_RDWR | syscall.O_CLOEXEC
f, err := syscall.Open(kvmDevice, flags, 0)
if err != nil {
return err
}
defer syscall.Close(f)
fieldLogger := kataLog.WithField("check-type", "full")
fieldLogger.WithField("device", kvmDevice).Info("device available")
vm, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(f),
uintptr(C.ioctl_KVM_CREATE_VM),
0)
if errno != 0 {
if errno == syscall.EBUSY {
fieldLogger.WithField("reason", "another hypervisor running").Error("cannot create VM")
}
return errno
}
defer syscall.Close(int(vm))
fieldLogger.WithField("feature", "create-vm").Info("feature available")
return nil
return genericKvmIsUsable()
}
func archHostCanCreateVMContainer() error {
return kvmIsUsable()
}
func archKernelParamHandler(onVMM bool, fields logrus.Fields, msg string) bool {
param, ok := fields["parameter"].(string)
if !ok {
return false
}
// This option is not required when
// already running under a hypervisor.
if param == "unrestricted_guest" && onVMM {
kataLog.WithFields(fields).Warn(kernelPropertyCorrect)
return true
}
if param == "nested" {
kataLog.WithFields(fields).Warn(msg)
return true
}
// don't ignore the error
return false
// hostIsVMContainerCapable checks to see if the host is theoretically capable
// of creating a VM container.
func hostIsVMContainerCapable(details vmContainerCapableDetails) error {
return genericHostIsVMContainerCapable(details)
}
func archKernelParamHandler(onVMM bool, fields logrus.Fields, msg string) bool {
return genericArchKernelParamHandler(onVMM, fields, msg)
}

22
cli/kata-check_arm64.go Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
// 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 archHostCanCreateVMContainer() error {
return kvmIsUsable()
}
// hostIsVMContainerCapable checks to see if the host is theoretically capable
// of creating a VM container.
func hostIsVMContainerCapable(details vmContainerCapableDetails) error {
return genericHostIsVMContainerCapable(details)
}

View File

@ -0,0 +1,114 @@
// Copyright (c) 2018 IBM
//
// SPDX-License-Identifier: Apache-2.0
//
package main
const testCPUInfoTemplate = `
processor : 0
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 8
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 16
cpu : POWER8E (raw), altivec supported
clock : 2360.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 24
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 32
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 40
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 48
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 56
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 64
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 72
cpu : POWER8E (raw), altivec supported
clock : 3059.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 80
cpu : POWER8E (raw), altivec supported
clock : 2693.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 88
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 96
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 104
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 112
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 120
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 128
cpu : POWER8E (raw), altivec supported
clock : 3690.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 136
cpu : POWER8E (raw), altivec supported
clock : 2061.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 144
cpu : POWER8E (raw), altivec supported
clock : 2294.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 152
cpu : POWER8E (raw), altivec supported
clock : 2560.000000MHz
revision : 2.1 (pvr 004b 0201)
timebase : 512000000
platform : PowerNV
model : 8247-22L
machine : PowerNV 8247-22L
firmware : OPAL v3
`

65
cli/kata-check_ppc64le.go Normal file
View File

@ -0,0 +1,65 @@
// Copyright (c) 2018 IBM
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"github.com/sirupsen/logrus"
)
// 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 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
}
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)
}

View File

@ -15,6 +15,7 @@ import (
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
runtim "runtime"
)
// Semantic version for the output of the command.
@ -173,6 +174,9 @@ func getHostInfo() (HostInfo, error) {
}
hostVMContainerCapable := true
if runtim.GOARCH == "ppc64le" {
hostVMContainerCapable = false
}
details := vmContainerCapableDetails{
cpuInfoFile: procCPUInfo,

View File

@ -443,8 +443,8 @@ func getHostMemorySizeKb(memInfoPath string) (uint64, error) {
// RunningOnVMM checks if the system is running inside a VM.
func RunningOnVMM(cpuInfoPath string) (bool, error) {
if runtime.GOARCH == "arm64" {
virtLog.Debugf("Unable to know if the system is running inside a VM")
if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" {
virtLog.Info("Unable to know if the system is running inside a VM")
return false, nil
}

View File

@ -11,6 +11,7 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@ -926,3 +927,82 @@ func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error {
func (q *qemu) getSandboxConsole(sandboxID string) (string, error) {
return utils.BuildSocketPath(runStoragePath, sandboxID, defaultConsole)
}
// genericAppendBridges appends to devices the given bridges
func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineType string) []govmmQemu.Device {
bus := defaultPCBridgeBus
if machineType == QemuQ35 {
bus = defaultBridgeBus
}
for idx, b := range bridges {
t := govmmQemu.PCIBridge
if b.Type == pcieBridge {
t = govmmQemu.PCIEBridge
}
bridges[idx].Addr = bridgePCIStartAddr + idx
devices = append(devices,
govmmQemu.BridgeDevice{
Type: t,
Bus: bus,
ID: b.ID,
// Each bridge is required to be assigned a unique chassis id > 0
Chassis: (idx + 1),
SHPC: true,
Addr: strconv.FormatInt(int64(bridges[idx].Addr), 10),
},
)
}
return devices
}
func genericBridges(number uint32, machineType string) []Bridge {
var bridges []Bridge
var bt bridgeType
switch machineType {
case QemuQ35:
// currently only pci bridges are supported
// qemu-2.10 will introduce pcie bridges
fallthrough
case QemuPC:
bt = pciBridge
case QemuPseries:
bt = pciBridge
default:
return nil
}
for i := uint32(0); i < number; i++ {
bridges = append(bridges, Bridge{
Type: bt,
ID: fmt.Sprintf("%s-bridge-%d", bt, i),
Address: make(map[uint32]string),
})
}
return bridges
}
func genericMemoryTopology(memoryMb, hostMemoryMb uint64) govmmQemu.Memory {
// NVDIMM device needs memory space 1024MB
// See https://github.com/clearcontainers/runtime/issues/380
memoryOffset := 1024
// add 1G memory space for nvdimm device (vm guest image)
memMax := fmt.Sprintf("%dM", hostMemoryMb+uint64(memoryOffset))
mem := fmt.Sprintf("%dM", memoryMb)
memory := govmmQemu.Memory{
Size: mem,
Slots: defaultMemSlots,
MaxMem: memMax,
}
return memory
}

View File

@ -6,9 +6,7 @@
package virtcontainers
import (
"fmt"
"os"
"strconv"
govmmQemu "github.com/intel/govmm/qemu"
)
@ -93,12 +91,7 @@ func newQemuArch(config HypervisorConfig) qemuArch {
},
}
if config.ImagePath != "" {
q.kernelParams = append(q.kernelParams, kernelRootParams...)
q.kernelParamsNonDebug = append(q.kernelParamsNonDebug, kernelParamsSystemdNonDebug...)
q.kernelParamsDebug = append(q.kernelParamsDebug, kernelParamsSystemdDebug...)
}
q.handleImagePath(config)
return q
}
@ -114,29 +107,7 @@ func (q *qemuAmd64) capabilities() capabilities {
}
func (q *qemuAmd64) bridges(number uint32) []Bridge {
var bridges []Bridge
var bt bridgeType
switch q.machineType {
case QemuQ35:
// currently only pci bridges are supported
// qemu-2.10 will introduce pcie bridges
fallthrough
case QemuPC:
bt = pciBridge
default:
return nil
}
for i := uint32(0); i < number; i++ {
bridges = append(bridges, Bridge{
Type: bt,
ID: fmt.Sprintf("%s-bridge-%d", bt, i),
Address: make(map[uint32]string),
})
}
return bridges
return genericBridges(number, q.machineType)
}
func (q *qemuAmd64) cpuModel() string {
@ -148,22 +119,7 @@ func (q *qemuAmd64) cpuModel() string {
}
func (q *qemuAmd64) memoryTopology(memoryMb, hostMemoryMb uint64) govmmQemu.Memory {
// NVDIMM device needs memory space 1024MB
// See https://github.com/clearcontainers/runtime/issues/380
memoryOffset := 1024
// add 1G memory space for nvdimm device (vm guest image)
memMax := fmt.Sprintf("%dM", hostMemoryMb+uint64(memoryOffset))
mem := fmt.Sprintf("%dM", memoryMb)
memory := govmmQemu.Memory{
Size: mem,
Slots: defaultMemSlots,
MaxMem: memMax,
}
return memory
return genericMemoryTopology(memoryMb, hostMemoryMb)
}
func (q *qemuAmd64) appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) {
@ -194,31 +150,5 @@ func (q *qemuAmd64) appendImage(devices []govmmQemu.Device, path string) ([]govm
// appendBridges appends to devices the given bridges
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device {
bus := defaultPCBridgeBus
if q.machineType == QemuQ35 {
bus = defaultBridgeBus
}
for idx, b := range bridges {
t := govmmQemu.PCIBridge
if b.Type == pcieBridge {
t = govmmQemu.PCIEBridge
}
bridges[idx].Addr = bridgePCIStartAddr + idx
devices = append(devices,
govmmQemu.BridgeDevice{
Type: t,
Bus: bus,
ID: b.ID,
// Each bridge is required to be assigned a unique chassis id > 0
Chassis: (idx + 1),
SHPC: true,
Addr: strconv.FormatInt(int64(bridges[idx].Addr), 10),
},
)
}
return devices
return genericAppendBridges(devices, bridges, q.machineType)
}

View File

@ -82,6 +82,9 @@ type qemuArch interface {
// appendVFIODevice appends a VFIO device to devices
appendVFIODevice(devices []govmmQemu.Device, vfioDevice drivers.VFIODevice) []govmmQemu.Device
// handleImagePath handles the Hypervisor Config image path
handleImagePath(config HypervisorConfig)
}
type qemuArchBase struct {
@ -131,6 +134,9 @@ const (
// QemuVirt is the QEMU virt machine type for aarch64
QemuVirt = "virt"
// QemuPseries is a QEMU virt machine type for for ppc64le
QemuPseries = "pseries"
)
// kernelParamsNonDebug is a list of the default kernel
@ -495,3 +501,11 @@ func (q *qemuArchBase) appendVFIODevice(devices []govmmQemu.Device, vfioDevice d
return devices
}
func (q *qemuArchBase) handleImagePath(config HypervisorConfig) {
if config.ImagePath != "" {
q.kernelParams = append(q.kernelParams, kernelRootParams...)
q.kernelParamsNonDebug = append(q.kernelParamsNonDebug, kernelParamsSystemdNonDebug...)
q.kernelParamsDebug = append(q.kernelParamsDebug, kernelParamsSystemdDebug...)
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2018 IBM
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"testing"
govmmQemu "github.com/intel/govmm/qemu"
"github.com/stretchr/testify/assert"
)
func newTestQemu(machineType string) qemuArch {
config := HypervisorConfig{
HypervisorMachineType: machineType,
}
return newQemuArch(config)
}
func TestQemuArm64CPUModel(t *testing.T) {
assert := assert.New(t)
arm64 := newTestQemu(virt)
expectedOut := defaultCPUModel
model := arm64.cpuModel()
assert.Equal(expectedOut, model)
arm64.enableNestingChecks()
expectedOut = defaultCPUModel + ",pmu=off"
model = arm64.cpuModel()
assert.Equal(expectedOut, model)
}
func TestQemuArm64MemoryTopology(t *testing.T) {
assert := assert.New(t)
arm64 := newTestQemu(virt)
memoryOffset := 1024
hostMem := uint64(1024)
mem := uint64(120)
expectedMemory := govmmQemu.Memory{
Size: fmt.Sprintf("%dM", mem),
Slots: defaultMemSlots,
MaxMem: fmt.Sprintf("%dM", hostMem+uint64(memoryOffset)),
}
m := arm64.memoryTopology(mem, hostMem)
assert.Equal(expectedMemory, m)
}

View File

@ -0,0 +1,137 @@
// Copyright (c) 2018 IBM
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"encoding/hex"
"os"
govmmQemu "github.com/intel/govmm/qemu"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils"
)
type qemuPPC64le struct {
// inherit from qemuArchBase, overwrite methods if needed
qemuArchBase
}
const defaultQemuPath = "/usr/bin/qemu-system-ppc64le"
const defaultQemuMachineType = QemuPseries
const defaultQemuMachineOptions = "accel=kvm,usb=off"
const defaultPCBridgeBus = "pci.0"
var qemuPaths = map[string]string{
QemuPseries: defaultQemuPath,
}
var kernelRootParams = []Param{}
var kernelParams = []Param{
{"tsc", "reliable"},
{"no_timer_check", ""},
{"rcupdate.rcu_expedited", "1"},
{"noreplace-smp", ""},
{"reboot", "k"},
{"console", "hvc0"},
{"console", "hvc1"},
{"iommu", "off"},
{"cryptomgr.notests", ""},
{"net.ifnames", "0"},
{"pci", "lastbus=0"},
}
var supportedQemuMachines = []govmmQemu.Machine{
{
Type: QemuPseries,
Options: defaultQemuMachineOptions,
},
}
// returns the maximum number of vCPUs supported
func MaxQemuVCPUs() uint32 {
return uint32(128)
}
func newQemuArch(config HypervisorConfig) qemuArch {
machineType := config.HypervisorMachineType
if machineType == "" {
machineType = defaultQemuMachineType
}
q := &qemuPPC64le{
qemuArchBase{
machineType: machineType,
qemuPaths: qemuPaths,
supportedQemuMachines: supportedQemuMachines,
kernelParamsNonDebug: kernelParamsNonDebug,
kernelParamsDebug: kernelParamsDebug,
kernelParams: kernelParams,
},
}
q.handleImagePath(config)
return q
}
func (q *qemuPPC64le) capabilities() capabilities {
var caps capabilities
// pseries machine type supports hotplugging drives
if q.machineType == QemuPseries {
caps.setBlockDeviceHotplugSupport()
}
return caps
}
func (q *qemuPPC64le) bridges(number uint32) []Bridge {
return genericBridges(number, q.machineType)
}
func (q *qemuPPC64le) cpuModel() string {
cpuModel := defaultCPUModel
if q.nestedRun {
cpuModel += ",pmu=off"
}
return cpuModel
}
func (q *qemuPPC64le) memoryTopology(memoryMb, hostMemoryMb uint64) govmmQemu.Memory {
// align hostMemoryMb to 256 MB multiples
hostMemoryMb -= (hostMemoryMb % 256)
return genericMemoryTopology(memoryMb, hostMemoryMb)
}
func (q *qemuPPC64le) appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, err
}
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return nil, err
}
id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize)
drive := drivers.Drive{
File: path,
Format: "raw",
ID: id,
}
return q.appendBlockDevice(devices, drive), nil
}
// appendBridges appends to devices the given bridges
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType)
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2018 IBM
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"testing"
govmmQemu "github.com/intel/govmm/qemu"
"github.com/stretchr/testify/assert"
)
func newTestQemu(machineType string) qemuArch {
config := HypervisorConfig{
HypervisorMachineType: machineType,
}
return newQemuArch(config)
}
func TestQemuPPC64leCPUModel(t *testing.T) {
assert := assert.New(t)
ppc64le := newTestQemu(QemuPseries)
expectedOut := defaultCPUModel
model := ppc64le.cpuModel()
assert.Equal(expectedOut, model)
ppc64le.enableNestingChecks()
expectedOut = defaultCPUModel + ",pmu=off"
model = ppc64le.cpuModel()
assert.Equal(expectedOut, model)
}
func TestQemuPPC64leMemoryTopology(t *testing.T) {
assert := assert.New(t)
ppc64le := newTestQemu(QemuPseries)
memoryOffset := 1024
hostMem := uint64(1024)
mem := uint64(120)
expectedMemory := govmmQemu.Memory{
Size: fmt.Sprintf("%dM", mem),
Slots: defaultMemSlots,
MaxMem: fmt.Sprintf("%dM", hostMem+uint64(memoryOffset)),
}
m := ppc64le.memoryTopology(mem, hostMem)
assert.Equal(expectedMemory, m)
}