From 73f3ce1e2c9717e8ba89d966a8c5c3fb53f254a2 Mon Sep 17 00:00:00 2001 From: Ye Yin Date: Fri, 5 May 2017 11:39:59 +0800 Subject: [PATCH] Support VF self Management --- README.md | 2 +- sriov/sriov.go | 94 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 78 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 46d60a1b9..5ed35b112 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ options ixgbe max_vfs=8,8 ## Extra arguments -* `vf` (int, optional): VF index, default value is 0 +* `vf` (int, optional): VF index. This plugin will allocate a free VF if not assigned * `vlan` (int, optional): VLAN ID for VF device * `mac` (string, optional): mac address for VF device diff --git a/sriov/sriov.go b/sriov/sriov.go index 60697161e..dcd629aa6 100644 --- a/sriov/sriov.go +++ b/sriov/sriov.go @@ -7,6 +7,8 @@ import ( "net" "os" "runtime" + "strconv" + "strings" "github.com/containernetworking/cni/pkg/ipam" "github.com/containernetworking/cni/pkg/ns" @@ -24,36 +26,33 @@ func init() { } func setupVF(conf *SriovConf, ifName string, netns ns.NetNS) error { + var ( + err error + vfDevName string + ) + vfIdx := 0 masterName := conf.Net.Master args := conf.Args if args.VF != 0 { vfIdx = int(args.VF) + vfDevName, err = getVFDeviceName(masterName, vfIdx) + if err != nil { + return err + } + } else { + // alloc a free virtual function + if vfIdx, vfDevName, err = allocFreeVF(masterName); err != nil { + return err + } } - // TODO: if conf.VF == nil, alloc vf randomly m, err := netlink.LinkByName(masterName) if err != nil { return fmt.Errorf("failed to lookup master %q: %v", masterName, err) } - vfDir := fmt.Sprintf("/sys/class/net/%s/device/virtfn%d/net", masterName, vfIdx) - if _, err := os.Lstat(vfDir); err != nil { - return err - } - - infos, err := ioutil.ReadDir(vfDir) - if err != nil { - return err - } - - if len(infos) != 1 { - return fmt.Errorf("no network devices in directory %s", vfDir) - } - - // VF NIC name - vfDevName := infos[0].Name() vfDev, err := netlink.LinkByName(vfDevName) if err != nil { return fmt.Errorf("failed to lookup vf device %q: %v", vfDevName, err) @@ -202,6 +201,67 @@ func renameLink(curName, newName string) error { return netlink.LinkSetName(link, newName) } +func allocFreeVF(master string) (int, string, error) { + vfIdx := -1 + devName := "" + + sriovFile := fmt.Sprintf("/sys/class/net/%s/device/sriov_numvfs", master) + if _, err := os.Lstat(sriovFile); err != nil { + return -1, "", fmt.Errorf("failed to open the sriov_numfs of device %q: %v", master, err) + } + + data, err := ioutil.ReadFile(sriovFile) + if err != nil { + return -1, "", fmt.Errorf("failed to read the sriov_numfs of device %q: %v", master, err) + } + + if len(data) == 0 { + return -1, "", fmt.Errorf("no data in the file %q", sriovFile) + } + + sriovNumfs := strings.TrimSpace(string(data)) + vfTotal, err := strconv.Atoi(sriovNumfs) + if err != nil { + return -1, "", fmt.Errorf("failed to convert sriov_numfs(byte value) to int of device %q: %v", master, err) + } + + if vfTotal <= 0 { + return -1, "", fmt.Errorf("no virtual function in the device %q: %v", master) + } + + for vf := 0; vf < vfTotal; vf++ { + devName, err = getVFDeviceName(master, vf) + + // got a free vf + if err == nil { + vfIdx = vf + break + } + } + + if vfIdx == -1 { + return -1, "", fmt.Errorf("can not get a free virtual function in directory %s", master) + } + return vfIdx, devName, nil +} + +func getVFDeviceName(master string, vf int) (string, error) { + vfDir := fmt.Sprintf("/sys/class/net/%s/device/virtfn%d/net", master, vf) + if _, err := os.Lstat(vfDir); err != nil { + return "", fmt.Errorf("failed to open the virtfn%d dir of the device %q: %v", vf, master, err) + } + + infos, err := ioutil.ReadDir(vfDir) + if err != nil { + return "", fmt.Errorf("failed to read the virtfn%d dir of the device %q: %v", vf, master, err) + } + + if len(infos) != 1 { + return "", fmt.Errorf("no network device in directory %s", vfDir) + } + return infos[0].Name(), nil +} + func main() { skel.PluginMain(cmdAdd, cmdDel) }