vendor: Update govmm vendoring

Shortlog:

f9b31c0 qemu: Allow disable-modern option from QMP
d617307 Run tests for the s390x build
b36b5a8 Contributors: Add Clare Chen to CONTRIBUTORS.md
b41939c Contributors: Add my name
dab4cf1 qmp: Add tests
5ea6da1 Verify govmm builds on s390x
ee75813 contributors: add my name
c80fc3b qemu: Add s390x support
ca477a1 Update source file headers
e68e005 Update the CONTRIBUTING.md
2b7db54 Add the CONTRIBUTORS.md file
b3b765c qemu: test Valid for Vsock for Context ID
3becff5 qemu: change of ContextID from uint32 to uint64
f30fd13 qmp: Output error detail when execute QMP command failed
7da6a4c qmp: fix mem-path properties for hotplug memory.
e4892e3 qemu/qmp: preparation for s390x support
110d2fa qemu/qmp: add new function ExecuteBlockdevAddWithCache
a0b0c86 qmp_test: Change QMP version from 2.6 to 2.9
10c36a1 qemu: add support for pidfile option

Fixes #983

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2018-12-05 23:46:07 -08:00
parent 0a7a4379dc
commit 018c8c1468
11 changed files with 458 additions and 148 deletions

4
Gopkg.lock generated
View File

@ -238,11 +238,11 @@
revision = "3520598351bb3500a49ae9563f5539666ae0a27c"
[[projects]]
digest = "1:6cfbc8646c1b7746e366eacb17a6f6f97f28beabd87eebffe961447419eb60bf"
digest = "1:40227c1b7841f35c5965b955b21cc84f3990b9b972d3224e5e31ba20a3dc1f37"
name = "github.com/intel/govmm"
packages = ["qemu"]
pruneopts = "NUT"
revision = "e82e8498c5a214b24ac75e0a05ace556bf91a9ab"
revision = "32f64a0630c7602d536be2a9c83bc3eee160359b"
[[projects]]
digest = "1:e96806ae1b041a36386249b22ef9eaf5af1788c0f86f686c6296e5a9caf53df8"

View File

@ -52,7 +52,7 @@
[[constraint]]
name = "github.com/intel/govmm"
revision = "e82e8498c5a214b24ac75e0a05ace556bf91a9ab"
revision = "32f64a0630c7602d536be2a9c83bc3eee160359b"
[[constraint]]
name = "github.com/kata-containers/agent"

21
vendor/github.com/intel/govmm/CONTRIBUTORS.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
This file is a partial list of contributors to the Virtual Machine
Manager for Go project. To see the full list of contributors, see the
revision history in source control.
Contributors who wish to be recognized in this file should add
themselves (or their employer, as appropriate).
- afrosi@de.ibm.com
- archana.m.shinde@intel.com
- caoruidong@huawei.com
- clare.chenhui@huawei.com
- eric.ernst@intel.com
- james.o.hunt@intel.com
- jose.carlos.venegas.munoz@intel.com
- julio.montes@intel.com
- manohar.r.castelino@intel.com
- mark.d.ryan@intel.com
- robert.bradford@intel.com
- sameo@linux.intel.com
- sebastien.boeuf@intel.com
- xinda.zhao@intel.com

View File

