diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 34f9c4139..d7c082236 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -17,6 +17,7 @@ package utils import ( "bytes" "fmt" + "github.com/golang/glog" "io/ioutil" "os" "path/filepath" @@ -31,8 +32,9 @@ var ( ) const ( - totalVfFile = "sriov_totalvfs" - configuredVfFile = "sriov_numvfs" + totalVfFile = "sriov_totalvfs" + configuredVfFile = "sriov_numvfs" + eswitchModeSwitchdev = "switchdev" ) // DetectPluginWatchMode returns true if plugins registry directory exist @@ -60,6 +62,25 @@ func GetPfAddr(pciAddr string) (string, error) { // GetPfName returns SRIOV PF name for the given VF // If device is not VF then it will return its own ifname if exist else empty string func GetPfName(pciAddr string) (string, error) { + pfEswitchMode, err := GetPfEswitchMode(pciAddr) + if err != nil { + // If device doesn't support eswitch mode query, fall back to the default implementation + if strings.Contains(strings.ToLower(fmt.Sprint(err)), "no such device") { + glog.Warningf("Devlink query for eswitch mode is not supported for device %s", pciAddr) + } else { + return "", err + } + } + if pfEswitchMode == eswitchModeSwitchdev { + name, err := GetSriovnetProvider().GetUplinkRepresentor(pciAddr) + + if err != nil { + return "", err + } + + return name, nil + } + path := filepath.Join(sysBusPci, pciAddr, "physfn", "net") files, err := ioutil.ReadDir(path) if err != nil { @@ -393,3 +414,17 @@ func GetVFID(pciAddr string) (vfID int, err error) { vfID = -1 return vfID, nil } + +// GetPfEswitchMode returns PF's eswitch mode for the given VF +// If device is not VF then it will return its own eswitch mode +func GetPfEswitchMode(pciAddr string) (string, error) { + pfAddr, err := GetPfAddr(pciAddr) + if err != nil { + return "", fmt.Errorf("error getting PF PCI address for device %s %v", pciAddr, err) + } + devLinkDeviceAttrs, err := GetNetlinkProvider().GetDevLinkDeviceEswitchAttrs(pfAddr) + if err != nil { + return "", err + } + return devLinkDeviceAttrs.Mode, nil +} diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 45dfca867..cc9a947e0 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -1,9 +1,16 @@ package utils import ( + "fmt" + "strings" + . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" + nl "github.com/vishvananda/netlink" + + mocks "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/utils/mocks" ) func assertShouldFail(err error, shouldFail bool) { @@ -396,35 +403,89 @@ var _ = Describe("In the utils package", func() { ) DescribeTable("getting PF names", - func(fs *FakeFilesystem, device string, expected string, shouldFail bool) { + func(fs *FakeFilesystem, eswitchMode string, device string, expected string, shouldFail bool) { + fakeNetlinkProvider := mocks.NetlinkProvider{} + fakeNetlinkProvider. + On("GetDevLinkDeviceEswitchAttrs", + mock.MatchedBy(func(arg string) bool { return !strings.Contains(arg, "Error") })). + Return(&nl.DevlinkDevEswitchAttr{Mode: eswitchMode}, nil). + On("GetDevLinkDeviceEswitchAttrs", "eswitchModeUnsupportedError"). + Return(nil, fmt.Errorf("devlink error: no such device")). + On("GetDevLinkDeviceEswitchAttrs", "unknownError"). + Return(nil, fmt.Errorf("unknown error")) + SetNetlinkProviderInst(&fakeNetlinkProvider) + + fakeSriovnetProvider := mocks.SriovnetProvider{} + fakeSriovnetProvider. + On("GetUplinkRepresentor", mock.AnythingOfType("string")). + Return("fakeSwitchdevPF", nil) + SetSriovnetProviderInst(&fakeSriovnetProvider) + defer fs.Use()() actual, err := GetPfName(device) Expect(actual).To(Equal(expected)) assertShouldFail(err, shouldFail) }, - Entry("device doesn't exist", &FakeFilesystem{}, "0000:01:10.0", nil, true), + Entry("device doesn't exist", &FakeFilesystem{}, "fake", "0000:01:10.0", nil, true), Entry("device is a VF and interface name exists", - &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/0000:01:10.0/physfn/net/fakePF"}}, - "0000:01:10.0", "fakePF", false, + &FakeFilesystem{ + Dirs: []string{ + "sys/bus/pci/devices/0000:01:10.0", + "sys/bus/pci/devices/0000:01:00.0/net/fakePF", + }, + Symlinks: map[string]string{ + "sys/bus/pci/devices/0000:01:10.0/physfn/": "../0000:01:00.0", + }, + }, + "fake", "0000:01:10.0", "fakePF", false, ), Entry("device is a VF and interface name does not exist", &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/0000:01:10.0/physfn/net/"}}, - "0000:01:10.0", "", true, + "fake", "0000:01:10.0", "", true, ), Entry("device is a PF and interface name exists", &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/0000:01:10.0/net/fakeIF"}}, - "0000:01:10.0", "fakeIF", false, + "fake", "0000:01:10.0", "fakeIF", false, ), Entry("device is a PF interface name does not exist", &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/0000:01:10.0/net/fakeIF"}}, - "0000:01:10.0", "fakeIF", false, + "fake", "0000:01:10.0", "fakeIF", false, ), Entry("net is not a directory at all", &FakeFilesystem{ Dirs: []string{"sys/bus/pci/devices/0000:01:10.0"}, Files: map[string][]byte{"sys/bus/pci/devices/0000:01:10.0/net": []byte("junk")}, }, - "0000:01:10.0", "", true, + "fake", "0000:01:10.0", "", true, + ), + Entry("device is a VF and PF is in switchdev mode", + &FakeFilesystem{ + Dirs: []string{ + "sys/bus/pci/devices/0000:01:10.0", + "sys/bus/pci/devices/0000:01:00.0/net/fakePF", + "sys/bus/pci/devices/0000:01:00.0/net/fakeVF", + }, + Symlinks: map[string]string{ + "sys/bus/pci/devices/0000:01:10.0/physfn/": "../0000:01:00.0", + }, + }, + "switchdev", "0000:01:10.0", "fakeSwitchdevPF", false, + ), + Entry("device is a PF in switchdev mode", + &FakeFilesystem{ + Dirs: []string{ + "sys/bus/pci/devices/0000:01:00.0/net/fakePF", + }, + }, + "switchdev", "0000:01:00.0", "fakeSwitchdevPF", false, + ), + Entry("device is a PF and doesn't support eswitch mode query", + &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/eswitchModeUnsupportedError/net/fakeIF"}}, + "", "eswitchModeUnsupportedError", "fakeIF", false, + ), + Entry("device is a PF and eswitch query failed", + &FakeFilesystem{Dirs: []string{"sys/bus/pci/devices/unknownError/net/fakeIF"}}, + "", "unknownError", "", true, ), )