Merge pull request #1122 from sameo/topic/asset-types

virtcontainers: Add Asset, Capabilities and Bridge to the types package
This commit is contained in:
Sebastien Boeuf 2019-01-16 09:03:45 -08:00 committed by GitHub
commit e03caf6234
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 328 additions and 288 deletions

View File

@ -137,7 +137,7 @@ type agent interface {
// capabilities should return a structure that specifies the capabilities // capabilities should return a structure that specifies the capabilities
// supported by the agent. // supported by the agent.
capabilities() capabilities capabilities() types.Capabilities
// check will check the agent liveness // check will check the agent liveness
check() error check() error

View File

@ -1,58 +0,0 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
const (
blockDeviceSupport = 1 << iota
blockDeviceHotplugSupport
multiQueueSupport
fsSharingUnsupported
)
type capabilities struct {
flags uint
}
func (caps *capabilities) isBlockDeviceSupported() bool {
if caps.flags&blockDeviceSupport != 0 {
return true
}
return false
}
func (caps *capabilities) setBlockDeviceSupport() {
caps.flags = caps.flags | blockDeviceSupport
}
func (caps *capabilities) isBlockDeviceHotplugSupported() bool {
if caps.flags&blockDeviceHotplugSupport != 0 {
return true
}
return false
}
func (caps *capabilities) setBlockDeviceHotplugSupport() {
caps.flags |= blockDeviceHotplugSupport
}
func (caps *capabilities) isMultiQueueSupported() bool {
if caps.flags&multiQueueSupport != 0 {
return true
}
return false
}
func (caps *capabilities) setMultiQueueSupport() {
caps.flags |= multiQueueSupport
}
func (caps *capabilities) isFsSharingSupported() bool {
return caps.flags&fsSharingUnsupported == 0
}
func (caps *capabilities) setFsSharingUnsupported() {
caps.flags |= fsSharingUnsupported
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import "testing"
func TestBlockDeviceCapability(t *testing.T) {
var caps capabilities
if caps.isBlockDeviceSupported() {
t.Fatal()
}
caps.setBlockDeviceSupport()
if !caps.isBlockDeviceSupported() {
t.Fatal()
}
}
func TestBlockDeviceHotplugCapability(t *testing.T) {
var caps capabilities
if caps.isBlockDeviceHotplugSupported() {
t.Fatal()
}
caps.setBlockDeviceHotplugSupport()
if !caps.isBlockDeviceHotplugSupported() {
t.Fatal()
}
}
func TestFsSharingCapability(t *testing.T) {
var caps capabilities
if !caps.isFsSharingSupported() {
t.Fatal()
}
caps.setFsSharingUnsupported()
if caps.isFsSharingSupported() {
t.Fatal()
}
}

View File

@ -445,7 +445,7 @@ func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir s
// copy file to contaier's rootfs if filesystem sharing is not supported, otherwise // copy file to contaier's rootfs if filesystem sharing is not supported, otherwise
// bind mount it in the shared directory. // bind mount it in the shared directory.
caps := c.sandbox.hypervisor.capabilities() caps := c.sandbox.hypervisor.capabilities()
if !caps.isFsSharingSupported() { if !caps.IsFsSharingSupported() {
c.Logger().Debug("filesystem sharing is not supported, files will be copied") c.Logger().Debug("filesystem sharing is not supported, files will be copied")
fileInfo, err := os.Stat(m.Source) fileInfo, err := os.Stat(m.Source)
@ -713,7 +713,7 @@ func (c *Container) checkBlockDeviceSupport() bool {
agentCaps := c.sandbox.agent.capabilities() agentCaps := c.sandbox.agent.capabilities()
hypervisorCaps := c.sandbox.hypervisor.capabilities() hypervisorCaps := c.sandbox.hypervisor.capabilities()
if agentCaps.isBlockDeviceSupported() && hypervisorCaps.isBlockDeviceHotplugSupported() { if agentCaps.IsBlockDeviceSupported() && hypervisorCaps.IsBlockDeviceHotplugSupported() {
return true return true
} }
} }

View File

@ -21,6 +21,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/types"
"net" "net"
"net/http" "net/http"
@ -656,12 +657,12 @@ func (fc *firecracker) disconnect() {
} }
// Adds all capabilities supported by firecracker implementation of hypervisor interface // Adds all capabilities supported by firecracker implementation of hypervisor interface
func (fc *firecracker) capabilities() capabilities { func (fc *firecracker) capabilities() types.Capabilities {
span, _ := fc.trace("capabilities") span, _ := fc.trace("capabilities")
defer span.Finish() defer span.Finish()
var caps capabilities var caps types.Capabilities
caps.setFsSharingUnsupported() caps.SetFsSharingUnsupported()
caps.setBlockDeviceHotplugSupport() caps.SetBlockDeviceHotplugSupport()
return caps return caps
} }

View File

@ -330,11 +330,11 @@ func (h *hyper) createSandbox(sandbox *Sandbox) (err error) {
return h.configure(sandbox.hypervisor, "", h.getSharePath(sandbox.id), false, nil) return h.configure(sandbox.hypervisor, "", h.getSharePath(sandbox.id), false, nil)
} }
func (h *hyper) capabilities() capabilities { func (h *hyper) capabilities() types.Capabilities {
var caps capabilities var caps types.Capabilities
// add all capabilities supported by agent // add all capabilities supported by agent
caps.setBlockDeviceSupport() caps.SetBlockDeviceSupport()
return caps return caps
} }

View File

@ -15,6 +15,7 @@ import (
"strings" "strings"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/types"
) )
// HypervisorType describes an hypervisor type. // HypervisorType describes an hypervisor type.
@ -221,7 +222,7 @@ type HypervisorConfig struct {
// Each value in that map takes precedence over the configured assets. // Each value in that map takes precedence over the configured assets.
// For example, if there is a value for the "kernel" key in this map, // For example, if there is a value for the "kernel" key in this map,
// it will be used for the sandbox's kernel path instead of KernelPath. // it will be used for the sandbox's kernel path instead of KernelPath.
customAssets map[assetType]*asset customAssets map[types.AssetType]*types.Asset
// BlockDeviceCacheSet specifies cache-related options will be set to block devices or not. // BlockDeviceCacheSet specifies cache-related options will be set to block devices or not.
BlockDeviceCacheSet bool BlockDeviceCacheSet bool
@ -357,53 +358,53 @@ func (conf *HypervisorConfig) AddKernelParam(p Param) error {
return nil return nil
} }
func (conf *HypervisorConfig) addCustomAsset(a *asset) error { func (conf *HypervisorConfig) addCustomAsset(a *types.Asset) error {
if a == nil || a.path == "" { if a == nil || a.Path() == "" {
// We did not get a custom asset, we will use the default one. // We did not get a custom asset, we will use the default one.
return nil return nil
} }
if !a.valid() { if !a.Valid() {
return fmt.Errorf("Invalid %s at %s", a.kind, a.path) return fmt.Errorf("Invalid %s at %s", a.Type(), a.Path())
} }
virtLog.Debugf("Using custom %v asset %s", a.kind, a.path) virtLog.Debugf("Using custom %v asset %s", a.Type(), a.Path())
if conf.customAssets == nil { if conf.customAssets == nil {
conf.customAssets = make(map[assetType]*asset) conf.customAssets = make(map[types.AssetType]*types.Asset)
} }
conf.customAssets[a.kind] = a conf.customAssets[a.Type()] = a
return nil return nil
} }
func (conf *HypervisorConfig) assetPath(t assetType) (string, error) { func (conf *HypervisorConfig) assetPath(t types.AssetType) (string, error) {
// Custom assets take precedence over the configured ones // Custom assets take precedence over the configured ones
a, ok := conf.customAssets[t] a, ok := conf.customAssets[t]
if ok { if ok {
return a.path, nil return a.Path(), nil
} }
// We could not find a custom asset for the given type, let's // We could not find a custom asset for the given type, let's
// fall back to the configured ones. // fall back to the configured ones.
switch t { switch t {
case kernelAsset: case types.KernelAsset:
return conf.KernelPath, nil return conf.KernelPath, nil
case imageAsset: case types.ImageAsset:
return conf.ImagePath, nil return conf.ImagePath, nil
case initrdAsset: case types.InitrdAsset:
return conf.InitrdPath, nil return conf.InitrdPath, nil
case hypervisorAsset: case types.HypervisorAsset:
return conf.HypervisorPath, nil return conf.HypervisorPath, nil
case firmwareAsset: case types.FirmwareAsset:
return conf.FirmwarePath, nil return conf.FirmwarePath, nil
default: default:
return "", fmt.Errorf("Unknown asset type %v", t) return "", fmt.Errorf("Unknown asset type %v", t)
} }
} }
func (conf *HypervisorConfig) isCustomAsset(t assetType) bool { func (conf *HypervisorConfig) isCustomAsset(t types.AssetType) bool {
_, ok := conf.customAssets[t] _, ok := conf.customAssets[t]
if ok { if ok {
return true return true
@ -414,52 +415,52 @@ func (conf *HypervisorConfig) isCustomAsset(t assetType) bool {
// KernelAssetPath returns the guest kernel path // KernelAssetPath returns the guest kernel path
func (conf *HypervisorConfig) KernelAssetPath() (string, error) { func (conf *HypervisorConfig) KernelAssetPath() (string, error) {
return conf.assetPath(kernelAsset) return conf.assetPath(types.KernelAsset)
} }
// CustomKernelAsset returns true if the kernel asset is a custom one, false otherwise. // CustomKernelAsset returns true if the kernel asset is a custom one, false otherwise.
func (conf *HypervisorConfig) CustomKernelAsset() bool { func (conf *HypervisorConfig) CustomKernelAsset() bool {
return conf.isCustomAsset(kernelAsset) return conf.isCustomAsset(types.KernelAsset)
} }
// ImageAssetPath returns the guest image path // ImageAssetPath returns the guest image path
func (conf *HypervisorConfig) ImageAssetPath() (string, error) { func (conf *HypervisorConfig) ImageAssetPath() (string, error) {
return conf.assetPath(imageAsset) return conf.assetPath(types.ImageAsset)
} }
// CustomImageAsset returns true if the image asset is a custom one, false otherwise. // CustomImageAsset returns true if the image asset is a custom one, false otherwise.
func (conf *HypervisorConfig) CustomImageAsset() bool { func (conf *HypervisorConfig) CustomImageAsset() bool {
return conf.isCustomAsset(imageAsset) return conf.isCustomAsset(types.ImageAsset)
} }
// InitrdAssetPath returns the guest initrd path // InitrdAssetPath returns the guest initrd path
func (conf *HypervisorConfig) InitrdAssetPath() (string, error) { func (conf *HypervisorConfig) InitrdAssetPath() (string, error) {
return conf.assetPath(initrdAsset) return conf.assetPath(types.InitrdAsset)
} }
// CustomInitrdAsset returns true if the initrd asset is a custom one, false otherwise. // CustomInitrdAsset returns true if the initrd asset is a custom one, false otherwise.
func (conf *HypervisorConfig) CustomInitrdAsset() bool { func (conf *HypervisorConfig) CustomInitrdAsset() bool {
return conf.isCustomAsset(initrdAsset) return conf.isCustomAsset(types.InitrdAsset)
} }
// HypervisorAssetPath returns the VM hypervisor path // HypervisorAssetPath returns the VM hypervisor path
func (conf *HypervisorConfig) HypervisorAssetPath() (string, error) { func (conf *HypervisorConfig) HypervisorAssetPath() (string, error) {
return conf.assetPath(hypervisorAsset) return conf.assetPath(types.HypervisorAsset)
} }
// CustomHypervisorAsset returns true if the hypervisor asset is a custom one, false otherwise. // CustomHypervisorAsset returns true if the hypervisor asset is a custom one, false otherwise.
func (conf *HypervisorConfig) CustomHypervisorAsset() bool { func (conf *HypervisorConfig) CustomHypervisorAsset() bool {
return conf.isCustomAsset(hypervisorAsset) return conf.isCustomAsset(types.HypervisorAsset)
} }
// FirmwareAssetPath returns the guest firmware path // FirmwareAssetPath returns the guest firmware path
func (conf *HypervisorConfig) FirmwareAssetPath() (string, error) { func (conf *HypervisorConfig) FirmwareAssetPath() (string, error) {
return conf.assetPath(firmwareAsset) return conf.assetPath(types.FirmwareAsset)
} }
// CustomFirmwareAsset returns true if the firmware asset is a custom one, false otherwise. // CustomFirmwareAsset returns true if the firmware asset is a custom one, false otherwise.
func (conf *HypervisorConfig) CustomFirmwareAsset() bool { func (conf *HypervisorConfig) CustomFirmwareAsset() bool {
return conf.isCustomAsset(firmwareAsset) return conf.isCustomAsset(types.FirmwareAsset)
} }
func appendParam(params []Param, parameter string, value string) []Param { func appendParam(params []Param, parameter string, value string) []Param {
@ -603,7 +604,7 @@ type hypervisor interface {
resizeVCPUs(vcpus uint32) (uint32, uint32, error) resizeVCPUs(vcpus uint32) (uint32, uint32, error)
getSandboxConsole(sandboxID string) (string, error) getSandboxConsole(sandboxID string) (string, error)
disconnect() disconnect()
capabilities() capabilities capabilities() types.Capabilities
hypervisorConfig() HypervisorConfig hypervisorConfig() HypervisorConfig
getThreadIDs() (*threadIDs, error) getThreadIDs() (*threadIDs, error)
cleanup() error cleanup() error

View File

@ -211,11 +211,11 @@ func (k *kataAgent) agentURL() (string, error) {
} }
} }
func (k *kataAgent) capabilities() capabilities { func (k *kataAgent) capabilities() types.Capabilities {
var caps capabilities var caps types.Capabilities
// add all capabilities supported by agent // add all capabilities supported by agent
caps.setBlockDeviceSupport() caps.SetBlockDeviceSupport()
return caps return caps
} }
@ -261,7 +261,7 @@ func (k *kataAgent) configure(h hypervisor, id, sharePath string, builtin bool,
// Neither create shared directory nor add 9p device if hypervisor // Neither create shared directory nor add 9p device if hypervisor
// doesn't support filesystem sharing. // doesn't support filesystem sharing.
caps := h.capabilities() caps := h.capabilities()
if !caps.isFsSharingSupported() { if !caps.IsFsSharingSupported() {
return nil return nil
} }
@ -629,7 +629,7 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
caps := sandbox.hypervisor.capabilities() caps := sandbox.hypervisor.capabilities()
// append 9p shared volume to storages only if filesystem sharing is supported // append 9p shared volume to storages only if filesystem sharing is supported
if caps.isFsSharingSupported() { if caps.IsFsSharingSupported() {
sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p)) sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
// We mount the shared directory in a predefined location // We mount the shared directory in a predefined location

View File

@ -8,13 +8,15 @@ package virtcontainers
import ( import (
"context" "context"
"os" "os"
"github.com/kata-containers/runtime/virtcontainers/types"
) )
type mockHypervisor struct { type mockHypervisor struct {
} }
func (m *mockHypervisor) capabilities() capabilities { func (m *mockHypervisor) capabilities() types.Capabilities {
return capabilities{} return types.Capabilities{}
} }
func (m *mockHypervisor) hypervisorConfig() HypervisorConfig { func (m *mockHypervisor) hypervisorConfig() HypervisorConfig {

View File

@ -511,7 +511,7 @@ func xConnectVMNetwork(endpoint Endpoint, h hypervisor) error {
queues := 0 queues := 0
caps := h.capabilities() caps := h.capabilities()
if caps.isMultiQueueSupported() { if caps.IsMultiQueueSupported() {
queues = int(h.hypervisorConfig().NumVCPUs) queues = int(h.hypervisorConfig().NumVCPUs)
} }

View File

@ -37,8 +37,8 @@ func (n *noopAgent) createSandbox(sandbox *Sandbox) error {
} }
// capabilities returns empty capabilities, i.e no capabilties are supported. // capabilities returns empty capabilities, i.e no capabilties are supported.
func (n *noopAgent) capabilities() capabilities { func (n *noopAgent) capabilities() types.Capabilities {
return capabilities{} return types.Capabilities{}
} }
// disconnect is the Noop agent connection closer. It does nothing. // disconnect is the Noop agent connection closer. It does nothing.

View File

@ -47,7 +47,7 @@ type CPUDevice struct {
// QemuState keeps Qemu's state // QemuState keeps Qemu's state
type QemuState struct { type QemuState struct {
Bridges []Bridge Bridges []types.PCIBridge
// HotpluggedCPUs is the list of CPUs that were hot-added // HotpluggedCPUs is the list of CPUs that were hot-added
HotpluggedVCPUs []CPUDevice HotpluggedVCPUs []CPUDevice
HotpluggedMemory int HotpluggedMemory int
@ -162,7 +162,7 @@ func (q *qemu) kernelParameters() string {
} }
// Adds all capabilities supported by qemu implementation of hypervisor interface // Adds all capabilities supported by qemu implementation of hypervisor interface
func (q *qemu) capabilities() capabilities { func (q *qemu) capabilities() types.Capabilities {
span, _ := q.trace("capabilities") span, _ := q.trace("capabilities")
defer span.Finish() defer span.Finish()
@ -722,25 +722,25 @@ func (q *qemu) qmpShutdown() {
} }
} }
func (q *qemu) addDeviceToBridge(ID string) (string, Bridge, error) { func (q *qemu) addDeviceToBridge(ID string) (string, types.PCIBridge, error) {
var err error var err error
var addr uint32 var addr uint32
// looking for an empty address in the bridges // looking for an empty address in the bridges
for _, b := range q.state.Bridges { for _, b := range q.state.Bridges {
addr, err = b.addDevice(ID) addr, err = b.AddDevice(ID)
if err == nil { if err == nil {
return fmt.Sprintf("%02x", addr), b, nil return fmt.Sprintf("%02x", addr), b, nil
} }
} }
return "", Bridge{}, err return "", types.PCIBridge{}, err
} }
func (q *qemu) removeDeviceFromBridge(ID string) error { func (q *qemu) removeDeviceFromBridge(ID string) error {
var err error var err error
for _, b := range q.state.Bridges { for _, b := range q.state.Bridges {
err = b.removeDevice(ID) err = b.RemoveDevice(ID)
if err == nil { if err == nil {
// device was removed correctly // device was removed correctly
return nil return nil
@ -1377,7 +1377,7 @@ func (q *qemu) resizeMemory(reqMemMB uint32, memoryBlockSizeMB uint32) (uint32,
} }
// genericAppendBridges appends to devices the given bridges // genericAppendBridges appends to devices the given bridges
func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineType string) []govmmQemu.Device { func genericAppendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge, machineType string) []govmmQemu.Device {
bus := defaultPCBridgeBus bus := defaultPCBridgeBus
switch machineType { switch machineType {
case QemuQ35, QemuVirt: case QemuQ35, QemuVirt:
@ -1386,7 +1386,7 @@ func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineT
for idx, b := range bridges { for idx, b := range bridges {
t := govmmQemu.PCIBridge t := govmmQemu.PCIBridge
if b.Type == pcieBridge { if b.Type == types.PCIE {
t = govmmQemu.PCIEBridge t = govmmQemu.PCIEBridge
} }
@ -1408,9 +1408,9 @@ func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineT
return devices return devices
} }
func genericBridges(number uint32, machineType string) []Bridge { func genericBridges(number uint32, machineType string) []types.PCIBridge {
var bridges []Bridge var bridges []types.PCIBridge
var bt bridgeType var bt types.PCIType
switch machineType { switch machineType {
case QemuQ35: case QemuQ35:
@ -1418,19 +1418,19 @@ func genericBridges(number uint32, machineType string) []Bridge {
// qemu-2.10 will introduce pcie bridges // qemu-2.10 will introduce pcie bridges
fallthrough fallthrough
case QemuPC: case QemuPC:
bt = pciBridge bt = types.PCI
case QemuVirt: case QemuVirt:
bt = pcieBridge bt = types.PCIE
case QemuPseries: case QemuPseries:
bt = pciBridge bt = types.PCI
case QemuCCWVirtio: case QemuCCWVirtio:
bt = pciBridge bt = types.PCI
default: default:
return nil return nil
} }
for i := uint32(0); i < number; i++ { for i := uint32(0); i < number; i++ {
bridges = append(bridges, Bridge{ bridges = append(bridges, types.PCIBridge{
Type: bt, Type: bt,
ID: fmt.Sprintf("%s-bridge-%d", bt, i), ID: fmt.Sprintf("%s-bridge-%d", bt, i),
Address: make(map[uint32]string), Address: make(map[uint32]string),

View File

@ -8,6 +8,8 @@ package virtcontainers
import ( import (
"os" "os"
"github.com/kata-containers/runtime/virtcontainers/types"
govmmQemu "github.com/intel/govmm/qemu" govmmQemu "github.com/intel/govmm/qemu"
) )
@ -101,21 +103,21 @@ func newQemuArch(config HypervisorConfig) qemuArch {
return q return q
} }
func (q *qemuAmd64) capabilities() capabilities { func (q *qemuAmd64) capabilities() types.Capabilities {
var caps capabilities var caps types.Capabilities
if q.machineType == QemuPC || if q.machineType == QemuPC ||
q.machineType == QemuQ35 || q.machineType == QemuQ35 ||
q.machineType == QemuVirt { q.machineType == QemuVirt {
caps.setBlockDeviceHotplugSupport() caps.SetBlockDeviceHotplugSupport()
} }
caps.setMultiQueueSupport() caps.SetMultiQueueSupport()
return caps return caps
} }
func (q *qemuAmd64) bridges(number uint32) []Bridge { func (q *qemuAmd64) bridges(number uint32) []types.PCIBridge {
return genericBridges(number, q.machineType) return genericBridges(number, q.machineType)
} }
@ -158,6 +160,6 @@ func (q *qemuAmd64) appendImage(devices []govmmQemu.Device, path string) ([]govm
} }
// appendBridges appends to devices the given bridges // appendBridges appends to devices the given bridges
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device { func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType) return genericAppendBridges(devices, bridges, q.machineType)
} }

View File

@ -12,6 +12,7 @@ import (
"testing" "testing"
govmmQemu "github.com/intel/govmm/qemu" govmmQemu "github.com/intel/govmm/qemu"
"github.com/kata-containers/runtime/virtcontainers/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -27,11 +28,11 @@ func TestQemuAmd64Capabilities(t *testing.T) {
amd64 := newTestQemu(QemuPC) amd64 := newTestQemu(QemuPC)
caps := amd64.capabilities() caps := amd64.capabilities()
assert.True(caps.isBlockDeviceHotplugSupported()) assert.True(caps.IsBlockDeviceHotplugSupported())
amd64 = newTestQemu(QemuQ35) amd64 = newTestQemu(QemuQ35)
caps = amd64.capabilities() caps = amd64.capabilities()
assert.True(caps.isBlockDeviceHotplugSupported()) assert.True(caps.IsBlockDeviceHotplugSupported())
} }
func TestQemuAmd64Bridges(t *testing.T) { func TestQemuAmd64Bridges(t *testing.T) {
@ -43,8 +44,8 @@ func TestQemuAmd64Bridges(t *testing.T) {
assert.Len(bridges, len) assert.Len(bridges, len)
for i, b := range bridges { for i, b := range bridges {
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i) id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(pciBridge, b.Type) assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID) assert.Equal(id, b.ID)
assert.NotNil(b.Address) assert.NotNil(b.Address)
} }
@ -54,8 +55,8 @@ func TestQemuAmd64Bridges(t *testing.T) {
assert.Len(bridges, len) assert.Len(bridges, len)
for i, b := range bridges { for i, b := range bridges {
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i) id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(pciBridge, b.Type) assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID) assert.Equal(id, b.ID)
assert.NotNil(b.Address) assert.NotNil(b.Address)
} }

View File

@ -45,10 +45,10 @@ type qemuArch interface {
kernelParameters(debug bool) []Param kernelParameters(debug bool) []Param
//capabilities returns the capabilities supported by QEMU //capabilities returns the capabilities supported by QEMU
capabilities() capabilities capabilities() types.Capabilities
// bridges returns the number bridges for the machine type // bridges returns the number bridges for the machine type
bridges(number uint32) []Bridge bridges(number uint32) []types.PCIBridge
// cpuTopology returns the CPU topology for the given amount of vcpus // cpuTopology returns the CPU topology for the given amount of vcpus
cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP
@ -69,7 +69,7 @@ type qemuArch interface {
appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread) appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread)
// appendBridges appends bridges to devices // appendBridges appends bridges to devices
appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device
// append9PVolume appends a 9P volume to devices // append9PVolume appends a 9P volume to devices
append9PVolume(devices []govmmQemu.Device, volume types.Volume) []govmmQemu.Device append9PVolume(devices []govmmQemu.Device, volume types.Volume) []govmmQemu.Device
@ -228,20 +228,20 @@ func (q *qemuArchBase) kernelParameters(debug bool) []Param {
return params return params
} }
func (q *qemuArchBase) capabilities() capabilities { func (q *qemuArchBase) capabilities() types.Capabilities {
var caps capabilities var caps types.Capabilities
caps.setBlockDeviceHotplugSupport() caps.SetBlockDeviceHotplugSupport()
caps.setMultiQueueSupport() caps.SetMultiQueueSupport()
return caps return caps
} }
func (q *qemuArchBase) bridges(number uint32) []Bridge { func (q *qemuArchBase) bridges(number uint32) []types.PCIBridge {
var bridges []Bridge var bridges []types.PCIBridge
for i := uint32(0); i < number; i++ { for i := uint32(0); i < number; i++ {
bridges = append(bridges, Bridge{ bridges = append(bridges, types.PCIBridge{
Type: pciBridge, Type: types.PCI,
ID: fmt.Sprintf("%s-bridge-%d", pciBridge, i), ID: fmt.Sprintf("%s-bridge-%d", types.PCI, i),
Address: make(map[uint32]string), Address: make(map[uint32]string),
}) })
} }
@ -346,10 +346,10 @@ func (q *qemuArchBase) appendSCSIController(devices []govmmQemu.Device, enableIO
} }
// appendBridges appends to devices the given bridges // appendBridges appends to devices the given bridges
func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device { func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
for idx, b := range bridges { for idx, b := range bridges {
t := govmmQemu.PCIBridge t := govmmQemu.PCIBridge
if b.Type == pcieBridge { if b.Type == types.PCIE {
t = govmmQemu.PCIEBridge t = govmmQemu.PCIEBridge
} }

View File

@ -138,7 +138,7 @@ func TestQemuArchBaseCapabilities(t *testing.T) {
qemuArchBase := newQemuArchBase() qemuArchBase := newQemuArchBase()
c := qemuArchBase.capabilities() c := qemuArchBase.capabilities()
assert.True(c.isBlockDeviceHotplugSupported()) assert.True(c.IsBlockDeviceHotplugSupported())
} }
func TestQemuArchBaseBridges(t *testing.T) { func TestQemuArchBaseBridges(t *testing.T) {
@ -150,8 +150,8 @@ func TestQemuArchBaseBridges(t *testing.T) {
assert.Len(bridges, len) assert.Len(bridges, len)
for i, b := range bridges { for i, b := range bridges {
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i) id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(pciBridge, b.Type) assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID) assert.Equal(id, b.ID)
assert.NotNil(b.Address) assert.NotNil(b.Address)
} }

View File

@ -11,6 +11,7 @@ import (
govmmQemu "github.com/intel/govmm/qemu" govmmQemu "github.com/intel/govmm/qemu"
deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config" deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/types"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -90,20 +91,20 @@ func newQemuArch(config HypervisorConfig) qemuArch {
return q return q
} }
func (q *qemuPPC64le) capabilities() capabilities { func (q *qemuPPC64le) capabilities() types.Capabilities {
var caps capabilities var caps types.Capabilities
// pseries machine type supports hotplugging drives // pseries machine type supports hotplugging drives
if q.machineType == QemuPseries { if q.machineType == QemuPseries {
caps.setBlockDeviceHotplugSupport() caps.SetBlockDeviceHotplugSupport()
} }
caps.setMultiQueueSupport() caps.SetMultiQueueSupport()
return caps return caps
} }
func (q *qemuPPC64le) bridges(number uint32) []Bridge { func (q *qemuPPC64le) bridges(number uint32) []types.PCIBridge {
return genericBridges(number, q.machineType) return genericBridges(number, q.machineType)
} }
@ -150,6 +151,6 @@ func (q *qemuPPC64le) appendImage(devices []govmmQemu.Device, path string) ([]go
} }
// appendBridges appends to devices the given bridges // appendBridges appends to devices the given bridges
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device { func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType) return genericAppendBridges(devices, bridges, q.machineType)
} }

View File

@ -306,7 +306,7 @@ func TestQemuCapabilities(t *testing.T) {
} }
caps := q.capabilities() caps := q.capabilities()
if !caps.isBlockDeviceHotplugSupported() { if !caps.IsBlockDeviceHotplugSupported() {
t.Fatal("Block device hotplug should be supported") t.Fatal("Block device hotplug should be supported")
} }
} }

View File

@ -435,26 +435,26 @@ func createAssets(ctx context.Context, sandboxConfig *SandboxConfig) error {
span, _ := trace(ctx, "createAssets") span, _ := trace(ctx, "createAssets")
defer span.Finish() defer span.Finish()
kernel, err := newAsset(sandboxConfig, kernelAsset) kernel, err := types.NewAsset(sandboxConfig.Annotations, types.KernelAsset)
if err != nil { if err != nil {
return err return err
} }
image, err := newAsset(sandboxConfig, imageAsset) image, err := types.NewAsset(sandboxConfig.Annotations, types.ImageAsset)
if err != nil { if err != nil {
return err return err
} }
initrd, err := newAsset(sandboxConfig, initrdAsset) initrd, err := types.NewAsset(sandboxConfig.Annotations, types.InitrdAsset)
if err != nil { if err != nil {
return err return err
} }
if image != nil && initrd != nil { if image != nil && initrd != nil {
return fmt.Errorf("%s and %s cannot be both set", imageAsset, initrdAsset) return fmt.Errorf("%s and %s cannot be both set", types.ImageAsset, types.InitrdAsset)
} }
for _, a := range []*asset{kernel, image, initrd} { for _, a := range []*types.Asset{kernel, image, initrd} {
if err := sandboxConfig.HypervisorConfig.addCustomAsset(a); err != nil { if err := sandboxConfig.HypervisorConfig.addCustomAsset(a); err != nil {
return err return err
} }

View File

@ -1201,6 +1201,10 @@ func TestSandboxAttachDevicesVFIO(t *testing.T) {
assert.Nil(t, err, "Error while detaching devices %s", err) assert.Nil(t, err, "Error while detaching devices %s", err)
} }
var assetContent = []byte("FakeAsset fake asset FAKE ASSET")
var assetContentHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c880"
var assetContentWrongHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c881"
func TestSandboxCreateAssets(t *testing.T) { func TestSandboxCreateAssets(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
@ -1234,9 +1238,9 @@ func TestSandboxCreateAssets(t *testing.T) {
err = createAssets(context.Background(), p) err = createAssets(context.Background(), p)
assert.Nil(err) assert.Nil(err)
a, ok := p.HypervisorConfig.customAssets[kernelAsset] a, ok := p.HypervisorConfig.customAssets[types.KernelAsset]
assert.True(ok) assert.True(ok)
assert.Equal(a.path, tmpfile.Name()) assert.Equal(a.Path(), tmpfile.Name())
p = &SandboxConfig{ p = &SandboxConfig{
Annotations: map[string]string{ Annotations: map[string]string{

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
package virtcontainers package types
import ( import (
"crypto/sha512" "crypto/sha512"
@ -15,19 +15,21 @@ import (
"github.com/kata-containers/runtime/virtcontainers/pkg/annotations" "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
) )
type assetType string // AssetType describe a type of assets.
type AssetType string
func (t assetType) annotations() (string, string, error) { // Annotations returns the path and hash annotations for a given Asset type.
func (t AssetType) Annotations() (string, string, error) {
switch t { switch t {
case kernelAsset: case KernelAsset:
return annotations.KernelPath, annotations.KernelHash, nil return annotations.KernelPath, annotations.KernelHash, nil
case imageAsset: case ImageAsset:
return annotations.ImagePath, annotations.ImageHash, nil return annotations.ImagePath, annotations.ImageHash, nil
case initrdAsset: case InitrdAsset:
return annotations.InitrdPath, annotations.InitrdHash, nil return annotations.InitrdPath, annotations.InitrdHash, nil
case hypervisorAsset: case HypervisorAsset:
return annotations.HypervisorPath, annotations.HypervisorHash, nil return annotations.HypervisorPath, annotations.HypervisorHash, nil
case firmwareAsset: case FirmwareAsset:
return annotations.FirmwarePath, annotations.FirmwareHash, nil return annotations.FirmwarePath, annotations.FirmwareHash, nil
} }
@ -35,42 +37,63 @@ func (t assetType) annotations() (string, string, error) {
} }
const ( const (
kernelAsset assetType = "kernel" // KernelAsset is a kernel asset.
imageAsset assetType = "image" KernelAsset AssetType = "kernel"
initrdAsset assetType = "initrd"
hypervisorAsset assetType = "hypervisor" // ImageAsset is an image asset.
firmwareAsset assetType = "firmware" ImageAsset AssetType = "image"
// InitrdAsset is an intird asset.
InitrdAsset AssetType = "initrd"
// HypervisorAsset is an hypervisor asset.
HypervisorAsset AssetType = "hypervisor"
// FirmwareAsset is a firmware asset.
FirmwareAsset AssetType = "firmware"
) )
type asset struct { // Asset represents a virtcontainers asset.
type Asset struct {
path string path string
computedHash string computedHash string
kind assetType kind AssetType
} }
func (a *asset) valid() bool { // Path returns an asset path.
func (a Asset) Path() string {
return a.path
}
// Type returns an asset type.
func (a Asset) Type() AssetType {
return a.kind
}
// Valid checks if an asset is valid or not.
func (a *Asset) Valid() bool {
if !filepath.IsAbs(a.path) { if !filepath.IsAbs(a.path) {
return false return false
} }
switch a.kind { switch a.kind {
case kernelAsset: case KernelAsset:
return true return true
case imageAsset: case ImageAsset:
return true return true
case initrdAsset: case InitrdAsset:
return true return true
case hypervisorAsset: case HypervisorAsset:
return true return true
case firmwareAsset: case FirmwareAsset:
return true return true
} }
return false return false
} }
// hash returns the hex encoded string for the asset hash // Hash returns the hex encoded string for the asset hash
func (a *asset) hash(hashType string) (string, error) { func (a *Asset) Hash(hashType string) (string, error) {
var hashEncodedLen int var hashEncodedLen int
var hash string var hash string
@ -88,13 +111,11 @@ func (a *asset) hash(hashType string) (string, error) {
// We only support SHA512 for now. // We only support SHA512 for now.
switch hashType { switch hashType {
case annotations.SHA512: case annotations.SHA512:
virtLog.Debugf("Computing %v hash", a.path)
hashComputed := sha512.Sum512(bytes) hashComputed := sha512.Sum512(bytes)
hashEncodedLen = hex.EncodedLen(len(hashComputed)) hashEncodedLen = hex.EncodedLen(len(hashComputed))
hashEncoded := make([]byte, hashEncodedLen) hashEncoded := make([]byte, hashEncodedLen)
hex.Encode(hashEncoded, hashComputed[:]) hex.Encode(hashEncoded, hashComputed[:])
hash = string(hashEncoded[:]) hash = string(hashEncoded[:])
virtLog.Debugf("%v hash: %s", a.path, hash)
default: default:
return "", fmt.Errorf("Invalid hash type %s", hashType) return "", fmt.Errorf("Invalid hash type %s", hashType)
} }
@ -104,9 +125,9 @@ func (a *asset) hash(hashType string) (string, error) {
return hash, nil return hash, nil
} }
// newAsset returns a new asset from the sandbox annotations. // NewAsset returns a new asset from a slice of annotations.
func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) { func NewAsset(anno map[string]string, t AssetType) (*Asset, error) {
pathAnnotation, hashAnnotation, err := t.annotations() pathAnnotation, hashAnnotation, err := t.Annotations()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -115,7 +136,7 @@ func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) {
return nil, fmt.Errorf("Missing annotation paths for %s", t) return nil, fmt.Errorf("Missing annotation paths for %s", t)
} }
path, ok := sandboxConfig.Annotations[pathAnnotation] path, ok := anno[pathAnnotation]
if !ok || path == "" { if !ok || path == "" {
return nil, nil return nil, nil
} }
@ -124,21 +145,20 @@ func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) {
return nil, fmt.Errorf("%s is not an absolute path", path) return nil, fmt.Errorf("%s is not an absolute path", path)
} }
a := &asset{path: path, kind: t} a := &Asset{path: path, kind: t}
hash, ok := sandboxConfig.Annotations[hashAnnotation] hash, ok := anno[hashAnnotation]
if !ok || hash == "" { if !ok || hash == "" {
return a, nil return a, nil
} }
// We have a hash annotation, we need to verify the asset against it. // We have a hash annotation, we need to verify the asset against it.
hashType, ok := sandboxConfig.Annotations[annotations.AssetHashType] hashType, ok := anno[annotations.AssetHashType]
if !ok { if !ok {
virtLog.Warningf("Unrecognized hash type: %s, switching to %s", hashType, annotations.SHA512)
hashType = annotations.SHA512 hashType = annotations.SHA512
} }
hashComputed, err := a.hash(hashType) hashComputed, err := a.Hash(hashType)
if err != nil { if err != nil {
return a, err return a, err
} }

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
package virtcontainers package types
import ( import (
"io/ioutil" "io/ioutil"
@ -32,11 +32,11 @@ func TestAssetWrongHashType(t *testing.T) {
_, err = tmpfile.Write(assetContent) _, err = tmpfile.Write(assetContent)
assert.Nil(err) assert.Nil(err)
a := &asset{ a := &Asset{
path: tmpfile.Name(), path: tmpfile.Name(),
} }
h, err := a.hash("shafoo") h, err := a.Hash("shafoo")
assert.Equal(h, "") assert.Equal(h, "")
assert.NotNil(err) assert.NotNil(err)
} }
@ -55,11 +55,11 @@ func TestAssetHash(t *testing.T) {
_, err = tmpfile.Write(assetContent) _, err = tmpfile.Write(assetContent)
assert.Nil(err) assert.Nil(err)
a := &asset{ a := &Asset{
path: tmpfile.Name(), path: tmpfile.Name(),
} }
hash, err := a.hash(annotations.SHA512) hash, err := a.Hash(annotations.SHA512)
assert.Nil(err) assert.Nil(err)
assert.Equal(assetContentHash, hash) assert.Equal(assetContentHash, hash)
assert.Equal(assetContentHash, a.computedHash) assert.Equal(assetContentHash, a.computedHash)
@ -79,28 +79,23 @@ func TestAssetNew(t *testing.T) {
_, err = tmpfile.Write(assetContent) _, err = tmpfile.Write(assetContent)
assert.Nil(err) assert.Nil(err)
p := &SandboxConfig{ anno := map[string]string{
Annotations: map[string]string{
annotations.KernelPath: tmpfile.Name(), annotations.KernelPath: tmpfile.Name(),
annotations.KernelHash: assetContentHash, annotations.KernelHash: assetContentHash,
},
} }
a, err := NewAsset(anno, ImageAsset)
a, err := newAsset(p, imageAsset)
assert.Nil(err) assert.Nil(err)
assert.Nil(a) assert.Nil(a)
a, err = newAsset(p, kernelAsset) a, err = NewAsset(anno, KernelAsset)
assert.Nil(err) assert.Nil(err)
assert.Equal(assetContentHash, a.computedHash) assert.Equal(assetContentHash, a.computedHash)
p = &SandboxConfig{ anno = map[string]string{
Annotations: map[string]string{
annotations.KernelPath: tmpfile.Name(), annotations.KernelPath: tmpfile.Name(),
annotations.KernelHash: assetContentWrongHash, annotations.KernelHash: assetContentWrongHash,
},
} }
_, err = newAsset(p, kernelAsset) _, err = NewAsset(anno, KernelAsset)
assert.NotNil(err) assert.NotNil(err)
} }

View File

@ -0,0 +1,68 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package types
const (
blockDeviceSupport = 1 << iota
blockDeviceHotplugSupport
multiQueueSupport
fsSharingUnsupported
)
// Capabilities describe a virtcontainers hypervisor capabilities
// through a bit mask.
type Capabilities struct {
flags uint
}
// IsBlockDeviceSupported tells if an hypervisor supports block devices.
func (caps *Capabilities) IsBlockDeviceSupported() bool {
if caps.flags&blockDeviceSupport != 0 {
return true
}
return false
}
// SetBlockDeviceSupport sets the block device support capability to true.
func (caps *Capabilities) SetBlockDeviceSupport() {
caps.flags = caps.flags | blockDeviceSupport
}
// IsBlockDeviceHotplugSupported tells if an hypervisor supports hotplugging block devices.
func (caps *Capabilities) IsBlockDeviceHotplugSupported() bool {
if caps.flags&blockDeviceHotplugSupport != 0 {
return true
}
return false
}
// SetBlockDeviceHotplugSupport sets the block device hotplugging capability to true.
func (caps *Capabilities) SetBlockDeviceHotplugSupport() {
caps.flags |= blockDeviceHotplugSupport
}
// IsMultiQueueSupported tells if an hypervisor supports device multi queue support.
func (caps *Capabilities) IsMultiQueueSupported() bool {
if caps.flags&multiQueueSupport != 0 {
return true
}
return false
}
// SetMultiQueueSupport sets the device multi queue capability to true.
func (caps *Capabilities) SetMultiQueueSupport() {
caps.flags |= multiQueueSupport
}
// IsFsSharingSupported tells if an hypervisor supports host filesystem sharing.
func (caps *Capabilities) IsFsSharingSupported() bool {
return caps.flags&fsSharingUnsupported == 0
}
// SetFsSharingUnsupported sets the host filesystem sharing capability to true.
func (caps *Capabilities) SetFsSharingUnsupported() {
caps.flags |= fsSharingUnsupported
}

View File

@ -0,0 +1,50 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package types
import "testing"
func TestBlockDeviceCapability(t *testing.T) {
var caps Capabilities
if caps.IsBlockDeviceSupported() {
t.Fatal()
}
caps.SetBlockDeviceSupport()
if !caps.IsBlockDeviceSupported() {
t.Fatal()
}
}
func TestBlockDeviceHotplugCapability(t *testing.T) {
var caps Capabilities
if caps.IsBlockDeviceHotplugSupported() {
t.Fatal()
}
caps.SetBlockDeviceHotplugSupport()
if !caps.IsBlockDeviceHotplugSupported() {
t.Fatal()
}
}
func TestFsSharingCapability(t *testing.T) {
var caps Capabilities
if !caps.IsFsSharingSupported() {
t.Fatal()
}
caps.SetFsSharingUnsupported()
if caps.IsFsSharingSupported() {
t.Fatal()
}
}

View File

@ -3,26 +3,30 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
package virtcontainers package types
import "fmt" import "fmt"
type bridgeType string // PCIType represents a type of PCI bus and bridge.
type PCIType string
const ( const (
pciBridge bridgeType = "pci" // PCI represents a PCI bus and bridge
pcieBridge bridgeType = "pcie" PCI PCIType = "pci"
// PCIE represents a PCIe bus and bridge
PCIE PCIType = "pcie"
) )
const pciBridgeMaxCapacity = 30 const pciBridgeMaxCapacity = 30
// Bridge is a bridge where devices can be hot plugged // PCIBridge is a PCI or PCIe bridge where devices can be hot plugged
type Bridge struct { type PCIBridge struct {
// Address contains information about devices plugged and its address in the bridge // Address contains information about devices plugged and its address in the bridge
Address map[uint32]string Address map[uint32]string
// Type is the type of the bridge (pci, pcie, etc) // Type is the PCI type of the bridge (pci, pcie, etc)
Type bridgeType Type PCIType
// ID is used to identify the bridge in the hypervisor // ID is used to identify the bridge in the hypervisor
ID string ID string
@ -31,9 +35,9 @@ type Bridge struct {
Addr int Addr int
} }
// addDevice on success adds the device ID to the bridge and return the address // AddDevice on success adds the device ID to the PCI bridge and returns
// where the device was added, otherwise an error is returned // the address where the device was added.
func (b *Bridge) addDevice(ID string) (uint32, error) { func (b *PCIBridge) AddDevice(ID string) (uint32, error) {
var addr uint32 var addr uint32
// looking for the first available address // looking for the first available address
@ -53,9 +57,8 @@ func (b *Bridge) addDevice(ID string) (uint32, error) {
return addr, nil return addr, nil
} }
// removeDevice on success removes the device ID from the bridge and return nil, // RemoveDevice removes the device ID from the PCI bridge.
// otherwise an error is returned func (b *PCIBridge) RemoveDevice(ID string) error {
func (b *Bridge) removeDevice(ID string) error {
// check if the device was hot plugged in the bridge // check if the device was hot plugged in the bridge
for addr, devID := range b.Address { for addr, devID := range b.Address {
if devID == ID { if devID == ID {

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
package virtcontainers package types
import ( import (
"fmt" "fmt"
@ -16,22 +16,22 @@ func TestAddRemoveDevice(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
// create a bridge // create a bridge
bridges := []*Bridge{{make(map[uint32]string), pciBridge, "rgb123", 5}} bridges := []*PCIBridge{{make(map[uint32]string), PCI, "rgb123", 5}}
// add device // add device
devID := "abc123" devID := "abc123"
b := bridges[0] b := bridges[0]
addr, err := b.addDevice(devID) addr, err := b.AddDevice(devID)
assert.NoError(err) assert.NoError(err)
if addr < 1 { if addr < 1 {
assert.Fail("address cannot be less than 1") assert.Fail("address cannot be less than 1")
} }
// remove device // remove device
err = b.removeDevice("") err = b.RemoveDevice("")
assert.Error(err) assert.Error(err)
err = b.removeDevice(devID) err = b.RemoveDevice(devID)
assert.NoError(err) assert.NoError(err)
// add device when the bridge is full // add device when the bridge is full
@ -39,7 +39,7 @@ func TestAddRemoveDevice(t *testing.T) {
for i := uint32(1); i <= pciBridgeMaxCapacity; i++ { for i := uint32(1); i <= pciBridgeMaxCapacity; i++ {
bridges[0].Address[i] = fmt.Sprintf("%d", i) bridges[0].Address[i] = fmt.Sprintf("%d", i)
} }
addr, err = b.addDevice(devID) addr, err = b.AddDevice(devID)
assert.Error(err) assert.Error(err)
if addr != 0 { if addr != 0 {
assert.Fail("address should be 0") assert.Fail("address should be 0")