Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
kata-check: Check and validate type-1 hypervisor for kata
Browse files Browse the repository at this point in the history
ACRN hypervisor is a type-1 hypervisor and this patch
adds support to check and validate if the system is
capable of running kata containers with ACRN hypervisor.

Depends-on: github.com/kata-containers/tests#1793

v3->v4:
Implemented a generic way to identify hypervisor and
test VM creation.

v2->v3:
1. Removed cgo structs and defined go structs.
2. Suppressed lint warnings due to unused createVM struct.

v1->v2:
1. Created an issue #1784 to address TODO item.
2. Fixed formatting of the log message.
3. Currently ACRN is only supported on amd64. So
   moved ACRN specific code to kata-check_amd64.go.

Fixes: #1778

Signed-off-by: Vijay Dhanraj <[email protected]>
  • Loading branch information
vijaydhanraj committed Jul 10, 2019
1 parent 4d26cee commit adcac93
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 109 deletions.
11 changes: 9 additions & 2 deletions cli/kata-check.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const int ioctl_KVM_CHECK_EXTENSION = KVM_CHECK_EXTENSION;
import "C"

import (
"errors"
"fmt"
"os"
"os/exec"
Expand All @@ -26,6 +27,7 @@ import (

"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -311,7 +313,12 @@ var kataCheckCLICommand = cli.Command{
span, _ := katautils.Trace(ctx, "kata-check")
defer span.Finish()

err = setCPUtype()
runtimeConfig, ok := context.App.Metadata["runtimeConfig"].(oci.RuntimeConfig)
if !ok {
return errors.New("kata-check: cannot determine runtime config")
}

err = setCPUtype(runtimeConfig.HypervisorType)
if err != nil {
return err
}
Expand All @@ -332,7 +339,7 @@ var kataCheckCLICommand = cli.Command{
kataLog.Info(successMessageCapable)

if os.Geteuid() == 0 {
err = archHostCanCreateVMContainer()
err = archHostCanCreateVMContainer(runtimeConfig.HypervisorType)
if err != nil {
return err
}
Expand Down
207 changes: 165 additions & 42 deletions cli/kata-check_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ package main

import (
"fmt"
"github.com/sirupsen/logrus"
"io/ioutil"
"strings"
"syscall"
"unsafe"

vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/sirupsen/logrus"
)

const (
Expand All @@ -24,6 +26,17 @@ const (
msgKernelVirtio = "Host kernel accelerator for virtio"
msgKernelVirtioNet = "Host kernel accelerator for virtio network"
msgKernelVirtioVhostVsock = "Host Support for Linux VM Sockets"
cpuFlagVMX = "vmx"
cpuFlagLM = "lm"
cpuFlagSVM = "svm"
cpuFlagSSE4_1 = "sse4_1"
kernelModvhm = "vhm_dev"
kernelModvhost = "vhost"
kernelModvhostnet = "vhost_net"
kernelModvhostvsock = "vhost_vsock"
kernelModkvm = "kvm"
kernelModkvmintel = "kvm_intel"
kernelModkvmamd = "kvm_amd"
)

// CPU types
Expand All @@ -33,6 +46,28 @@ const (
cpuTypeUnknown = -1
)

const acrnDevice = "/dev/acrn_vhm"

// ioctl_ACRN_CREATE_VM is the IOCTL to create VM in ACRN.
// Current Linux mainstream kernel doesn't have support for ACRN.
// Due to this several macros are not defined in Linux headers.
// Until the support is available, directly use the value instead
// of macros.
//https://github.com/kata-containers/runtime/issues/1784
const ioctl_ACRN_CREATE_VM = 0x43000010 //nolint
const ioctl_ACRN_DESTROY_VM = 0x43000011 //nolint

type acrn_create_vm struct { //nolint
vmid uint16 //nolint
reserved0 uint16 //nolint
vcpu_num uint16 //nolint
reserved1 uint16 //nolint
uuid [16]uint8
vm_flag uint64 //nolint
req_buf uint64 //nolint
reserved2 [16]uint8 //nolint
}

// cpuType save the CPU type
var cpuType int

Expand All @@ -49,7 +84,7 @@ var archRequiredCPUAttribs map[string]string
// required module parameters.
var archRequiredKernelModules map[string]kernelModule

func setCPUtype() error {
func setCPUtype(hypervisorType vc.HypervisorType) error {
cpuType = getCPUtype()

if cpuType == cpuTypeUnknown {
Expand All @@ -66,64 +101,88 @@ func setCPUtype() error {
"unrestricted_guest": "Y",
}
}
archRequiredCPUFlags = map[string]string{
"vmx": "Virtualization support",
"lm": "64Bit CPU",
"sse4_1": "SSE4.1",
}
archRequiredCPUAttribs = map[string]string{
archGenuineIntel: "Intel Architecture CPU",
}
archRequiredKernelModules = map[string]kernelModule{
"kvm": {
desc: msgKernelVM,
required: true,
},
"kvm_intel": {
desc: "Intel KVM",
parameters: kvmIntelParams,
required: true,
},
"vhost": {
desc: msgKernelVirtio,
required: true,
},
"vhost_net": {
desc: msgKernelVirtioNet,
required: true,
},
"vhost_vsock": {
desc: msgKernelVirtioVhostVsock,
required: false,
},

switch hypervisorType {
case "firecracker":
fallthrough
case "qemu":
archRequiredCPUFlags = map[string]string{
cpuFlagVMX: "Virtualization support",
cpuFlagLM: "64Bit CPU",
cpuFlagSSE4_1: "SSE4.1",
}
archRequiredCPUAttribs = map[string]string{
archGenuineIntel: "Intel Architecture CPU",
}
archRequiredKernelModules = map[string]kernelModule{
kernelModkvm: {
desc: msgKernelVM,
},
kernelModkvmintel: {
desc: "Intel KVM",
parameters: kvmIntelParams,
},
kernelModvhost: {
desc: msgKernelVirtio,
},
kernelModvhostnet: {
desc: msgKernelVirtioNet,
},
kernelModvhostvsock: {
desc: msgKernelVirtioVhostVsock,
required: false,
},
}
case "acrn":
archRequiredCPUFlags = map[string]string{
cpuFlagLM: "64Bit CPU",
cpuFlagSSE4_1: "SSE4.1",
}
archRequiredCPUAttribs = map[string]string{
archGenuineIntel: "Intel Architecture CPU",
}
archRequiredKernelModules = map[string]kernelModule{
kernelModvhm: {
desc: "Intel ACRN",
},
kernelModvhost: {
desc: msgKernelVirtio,
},
kernelModvhostnet: {
desc: msgKernelVirtioNet,
},
}
default:
return fmt.Errorf("setCPUtype: Unknown hypervisor type %s", hypervisorType)
}

} else if cpuType == cpuTypeAMD {
archRequiredCPUFlags = map[string]string{
"svm": "Virtualization support",
"lm": "64Bit CPU",
"sse4_1": "SSE4.1",
cpuFlagSVM: "Virtualization support",
cpuFlagLM: "64Bit CPU",
cpuFlagSSE4_1: "SSE4.1",
}
archRequiredCPUAttribs = map[string]string{
archAuthenticAMD: "AMD Architecture CPU",
}
archRequiredKernelModules = map[string]kernelModule{
"kvm": {
kernelModkvm: {
desc: msgKernelVM,
required: true,
},
"kvm_amd": {
kernelModkvmamd: {
desc: "AMD KVM",
required: true,
},
"vhost": {
kernelModvhost: {
desc: msgKernelVirtio,
required: true,
},
"vhost_net": {
kernelModvhostnet: {
desc: msgKernelVirtioNet,
required: true,
},
"vhost_vsock": {
kernelModvhostvsock: {
desc: msgKernelVirtioVhostVsock,
required: false,
},
Expand Down Expand Up @@ -155,8 +214,72 @@ func kvmIsUsable() error {
return genericKvmIsUsable()
}

func archHostCanCreateVMContainer() error {
return kvmIsUsable()
// acrnIsUsable determines if it will be possible to create a full virtual machine
// by creating a minimal VM and then deleting it.
func acrnIsUsable() error {
flags := syscall.O_RDWR | syscall.O_CLOEXEC

f, err := syscall.Open(acrnDevice, flags, 0)
if err != nil {
return err
}
defer syscall.Close(f)

fieldLogger := kataLog.WithField("check-type", "full")

fieldLogger.WithField("device", acrnDevice).Info("device available")

createVM := acrn_create_vm{
uuid: [16]uint8{
0xd2, 0x79, 0x54, 0x38, 0x25, 0xd6, 0x11, 0xe8,
0x86, 0x4e, 0xcb, 0x7a, 0x18, 0xb3, 0x46, 0x43,
},
}

ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(f),
uintptr(ioctl_ACRN_CREATE_VM),
uintptr(unsafe.Pointer(&createVM)))
if ret != 0 || errno != 0 {
if errno == syscall.EBUSY {
fieldLogger.WithField("reason", "another hypervisor running").Error("cannot create VM")
}
fieldLogger.WithFields(logrus.Fields{
"ret": ret,
"errno": errno,
}).Info("Create VM Error")
return errno
}

ret, _, errno = syscall.Syscall(syscall.SYS_IOCTL,
uintptr(f),
uintptr(ioctl_ACRN_DESTROY_VM),
0)
if ret != 0 || errno != 0 {
fieldLogger.WithFields(logrus.Fields{
"ret": ret,
"errno": errno,
}).Info("Destroy VM Error")
return errno
}

fieldLogger.WithField("feature", "create-vm").Info("feature available")

return nil
}

func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error {

switch hypervisorType {
case "qemu":
fallthrough
case "firecracker":
return kvmIsUsable()
case "acrn":
return acrnIsUsable()
default:
return fmt.Errorf("archHostCanCreateVMContainer: Unknown hypervisor type %s", hypervisorType)
}
}

// hostIsVMContainerCapable checks to see if the host is theoretically capable
Expand Down
13 changes: 12 additions & 1 deletion cli/kata-check_amd64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func TestCCCheckCLIFunction(t *testing.T) {
}
defer os.RemoveAll(dir)

_, config, err := makeRuntimeConfig(dir)
assert.NoError(err)

savedSysModuleDir := sysModuleDir
savedProcCPUInfo := procCPUInfo

Expand Down Expand Up @@ -108,6 +111,7 @@ func TestCCCheckCLIFunction(t *testing.T) {

ctx := createCLIContext(nil)
ctx.App.Name = "foo"
ctx.App.Metadata["runtimeConfig"] = config

// create buffer to save logger output
buf := &bytes.Buffer{}
Expand Down Expand Up @@ -514,6 +518,10 @@ foo : bar
func TestSetCPUtype(t *testing.T) {
assert := assert.New(t)

tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)

savedArchRequiredCPUFlags := archRequiredCPUFlags
savedArchRequiredCPUAttribs := archRequiredCPUAttribs
savedArchRequiredKernelModules := archRequiredKernelModules
Expand All @@ -528,7 +536,10 @@ func TestSetCPUtype(t *testing.T) {
archRequiredCPUAttribs = map[string]string{}
archRequiredKernelModules = map[string]kernelModule{}

setCPUtype()
_, config, err := makeRuntimeConfig(tmpdir)
assert.NoError(err)

setCPUtype(config.HypervisorType)

assert.NotEmpty(archRequiredCPUFlags)
assert.NotEmpty(archRequiredCPUAttribs)
Expand Down
5 changes: 3 additions & 2 deletions cli/kata-check_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package main
import (
"fmt"

vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -56,7 +57,7 @@ var archRequiredKVMExtensions = map[string]kvmExtension{
},
}

func setCPUtype() error {
func setCPUtype(hypervisorType vc.HypervisorType) error {
return nil
}

Expand Down Expand Up @@ -84,7 +85,7 @@ func checkKVMExtensions() error {
return nil
}

func archHostCanCreateVMContainer() error {
func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error {
if err := kvmIsUsable(); err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions cli/kata-check_arm64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func TestCCCheckCLIFunction(t *testing.T) {
}
defer os.RemoveAll(dir)

_, config, err := makeRuntimeConfig(dir)
assert.NoError(err)

savedSysModuleDir := sysModuleDir
savedProcCPUInfo := procCPUInfo

Expand Down Expand Up @@ -78,6 +81,7 @@ func TestCCCheckCLIFunction(t *testing.T) {

ctx := createCLIContext(nil)
ctx.App.Name = "foo"
ctx.App.Metadata["runtimeConfig"] = config

// create buffer to save logger output
buf := &bytes.Buffer{}
Expand Down
Loading

0 comments on commit adcac93

Please sign in to comment.