diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 961394117..d24928a0f 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -15,6 +15,8 @@ var ( NetDirectory = "/sys/class/net" // SysBusPci is sysfs pci device directory SysBusPci = "/sys/bus/pci/devices" + // UserspaceDrivers is a list of driver names that don't have netlink representation for their devices + UserspaceDrivers = []string{"vfio-pci", "uio_pci_generic"} ) // GetSriovNumVfs takes in a PF name(ifName) as string and returns number of VF configured as int @@ -138,12 +140,40 @@ func GetSharedPF(ifName string) (string, error) { return pfName, fmt.Errorf("Shared PF not found") } +// ShouldHaveNetlink determines whether VF is expected to have a netlink interface +func ShouldHaveNetlink(pfName string, vfID int) (bool, error) { + driverLink := filepath.Join(NetDirectory, pfName, "device", fmt.Sprintf("virtfn%d", vfID), "driver") + driverPath, err := filepath.EvalSymlinks(driverLink) + if err != nil { + return false, err + } + driverStat, err := os.Stat(driverPath) + if err != nil { + return false, err + } + driverName := driverStat.Name() + for _, drv := range UserspaceDrivers { + if driverName == drv { + return false, nil + } + } + return true, nil +} + // GetVFLinkNames returns VF's network interface name given it's PF name as string and VF id as int func GetVFLinkNames(pfName string, vfID int) ([]string, error) { - var names []string + var names = make([]string, 0) + vfDir := filepath.Join(NetDirectory, pfName, "device", fmt.Sprintf("virtfn%d", vfID), "net") if _, err := os.Lstat(vfDir); err != nil { - return nil, err + netlinkExpected, shouldHaveNetlinkErr := ShouldHaveNetlink(pfName, vfID) + if shouldHaveNetlinkErr != nil { + return nil, shouldHaveNetlinkErr + } + if netlinkExpected { + return nil, err + } + return names, nil } fInfos, err := ioutil.ReadDir(vfDir) @@ -151,7 +181,6 @@ func GetVFLinkNames(pfName string, vfID int) ([]string, error) { return nil, fmt.Errorf("failed to read the virtfn%d dir of the device %q: %v", vfID, pfName, err) } - names = make([]string, 0) for _, f := range fInfos { names = append(names, f.Name()) } diff --git a/sriov/main.go b/sriov/main.go index a427eaf95..b67ba246e 100644 --- a/sriov/main.go +++ b/sriov/main.go @@ -11,6 +11,7 @@ import ( "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/version" "github.com/intel/sriov-cni/pkg/config" + "github.com/intel/sriov-cni/pkg/utils" "github.com/vishvananda/netlink" ) @@ -78,9 +79,14 @@ func cmdAdd(args *skel.CmdArgs) error { return fmt.Errorf("VF information are not available to invoke setupVF()") } + vfLinks, err := utils.GetVFLinkNames(n.Master, n.DeviceInfo.Vfid) + if err != nil { + return err + } + // skip the IPAM allocation for the DPDK and L2 mode var result *types.Result - if n.DPDKMode || n.L2Mode { + if n.DPDKMode || n.L2Mode || len(vfLinks) == 0 { return result.Print() } diff --git a/sriov/sriov.go b/sriov/sriov.go index 055b7ea59..897760894 100644 --- a/sriov/sriov.go +++ b/sriov/sriov.go @@ -114,6 +114,10 @@ func setupVF(conf *sriovtypes.NetConf, podifName string, cid string, netns ns.Ne return err } + if len(vfLinks) == 0 { + return nil + } + if conf.Vlan != 0 { if err = netlink.LinkSetVfVlan(m, conf.DeviceInfo.Vfid, conf.Vlan); err != nil { return fmt.Errorf("failed to set vf %d vlan: %v", conf.DeviceInfo.Vfid, err) @@ -201,6 +205,14 @@ func releaseVF(conf *sriovtypes.NetConf, podifName string, cid string, netns ns. return nil } + netlinkExpected, err := utils.ShouldHaveNetlink(conf.Master, conf.DeviceInfo.Vfid) + if err != nil { + return fmt.Errorf("failed to determine if interface should have netlink device: %v", err) + } + if !netlinkExpected { + return nil + } + initns, err := ns.GetCurrentNS() if err != nil { return fmt.Errorf("failed to get init netns: %v", err)