mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 19:54:35 +00:00
runtime: Introduce PciSlot and PciPath types
This is a dedicated data type for representing PCI paths, that is, PCI
devices described by the slot numbers of the bridges we need to reach
them.
There are a number of places that uses strings with that structure for
things. The plan is to use this data type to consolidate their
handling. These are essentially Go equivalents of the pci::Slot and
pci::Path types introduced in the Rust agent.
Forward port of
185b3ab044
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
7464d055a7
commit
8e5fd8ee84
100
src/runtime/virtcontainers/pkg/types/pcipath.go
Normal file
100
src/runtime/virtcontainers/pkg/types/pcipath.go
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright Red Hat.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// The PCI spec reserves 5 bits for slot number (a.k.a. device
|
||||
// number), giving slots 0..31
|
||||
pciSlotBits = 5
|
||||
maxPciSlot = (1 << pciSlotBits) - 1
|
||||
)
|
||||
|
||||
// A PciSlot describes where a PCI device sits on a single bus
|
||||
//
|
||||
// This encapsulates the PCI slot number a.k.a device number, which is
|
||||
// limited to a 5 bit value [0x00..0x1f] by the PCI specification
|
||||
//
|
||||
// XXX In order to support multifunction device's we'll need to extend
|
||||
// this to include the PCI 3-bit function number as well.
|
||||
type PciSlot struct{ slot uint8 }
|
||||
|
||||
func PciSlotFromString(s string) (PciSlot, error) {
|
||||
v, err := strconv.ParseUint(s, 16, pciSlotBits)
|
||||
if err != nil {
|
||||
return PciSlot{}, err
|
||||
}
|
||||
// The 5 bit width passed to ParseUint ensures the value is <=
|
||||
// maxPciSlot
|
||||
return PciSlot{slot: uint8(v)}, nil
|
||||
}
|
||||
|
||||
func PciSlotFromInt(v int) (PciSlot, error) {
|
||||
if v < 0 || v > maxPciSlot {
|
||||
return PciSlot{}, fmt.Errorf("PCI slot 0x%x should be in range [0..0x%x]", v, maxPciSlot)
|
||||
}
|
||||
return PciSlot{slot: uint8(v)}, nil
|
||||
}
|
||||
|
||||
func (slot PciSlot) String() string {
|
||||
return fmt.Sprintf("%02x", slot.slot)
|
||||
}
|
||||
|
||||
// A PciPath describes where a PCI sits in a PCI hierarchy.
|
||||
//
|
||||
// Consists of a list of PCI slots, giving the slot of each bridge
|
||||
// that must be traversed from the PCI root to reach the device,
|
||||
// followed by the slot of the device itself
|
||||
//
|
||||
// When formatted into a string is written as "xx/.../yy/zz" Here, zz
|
||||
// is the slot of the device on its PCI bridge, yy is the slot of the
|
||||
// bridge on its parent bridge and so forth until xx is the slot of
|
||||
// the "most upstream" bridge on the root bus. If a device is
|
||||
// connected directly to the root bus, its PciPath is just "zz"
|
||||
type PciPath struct {
|
||||
slots []PciSlot
|
||||
}
|
||||
|
||||
func (p PciPath) String() string {
|
||||
tokens := make([]string, len(p.slots))
|
||||
for i, slot := range p.slots {
|
||||
tokens[i] = slot.String()
|
||||
}
|
||||
return strings.Join(tokens, "/")
|
||||
}
|
||||
|
||||
func (p PciPath) IsNil() bool {
|
||||
return p.slots == nil
|
||||
}
|
||||
|
||||
func PciPathFromString(s string) (PciPath, error) {
|
||||
if s == "" {
|
||||
return PciPath{}, nil
|
||||
}
|
||||
|
||||
tokens := strings.Split(s, "/")
|
||||
slots := make([]PciSlot, len(tokens))
|
||||
for i, t := range tokens {
|
||||
var err error
|
||||
slots[i], err = PciSlotFromString(t)
|
||||
if err != nil {
|
||||
return PciPath{}, err
|
||||
}
|
||||
}
|
||||
return PciPath{slots: slots}, nil
|
||||
}
|
||||
|
||||
func PciPathFromSlots(slots ...PciSlot) (PciPath, error) {
|
||||
if len(slots) == 0 {
|
||||
return PciPath{}, fmt.Errorf("PCI path needs at least one component")
|
||||
}
|
||||
return PciPath{slots: slots}, nil
|
||||
}
|
110
src/runtime/virtcontainers/pkg/types/pcipath_test.go
Normal file
110
src/runtime/virtcontainers/pkg/types/pcipath_test.go
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright Red Hat.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPciSlot(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// Valid slots
|
||||
slot, err := PciSlotFromInt(0x00)
|
||||
assert.NoError(err)
|
||||
assert.Equal(slot, PciSlot{})
|
||||
assert.Equal(slot.String(), "00")
|
||||
|
||||
slot, err = PciSlotFromString("00")
|
||||
assert.NoError(err)
|
||||
assert.Equal(slot, PciSlot{})
|
||||
|
||||
slot, err = PciSlotFromInt(31)
|
||||
assert.NoError(err)
|
||||
slot2, err := PciSlotFromString("1f")
|
||||
assert.NoError(err)
|
||||
assert.Equal(slot, slot2)
|
||||
|
||||
// Bad slots
|
||||
_, err = PciSlotFromInt(-1)
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciSlotFromInt(32)
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciSlotFromString("20")
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciSlotFromString("xy")
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciSlotFromString("00/")
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciSlotFromString("")
|
||||
assert.Error(err)
|
||||
}
|
||||
|
||||
func TestPciPath(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
slot3, err := PciSlotFromInt(0x03)
|
||||
assert.NoError(err)
|
||||
slot4, err := PciSlotFromInt(0x04)
|
||||
assert.NoError(err)
|
||||
slot5, err := PciSlotFromInt(0x05)
|
||||
assert.NoError(err)
|
||||
|
||||
// Empty/nil paths
|
||||
pcipath := PciPath{}
|
||||
assert.True(pcipath.IsNil())
|
||||
|
||||
pcipath, err = PciPathFromString("")
|
||||
assert.NoError(err)
|
||||
assert.True(pcipath.IsNil())
|
||||
assert.Equal(pcipath, PciPath{})
|
||||
|
||||
// Valid paths
|
||||
pcipath, err = PciPathFromSlots(slot3)
|
||||
assert.NoError(err)
|
||||
assert.False(pcipath.IsNil())
|
||||
assert.Equal(pcipath.String(), "03")
|
||||
pcipath2, err := PciPathFromString("03")
|
||||
assert.NoError(err)
|
||||
assert.Equal(pcipath, pcipath2)
|
||||
|
||||
pcipath, err = PciPathFromSlots(slot3, slot4)
|
||||
assert.NoError(err)
|
||||
assert.False(pcipath.IsNil())
|
||||
assert.Equal(pcipath.String(), "03/04")
|
||||
pcipath2, err = PciPathFromString("03/04")
|
||||
assert.NoError(err)
|
||||
assert.Equal(pcipath, pcipath2)
|
||||
|
||||
pcipath, err = PciPathFromSlots(slot3, slot4, slot5)
|
||||
assert.NoError(err)
|
||||
assert.False(pcipath.IsNil())
|
||||
assert.Equal(pcipath.String(), "03/04/05")
|
||||
pcipath2, err = PciPathFromString("03/04/05")
|
||||
assert.NoError(err)
|
||||
assert.Equal(pcipath, pcipath2)
|
||||
|
||||
// Bad paths
|
||||
_, err = PciPathFromSlots()
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciPathFromString("20")
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciPathFromString("//")
|
||||
assert.Error(err)
|
||||
|
||||
_, err = PciPathFromString("xyz")
|
||||
assert.Error(err)
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user