virtio-mmio: Add support for virtio-mmio

Start adding support for virtio-mmio devices starting with block.
The devices show within the vm as vda, vdb,... based on order of
insertion and such within the VM resemble virtio-blk devices.

They need to be explicitly differentiated to ensure that the
agent logic within the VM can discover and mount them appropropriately.
The agent uses PCI location to discover them for virtio-blk.
For virtio-mmio we need to use the predicted device name for now.

Note: Kata used a disk for the VM rootfs in the case of Firecracker.
(Instead of initrd or virtual-nvdimm). The Kata code today does not
handle this case properly.

For now as Firecracker is the only Hypervisor in Kata that
uses virtio-mmio directly offset the drive index to comprehend
this.

Longer term we should track if the rootfs is setup as a block
device explicitly.

Fixes: #1046

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
Signed-off-by: Manohar Castelino <manohar.r.castelino@intel.com>
This commit is contained in:
Manohar Castelino 2018-12-05 18:03:20 -08:00
parent 5d91edd695
commit 0d84d799ea
11 changed files with 90 additions and 35 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
vc "github.com/kata-containers/runtime/virtcontainers" vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci" "github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -292,15 +293,19 @@ func (h hypervisor) defaultBridges() uint32 {
} }
func (h hypervisor) blockDeviceDriver() (string, error) { func (h hypervisor) blockDeviceDriver() (string, error) {
supportedBlockDrivers := []string{config.VirtioSCSI, config.VirtioBlock, config.VirtioMmio}
if h.BlockDeviceDriver == "" { if h.BlockDeviceDriver == "" {
return defaultBlockDeviceDriver, nil return defaultBlockDeviceDriver, nil
} }
if h.BlockDeviceDriver != vc.VirtioSCSI && h.BlockDeviceDriver != vc.VirtioBlock { for _, b := range supportedBlockDrivers {
return "", fmt.Errorf("Invalid value %s provided for hypervisor block storage driver, can be either %s or %s", h.BlockDeviceDriver, vc.VirtioSCSI, vc.VirtioBlock) if b == h.BlockDeviceDriver {
return h.BlockDeviceDriver, nil
}
} }
return h.BlockDeviceDriver, nil return "", fmt.Errorf("Invalid hypervisor block storage driver %v specified (supported drivers: %v)", h.BlockDeviceDriver, supportedBlockDrivers)
} }
func (h hypervisor) msize9p() uint32 { func (h hypervisor) msize9p() uint32 {

View File

@ -38,6 +38,17 @@ const (
VhostUserBlk = "vhost-user-blk-pci" VhostUserBlk = "vhost-user-blk-pci"
) )
const (
// VirtioMmio means use virtio-mmio for mmio based drives
VirtioMmio = "virtio-mmio"
// VirtioBlock means use virtio-blk for hotplugging drives
VirtioBlock = "virtio-blk"
// VirtioSCSI means use virtio-scsi for hotplugging drives
VirtioSCSI = "virtio-scsi"
)
// Defining these as a variable instead of a const, to allow // Defining these as a variable instead of a const, to allow
// overriding this in the tests. // overriding this in the tests.
@ -98,6 +109,9 @@ type BlockDrive struct {
// Index assigned to the drive. In case of virtio-scsi, this is used as SCSI LUN index // Index assigned to the drive. In case of virtio-scsi, this is used as SCSI LUN index
Index int Index int
// MmioAddr is used to identify the slot at which the drive is attached (order?).
MmioAddr string
// PCIAddr is the PCI address used to identify the slot at which the drive is attached. // PCIAddr is the PCI address used to identify the slot at which the drive is attached.
PCIAddr string PCIAddr string

View File

@ -67,21 +67,39 @@ func (device *BlockDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
Index: index, Index: index,
} }
driveName, err := utils.GetVirtDriveName(index)
if err != nil {
return err
}
customOptions := device.DeviceInfo.DriverOptions customOptions := device.DeviceInfo.DriverOptions
if customOptions != nil && customOptions["block-driver"] == "virtio-blk" { if customOptions == nil ||
drive.VirtPath = filepath.Join("/dev", driveName) customOptions["block-driver"] == "virtio-scsi" {
} else { // User has not chosen a specific block device type
// Default to SCSI
scsiAddr, err := utils.GetSCSIAddress(index) scsiAddr, err := utils.GetSCSIAddress(index)
if err != nil { if err != nil {
return err return err
} }
drive.SCSIAddr = scsiAddr drive.SCSIAddr = scsiAddr
} else {
var globalIdx int
switch customOptions["block-driver"] {
case "virtio-blk":
globalIdx = index
case "virtio-mmio":
//With firecracker the rootfs for the VM itself
//sits at /dev/vda and consumes the first index.
//Longer term block based VM rootfs should be added
//as a regular block device which eliminates the
//offset.
//https://github.com/kata-containers/runtime/issues/1061
globalIdx = index + 1
}
driveName, err := utils.GetVirtDriveName(globalIdx)
if err != nil {
return err
}
drive.VirtPath = filepath.Join("/dev", driveName)
} }
deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Attaching block device") deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Attaching block device")