@ -1,5 +1,5 @@
/*
// Copyright (c) 2017 Intel Corporation
// Copyright contributors to the Virtual Machine Manager for Go project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
// Copyright (c) 2016 Intel Corporation
// Copyright contributors to the Virtual Machine Manager for Go project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -62,17 +62,11 @@ const (
// NVDIMM is the Non Volatile DIMM device driver.
NVDIMM DeviceDriver = "nvdimm"
// Virtio9P is the 9pfs device driver.
Virtio9P DeviceDriver = "virtio-9p-pci"
// VirtioNet is the virt-io networking device driver.
VirtioNet DeviceDriver = "virtio-net"
// VirtioNetPCI is the virt-io pci networking device driver.
VirtioNetPCI DeviceDriver = "virtio-net-pci"
// VirtioSerial is the serial device driver.
VirtioSerial DeviceDriver = "virtio-serial-pci"
// VirtioNetCCW is the virt-io ccw networking device driver.
VirtioNetCCW DeviceDriver = "virtio-net-ccw"
// VirtioBlock is the block device driver.
VirtioBlock DeviceDriver = "virtio-blk"
@ -83,9 +77,6 @@ const (
// VirtioSerialPort is the serial port device driver.
VirtioSerialPort DeviceDriver = "virtserialport"
// VHostVSockPCI is the vhost vsock pci driver.
VHostVSockPCI DeviceDriver = "vhost-vsock-pci"
// VirtioRng is the paravirtualized RNG device driver.
VirtioRng DeviceDriver = "virtio-rng"
@ -101,12 +92,6 @@ const (
//VhostUserBlk represents a block vhostuser device type.
VhostUserBlk DeviceDriver = "vhost-user-blk-pci"
// VfioPCI represent a VFIO device type.
VfioPCI DeviceDriver = "vfio-pci"
// VirtioScsiPCI represents a SCSI device type.
VirtioScsiPCI DeviceDriver = "virtio-scsi-pci"
// PCIBridgeDriver represents a PCI bridge device type.
PCIBridgeDriver DeviceDriver = "pci-bridge"
@ -114,27 +99,19 @@ const (
PCIePCIBridgeDriver DeviceDriver = "pcie-pci-bridge"
)
// isVirtioPCI is a map indicating if a DeviceDriver is considered as a
// virtio PCI device, which is helpful to determine if the option "romfile"
// applies or not to this specific device.
var isVirtioPCI = map[DeviceDriver]bool{
NVDIMM: false,
Virtio9P: true,
VirtioNet: true,
VirtioNetPCI: true,
VirtioSerial: true,
VirtioBlock: true,
Console: false,
VirtioSerialPort: false,
VHostVSockPCI: true,
VirtioRng: true,
VirtioBalloon: true,
VhostUserSCSI: true,
VhostUserBlk: true,
VfioPCI: true,
VirtioScsiPCI: true,
PCIBridgeDriver: true,
PCIePCIBridgeDriver: true,
// disableModern returns the parameters with the disable-modern option.
// In case the device driver is not a PCI device and it doesn't have the option
// an empty string is returned.
func (driver DeviceDriver) disableModern(disable bool) string {
if !isVirtioPCI[driver] {
return ""
}
if disable {
return "disable-modern=true"
}
return "disable-modern=false"
}
// ObjectType is a string representing a qemu object type.
@ -284,8 +261,8 @@ func (fsdev FSDevice) QemuParams(config *Config) []string {
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", fsdev.Driver))
if fsdev.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := fsdev.Driver.disableModern(fsdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
deviceParams = append(deviceParams, fmt.Sprintf(",fsdev=%s", fsdev.ID))
deviceParams = append(deviceParams, fmt.Sprintf(",mount_tag=%s", fsdev.MountTag))
@ -370,8 +347,8 @@ func (cdev CharDevice) QemuParams(config *Config) []string {
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", cdev.Driver))
if cdev.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := cdev.Driver.disableModern(cdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
if cdev.Bus != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",bus=%s", cdev.Bus))
@ -425,48 +402,6 @@ const (
VHOSTUSER NetDeviceType = "vhostuser"
)
// QemuNetdevParam converts to the QEMU -netdev parameter notation
func (n NetDeviceType) QemuNetdevParam() string {
switch n {
case TAP:
return "tap"
case MACVTAP:
return "tap"
case IPVTAP:
return "tap"
case VETHTAP:
return "tap" // -netdev type=tap -device virtio-net-pci
case VFIO:
return "" // -device vfio-pci (no netdev)
case VHOSTUSER:
return "vhost-user" // -netdev type=vhost-user (no device)
default:
return ""
}
}
// QemuDeviceParam converts to the QEMU -device parameter notation
func (n NetDeviceType) QemuDeviceParam() DeviceDriver {
switch n {
case TAP:
return "virtio-net-pci"
case MACVTAP:
return "virtio-net-pci"
case IPVTAP:
return "virtio-net-pci"
case VETHTAP:
return "virtio-net-pci" // -netdev type=tap -device virtio-net-pci
case VFIO:
return "vfio-pci" // -device vfio-pci (no netdev)
case VHOSTUSER:
return "" // -netdev type=vhost-user (no device)
default:
return ""
}
}
// NetDevice represents a guest networking device
type NetDevice struct {
// Type is the netdev type (e.g. tap).
@ -527,6 +462,29 @@ func (netdev NetDevice) Valid() bool {
}
}
// mqParameter returns the parameters for multi-queue driver. If the driver is a PCI device then the
// vector flag is required. If the driver is a CCW type than the vector flag is not implemented and only
// multi-queue option mq needs to be activated. See comment in libvirt code at
// https://github.com/libvirt/libvirt/blob/6e7e965dcd3d885739129b1454ce19e819b54c25/src/qemu/qemu_command.c#L3633
func (netdev NetDevice) mqParameter() string {
p := []string{",mq=on"}
if isVirtioPCI[netdev.Driver] {
// https://www.linux-kvm.org/page/Multiqueue
// -netdev tap,vhost=on,queues=N
// enable mq and specify msix vectors in qemu cmdline
// (2N+2 vectors, N for tx queues, N for rx queues, 1 for config, and one for possible control vq)
// -device virtio-net-pci,mq=on,vectors=2N+2...
// enable mq in guest by 'ethtool -L eth0 combined $queue_num'
// Clearlinux automatically sets up the queues properly
// The agent implementation should do this to ensure that it is
// always set
vectors := len(netdev.FDs)*2 + 2
p = append(p, fmt.Sprintf(",vectors=%d", vectors))
}
return strings.Join(p, "")
}
// QemuDeviceParams returns the -device parameters for this network device
func (netdev NetDevice) QemuDeviceParams(config *Config) []string {
var deviceParams []string
@ -549,26 +507,13 @@ func (netdev NetDevice) QemuDeviceParams(config *Config) []string {
deviceParams = append(deviceParams, fmt.Sprintf(",addr=%x", addr))
}
}
if netdev.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := netdev.Driver.disableModern(netdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
if len(netdev.FDs) > 0 {
// https://www.linux-kvm.org/page/Multiqueue
// -netdev tap,vhost=on,queues=N
// enable mq and specify msix vectors in qemu cmdline
// (2N+2 vectors, N for tx queues, N for rx queues, 1 for config, and one for possible control vq)
// -device virtio-net-pci,mq=on,vectors=2N+2...
// enable mq in guest by 'ethtool -L eth0 combined $queue_num'
// Clearlinux automatically sets up the queues properly
// The agent implementation should do this to ensure that it is
// always set
vectors := len(netdev.FDs)*2 + 2
// Note: We are appending to the device params here
deviceParams = append(deviceParams, ",mq=on")
deviceParams = append(deviceParams, fmt.Sprintf(",vectors=%d", vectors))
deviceParams = append(deviceParams, netdev.mqParameter())
}
if isVirtioPCI[netdev.Driver] {
@ -683,8 +628,8 @@ func (dev SerialDevice) QemuParams(config *Config) []string {
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", dev.Driver))
if dev.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := dev.Driver.disableModern(dev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", dev.ID))
if isVirtioPCI[dev.Driver] {
@ -761,8 +706,8 @@ func (blkdev BlockDevice) QemuParams(config *Config) []string {
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", blkdev.Driver))
if blkdev.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := blkdev.Driver.disableModern(blkdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
deviceParams = append(deviceParams, fmt.Sprintf(",drive=%s", blkdev.ID))
if blkdev.SCSI == false {
@ -909,7 +854,7 @@ func (vfioDev VFIODevice) QemuParams(config *Config) []string {
var qemuParams []string
var deviceParams []string
driver := VfioPCI
driver := Vfio
deviceParams = append(deviceParams, fmt.Sprintf("%s,host=%s", driver, vfioDev.BDF))
if isVirtioPCI[driver] {
@ -956,7 +901,7 @@ func (scsiCon SCSIController) QemuParams(config *Config) []string {
var qemuParams []string
var devParams []string
driver := VirtioScsiPCI
driver := VirtioScsi
devParams = append(devParams, fmt.Sprintf("%s,id=%s", driver, scsiCon.ID))
if scsiCon.Bus != "" {
devParams = append(devParams, fmt.Sprintf("bus=%s", scsiCon.Bus))
@ -964,8 +909,8 @@ func (scsiCon SCSIController) QemuParams(config *Config) []string {
if scsiCon.Addr != "" {
devParams = append(devParams, fmt.Sprintf("addr=%s", scsiCon.Addr))
}
if scsiCon.DisableModern {
devParams = append(devParams, fmt.Sprintf("disable-modern=true"))
if s := driver.disableModern(scsiCon.DisableModern); s != "" {
devParams = append(devParams, fmt.Sprintf("%s", s))
}
if scsiCon.IOThread != "" {
devParams = append(devParams, fmt.Sprintf("iothread=%s", scsiCon.IOThread))
@ -1072,7 +1017,7 @@ func (bridgeDev BridgeDevice) QemuParams(config *Config) []string {
type VSOCKDevice struct {
ID string
ContextID uint32
ContextID uint64
// VHostFD vhost file descriptor that holds the ContextID
VHostFD *os.File
@ -1086,15 +1031,20 @@ type VSOCKDevice struct {
const (
// MinimalGuestCID is the smallest valid context ID for a guest.
MinimalGuestCID uint32 = 3
MinimalGuestCID uint64 = 3
// MaxGuestCID is the largest valid context ID for a guest.
MaxGuestCID uint64 = 1<<32 - 1
)
const (
// VSOCKGuestCID is the VSOCK guest CID parameter.
VSOCKGuestCID = "guest-cid"
)
// Valid returns true if the VSOCKDevice structure is valid and complete.
func (vsock VSOCKDevice) Valid() bool {
if vsock.ID == "" || vsock.ContextID < MinimalGuestCID {
if vsock.ID == "" || vsock.ContextID < MinimalGuestCID || vsock.ContextID > MaxGuestCID {
return false
}
@ -1106,10 +1056,10 @@ func (vsock VSOCKDevice) QemuParams(config *Config) []string {
var deviceParams []string
var qemuParams []string
driver := VHostVSockPCI
driver := VHostVSock
deviceParams = append(deviceParams, fmt.Sprintf("%s", driver))
if vsock.DisableModern {
deviceParams = append(deviceParams, ",disable-modern=true")
if s := driver.disableModern(vsock.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
if vsock.VHostFD != nil {
qemuFDs := config.appendFDs([]*os.File{vsock.VHostFD})
@ -1223,13 +1173,9 @@ func (b BalloonDevice) QemuParams(_ *Config) []string {
} else {
deviceParams = append(deviceParams, "deflate-on-oom=off")
}
if b.DisableModern {
deviceParams = append(deviceParams, "disable-modern=on")
} else {
deviceParams = append(deviceParams, "disable-modern=off")
if s := driver.disableModern(b.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf("%s", s))
}
qemuParams = append(qemuParams, "-device")
qemuParams = append(qemuParams, strings.Join(deviceParams, ","))
@ -1516,6 +1462,9 @@ type Config struct {
IOThreads []IOThread
// PidFile is the -pidfile parameter
PidFile string
qemuParams []string
}
@ -1830,6 +1779,13 @@ func (config *Config) appendIncoming() {
config.qemuParams = append(config.qemuParams, "-S", "-incoming", uri)
}
func (config *Config) appendPidFile() {
if config.PidFile != "" {
config.qemuParams = append(config.qemuParams, "-pidfile")
config.qemuParams = append(config.qemuParams, config.PidFile)
}
}
// LaunchQemu can be used to launch a new qemu instance.
//
// The Config parameter contains a set of qemu parameters and settings.
@ -1855,6 +1811,7 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) {
config.appendBios()
config.appendIOThreads()
config.appendIncoming()
config.appendPidFile()
if err := config.appendCPUs(); err != nil {
return "", err

103
vendor/github.com/intel/govmm/qemu/qemu_arch_base.go generated vendored Normal file
View File

@ -0,0 +1,103 @@
// +build !s390x,!s390x_test
/*
// Copyright contributors to the Virtual Machine Manager for Go project
//
// 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 qemu
const (
// Virtio9P is the 9pfs device driver.
Virtio9P DeviceDriver = "virtio-9p-pci"
// VirtioSerial is the serial device driver.
VirtioSerial DeviceDriver = "virtio-serial-pci"
// VirtioNet is the virt-io pci networking device driver.
VirtioNet DeviceDriver = VirtioNetPCI
// Vfio is the vfio driver
Vfio DeviceDriver = "vfio-pci"
// VirtioScsi is the virtio-scsi device
VirtioScsi DeviceDriver = "virtio-scsi-pci"
// VHostVSock is a generic Vsock vhost device
VHostVSock DeviceDriver = "vhost-vsock-pci"
)
// isVirtioPCI is a map indicating if a DeviceDriver is considered as a
// virtio PCI device, which is helpful to determine if the option "romfile"
// applies or not to this specific device.
var isVirtioPCI = map[DeviceDriver]bool{
NVDIMM: false,
Virtio9P: true,
VirtioNetPCI: true,
VirtioSerial: true,
VirtioBlock: true,
Console: false,
VirtioSerialPort: false,
VHostVSock: true,
VirtioRng: true,
VirtioBalloon: true,
VhostUserSCSI: true,
VhostUserBlk: true,
Vfio: true,
VirtioScsi: true,
PCIBridgeDriver: true,
PCIePCIBridgeDriver: true,
}
// QemuNetdevParam converts to the QEMU -netdev parameter notation
func (n NetDeviceType) QemuNetdevParam() string {
switch n {
case TAP:
return "tap"
case MACVTAP:
return "tap"
case IPVTAP:
return "tap"
case VETHTAP:
return "tap" // -netdev type=tap -device virtio-net-pci
case VFIO:
return "" // -device vfio-pci (no netdev)
case VHOSTUSER:
return "vhost-user" // -netdev type=vhost-user (no device)
default:
return ""
}
}
// QemuDeviceParam converts to the QEMU -device parameter notation
func (n NetDeviceType) QemuDeviceParam() DeviceDriver {
switch n {
case TAP:
return "virtio-net-pci"
case MACVTAP:
return "virtio-net-pci"
case IPVTAP:
return "virtio-net-pci"
case VETHTAP:
return "virtio-net-pci" // -netdev type=tap -device virtio-net-pci
case VFIO:
return "vfio-pci" // -device vfio-pci (no netdev)
case VHOSTUSER:
return "" // -netdev type=vhost-user (no device)
default:
return ""
}
}

115
vendor/github.com/intel/govmm/qemu/qemus390x.go generated vendored Normal file
View File

@ -0,0 +1,115 @@
// +build s390x s390x_test
/*
// Copyright contributors to the Virtual Machine Manager for Go project
//
// 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 qemu
import "log"
// IBM Z uses CCW devices intead of PCI devices.
// See https://wiki.qemu.org/Documentation/Platforms/S390X
const (
// Virtio9P is the 9pfs device driver.
Virtio9P DeviceDriver = "virtio-9p-ccw"
// VirtioSerial is the serial device driver.
VirtioSerial DeviceDriver = "virtio-serial-ccw"
// VirtioNet is the virt-io ccw networking device driver.
VirtioNet DeviceDriver = VirtioNetCCW
// Vfio is the vfio driver
Vfio DeviceDriver = "vfio-ccw"
// VirtioScsi is the virtio-scsi device
VirtioScsi DeviceDriver = "virtio-scsi-ccw"
// VHostVSock is a generic Vsock Device
VHostVSock DeviceDriver = "vhost-vsock-ccw"
)
// isVirtioPCI is a fake map on s390x to always avoid the "romfile"
// option
var isVirtioPCI = map[DeviceDriver]bool{
NVDIMM: false,
Virtio9P: false,
VirtioNetCCW: false,
VirtioSerial: false,
VirtioBlock: false,
Console: false,
VirtioSerialPort: false,
VHostVSock: false,
VirtioRng: false,
VirtioBalloon: false,
VhostUserSCSI: false,
VhostUserBlk: false,
Vfio: false,
VirtioScsi: false,
PCIBridgeDriver: false,
PCIePCIBridgeDriver: false,
}
// QemuDeviceParam converts to the QEMU -device parameter notation
// This function has been reimplemented for the s390x architecture to deal
// with the VHOSTUSER case. Vhost user devices are not implemented on s390x
// architecture. For further details see issue
// https://github.com/kata-containers/runtime/issues/659
func (n NetDeviceType) QemuDeviceParam() string {
switch n {
case TAP:
return string(VirtioNet)
case MACVTAP:
return string(VirtioNet)
case IPVTAP:
return string(VirtioNet)
case VETHTAP:
return string(VirtioNet)
case VFIO:
return string(Vfio)
case VHOSTUSER:
log.Fatal("vhost-user devices are not supported on IBM Z")
return ""
default:
return ""
}
}
// QemuNetdevParam converts to the QEMU -netdev parameter notation
// This function has been reimplemented for the s390x architecture to deal
// with the VHOSTUSER case. Vhost user devices are not implemented on s390x
// architecture. For further details see issue
// https://github.com/kata-containers/runtime/issues/659
func (n NetDeviceType) QemuNetdevParam() string {
switch n {
case TAP:
return "tap"
case MACVTAP:
return "tap"
case IPVTAP:
return "tap"
case VETHTAP:
return "tap"
case VFIO:
return ""
case VHOSTUSER:
log.Fatal("vhost-user devices are not supported on IBM Z")
return ""
default:
return ""
}
}

View File

@ -1,5 +1,5 @@
/*
// Copyright (c) 2016 Intel Corporation
// Copyright contributors to the Virtual Machine Manager for Go project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -313,7 +313,7 @@ func (q *QMP) finaliseCommandWithResponse(cmdEl *list.Element, cmdQueue *list.Li
if succeeded {
cmd.res <- qmpResult{response: response}
} else {
cmd.res <- qmpResult{err: fmt.Errorf("QMP command failed")}
cmd.res <- qmpResult{err: fmt.Errorf("QMP command failed: %v", response)}
}
}
if cmdQueue.Len() > 0 {
@ -325,6 +325,23 @@ func (q *QMP) finaliseCommand(cmdEl *list.Element, cmdQueue *list.List, succeede
q.finaliseCommandWithResponse(cmdEl, cmdQueue, succeeded, nil)
}
func (q *QMP) errorDesc(errorData interface{}) (string, error) {
// convert error to json
data, err := json.Marshal(errorData)
if err != nil {
return "", fmt.Errorf("Unable to extract error information: %v", err)
}
// see: https://github.com/qemu/qemu/blob/stable-2.12/qapi/qmp-dispatch.c#L125
var qmpErr map[string]string
// convert json to qmpError
if err = json.Unmarshal(data, &qmpErr); err != nil {
return "", fmt.Errorf("Unable to convert json to qmpError: %v", err)
}
return qmpErr["desc"], nil
}
func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
var vmData map[string]interface{}
err := json.Unmarshal(line, &vmData)
@ -339,7 +356,7 @@ func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
}
response, succeeded := vmData["return"]
_, failed := vmData["error"]
errData, failed := vmData["error"]
if !succeeded && !failed {
return
@ -353,6 +370,14 @@ func (q *QMP) processQMPInput(line []byte, cmdQueue *list.List) {
}
cmd := cmdEl.Value.(*qmpCommand)
if failed || cmd.filter == nil {
if errData != nil {
desc, err := q.errorDesc(errData)
if err != nil {
q.cfg.Logger.Infof("Get error description failed: %v", err)
} else {
response = desc
}
}
q.finaliseCommandWithResponse(cmdEl, cmdQueue, succeeded, response)
} else {
cmd.resultReceived = true
@ -722,11 +747,7 @@ func (q *QMP) ExecuteQuit(ctx context.Context) error {
return q.executeCommand(ctx, "quit", nil, nil)
}
// ExecuteBlockdevAdd sends a blockdev-add to the QEMU instance. device is the
// path of the device to add, e.g., /dev/rdb0, and blockdevID is an identifier
// used to name the device. As this identifier will be passed directly to QMP,
// it must obey QMP's naming rules, e,g., it must start with a letter.
func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string) error {
func (q *QMP) blockdevAddBaseArgs(device, blockdevID string) (map[string]interface{}, map[string]interface{}) {
var args map[string]interface{}
blockdevArgs := map[string]interface{}{
@ -747,6 +768,39 @@ func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string)
}
}
return args, blockdevArgs
}
// ExecuteBlockdevAdd sends a blockdev-add to the QEMU instance. device is the
// path of the device to add, e.g., /dev/rdb0, and blockdevID is an identifier
// used to name the device. As this identifier will be passed directly to QMP,
// it must obey QMP's naming rules, e,g., it must start with a letter.
func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string) error {
args, _ := q.blockdevAddBaseArgs(device, blockdevID)
return q.executeCommand(ctx, "blockdev-add", args, nil)
}
// ExecuteBlockdevAddWithCache has two more parameters direct and noFlush
// than ExecuteBlockdevAdd.
// They are cache-related options for block devices that are described in
// https://github.com/qemu/qemu/blob/master/qapi/block-core.json.
// direct denotes whether use of O_DIRECT (bypass the host page cache)
// is enabled. noFlush denotes whether flush requests for the device are
// ignored.
func (q *QMP) ExecuteBlockdevAddWithCache(ctx context.Context, device, blockdevID string, direct, noFlush bool) error {
args, blockdevArgs := q.blockdevAddBaseArgs(device, blockdevID)
if q.version.Major < 2 || (q.version.Major == 2 && q.version.Minor < 9) {
return fmt.Errorf("versions of qemu (%d.%d) older than 2.9 do not support set cache-related options for block devices",
q.version.Major, q.version.Minor)
}
blockdevArgs["cache"] = map[string]interface{}{
"direct": direct,
"no-flush": noFlush,
}
return q.executeCommand(ctx, "blockdev-add", args, nil)
}
@ -756,7 +810,10 @@ func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string)
// add. Both strings must be valid QMP identifiers. driver is the name of the
// driver,e.g., virtio-blk-pci, and bus is the name of the bus. bus is optional.
// shared denotes if the drive can be shared allowing it to be passed more than once.
func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, shared bool) error {
// disableModern indicates if virtio version 1.0 should be replaced by the
// former version 0.9, as there is a KVM bug that occurs when using virtio
// 1.0 in nested environments.
func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, shared, disableModern bool) error {
args := map[string]interface{}{
"id": devID,
"driver": driver,
@ -770,6 +827,10 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b
}
if isVirtioPCI[DeviceDriver(driver)] {
args["romfile"] = romfile
if disableModern {
args["disable-modern"] = disableModern
}
}
return q.executeCommand(ctx, "device_add", args, nil)
@ -783,7 +844,10 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b
// scsiID is the SCSI id, lun is logical unit number. scsiID and lun are optional, a negative value
// for scsiID and lun is ignored. shared denotes if the drive can be shared allowing it
// to be passed more than once.
func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, scsiID, lun int, shared bool) error {
// disableModern indicates if virtio version 1.0 should be replaced by the
// former version 0.9, as there is a KVM bug that occurs when using virtio
// 1.0 in nested environments.
func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, scsiID, lun int, shared, disableModern bool) error {
// TBD: Add drivers for scsi passthrough like scsi-generic and scsi-block
drivers := []string{"scsi-hd", "scsi-cd", "scsi-disk"}
@ -816,6 +880,10 @@ func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, drive
}
if isVirtioPCI[DeviceDriver(driver)] {
args["romfile"] = romfile
if disableModern {
args["disable-modern"] = disableModern
}
}
return q.executeCommand(ctx, "device_add", args, nil)
@ -908,7 +976,10 @@ func (q *QMP) ExecuteNetdevDel(ctx context.Context, netdevID string) error {
// using the device_add command. devID is the id of the device to add.
// Must be valid QMP identifier. netdevID is the id of nic added by previous netdev_add.
// queues is the number of queues of a nic.
func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus, romfile string, queues int) error {
// disableModern indicates if virtio version 1.0 should be replaced by the
// former version 0.9, as there is a KVM bug that occurs when using virtio
// 1.0 in nested environments.
func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus, romfile string, queues int, disableModern bool) error {
args := map[string]interface{}{
"id": devID,
"driver": VirtioNetPCI,
@ -927,6 +998,9 @@ func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAd
if netdevID != "" {
args["netdev"] = netdevID
}
if disableModern {
args["disable-modern"] = disableModern
}
if queues > 0 {
// (2N+2 vectors, N for tx queues, N for rx queues, 1 for config, and one for possible control vq)
@ -942,6 +1016,26 @@ func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAd
return q.executeCommand(ctx, "device_add", args, nil)
}
// ExecuteNetCCWDeviceAdd adds a Net CCW device to a QEMU instance
// using the device_add command. devID is the id of the device to add.
// Must be valid QMP identifier. netdevID is the id of nic added by previous netdev_add.
// queues is the number of queues of a nic.
func (q *QMP) ExecuteNetCCWDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus string, queues int) error {
args := map[string]interface{}{
"id": devID,
"driver": VirtioNetCCW,
"netdev": netdevID,
"mac": macAddr,
"addr": addr,
}
if queues > 0 {
args["mq"] = "on"
}
return q.executeCommand(ctx, "device_add", args, nil)
}
// ExecuteDeviceDel deletes guest portion of a QEMU device by sending a
// device_del command. devId is the identifier of the device to delete.
// Typically it would match the devID parameter passed to an earlier call
@ -964,7 +1058,10 @@ func (q *QMP) ExecuteDeviceDel(ctx context.Context, devID string) error {
// to hot plug PCI devices on PCI(E) bridges, unlike ExecuteDeviceAdd this function receive the
// device address on its parent bus. bus is optional. shared denotes if the drive can be shared
// allowing it to be passed more than once.
func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus, romfile string, shared bool) error {
// disableModern indicates if virtio version 1.0 should be replaced by the
// former version 0.9, as there is a KVM bug that occurs when using virtio
// 1.0 in nested environments.
func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus, romfile string, shared, disableModern bool) error {
args := map[string]interface{}{
"id": devID,
"driver": driver,
@ -979,6 +1076,10 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver
}
if isVirtioPCI[DeviceDriver(driver)] {
args["romfile"] = romfile
if disableModern {
args["disable-modern"] = disableModern
}
}
return q.executeCommand(ctx, "device_add", args, nil)
@ -991,7 +1092,7 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver
func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, romfile string) error {
args := map[string]interface{}{
"id": devID,
"driver": "vfio-pci",
"driver": Vfio,
"host": bdf,
"romfile": romfile,
}
@ -1006,11 +1107,12 @@ func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, romfile stri
func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus, romfile string) error {
args := map[string]interface{}{
"id": devID,
"driver": "vfio-pci",
"driver": Vfio,
"host": bdf,
"addr": addr,
"romfile": romfile,
}
if bus != "" {
args["bus"] = bus
}
@ -1025,10 +1127,11 @@ func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus
func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsdev, addr, bus, romfile string) error {
args := map[string]interface{}{
"id": devID,
"driver": "vfio-pci",
"driver": Vfio,
"sysfsdev": sysfsdev,
"romfile": romfile,
}
if bus != "" {
args["bus"] = bus
}
@ -1170,13 +1273,14 @@ func (q *QMP) ExecQueryCpusFast(ctx context.Context) ([]CPUInfoFast, error) {
// ExecHotplugMemory adds size of MiB memory to the guest
func (q *QMP) ExecHotplugMemory(ctx context.Context, qomtype, id, mempath string, size int) error {
props := map[string]interface{}{"size": uint64(size) << 20}
args := map[string]interface{}{
"qom-type": qomtype,
"id": id,
"props": map[string]interface{}{"size": uint64(size) << 20},
"props": props,
}
if mempath != "" {
args["mem-path"] = mempath
props["mem-path"] = mempath
}
err := q.executeCommand(ctx, "object-add", args, nil)
if err != nil {
@ -1213,9 +1317,12 @@ func (q *QMP) ExecuteBalloon(ctx context.Context, bytes uint64) error {
}
// ExecutePCIVSockAdd adds a vhost-vsock-pci bus
// disableModern indicates if virtio version 1.0 should be replaced by the
// former version 0.9, as there is a KVM bug that occurs when using virtio
// 1.0 in nested environments.
func (q *QMP) ExecutePCIVSockAdd(ctx context.Context, id, guestCID, vhostfd, addr, bus, romfile string, disableModern bool) error {
args := map[string]interface{}{
"driver": VHostVSockPCI,
"driver": VHostVSock,
"id": id,
"guest-cid": guestCID,
"vhostfd": vhostfd,

View File

@ -750,7 +750,7 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
// PCI address is in the format bridge-addr/device-addr eg. "03/02"
drive.PCIAddr = fmt.Sprintf("%02x", bridge.Addr) + "/" + addr
if err = q.qmpMonitorCh.qmp.ExecutePCIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, addr, bridge.ID, romFile, true); err != nil {
if err = q.qmpMonitorCh.qmp.ExecutePCIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, addr, bridge.ID, romFile, true, q.arch.runNested()); err != nil {
return err
}
} else {
@ -765,7 +765,7 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
return err
}
if err = q.qmpMonitorCh.qmp.ExecuteSCSIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, bus, romFile, scsiID, lun, true); err != nil {
if err = q.qmpMonitorCh.qmp.ExecuteSCSIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, bus, romFile, scsiID, lun, true, q.arch.runNested()); err != nil {
return err
}
}
@ -892,7 +892,7 @@ func (q *qemu) hotplugNetDevice(endpoint Endpoint, op operation) error {
endpoint.SetPciAddr(pciAddr)
devID := "virtio-" + tap.ID
if err = q.qmpMonitorCh.qmp.ExecuteNetPCIDeviceAdd(q.qmpMonitorCh.ctx, tap.Name, devID, endpoint.HardwareAddr(), addr, bridge.ID, romFile, int(q.config.NumVCPUs)); err != nil {
if err = q.qmpMonitorCh.qmp.ExecuteNetPCIDeviceAdd(q.qmpMonitorCh.ctx, tap.Name, devID, endpoint.HardwareAddr(), addr, bridge.ID, romFile, int(q.config.NumVCPUs), q.arch.runNested()); err != nil {
return err
}
} else {

View File

@ -24,6 +24,9 @@ type qemuArch interface {
// disableNestingChecks nesting checks will be ignored
disableNestingChecks()
// runNested indicates if the hypervisor runs in a nested environment
runNested() bool
// enableVhostNet vhost will be enabled
enableVhostNet()
@ -185,6 +188,10 @@ func (q *qemuArchBase) disableNestingChecks() {
q.nestedRun = false
}
func (q *qemuArchBase) runNested() bool {
return q.nestedRun
}
func (q *qemuArchBase) enableVhostNet() {
q.vhost = true
}
@ -415,7 +422,7 @@ func (q *qemuArchBase) appendVSockPCI(devices []govmmQemu.Device, vsock kataVSOC
devices = append(devices,
govmmQemu.VSOCKDevice{
ID: fmt.Sprintf("vsock-%d", vsock.contextID),
ContextID: vsock.contextID,
ContextID: uint64(vsock.contextID),
VHostFD: vsock.vhostFd,
DisableModern: q.nestedRun,
},

View File

@ -256,7 +256,7 @@ func TestQemuAddDeviceKataVSOCK(t *testing.T) {
expectedOut := []govmmQemu.Device{
govmmQemu.VSOCKDevice{
ID: fmt.Sprintf("vsock-%d", contextID),
ContextID: contextID,
ContextID: uint64(contextID),
VHostFD: vHostFD,
},
}