diff --git a/virtcontainers/device/api/interface.go b/virtcontainers/device/api/interface.go index 7f75bd64e..eb9ce6b6a 100644 --- a/virtcontainers/device/api/interface.go +++ b/virtcontainers/device/api/interface.go @@ -35,17 +35,8 @@ type DeviceReceiver interface { GetAndSetSandboxBlockIndex() (int, error) DecrementSandboxBlockIndex() error - // this is for vhost_user devices - AddVhostUserDevice(VhostUserDevice, config.DeviceType) error -} - -// VhostUserDevice represents a vhost-user device. Shared -// attributes of a vhost-user device can be retrieved using -// the Attrs() method. Unique data can be obtained by casting -// the object to the proper type. -type VhostUserDevice interface { - Attrs() *config.VhostUserDeviceAttrs - Type() config.DeviceType + // this is for appending device to hypervisor boot params + AppendDevice(Device) error } // Device is the virtcontainers device interface. diff --git a/virtcontainers/device/api/mockDeviceReceiver.go b/virtcontainers/device/api/mockDeviceReceiver.go index b5d2472c3..c080d072d 100644 --- a/virtcontainers/device/api/mockDeviceReceiver.go +++ b/virtcontainers/device/api/mockDeviceReceiver.go @@ -32,7 +32,7 @@ func (mockDC *MockDeviceReceiver) DecrementSandboxBlockIndex() error { return nil } -// AddVhostUserDevice adds new vhost user device -func (mockDC *MockDeviceReceiver) AddVhostUserDevice(VhostUserDevice, config.DeviceType) error { +// AppendDevice adds new vhost user device +func (mockDC *MockDeviceReceiver) AppendDevice(Device) error { return nil } diff --git a/virtcontainers/device/config/config.go b/virtcontainers/device/config/config.go index c099a5cfc..c6fe71208 100644 --- a/virtcontainers/device/config/config.go +++ b/virtcontainers/device/config/config.go @@ -123,10 +123,12 @@ type VFIODrive struct { // VhostUserDeviceAttrs represents data shared by most vhost-user devices type VhostUserDeviceAttrs struct { - DevType DeviceType - DeviceInfo DeviceInfo - SocketPath string ID string + SocketPath string + Type DeviceType + + // MacAddress is only meaningful for vhost user net device + MacAddress string } // GetHostPathFunc is function pointer used to mock GetHostPath in tests. diff --git a/virtcontainers/device/drivers/vhost_user.go b/virtcontainers/device/drivers/vhost_user.go deleted file mode 100644 index 0bd13d1db..000000000 --- a/virtcontainers/device/drivers/vhost_user.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2017-2018 Intel Corporation -// Copyright (c) 2018 Huawei Corporation -// -// SPDX-License-Identifier: Apache-2.0 -// - -package drivers - -import ( - "encoding/hex" - - "github.com/kata-containers/runtime/virtcontainers/device/api" - "github.com/kata-containers/runtime/virtcontainers/utils" -) - -// vhostUserAttach handles the common logic among all of the vhost-user device's -// attach functions -func vhostUserAttach(device api.VhostUserDevice, devReceiver api.DeviceReceiver) error { - // generate a unique ID to be used for hypervisor commandline fields - randBytes, err := utils.GenerateRandomBytes(8) - if err != nil { - return err - } - id := hex.EncodeToString(randBytes) - - device.Attrs().ID = id - - return devReceiver.AddVhostUserDevice(device, device.Type()) -} diff --git a/virtcontainers/device/drivers/vhost_user_blk.go b/virtcontainers/device/drivers/vhost_user_blk.go index b03fedd16..dc4b4db1b 100644 --- a/virtcontainers/device/drivers/vhost_user_blk.go +++ b/virtcontainers/device/drivers/vhost_user_blk.go @@ -7,23 +7,17 @@ package drivers import ( + "encoding/hex" + "github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/config" + "github.com/kata-containers/runtime/virtcontainers/utils" ) // VhostUserBlkDevice is a block vhost-user based device type VhostUserBlkDevice struct { config.VhostUserDeviceAttrs -} - -// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device -func (vhostUserBlkDevice *VhostUserBlkDevice) Attrs() *config.VhostUserDeviceAttrs { - return &vhostUserBlkDevice.VhostUserDeviceAttrs -} - -// Type returns the type associated with the vhost-user device -func (vhostUserBlkDevice *VhostUserBlkDevice) Type() config.DeviceType { - return config.VhostUserBlk + DeviceInfo *config.DeviceInfo } // @@ -32,17 +26,54 @@ func (vhostUserBlkDevice *VhostUserBlkDevice) Type() config.DeviceType { // Attach is standard interface of api.Device, it's used to add device to some // DeviceReceiver -func (vhostUserBlkDevice *VhostUserBlkDevice) Attach(devReceiver api.DeviceReceiver) (err error) { - return vhostUserAttach(vhostUserBlkDevice, devReceiver) +func (device *VhostUserBlkDevice) Attach(devReceiver api.DeviceReceiver) (err error) { + // generate a unique ID to be used for hypervisor commandline fields + randBytes, err := utils.GenerateRandomBytes(8) + if err != nil { + return err + } + id := hex.EncodeToString(randBytes) + + device.ID = id + device.Type = device.DeviceType() + + defer func() { + if err == nil { + device.DeviceInfo.Hotplugged = true + } + }() + return devReceiver.AppendDevice(device) } // Detach is standard interface of api.Device, it's used to remove device from some // DeviceReceiver -func (vhostUserBlkDevice *VhostUserBlkDevice) Detach(devReceiver api.DeviceReceiver) error { +func (device *VhostUserBlkDevice) Detach(devReceiver api.DeviceReceiver) error { + device.DeviceInfo.Hotplugged = false return nil } -// DeviceType is standard interface of api.Device, it returns device type -func (vhostUserBlkDevice *VhostUserBlkDevice) DeviceType() config.DeviceType { - return vhostUserBlkDevice.DevType +// IsAttached checks if the device is attached +func (device *VhostUserBlkDevice) IsAttached() bool { + return device.DeviceInfo.Hotplugged +} + +// DeviceID returns device ID +func (device *VhostUserBlkDevice) DeviceID() string { + return device.ID +} + +// DeviceType is standard interface of api.Device, it returns device type +func (device *VhostUserBlkDevice) DeviceType() config.DeviceType { + return config.VhostUserBlk +} + +// GetDeviceInfo returns device information that the device is created based on +func (device *VhostUserBlkDevice) GetDeviceInfo() *config.DeviceInfo { + return device.DeviceInfo +} + +// GetDeviceDrive returns device information used for creating +func (device *VhostUserBlkDevice) GetDeviceDrive() interface{} { + device.Type = device.DeviceType() + return &device.VhostUserDeviceAttrs } diff --git a/virtcontainers/device/drivers/vhost_user_net.go b/virtcontainers/device/drivers/vhost_user_net.go index 7bf7517b9..dd3bd53d9 100644 --- a/virtcontainers/device/drivers/vhost_user_net.go +++ b/virtcontainers/device/drivers/vhost_user_net.go @@ -7,24 +7,17 @@ package drivers import ( + "encoding/hex" + "github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/config" + "github.com/kata-containers/runtime/virtcontainers/utils" ) // VhostUserNetDevice is a network vhost-user based device type VhostUserNetDevice struct { config.VhostUserDeviceAttrs - MacAddress string -} - -// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device -func (vhostUserNetDevice *VhostUserNetDevice) Attrs() *config.VhostUserDeviceAttrs { - return &vhostUserNetDevice.VhostUserDeviceAttrs -} - -// Type returns the type associated with the vhost-user device -func (vhostUserNetDevice *VhostUserNetDevice) Type() config.DeviceType { - return config.VhostUserNet + DeviceInfo *config.DeviceInfo } // @@ -33,17 +26,54 @@ func (vhostUserNetDevice *VhostUserNetDevice) Type() config.DeviceType { // Attach is standard interface of api.Device, it's used to add device to some // DeviceReceiver -func (vhostUserNetDevice *VhostUserNetDevice) Attach(devReceiver api.DeviceReceiver) (err error) { - return vhostUserAttach(vhostUserNetDevice, devReceiver) +func (device *VhostUserNetDevice) Attach(devReceiver api.DeviceReceiver) (err error) { + // generate a unique ID to be used for hypervisor commandline fields + randBytes, err := utils.GenerateRandomBytes(8) + if err != nil { + return err + } + id := hex.EncodeToString(randBytes) + + device.ID = id + device.Type = device.DeviceType() + + defer func() { + if err == nil { + device.DeviceInfo.Hotplugged = true + } + }() + return devReceiver.AppendDevice(device) } // Detach is standard interface of api.Device, it's used to remove device from some // DeviceReceiver -func (vhostUserNetDevice *VhostUserNetDevice) Detach(devReceiver api.DeviceReceiver) error { +func (device *VhostUserNetDevice) Detach(devReceiver api.DeviceReceiver) error { + device.DeviceInfo.Hotplugged = false return nil } -// DeviceType is standard interface of api.Device, it returns device type -func (vhostUserNetDevice *VhostUserNetDevice) DeviceType() config.DeviceType { - return vhostUserNetDevice.DevType +// IsAttached checks if the device is attached +func (device *VhostUserNetDevice) IsAttached() bool { + return device.DeviceInfo.Hotplugged +} + +// DeviceID returns device ID +func (device *VhostUserNetDevice) DeviceID() string { + return device.ID +} + +// DeviceType is standard interface of api.Device, it returns device type +func (device *VhostUserNetDevice) DeviceType() config.DeviceType { + return config.VhostUserNet +} + +// GetDeviceInfo returns device information that the device is created based on +func (device *VhostUserNetDevice) GetDeviceInfo() *config.DeviceInfo { + return device.DeviceInfo +} + +// GetDeviceDrive returns device information used for creating +func (device *VhostUserNetDevice) GetDeviceDrive() interface{} { + device.Type = device.DeviceType() + return &device.VhostUserDeviceAttrs } diff --git a/virtcontainers/device/drivers/vhost_user_scsi.go b/virtcontainers/device/drivers/vhost_user_scsi.go index 6d485baec..ec273f39d 100644 --- a/virtcontainers/device/drivers/vhost_user_scsi.go +++ b/virtcontainers/device/drivers/vhost_user_scsi.go @@ -7,23 +7,17 @@ package drivers import ( + "encoding/hex" + "github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/config" + "github.com/kata-containers/runtime/virtcontainers/utils" ) // VhostUserSCSIDevice is a SCSI vhost-user based device type VhostUserSCSIDevice struct { config.VhostUserDeviceAttrs -} - -// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device -func (vhostUserSCSIDevice *VhostUserSCSIDevice) Attrs() *config.VhostUserDeviceAttrs { - return &vhostUserSCSIDevice.VhostUserDeviceAttrs -} - -// Type returns the type associated with the vhost-user device -func (vhostUserSCSIDevice *VhostUserSCSIDevice) Type() config.DeviceType { - return config.VhostUserSCSI + DeviceInfo *config.DeviceInfo } // @@ -32,17 +26,54 @@ func (vhostUserSCSIDevice *VhostUserSCSIDevice) Type() config.DeviceType { // Attach is standard interface of api.Device, it's used to add device to some // DeviceReceiver -func (vhostUserSCSIDevice *VhostUserSCSIDevice) Attach(devReceiver api.DeviceReceiver) (err error) { - return vhostUserAttach(vhostUserSCSIDevice, devReceiver) +func (device *VhostUserSCSIDevice) Attach(devReceiver api.DeviceReceiver) (err error) { + // generate a unique ID to be used for hypervisor commandline fields + randBytes, err := utils.GenerateRandomBytes(8) + if err != nil { + return err + } + id := hex.EncodeToString(randBytes) + + device.ID = id + device.Type = device.DeviceType() + + defer func() { + if err == nil { + device.DeviceInfo.Hotplugged = true + } + }() + return devReceiver.AppendDevice(device) } // Detach is standard interface of api.Device, it's used to remove device from some // DeviceReceiver -func (vhostUserSCSIDevice *VhostUserSCSIDevice) Detach(devReceiver api.DeviceReceiver) error { +func (device *VhostUserSCSIDevice) Detach(devReceiver api.DeviceReceiver) error { + device.DeviceInfo.Hotplugged = false return nil } -// DeviceType is standard interface of api.Device, it returns device type -func (vhostUserSCSIDevice *VhostUserSCSIDevice) DeviceType() config.DeviceType { - return vhostUserSCSIDevice.DevType +// IsAttached checks if the device is attached +func (device *VhostUserSCSIDevice) IsAttached() bool { + return device.DeviceInfo.Hotplugged +} + +// DeviceID returns device ID +func (device *VhostUserSCSIDevice) DeviceID() string { + return device.ID +} + +// DeviceType is standard interface of api.Device, it returns device type +func (device *VhostUserSCSIDevice) DeviceType() config.DeviceType { + return config.VhostUserSCSI +} + +// GetDeviceInfo returns device information that the device is created based on +func (device *VhostUserSCSIDevice) GetDeviceInfo() *config.DeviceInfo { + return device.DeviceInfo +} + +// GetDeviceDrive returns device information used for creating +func (device *VhostUserSCSIDevice) GetDeviceDrive() interface{} { + device.Type = device.DeviceType() + return &device.VhostUserDeviceAttrs } diff --git a/virtcontainers/network.go b/virtcontainers/network.go index ef7615740..6381d4620 100644 --- a/virtcontainers/network.go +++ b/virtcontainers/network.go @@ -281,11 +281,11 @@ func (endpoint *VhostUserEndpoint) Attach(h hypervisor) error { } id := hex.EncodeToString(randBytes) - d := &drivers.VhostUserNetDevice{ + d := config.VhostUserDeviceAttrs{ + ID: id, + SocketPath: endpoint.SocketPath, MacAddress: endpoint.HardAddr, } - d.SocketPath = endpoint.SocketPath - d.ID = id return h.addDevice(d, vhostuserDev) } diff --git a/virtcontainers/qemu.go b/virtcontainers/qemu.go index 8a932939c..7fb56d4a2 100644 --- a/virtcontainers/qemu.go +++ b/virtcontainers/qemu.go @@ -19,7 +19,6 @@ import ( "github.com/kata-containers/runtime/virtcontainers/pkg/uuid" "github.com/sirupsen/logrus" - "github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/utils" ) @@ -942,13 +941,6 @@ func (q *qemu) resumeSandbox() error { // addDevice will add extra devices to Qemu command line. func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error { - switch devType { - case vhostuserDev: - vhostDev := devInfo.(api.VhostUserDevice) - q.qemuConfig.Devices = q.arch.appendVhostUserDevice(q.qemuConfig.Devices, vhostDev) - return nil - } - switch v := devInfo.(type) { case Volume: q.qemuConfig.Devices = q.arch.append9PVolume(q.qemuConfig.Devices, v) @@ -958,7 +950,8 @@ func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error { q.qemuConfig.Devices = q.arch.appendNetwork(q.qemuConfig.Devices, v) case config.BlockDrive: q.qemuConfig.Devices = q.arch.appendBlockDevice(q.qemuConfig.Devices, v) - + case config.VhostUserDeviceAttrs: + q.qemuConfig.Devices = q.arch.appendVhostUserDevice(q.qemuConfig.Devices, v) case config.VFIODrive: q.qemuConfig.Devices = q.arch.appendVFIODevice(q.qemuConfig.Devices, v) default: diff --git a/virtcontainers/qemu_arch_base.go b/virtcontainers/qemu_arch_base.go index 53356b9d4..6c556441b 100644 --- a/virtcontainers/qemu_arch_base.go +++ b/virtcontainers/qemu_arch_base.go @@ -13,9 +13,7 @@ import ( govmmQemu "github.com/intel/govmm/qemu" - "github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/config" - "github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/utils" ) @@ -76,7 +74,7 @@ type qemuArch interface { appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) []govmmQemu.Device // appendVhostUserDevice appends a vhost user device to devices - appendVhostUserDevice(devices []govmmQemu.Device, vhostUserDevice api.VhostUserDevice) []govmmQemu.Device + appendVhostUserDevice(devices []govmmQemu.Device, drive config.VhostUserDeviceAttrs) []govmmQemu.Device // appendVFIODevice appends a VFIO device to devices appendVFIODevice(devices []govmmQemu.Device, vfioDevice config.VFIODrive) []govmmQemu.Device @@ -455,22 +453,22 @@ func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive confi return devices } -func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, vhostUserDevice api.VhostUserDevice) []govmmQemu.Device { +func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, attr config.VhostUserDeviceAttrs) []govmmQemu.Device { qemuVhostUserDevice := govmmQemu.VhostUserDevice{} // TODO: find a way to remove dependency of drivers package - switch vhostUserDevice := vhostUserDevice.(type) { - case *drivers.VhostUserNetDevice: - qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", vhostUserDevice.ID, maxDevIDSize) - qemuVhostUserDevice.Address = vhostUserDevice.MacAddress - case *drivers.VhostUserSCSIDevice: - qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", vhostUserDevice.ID, maxDevIDSize) - case *drivers.VhostUserBlkDevice: + switch attr.Type { + case config.VhostUserNet: + qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", attr.ID, maxDevIDSize) + qemuVhostUserDevice.Address = attr.MacAddress + case config.VhostUserSCSI: + qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.ID, maxDevIDSize) + case config.VhostUserBlk: } - qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserDeviceType(vhostUserDevice.Type()) - qemuVhostUserDevice.SocketPath = vhostUserDevice.Attrs().SocketPath - qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", vhostUserDevice.Attrs().ID, maxDevIDSize) + qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserDeviceType(attr.Type) + qemuVhostUserDevice.SocketPath = attr.SocketPath + qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", attr.ID, maxDevIDSize) devices = append(devices, qemuVhostUserDevice) diff --git a/virtcontainers/sandbox.go b/virtcontainers/sandbox.go index f6a63eb23..e52be3ead 100644 --- a/virtcontainers/sandbox.go +++ b/virtcontainers/sandbox.go @@ -1503,12 +1503,13 @@ func (s *Sandbox) DecrementSandboxBlockIndex() error { return s.decrementSandboxBlockIndex() } -// AddVhostUserDevice adds a vhost user device to sandbox +// AppendDevice can only handle vhost user device currently, it adds a +// vhost user device to sandbox // Sandbox implement DeviceReceiver interface from device/api/interface.go -func (s *Sandbox) AddVhostUserDevice(devInfo api.VhostUserDevice, devType config.DeviceType) error { - switch devType { +func (s *Sandbox) AppendDevice(device api.Device) error { + switch device.DeviceType() { case config.VhostUserSCSI, config.VhostUserNet, config.VhostUserBlk: - return s.hypervisor.addDevice(devInfo, vhostuserDev) + return s.hypervisor.addDevice(device.GetDeviceDrive().(*config.VhostUserDeviceAttrs), vhostuserDev) } return fmt.Errorf("unsupported device type") }