mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-28 16:27:50 +00:00
Merge pull request #286 from nitkon/master
Enable Kata container on ppc64le arch
This commit is contained in:
commit
2400978f6a
9
Makefile
9
Makefile
@ -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
12
arch/ppc64le-options.mk
Normal 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
|
@ -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
|
||||
}
|
||||
|
@ -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
22
cli/kata-check_arm64.go
Normal 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)
|
||||
}
|
114
cli/kata-check_data_ppc64le_test.go
Normal file
114
cli/kata-check_data_ppc64le_test.go
Normal 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
65
cli/kata-check_ppc64le.go
Normal 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)
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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...)
|
||||
}
|
||||
}
|
||||
|
52
virtcontainers/qemu_arm64_test.go
Normal file
52
virtcontainers/qemu_arm64_test.go
Normal 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)
|
||||
}
|
137
virtcontainers/qemu_ppc64le.go
Normal file
137
virtcontainers/qemu_ppc64le.go
Normal 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)
|
||||
}
|
52
virtcontainers/qemu_ppc64le_test.go
Normal file
52
virtcontainers/qemu_ppc64le_test.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user