View File

@ -20,6 +20,8 @@ import (
) )
const ( const (
// VirtioMmio indicates block driver is virtio-mmio based
VirtioMmio string = "virtio-mmio"
// VirtioBlock indicates block driver is virtio-blk based // VirtioBlock indicates block driver is virtio-blk based
VirtioBlock string = "virtio-blk" VirtioBlock string = "virtio-blk"
// VirtioSCSI indicates block driver is virtio-scsi based // VirtioSCSI indicates block driver is virtio-scsi based
@ -55,7 +57,9 @@ func NewDeviceManager(blockDriver string, devices []api.Device) api.DeviceManage
dm := &deviceManager{ dm := &deviceManager{
devices: make(map[string]api.Device), devices: make(map[string]api.Device),
} }
if blockDriver == VirtioBlock { if blockDriver == VirtioMmio {
dm.blockDriver = VirtioMmio
} else if blockDriver == VirtioBlock {
dm.blockDriver = VirtioBlock dm.blockDriver = VirtioBlock
} else { } else {
dm.blockDriver = VirtioSCSI dm.blockDriver = VirtioSCSI

View File

@ -522,7 +522,8 @@ func (h *hyper) startOneContainer(sandbox *Sandbox, c *Container) error {
if c.state.Fstype != "" { if c.state.Fstype != "" {
// Pass a drive name only in case of block driver // Pass a drive name only in case of block driver
if sandbox.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { if sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock ||
sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio {
driveName, err := utils.GetVirtDriveName(c.state.BlockIndex) driveName, err := utils.GetVirtDriveName(c.state.BlockIndex)
if err != nil { if err != nil {
return err return err

View File

@ -13,6 +13,8 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"github.com/kata-containers/runtime/virtcontainers/device/config"
) )
// HypervisorType describes an hypervisor type. // HypervisorType describes an hypervisor type.
@ -38,7 +40,7 @@ const (
defaultBridges = 1 defaultBridges = 1
defaultBlockDriver = VirtioSCSI defaultBlockDriver = config.VirtioSCSI
) )
// In some architectures the maximum number of vCPUs depends on the number of physical cores. // In some architectures the maximum number of vCPUs depends on the number of physical cores.

View File

@ -57,6 +57,7 @@ var (
// CAP_NET_BIND_SERVICE capability may bind to these port numbers. // CAP_NET_BIND_SERVICE capability may bind to these port numbers.
vSockPort = 1024 vSockPort = 1024
kata9pDevType = "9p" kata9pDevType = "9p"
kataMmioBlkDevType = "mmioblk"
kataBlkDevType = "blk" kataBlkDevType = "blk"
kataSCSIDevType = "scsi" kataSCSIDevType = "scsi"
sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L,cache=mmap", "nodev"} sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L,cache=mmap", "nodev"}
@ -831,10 +832,15 @@ func (k *kataAgent) appendDevices(deviceList []*grpc.Device, c *Container) []*gr
ContainerPath: dev.ContainerPath, ContainerPath: dev.ContainerPath,
} }
if d.SCSIAddr == "" { switch c.sandbox.config.HypervisorConfig.BlockDeviceDriver {
case config.VirtioMmio:
kataDevice.Type = kataMmioBlkDevType
kataDevice.Id = d.VirtPath
kataDevice.VmPath = d.VirtPath
case config.VirtioBlock:
kataDevice.Type = kataBlkDevType kataDevice.Type = kataBlkDevType
kataDevice.Id = d.PCIAddr kataDevice.Id = d.PCIAddr
} else { case config.VirtioSCSI:
kataDevice.Type = kataSCSIDevType kataDevice.Type = kataSCSIDevType
kataDevice.Id = d.SCSIAddr kataDevice.Id = d.SCSIAddr
} }
@ -883,7 +889,10 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat
return nil, fmt.Errorf("malformed block drive") return nil, fmt.Errorf("malformed block drive")
} }
if sandbox.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { if sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio {
rootfs.Driver = kataMmioBlkDevType
rootfs.Source = blockDrive.VirtPath
} else if sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock {
rootfs.Driver = kataBlkDevType rootfs.Driver = kataBlkDevType
rootfs.Source = blockDrive.PCIAddr rootfs.Source = blockDrive.PCIAddr
} else { } else {
@ -1086,9 +1095,12 @@ func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {
k.Logger().Error("malformed block drive") k.Logger().Error("malformed block drive")
continue continue
} }
if c.sandbox.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { if c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioBlock {
vol.Driver = kataBlkDevType vol.Driver = kataBlkDevType
vol.Source = blockDrive.PCIAddr vol.Source = blockDrive.PCIAddr
} else if c.sandbox.config.HypervisorConfig.BlockDeviceDriver == config.VirtioMmio {
vol.Driver = kataMmioBlkDevType
vol.Source = blockDrive.VirtPath
} else { } else {
vol.Driver = kataSCSIDevType vol.Driver = kataSCSIDevType
vol.Source = blockDrive.SCSIAddr vol.Source = blockDrive.SCSIAddr

View File

@ -402,9 +402,16 @@ func TestAppendDevices(t *testing.T) {
}, },
} }
sandboxConfig := &SandboxConfig{
HypervisorConfig: HypervisorConfig{
BlockDeviceDriver: config.VirtioBlock,
},
}
c := &Container{ c := &Container{
sandbox: &Sandbox{ sandbox: &Sandbox{
devManager: manager.NewDeviceManager("virtio-scsi", ctrDevices), devManager: manager.NewDeviceManager("virtio-blk", ctrDevices),
config: sandboxConfig,
}, },
} }
c.devices = append(c.devices, ContainerDevice{ c.devices = append(c.devices, ContainerDevice{

View File

@ -372,7 +372,7 @@ func (q *qemu) buildDevices(initrdPath string) ([]govmmQemu.Device, *govmmQemu.I
} }
var ioThread *govmmQemu.IOThread var ioThread *govmmQemu.IOThread
if q.config.BlockDeviceDriver == VirtioSCSI { if q.config.BlockDeviceDriver == config.VirtioSCSI {
devices, ioThread = q.arch.appendSCSIController(devices, q.config.EnableIOThreads) devices, ioThread = q.arch.appendSCSIController(devices, q.config.EnableIOThreads)
} }
@ -746,7 +746,7 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
return err return err
} }
if q.config.BlockDeviceDriver == VirtioBlock { if q.config.BlockDeviceDriver == config.VirtioBlock {
driver := "virtio-blk-pci" driver := "virtio-blk-pci"
addr, bridge, err := q.addDeviceToBridge(drive.ID) addr, bridge, err := q.addDeviceToBridge(drive.ID)
if err != nil { if err != nil {
@ -776,7 +776,7 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
} }
} }
} else { } else {
if q.config.BlockDeviceDriver == VirtioBlock { if q.config.BlockDeviceDriver == config.VirtioBlock {
if err := q.removeDeviceFromBridge(drive.ID); err != nil { if err := q.removeDeviceFromBridge(drive.ID); err != nil {
return err return err
} }

View File

@ -128,14 +128,6 @@ const (
// 0 is reserved. // 0 is reserved.
const bridgePCIStartAddr = 2 const bridgePCIStartAddr = 2
const (
// VirtioBlock means use virtio-blk for hotplugging drives
VirtioBlock = "virtio-blk"
// VirtioSCSI means use virtio-scsi for hotplugging drives
VirtioSCSI = "virtio-scsi"
)
const ( const (
// QemuPCLite is the QEMU pc-lite machine type for amd64 // QemuPCLite is the QEMU pc-lite machine type for amd64
QemuPCLite = "pc-lite" QemuPCLite = "pc-lite"

View File

@ -1553,7 +1553,7 @@ func TestAttachBlockDevice(t *testing.T) {
hypervisor := &mockHypervisor{} hypervisor := &mockHypervisor{}
hConfig := HypervisorConfig{ hConfig := HypervisorConfig{
BlockDeviceDriver: VirtioBlock, BlockDeviceDriver: config.VirtioBlock,
} }
sconfig := &SandboxConfig{ sconfig := &SandboxConfig{
@ -1598,7 +1598,7 @@ func TestAttachBlockDevice(t *testing.T) {
DevType: "b", DevType: "b",
} }
dm := manager.NewDeviceManager(VirtioBlock, nil) dm := manager.NewDeviceManager(config.VirtioBlock, nil)
device, err := dm.NewDevice(deviceInfo) device, err := dm.NewDevice(deviceInfo)
assert.Nil(t, err) assert.Nil(t, err)
_, ok := device.(*drivers.BlockDevice) _, ok := device.(*drivers.BlockDevice)
@ -1618,7 +1618,7 @@ func TestAttachBlockDevice(t *testing.T) {
err = device.Detach(sandbox) err = device.Detach(sandbox)
assert.Nil(t, err) assert.Nil(t, err)
container.sandbox.config.HypervisorConfig.BlockDeviceDriver = VirtioSCSI container.sandbox.config.HypervisorConfig.BlockDeviceDriver = config.VirtioSCSI
err = device.Attach(sandbox) err = device.Attach(sandbox)
assert.Nil(t, err) assert.Nil(t, err)
@ -1638,14 +1638,14 @@ func TestPreAddDevice(t *testing.T) {
hypervisor := &mockHypervisor{} hypervisor := &mockHypervisor{}
hConfig := HypervisorConfig{ hConfig := HypervisorConfig{
BlockDeviceDriver: VirtioBlock, BlockDeviceDriver: config.VirtioBlock,
} }
sconfig := &SandboxConfig{ sconfig := &SandboxConfig{
HypervisorConfig: hConfig, HypervisorConfig: hConfig,
} }
dm := manager.NewDeviceManager(VirtioBlock, nil) dm := manager.NewDeviceManager(config.VirtioBlock, nil)
// create a sandbox first // create a sandbox first
sandbox := &Sandbox{ sandbox := &Sandbox{
id: testSandboxID, id: testSandboxID,