Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support DeviceID on Auxiliary Bus #1003

Merged
merged 2 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 58 additions & 31 deletions plugins/main/host-device/host-device.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ import (
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)

var sysBusPCI = "/sys/bus/pci/devices"
var (
sysBusPCI = "/sys/bus/pci/devices"
sysBusAuxiliary = "/sys/bus/auxiliary/devices"
)

// Array of different linux drivers bound to network device needed for DPDK
var userspaceDrivers = []string{"vfio-pci", "uio_pci_generic", "igb_uio"}
Expand All @@ -53,6 +56,9 @@ type NetConf struct {
RuntimeConfig struct {
DeviceID string `json:"deviceID,omitempty"`
} `json:"runtimeConfig,omitempty"`

// for internal use
auxDevice string `json:"-"` // Auxiliary device name as appears on Auxiliary bus (/sys/bus/auxiliary)
}

func init() {
Expand All @@ -62,19 +68,44 @@ func init() {
runtime.LockOSThread()
}

// handleDeviceID updates netconf fields with DeviceID runtime config
func handleDeviceID(netconf *NetConf) error {
deviceID := netconf.RuntimeConfig.DeviceID
if deviceID == "" {
return nil
}

// Check if deviceID is a PCI device
pciPath := filepath.Join(sysBusPCI, deviceID)
if _, err := os.Stat(pciPath); err == nil {
netconf.PCIAddr = deviceID
return nil
}

// Check if deviceID is an Auxiliary device
auxPath := filepath.Join(sysBusAuxiliary, deviceID)
if _, err := os.Stat(auxPath); err == nil {
netconf.PCIAddr = ""
netconf.auxDevice = deviceID
return nil
}

return fmt.Errorf("runtime config DeviceID %s not found or unsupported", deviceID)
}

func loadConf(bytes []byte) (*NetConf, error) {
n := &NetConf{}
var err error
if err = json.Unmarshal(bytes, n); err != nil {
return nil, fmt.Errorf("failed to load netconf: %v", err)
}

if n.RuntimeConfig.DeviceID != "" {
// Override PCI device with the standardized DeviceID provided in Runtime Config.
n.PCIAddr = n.RuntimeConfig.DeviceID
// Override device with the standardized DeviceID if provided in Runtime Config.
if err := handleDeviceID(n); err != nil {
return nil, err
}

if n.Device == "" && n.HWAddr == "" && n.KernelPath == "" && n.PCIAddr == "" {
if n.Device == "" && n.HWAddr == "" && n.KernelPath == "" && n.PCIAddr == "" && n.auxDevice == "" {
return nil, fmt.Errorf(`specify either "device", "hwaddr", "kernelpath" or "pciBusID"`)
}

Expand Down Expand Up @@ -102,7 +133,7 @@ func cmdAdd(args *skel.CmdArgs) error {
result := &current.Result{}
var contDev netlink.Link
if !cfg.DPDKMode {
hostDev, err := getLink(cfg.Device, cfg.HWAddr, cfg.KernelPath, cfg.PCIAddr)
hostDev, err := getLink(cfg.Device, cfg.HWAddr, cfg.KernelPath, cfg.PCIAddr, cfg.auxDevice)
if err != nil {
return fmt.Errorf("failed to find host device: %v", err)
}
Expand Down Expand Up @@ -428,11 +459,19 @@ func printLink(dev netlink.Link, cniVersion string, containerNs ns.NetNS) error
return types.PrintResult(&result, cniVersion)
}

func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error) {
links, err := netlink.LinkList()
func linkFromPath(path string) (netlink.Link, error) {
entries, err := os.ReadDir(path)
if err != nil {
return nil, fmt.Errorf("failed to list node links: %v", err)
return nil, fmt.Errorf("failed to read directory %s: %q", path, err)
}
if len(entries) > 0 {
// grab the first net device
return netlink.LinkByName(entries[0].Name())
}
return nil, fmt.Errorf("failed to find network device in path %s", path)
}

func getLink(devname, hwaddr, kernelpath, pciaddr string, auxDev string) (netlink.Link, error) {
switch {

case len(devname) > 0:
Expand All @@ -443,6 +482,11 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
return nil, fmt.Errorf("failed to parse MAC address %q: %v", hwaddr, err)
}

links, err := netlink.LinkList()
if err != nil {
return nil, fmt.Errorf("failed to list node links: %v", err)
}

for _, link := range links {
if bytes.Equal(link.Attrs().HardwareAddr, hwAddr) {
return link, nil
Expand All @@ -453,20 +497,7 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
return nil, fmt.Errorf("kernel device path %q must be absolute and begin with /sys/devices/", kernelpath)
}
netDir := filepath.Join(kernelpath, "net")
entries, err := os.ReadDir(netDir)
if err != nil {
return nil, fmt.Errorf("failed to find network devices at %q", netDir)
}

// Grab the first device from eg /sys/devices/pci0000:00/0000:00:19.0/net
for _, entry := range entries {
// Make sure it's really an interface
for _, l := range links {
if entry.Name() == l.Attrs().Name {
return l, nil
}
}
}
return linkFromPath(netDir)
case len(pciaddr) > 0:
netDir := filepath.Join(sysBusPCI, pciaddr, "net")
if _, err := os.Lstat(netDir); err != nil {
Expand All @@ -477,14 +508,10 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
}
netDir = matches[0]
}
entries, err := os.ReadDir(netDir)
if err != nil {
return nil, fmt.Errorf("failed to read net directory %s: %q", netDir, err)
}
if len(entries) > 0 {
return netlink.LinkByName(entries[0].Name())
}
return nil, fmt.Errorf("failed to find device name for pci address %s", pciaddr)
return linkFromPath(netDir)
case len(auxDev) > 0:
netDir := filepath.Join(sysBusAuxiliary, auxDev, "net")
return linkFromPath(netDir)
}

return nil, fmt.Errorf("failed to find physical interface")
Expand Down
66 changes: 66 additions & 0 deletions plugins/main/host-device/host-device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,71 @@ var _ = Describe("base functionality", func() {
})
})

It(fmt.Sprintf("Works with a valid %s config on auxiliary device", ver), func() {
var origLink netlink.Link
ifname := "eth0"

fs := &fakeFilesystem{
dirs: []string{
fmt.Sprintf("sys/bus/auxiliary/devices/mlx5_core.sf.4/net/%s", ifname),
},
}
defer fs.use()()

// prepare ifname in original namespace
_ = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
err := netlink.LinkAdd(&netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: ifname,
},
})
Expect(err).NotTo(HaveOccurred())
origLink, err = netlink.LinkByName(ifname)
Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(origLink)
Expect(err).NotTo(HaveOccurred())
return nil
})

// call CmdAdd
cniName := "net1"
conf := fmt.Sprintf(`{
"cniVersion": "%s",
"name": "cni-plugin-host-device-test",
"type": "host-device",
"runtimeConfig": {"deviceID": %q}
}`, ver, "mlx5_core.sf.4")
args := &skel.CmdArgs{
ContainerID: "dummy",
IfName: cniName,
Netns: targetNS.Path(),
StdinData: []byte(conf),
}
var resI types.Result
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
var err error
resI, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
return err
})
Expect(err).NotTo(HaveOccurred())

// check that the result was sane
t := newTesterByVersion(ver)
t.expectInterfaces(resI, cniName, origLink.Attrs().HardwareAddr.String(), targetNS.Path())

// call CmdDel
_ = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
err = testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
return nil
})
})

It(fmt.Sprintf("Works with a valid %s config with IPAM", ver), func() {
var origLink netlink.Link

Expand Down Expand Up @@ -1289,6 +1354,7 @@ func (fs *fakeFilesystem) use() func() {
}

sysBusPCI = path.Join(fs.rootDir, "/sys/bus/pci/devices")
sysBusAuxiliary = path.Join(fs.rootDir, "/sys/bus/auxiliary/devices")

return func() {
// remove temporary fake fs
Expand Down