Skip to content

Commit

Permalink
Don't do anything if there are no netlink interfaces
Browse files Browse the repository at this point in the history
If a pci device allocated to a container by SR-IOV device plugin is of
vfio type then it doesn't have a netlink representation, so moving the
interface into container namespace is useless and actually breaks the
CNI plugin.

We could perhaps go with a separate noop CNI plugin to do the same but
there are plans to, in the future, allocate IPAM info for the device
and expose it by one means or another (it could be a fake veth pair to
carry the information: see issue k8snetworkplumbingwg#37; or some other mechanism).

Fixes k8snetworkplumbingwg#63
  • Loading branch information
booxter committed Feb 19, 2019
1 parent a87cb21 commit 8c0e404
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 4 deletions.
35 changes: 32 additions & 3 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -138,20 +140,47 @@ 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)
if err != nil {
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())
}
Expand Down
8 changes: 7 additions & 1 deletion sriov/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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()
}

Expand Down
12 changes: 12 additions & 0 deletions sriov/sriov.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 8c0e404

Please sign in to comment.