From 1b41001cf35aed3ea8b6bcc642439619c4ec7fe6 Mon Sep 17 00:00:00 2001 From: Francesco Romani Date: Wed, 24 Feb 2021 12:56:04 +0100 Subject: [PATCH] sriov: add support Add support to report SRIOV devices. Much like GPU devices, support is added using a new top-level package. SRIOV devices are either Physical Functions or Virtual functions. The preferred representation for ghw is Physical Functions, whose dependent devices will be Virtual Functions; however, for the sake of practicality, the API also exposes soft references to Virtual Functions, so consumers of the API can access them directly and not navigating the parent devices. This patch also adds support in `ghwc`, to report the sriov information, and in the `snapshot` package, to make sure to capture all the files in sysfs that ghw cares about. Last but not least, lacking access to suitable non-linux systems, support is provided only on linux OS, even though the API tries hard not to be linux-specific. Resolves: https://github.com/jaypipes/ghw/issues/92 Signed-off-by: Francesco Romani --- README.md | 61 ++++++ alias.go | 9 + cmd/ghwc/commands/sriov.go | 48 +++++ host.go | 41 ++-- pkg/pci/address/address.go | 11 + pkg/pci/address/address_test.go | 8 + pkg/snapshot/clonetree.go | 6 + pkg/snapshot/clonetree_pci.go | 17 ++ pkg/sriov/sriov.go | 125 +++++++++++ pkg/sriov/sriov_linux.go | 135 ++++++++++++ pkg/sriov/sriov_linux_test.go | 198 ++++++++++++++++++ pkg/sriov/sriov_stub.go | 17 ++ ...64-8581cf3a529e5d8b97ea876eade2f60d.tar.gz | Bin 44675 -> 46506 bytes 13 files changed, 662 insertions(+), 14 deletions(-) create mode 100644 cmd/ghwc/commands/sriov.go create mode 100644 pkg/sriov/sriov.go create mode 100644 pkg/sriov/sriov_linux.go create mode 100644 pkg/sriov/sriov_linux_test.go create mode 100644 pkg/sriov/sriov_stub.go diff --git a/README.md b/README.md index 60b52308..721cf3c7 100644 --- a/README.md +++ b/README.md @@ -1039,6 +1039,67 @@ information `ghw.TopologyNode` struct if you'd like to dig deeper into the NUMA/topology subsystem +### SRIOV + +*This API is PROVISIONAL! ghw will try hard to not make breaking changes to this API, but still users are advice this new API is not +declared stable yet. We expect to declare it stable with ghw version 1.0.0* + +SRIOV (Single-Root Input/Output Virtualization) is a class of PCI devices that ghw models explicitly, like gpus. + +```go +package main + +import ( + "fmt" + + "github.com/jaypipes/ghw" +) + +func main() { + sriov, err := ghw.SRIOV() + if err != nil { + fmt.Fprintf(os.Stderr, "Error getting SRIOV info: %v", err) + } + + fmt.Printf("%v\n", sriov) + + for _, dev := range sriov.PhysicalFunctions { + fmt.Printf(" %v\n", dev) + } +} +``` + +ghw discovers the SRIOV devices starting from the Physical Function (PF) and exposes them in the `PhysicalFunctions` slice. +Virtual Function (VF) are exposed as properties of the PF instance with exposes them. +However, in some cases users are interested in the VFs first, so it's clumsy to navigate the PFs to learn about VFs. +To make this easier, ghw also exposes a slice of VF instances. These instances are soft references to the very same VF objects +you can find from the PF objects. + +```go +package main + +import ( + "fmt" + + "github.com/jaypipes/ghw" +) + +func main() { + sriov, err := ghw.SRIOV() + if err != nil { + fmt.Fprintf(os.Stderr, "Error getting SRIOV info: %v", err) + } + + fmt.Printf("%v\n", sriov) + + // you will see the very same VF data data you seen from the previous example + for _, dev := range sriov.VirtualFunctions { + fmt.Printf(" %v\n", dev) + } +} +``` + + ### Chassis The host's chassis information is accessible with the `ghw.Chassis()` function. This diff --git a/alias.go b/alias.go index 66b4f2b9..53323e67 100644 --- a/alias.go +++ b/alias.go @@ -19,6 +19,7 @@ import ( "github.com/jaypipes/ghw/pkg/pci" pciaddress "github.com/jaypipes/ghw/pkg/pci/address" "github.com/jaypipes/ghw/pkg/product" + "github.com/jaypipes/ghw/pkg/sriov" "github.com/jaypipes/ghw/pkg/topology" ) @@ -146,3 +147,11 @@ type GraphicsCard = gpu.GraphicsCard var ( GPU = gpu.New ) + +type SRIOVInfo = sriov.Info +type PhysicalFunction = sriov.PhysicalFunction +type VirtualFunction = sriov.VirtualFunction + +var ( + SRIOV = sriov.New +) diff --git a/cmd/ghwc/commands/sriov.go b/cmd/ghwc/commands/sriov.go new file mode 100644 index 00000000..c6048c8d --- /dev/null +++ b/cmd/ghwc/commands/sriov.go @@ -0,0 +1,48 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package commands + +import ( + "fmt" + + "github.com/jaypipes/ghw" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// sriovCmd represents the listing command +var sriovCmd = &cobra.Command{ + Use: "sriov", + Short: "Show SRIOV devices information for the host system", + RunE: showSRIOV, +} + +// showSRIOV show SRIOV physical device information for the host system. +func showSRIOV(cmd *cobra.Command, args []string) error { + sriov, err := ghw.SRIOV() + if err != nil { + return errors.Wrap(err, "error getting SRIOV info") + } + + switch outputFormat { + case outputFormatHuman: + fmt.Printf("%v\n", sriov) + + for _, dev := range sriov.PhysicalFunctions { + fmt.Printf(" %v\n", dev) + } + case outputFormatJSON: + fmt.Printf("%s\n", sriov.JSONString(pretty)) + case outputFormatYAML: + fmt.Printf("%s", sriov.YAMLString()) + } + return nil +} + +func init() { + rootCmd.AddCommand(sriovCmd) +} diff --git a/host.go b/host.go index 5d82a53a..a9905011 100644 --- a/host.go +++ b/host.go @@ -8,6 +8,7 @@ package ghw import ( "fmt" + "strings" "github.com/jaypipes/ghw/pkg/context" @@ -22,6 +23,7 @@ import ( "github.com/jaypipes/ghw/pkg/net" "github.com/jaypipes/ghw/pkg/pci" "github.com/jaypipes/ghw/pkg/product" + "github.com/jaypipes/ghw/pkg/sriov" "github.com/jaypipes/ghw/pkg/topology" ) @@ -40,6 +42,7 @@ type HostInfo struct { Baseboard *baseboard.Info `json:"baseboard"` Product *product.Info `json:"product"` PCI *pci.Info `json:"pci"` + SRIOV *sriov.Info `json:"sriov"` } // Host returns a pointer to a HostInfo struct that contains fields with @@ -91,6 +94,10 @@ func Host(opts ...*WithOption) (*HostInfo, error) { if err != nil { return nil, err } + sriovInfo, err := sriov.New(opts...) + if err != nil { + return nil, err + } return &HostInfo{ ctx: ctx, CPU: cpuInfo, @@ -104,26 +111,32 @@ func Host(opts ...*WithOption) (*HostInfo, error) { Baseboard: baseboardInfo, Product: productInfo, PCI: pciInfo, + SRIOV: sriovInfo, }, nil } // String returns a newline-separated output of the HostInfo's component // structs' String-ified output func (info *HostInfo) String() string { - return fmt.Sprintf( - "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", - info.Block.String(), - info.CPU.String(), - info.GPU.String(), - info.Memory.String(), - info.Network.String(), - info.Topology.String(), - info.Chassis.String(), - info.BIOS.String(), - info.Baseboard.String(), - info.Product.String(), - info.PCI.String(), - ) + var b strings.Builder + for _, s := range []fmt.Stringer{ + info.Block, + info.CPU, + info.GPU, + info.Memory, + info.Network, + info.Topology, + info.Chassis, + info.BIOS, + info.Baseboard, + info.Product, + info.PCI, + info.SRIOV, + } { + b.WriteString(s.String()) + b.WriteString("\n") + } + return b.String() } // YAMLString returns a string with the host information formatted as YAML diff --git a/pkg/pci/address/address.go b/pkg/pci/address/address.go index 7b136053..a841ad50 100644 --- a/pkg/pci/address/address.go +++ b/pkg/pci/address/address.go @@ -24,6 +24,17 @@ type Address struct { Function string } +// Equal tells if two Addresses are equal or not +func (addr *Address) Equal(a *Address) bool { + if addr == nil && a == nil { + return true + } + if addr != nil && a != nil { + return addr.Domain == a.Domain && addr.Bus == a.Bus && addr.Slot == a.Slot && addr.Function == a.Function + } + return false +} + // String() returns the canonical [D]BSF representation of this Address func (addr *Address) String() string { return addr.Domain + ":" + addr.Bus + ":" + addr.Slot + "." + addr.Function diff --git a/pkg/pci/address/address_test.go b/pkg/pci/address/address_test.go index 4edf3d7a..d3179963 100644 --- a/pkg/pci/address/address_test.go +++ b/pkg/pci/address/address_test.go @@ -80,3 +80,11 @@ func TestPCIAddressFromString(t *testing.T) { } } } + +func TestPCIAddressEqual(t *testing.T) { + addr1 := pciaddr.FromString("0000:03:00.A") + addr2 := pciaddr.FromString("03:00.A") + if addr1.Equal(addr2) == false { + t.Fatalf("addr1 %v and addr2 %v should be equal", addr1, addr2) + } +} diff --git a/pkg/snapshot/clonetree.go b/pkg/snapshot/clonetree.go index ba9f8f10..2cbb15a3 100644 --- a/pkg/snapshot/clonetree.go +++ b/pkg/snapshot/clonetree.go @@ -7,6 +7,7 @@ package snapshot import ( + "errors" "io/ioutil" "os" "path/filepath" @@ -197,6 +198,11 @@ func copyLink(path, targetPath string) error { return err } if err := os.Symlink(target, targetPath); err != nil { + // multiple sources can link back to the same entry: a notable example is + // all the SRIOV VFs linking back to the same driver. + if errors.Is(err, os.ErrExist) { + return nil + } return err } diff --git a/pkg/snapshot/clonetree_pci.go b/pkg/snapshot/clonetree_pci.go index 503a562d..0b8b3f85 100644 --- a/pkg/snapshot/clonetree_pci.go +++ b/pkg/snapshot/clonetree_pci.go @@ -67,6 +67,15 @@ func scanPCIDeviceRoot(root string) (fileSpecs []string, pciRoots []string) { "revision", "vendor", } + + perDevEntriesOpt := []string{ + "driver", + "net/*", + "physfn", + "sriov_*", + "virtfn*", + } + entries, err := ioutil.ReadDir(root) if err != nil { return []string{}, []string{} @@ -93,6 +102,14 @@ func scanPCIDeviceRoot(root string) (fileSpecs []string, pciRoots []string) { fileSpecs = append(fileSpecs, filepath.Join(pciEntry, perNetEntry)) } + for _, perNetEntryOpt := range perDevEntriesOpt { + netEntryOptPath := filepath.Join(pciEntry, perNetEntryOpt) + if items, err := filepath.Glob(netEntryOptPath); err == nil && len(items) > 0 { + fileSpecs = append(fileSpecs, netEntryOptPath) + } + + } + if isPCIBridge(entryPath) { trace("adding new PCI root %q\n", entryName) pciRoots = append(pciRoots, pciEntry) diff --git a/pkg/sriov/sriov.go b/pkg/sriov/sriov.go new file mode 100644 index 00000000..b7329528 --- /dev/null +++ b/pkg/sriov/sriov.go @@ -0,0 +1,125 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package sriov + +import ( + "fmt" + + "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/pkg/marshal" + "github.com/jaypipes/ghw/pkg/option" + "github.com/jaypipes/ghw/pkg/pci" + pciaddr "github.com/jaypipes/ghw/pkg/pci/address" +) + +type Device struct { + Driver string `json:"driver"` + Interfaces []string `json:"interfaces"` + // the PCI address where the SRIOV instance can be found + Address *pciaddr.Address `json:"address"` + PCI *pci.Device `json:"pci"` +} + +func (d Device) ToString(devType string) string { + deviceStr := d.Address.String() + nodeStr := "" + if d.PCI != nil { + deviceStr = d.PCI.String() + if d.PCI.Node != nil { + nodeStr = fmt.Sprintf(" [affined to NUMA node %d]", d.PCI.Node.ID) + } + } + return fmt.Sprintf("%s function %s@%s", devType, nodeStr, deviceStr) +} + +type PhysicalFunction struct { + Device + MaxVFNum int `json:"max_vf_num,omitempty"` + VFs []VirtualFunction `json:"vfs,omitempty"` +} + +type VirtualFunction struct { + Device + ID int `json:"id"` + // Address of the (parent) Physical Function this Virtual Function pertains to. + ParentAddress *pciaddr.Address `json:"parent_address,omitempty"` +} + +func (pf *PhysicalFunction) String() string { + return fmt.Sprintf("%s with %d/%d virtual functions", + pf.Device.ToString("physical"), + len(pf.VFs), + pf.MaxVFNum, + ) +} + +func (vf *VirtualFunction) String() string { + return fmt.Sprintf("%s index %d from %s", + vf.Device.ToString("virtual"), + vf.ID, + vf.ParentAddress, + ) +} + +type Info struct { + ctx *context.Context + // All the Physical Functions found in the host system, + PhysicalFunctions []*PhysicalFunction `json:"physical_functions,omitempty"` + // All the Virtual Functions found in the host system, + // This is the very same data found navigating the `PhysicalFunctions`; + // These pointers point back to the corresponding structs in the `PhysicalFunctions` + // slice. + VirtualFunctions []*VirtualFunction `json:"virtual_functions,omitempty"` +} + +// New returns a pointer to an Info struct that contains information about the +// SRIOV devices on the host system. +func New(opts ...*option.Option) (*Info, error) { + return newWithContext(context.New(opts...)) +} + +// New returns a pointer to an Info struct that contains information about the +// SRIOV devices on the host system, reusing a given context. +// Use this function when you want to consume this package from another, +// ensuring the two see a coherent set of resources. +func NewWithContext(ctx *context.Context) (*Info, error) { + return newWithContext(context.FromParent(ctx)) +} + +func newWithContext(ctx *context.Context) (*Info, error) { + info := &Info{ctx: ctx} + if err := ctx.Do(info.load); err != nil { + return nil, err + } + return info, nil +} + +func (i *Info) String() string { + return fmt.Sprintf( + "sriov (%d phsyical %d virtual devices)", + len(i.PhysicalFunctions), + len(i.VirtualFunctions), + ) +} + +// simple private struct used to encapsulate SRIOV information in a top-level +// "sriov" YAML/JSON map/object key +type sriovPrinter struct { + Info *Info `json:"sriov,omitempty"` +} + +// YAMLString returns a string with the SRIOV information formatted as YAML +// under a top-level "sriov:" key +func (i *Info) YAMLString() string { + return marshal.SafeYAML(i.ctx, sriovPrinter{i}) +} + +// JSONString returns a string with the SRIOV information formatted as JSON +// under a top-level "sriov:" key +func (i *Info) JSONString(indent bool) string { + return marshal.SafeJSON(i.ctx, sriovPrinter{i}, indent) +} diff --git a/pkg/sriov/sriov_linux.go b/pkg/sriov/sriov_linux.go new file mode 100644 index 00000000..e60d23c9 --- /dev/null +++ b/pkg/sriov/sriov_linux.go @@ -0,0 +1,135 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package sriov + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/pkg/linuxpath" + "github.com/jaypipes/ghw/pkg/pci" + pciaddress "github.com/jaypipes/ghw/pkg/pci/address" + "github.com/jaypipes/ghw/pkg/util" +) + +func (info *Info) load() error { + // SRIOV device do not have a specific class (as in "entry in /sys/class"), + // so we need to iterate over all the PCI devices. + pciInfo, err := pci.NewWithContext(info.ctx) + if err != nil { + return err + } + + for _, dev := range pciInfo.Devices { + err := info.scanDevice(pciInfo, dev) + if err != nil { + return err + } + } + + return nil +} + +func (info *Info) scanDevice(pciInfo *pci.Info, dev *pci.Device) error { + paths := linuxpath.New(info.ctx) + devPath := filepath.Join(paths.SysBusPciDevices, dev.Address) + + buf, err := ioutil.ReadFile(filepath.Join(devPath, "sriov_totalvfs")) + if err != nil { + // is not a physfn. Since we will fill virtfn from physfn, we can give up now + return nil + } + + maxVFs, err := strconv.Atoi(strings.TrimSpace(string(buf))) + if err != nil { + info.ctx.Warn("error reading sriov_totalvfn for %q: %v", devPath, err) + return nil + } + + virtFNs := findVFsFromPF(info, pciInfo, dev.Address, devPath) + physFN := PhysicalFunction{ + Device: info.newDevice(dev, devPath), + MaxVFNum: maxVFs, + VFs: virtFNs, + } + + info.PhysicalFunctions = append(info.PhysicalFunctions, &physFN) + for idx := 0; idx < len(virtFNs); idx++ { + info.VirtualFunctions = append(info.VirtualFunctions, &virtFNs[idx]) + } + + return nil +} + +func findVFsFromPF(info *Info, pciInfo *pci.Info, parentAddr, parentPath string) []VirtualFunction { + numVfs := util.SafeIntFromFile(info.ctx, filepath.Join(parentPath, "sriov_numvfs")) + if numVfs == -1 { + return nil + } + + var vfs []VirtualFunction + for vfnIdx := 0; vfnIdx < numVfs; vfnIdx++ { + virtFn := fmt.Sprintf("virtfn%d", vfnIdx) + vfnDest, err := os.Readlink(filepath.Join(parentPath, virtFn)) + if err != nil { + info.ctx.Warn("error reading backing device for virtfn %q physfn %q: %v", virtFn, parentPath, err) + return nil + } + + vfnPath := filepath.Clean(filepath.Join(parentPath, vfnDest)) + vfnAddr := filepath.Base(vfnDest) + vfnDev := pciInfo.GetDevice(vfnAddr) + if vfnDev == nil { + info.ctx.Warn("error finding the PCI device for virtfn %s physfn %s", vfnAddr, parentAddr) + return nil + } + + vfs = append(vfs, VirtualFunction{ + Device: info.newDevice(vfnDev, vfnPath), + ID: vfnIdx, + ParentAddress: pciaddress.FromString(parentAddr), + }) + } + return vfs +} + +func (info *Info) newDevice(dev *pci.Device, devPath string) Device { + // see: https://doc.dpdk.org/guides/linux_gsg/linux_drivers.html + driver := "" + if dest, err := os.Readlink(filepath.Join(devPath, "driver")); err == nil { + driver = filepath.Base(dest) + } + networkNames := findNetworks(info.ctx, devPath) + + return Device{ + Address: pciaddress.FromString(dev.Address), + Driver: driver, + Interfaces: networkNames, + PCI: dev, + } +} + +func findNetworks(ctx *context.Context, devPath string) []string { + netPath := filepath.Join(devPath, "net") + + netEntries, err := ioutil.ReadDir(netPath) + if err != nil { + ctx.Warn("cannot enumerate network names for %q: %v", devPath, err) + return nil + } + + var networks []string + for _, netEntry := range netEntries { + networks = append(networks, netEntry.Name()) + } + + return networks +} diff --git a/pkg/sriov/sriov_linux_test.go b/pkg/sriov/sriov_linux_test.go new file mode 100644 index 00000000..5de4968c --- /dev/null +++ b/pkg/sriov/sriov_linux_test.go @@ -0,0 +1,198 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package sriov_test + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/jaypipes/ghw/pkg/option" + pciaddr "github.com/jaypipes/ghw/pkg/pci/address" + "github.com/jaypipes/ghw/pkg/sriov" + + "github.com/jaypipes/ghw/testdata" +) + +// nolint: gocyclo +func TestStringify(t *testing.T) { + info := sriovTestSetup(t) + + for _, physFn := range info.PhysicalFunctions { + s := physFn.String() + if s == "" || !strings.Contains(s, "function") || !strings.Contains(s, "physical") { + t.Errorf("Wrong string representation %q", s) + } + } + + for _, virtFn := range info.VirtualFunctions { + s := virtFn.String() + if s == "" || !strings.Contains(s, "function") || !strings.Contains(s, "virtual") { + t.Errorf("Wrong string representation %q", s) + } + } + +} + +// nolint: gocyclo +func TestCountDevices(t *testing.T) { + info := sriovTestSetup(t) + + // Check the content of + // GHW_SNAPSHOT_PATH="/path/to/linux-amd64-intel-xeon-L5640.tar.gz" ghwc sriov + // to verify these magic numbers + expectedPhysDevs := 2 + expectedVirtDevsPerPhys := 4 + numPhysDevs := len(info.PhysicalFunctions) + if numPhysDevs != expectedPhysDevs { + t.Errorf("Expected %d physical devices found %d", expectedPhysDevs, numPhysDevs) + } + numVirtDevs := len(info.VirtualFunctions) + if numPhysDevs*expectedVirtDevsPerPhys != numVirtDevs { + t.Errorf("Expected %d=(%d*%d) virtual devices found %d", numPhysDevs*expectedVirtDevsPerPhys, numPhysDevs, expectedVirtDevsPerPhys, numVirtDevs) + } + + for _, physDev := range info.PhysicalFunctions { + numVFs := len(physDev.VFs) + if numVFs != expectedVirtDevsPerPhys { + t.Errorf("Expected %d virtual devices for PF %s found %d", expectedVirtDevsPerPhys, physDev.Address.String(), numVFs) + } + } +} + +type pfTestCase struct { + addr string + netname string +} + +// nolint: gocyclo +func TestMatchPhysicalFunction(t *testing.T) { + info := sriovTestSetup(t) + + // Check the content of + // GHW_SNAPSHOT_PATH="/path/to/linux-amd64-intel-xeon-L5640.tar.gz" ghwc sriov + // to verify these magic numbers + for _, pfTC := range []pfTestCase{ + { + addr: "0000:05:00.0", + netname: "enp5s0f0", + }, + { + addr: "0000:05:00.1", + netname: "enp5s0f1", + }, + } { + addr := pciaddr.FromString(pfTC.addr) + pf := findPF(info.PhysicalFunctions, addr) + if pf == nil { + t.Fatalf("missing PF at addr %q", addr.String()) + } + if pf.PCI == nil { + t.Errorf("missing PCI device for %q", addr.String()) + } + if pf.Driver != "igb" { + t.Errorf("unexpected driver for %#v: %q", pf, pf.Driver) + } + if len(pf.Interfaces) != 1 || pf.Interfaces[0] != pfTC.netname { + t.Errorf("unexpected interfaces for %#v: %v", pf, pf.Interfaces) + } + if pf.MaxVFNum != 7 { + t.Errorf("unexpected MaxVFNum for %#v: %d", pf, pf.MaxVFNum) + } + if len(pf.VFs) != 4 { + t.Errorf("unexpected VF count for %#v: %d", pf, len(pf.VFs)) + } + for _, vfInst := range pf.VFs { + vf := findVF(info.VirtualFunctions, vfInst.Address) + if vf == nil { + t.Errorf("VF %#v from %#v not found among info.VirtualFunctions", vfInst, pf) + } + } + } +} + +func TestMatchVirtualFunction(t *testing.T) { + info := sriovTestSetup(t) + + // Check the content of + // GHW_SNAPSHOT_PATH="/path/to/linux-amd64-intel-xeon-L5640.tar.gz" ghwc sriov + // to verify these magic numbers + + for _, vf := range info.VirtualFunctions { + if vf.PCI == nil { + t.Errorf("missing PCI device for %q", vf.Address.String()) + } + if vf.Driver != "igbvf" { + t.Errorf("unexpected driver for %#v: %q", vf, vf.Driver) + } + + pf := findPF(info.PhysicalFunctions, vf.ParentAddress) + if pf == nil { + t.Fatalf("missing parent device for %q", vf.Address.String()) + } + if vf2 := findVFInst(pf.VFs, vf.Address); vf2 == nil { + t.Errorf("VF %#v not included in parent %#v VFs", vf, pf) + } + } +} + +func findPF(pfs []*sriov.PhysicalFunction, addr *pciaddr.Address) *sriov.PhysicalFunction { + for _, pf := range pfs { + if pf.Address.Equal(addr) { + return pf + } + } + return nil +} + +func findVF(vfs []*sriov.VirtualFunction, addr *pciaddr.Address) *sriov.VirtualFunction { + for _, vf := range vfs { + if vf.Address.Equal(addr) { + return vf + } + } + return nil +} + +func findVFInst(vfs []sriov.VirtualFunction, addr *pciaddr.Address) *sriov.VirtualFunction { + for idx := 0; idx < len(vfs); idx++ { + if vfs[idx].Address.Equal(addr) { + return &vfs[idx] + } + } + return nil +} + +func sriovTestSetup(t *testing.T) *sriov.Info { + if _, ok := os.LookupEnv("GHW_TESTING_SKIP_SRIOV"); ok { + t.Skip("Skipping SRIOV tests.") + } + + testdataPath, err := testdata.SnapshotsDirectory() + if err != nil { + t.Fatalf("Expected nil err, but got %v", err) + } + + multiNumaSnapshot := filepath.Join(testdataPath, "linux-amd64-intel-xeon-L5640.tar.gz") + // from now on we use constants reflecting the content of the snapshot we requested, + // which we reviewed beforehand. IOW, you need to know the content of the + // snapshot to fully understand this test. Inspect it using + // GHW_SNAPSHOT_PATH="/path/to/linux-amd64-intel-xeon-L5640.tar.gz" ghwc sriov + + info, err := sriov.New(option.WithSnapshot(option.SnapshotOptions{ + Path: multiNumaSnapshot, + })) + + if err != nil { + t.Fatalf("Expected nil err, but got %v", err) + } + if info == nil { + t.Fatalf("Expected non-nil SRIOVInfo, but got nil") + } + return info +} diff --git a/pkg/sriov/sriov_stub.go b/pkg/sriov/sriov_stub.go new file mode 100644 index 00000000..55b8e708 --- /dev/null +++ b/pkg/sriov/sriov_stub.go @@ -0,0 +1,17 @@ +// +build !linux +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package sriov + +import ( + "runtime" + + "github.com/pkg/errors" +) + +func (i *Info) load() error { + return errors.New("SRIOV load() not implemented on " + runtime.GOOS) +} diff --git a/testdata/snapshots/linux-amd64-8581cf3a529e5d8b97ea876eade2f60d.tar.gz b/testdata/snapshots/linux-amd64-8581cf3a529e5d8b97ea876eade2f60d.tar.gz index 60454786f40f81288102ea44245b7be81c0d9085..1a996d183d624c90e645c5ef8f8f8f87b88e6b3e 100644 GIT binary patch literal 46506 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 Qu>ok`{+;GFGy2&4AE3eA%m4rY literal 44675 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 I9e0QS15`1~hX4Qo