Skip to content

Commit

Permalink
bridges: abstraction of bridge type
Browse files Browse the repository at this point in the history
The abstraction of the bridge type to add additional types.

Fixes: kata-containers#1153

Signed-off-by: Alice Frosi <afrosi@de.ibm.com>
Co-authored-by: Jan Schintag <jan.schintag@de.ibm.com>
  • Loading branch information
Alice Frosi and jschintag committed Sep 5, 2019
1 parent 87eca1f commit 57a5f63
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 121 deletions.
32 changes: 12 additions & 20 deletions virtcontainers/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type CPUDevice struct {

// QemuState keeps Qemu's state
type QemuState struct {
Bridges []types.PCIBridge
Bridges []types.Bridge
// HotpluggedCPUs is the list of CPUs that were hot-added
HotpluggedVCPUs []CPUDevice
HotpluggedMemory int
Expand Down Expand Up @@ -984,12 +984,12 @@ func (q *qemu) qmpShutdown() {
}
}

func (q *qemu) addDeviceToBridge(ID string) (string, types.PCIBridge, error) {
func (q *qemu) addDeviceToBridge(ID string) (string, types.Bridge, error) {
var err error
var addr uint32

if len(q.state.Bridges) == 0 {
return "", types.PCIBridge{}, errors.New("failed to get available address from bridges")
return "", types.Bridge{}, errors.New("failed to get available address from bridges")
}

// looking for an empty address in the bridges
Expand All @@ -1000,7 +1000,7 @@ func (q *qemu) addDeviceToBridge(ID string) (string, types.PCIBridge, error) {
}
}

return "", types.PCIBridge{}, fmt.Errorf("no more bridge slots available")
return "", types.Bridge{}, fmt.Errorf("no more bridge slots available")
}

func (q *qemu) removeDeviceFromBridge(ID string) error {
Expand Down Expand Up @@ -1750,7 +1750,7 @@ func (q *qemu) resizeMemory(reqMemMB uint32, memoryBlockSizeMB uint32, probe boo

// genericAppendBridges appends to devices the given bridges
// nolint: unused, deadcode
func genericAppendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge, machineType string) []govmmQemu.Device {
func genericAppendBridges(devices []govmmQemu.Device, bridges []types.Bridge, machineType string) []govmmQemu.Device {
bus := defaultPCBridgeBus
switch machineType {
case QemuQ35, QemuVirt:
Expand Down Expand Up @@ -1782,9 +1782,9 @@ func genericAppendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge,
}

// nolint: unused, deadcode
func genericBridges(number uint32, machineType string) []types.PCIBridge {
var bridges []types.PCIBridge
var bt types.PCIType
func genericBridges(number uint32, machineType string) []types.Bridge {
var bridges []types.Bridge
var bt types.Type

switch machineType {
case QemuQ35:
Expand All @@ -1804,11 +1804,7 @@ func genericBridges(number uint32, machineType string) []types.PCIBridge {
}

for i := uint32(0); i < number; i++ {
bridges = append(bridges, types.PCIBridge{
Type: bt,
ID: fmt.Sprintf("%s-bridge-%d", bt, i),
Address: make(map[uint32]string),
})
bridges = append(bridges, types.NewBridge(bt, fmt.Sprintf("%s-bridge-%d", bt, i), make(map[uint32]string), 0))
}

return bridges
Expand Down Expand Up @@ -2010,7 +2006,7 @@ func (q *qemu) save() (s persistapi.HypervisorState) {

for _, bridge := range q.state.Bridges {
s.Bridges = append(s.Bridges, persistapi.Bridge{
DeviceAddr: bridge.Address,
DeviceAddr: bridge.Devices,
Type: string(bridge.Type),
ID: bridge.ID,
Addr: bridge.Addr,
Expand All @@ -2032,12 +2028,8 @@ func (q *qemu) load(s persistapi.HypervisorState) {
q.state.VirtiofsdPid = s.VirtiofsdPid

for _, bridge := range s.Bridges {
q.state.Bridges = append(q.state.Bridges, types.PCIBridge{
Address: bridge.DeviceAddr,
Type: types.PCIType(bridge.Type),
ID: bridge.ID,
Addr: bridge.Addr,
})
b := types.NewBridge(types.Type(bridge.Type), bridge.ID, bridge.DeviceAddr, bridge.Addr)
q.state.Bridges = append(q.state.Bridges, b)
}

for _, cpu := range s.HotpluggedVCPUs {
Expand Down
4 changes: 2 additions & 2 deletions virtcontainers/qemu_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (q *qemuAmd64) capabilities() types.Capabilities {
return caps
}

func (q *qemuAmd64) bridges(number uint32) []types.PCIBridge {
func (q *qemuAmd64) bridges(number uint32) []types.Bridge {
return genericBridges(number, q.machineType)
}

Expand Down Expand Up @@ -173,6 +173,6 @@ func (q *qemuAmd64) appendImage(devices []govmmQemu.Device, path string) ([]govm
}

// appendBridges appends to devices the given bridges
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType)
}
4 changes: 2 additions & 2 deletions virtcontainers/qemu_amd64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestQemuAmd64Bridges(t *testing.T) {
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID)
assert.NotNil(b.Address)
assert.NotNil(b.Devices)
}

amd64 = newTestQemu(QemuQ35)
Expand All @@ -58,7 +58,7 @@ func TestQemuAmd64Bridges(t *testing.T) {
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID)
assert.NotNil(b.Address)
assert.NotNil(b.Devices)
}

amd64 = newTestQemu(QemuQ35 + QemuPC)
Expand Down
16 changes: 6 additions & 10 deletions virtcontainers/qemu_arch_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type qemuArch interface {
capabilities() types.Capabilities

// bridges returns the number bridges for the machine type
bridges(number uint32) []types.PCIBridge
bridges(number uint32) []types.Bridge

// cpuTopology returns the CPU topology for the given amount of vcpus
cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP
Expand All @@ -70,7 +70,7 @@ type qemuArch interface {
appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread)

// appendBridges appends bridges to devices
appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device
appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device

// append9PVolume appends a 9P volume to devices
append9PVolume(devices []govmmQemu.Device, volume types.Volume) []govmmQemu.Device
Expand Down Expand Up @@ -242,15 +242,11 @@ func (q *qemuArchBase) capabilities() types.Capabilities {
return caps
}

func (q *qemuArchBase) bridges(number uint32) []types.PCIBridge {
var bridges []types.PCIBridge
func (q *qemuArchBase) bridges(number uint32) []types.Bridge {
var bridges []types.Bridge

for i := uint32(0); i < number; i++ {
bridges = append(bridges, types.PCIBridge{
Type: types.PCI,
ID: fmt.Sprintf("%s-bridge-%d", types.PCI, i),
Address: make(map[uint32]string),
})
bridges = append(bridges, types.NewBridge(types.PCI, fmt.Sprintf("%s-bridge-%d", types.PCI, i), make(map[uint32]string), 0))
}

return bridges
Expand Down Expand Up @@ -351,7 +347,7 @@ func (q *qemuArchBase) appendSCSIController(devices []govmmQemu.Device, enableIO
}

// appendBridges appends to devices the given bridges
func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device {
for idx, b := range bridges {
t := govmmQemu.PCIBridge
if b.Type == types.PCIE {
Expand Down
2 changes: 1 addition & 1 deletion virtcontainers/qemu_arch_base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestQemuArchBaseBridges(t *testing.T) {
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
assert.Equal(types.PCI, b.Type)
assert.Equal(id, b.ID)
assert.NotNil(b.Address)
assert.NotNil(b.Devices)
}
}

Expand Down
4 changes: 2 additions & 2 deletions virtcontainers/qemu_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,12 @@ func newQemuArch(config HypervisorConfig) qemuArch {
return q
}

func (q *qemuArm64) bridges(number uint32) []types.PCIBridge {
func (q *qemuArm64) bridges(number uint32) []types.Bridge {
return genericBridges(number, q.machineType)
}

// appendBridges appends to devices the given bridges
func (q *qemuArm64) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
func (q *qemuArm64) appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType)
}

Expand Down
4 changes: 2 additions & 2 deletions virtcontainers/qemu_ppc64le.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (q *qemuPPC64le) capabilities() types.Capabilities {
return caps
}

func (q *qemuPPC64le) bridges(number uint32) []types.PCIBridge {
func (q *qemuPPC64le) bridges(number uint32) []types.Bridge {
return genericBridges(number, q.machineType)
}

Expand Down Expand Up @@ -152,6 +152,6 @@ func (q *qemuPPC64le) appendImage(devices []govmmQemu.Device, path string) ([]go
}

// appendBridges appends to devices the given bridges
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType)
}
4 changes: 2 additions & 2 deletions virtcontainers/qemu_s390x.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ func newQemuArch(config HypervisorConfig) qemuArch {
return q
}

func (q *qemuS390x) bridges(number uint32) []types.PCIBridge {
func (q *qemuS390x) bridges(number uint32) []types.Bridge {
return genericBridges(number, q.machineType)
}

// appendBridges appends to devices the given bridges
func (q *qemuS390x) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
func (q *qemuS390x) appendBridges(devices []govmmQemu.Device, bridges []types.Bridge) []govmmQemu.Device {
return genericAppendBridges(devices, bridges, q.machineType)
}

Expand Down
90 changes: 90 additions & 0 deletions virtcontainers/types/bridges.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package types

import "fmt"

// Type represents a type of bus and bridge.
type Type string

const pciBridgeMaxCapacity = 30

const (
// PCI represents a PCI bus and bridge
PCI Type = "pci"

// PCIE represents a PCIe bus and bridge
PCIE Type = "pcie"
)

type Bridge struct {
// Devices contains information about devices plugged and its address in the bridge
Devices map[uint32]string

// ID is used to identify the bridge in the hypervisor
ID string

// Addr is the slot of the bridge
Addr int

// Type is the type of the bridge (pci, pcie, etc)
Type Type

// MaxCapacity is the max capacity of the bridge
MaxCapacity uint32
}

func NewBridge(bt Type, id string, devices map[uint32]string, addr int) Bridge {
var maxCapacity uint32
switch bt {
case PCI:
fallthrough
case PCIE:
maxCapacity = pciBridgeMaxCapacity
default:
maxCapacity = 0
}
return Bridge{
Devices: devices,
ID: id,
Addr: addr,
Type: bt,
MaxCapacity: maxCapacity,
}
}

func (b *Bridge) AddDevice(ID string) (uint32, error) {
var addr uint32

// looking for the first available address
for i := uint32(1); i <= b.MaxCapacity; i++ {
if _, ok := b.Devices[i]; !ok {
addr = i
break
}
}

if addr == 0 {
return 0, fmt.Errorf("Unable to hot plug device on bridge: there are no empty slots")
}

// save address and device
b.Devices[addr] = ID
return addr, nil
}

func (b *Bridge) RemoveDevice(ID string) error {
// check if the device was hot plugged in the bridge
for addr, devID := range b.Devices {
if devID == ID {
// free address to re-use the same slot with other devices
delete(b.Devices, addr)
return nil
}
}

return fmt.Errorf("Unable to hot unplug device %s: not present on bridge", ID)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ import (
"github.com/stretchr/testify/assert"
)

func TestAddRemoveDevice(t *testing.T) {
func testAddRemoveDevice(t *testing.T, b *Bridge) {
assert := assert.New(t)

// create a bridge
bridges := []*PCIBridge{{make(map[uint32]string), PCI, "rgb123", 5}}

// add device
devID := "abc123"
b := bridges[0]

addr, err := b.AddDevice(devID)
assert.NoError(err)
if addr < 1 {
Expand All @@ -35,13 +32,21 @@ func TestAddRemoveDevice(t *testing.T) {
assert.NoError(err)

// add device when the bridge is full
bridges[0].Address = make(map[uint32]string)
for i := uint32(1); i <= pciBridgeMaxCapacity; i++ {
bridges[0].Address[i] = fmt.Sprintf("%d", i)
b.Devices = make(map[uint32]string)
for i := uint32(1); i <= b.MaxCapacity; i++ {
b.Devices[i] = fmt.Sprintf("%d", i)
}
addr, err = b.AddDevice(devID)
assert.Error(err)
if addr != 0 {
assert.Fail("address should be 0")
}
}

func TestAddRemoveDevicePCI(t *testing.T) {

// create a pci bridge
bridges := []*Bridge{{make(map[uint32]string), "rgb123", 5, PCI, pciBridgeMaxCapacity}}

testAddRemoveDevice(t, bridges[0])
}

0 comments on commit 57a5f63

Please sign in to comment.