Skip to content

Commit

Permalink
conformance-test: Filter NIC by env var
Browse files Browse the repository at this point in the history
In order to verify a specific NIC works well with
the operator, the user who runs the test suite should
be able to select involved devices.

This commit introduces the environment variable
`SRIOV_DEVICE_NAME_FILTER` to implement the selection
behavior.

examples:
`SRIOV_DEVICE_NAME_FILTER=ens1f1` tells the test suite
to use a specific device selecting it by its name

`SRIOV_DEVICE_NAME_FILTER="ens1*"` tells the test suite
that every device whose name starts with "ens1" can be
used by the tests.

Signed-off-by: Andrea Panattoni <[email protected]>
  • Loading branch information
zeeke committed Sep 29, 2023
1 parent 532df8a commit 5fbefa6
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 18 deletions.
53 changes: 35 additions & 18 deletions test/util/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -35,6 +36,8 @@ var (
intelVendorID = "8086"
)

const DeviceNameFilterEnvVar string = "SRIOV_DEVICE_NAME_FILTER"

// DiscoverSriov retrieves Sriov related information of a given cluster.
func DiscoverSriov(clients *testclient.ClientSet, operatorNamespace string) (*EnabledNodes, error) {
nodeStates, err := clients.SriovNetworkNodeStates(operatorNamespace).List(context.Background(), metav1.ListOptions{})
Expand Down Expand Up @@ -93,33 +96,47 @@ func DiscoverSriov(clients *testclient.ClientSet, operatorNamespace string) (*En

// FindOneSriovDevice retrieves a valid sriov device for the given node.
func (n *EnabledNodes) FindOneSriovDevice(node string) (*sriovv1.InterfaceExt, error) {
s, ok := n.States[node]
ret, err := n.FindSriovDevices(node)
if err != nil {
return nil, err
}

if len(ret) == 0 {
return nil, fmt.Errorf("unable to find sriov devices in node %s", node)
}

return ret[0], nil
}

// FindSriovDevices retrieves all valid sriov devices for the given node, filtered by `SRIOV_DEVICE_NAME_FILTER` environment variable.
func (n *EnabledNodes) FindSriovDevices(node string) ([]*sriovv1.InterfaceExt, error) {
devices, err := n.FindSriovDevicesIgnoreFilters(node)
if err != nil {
return nil, err
}

sriovDeviceNameFilter, ok := os.LookupEnv(DeviceNameFilterEnvVar)
if !ok {
return nil, fmt.Errorf("node %s not found", node)
return devices, nil
}
for _, itf := range s.Status.Interfaces {
if IsPFDriverSupported(itf.Driver) && sriovv1.IsSupportedDevice(itf.DeviceID) {
// Skip mlx interfaces if secure boot is enabled
// TODO: remove this when mlx support secure boot/lockdown mode
if itf.Vendor == mlxVendorID && n.IsSecureBootEnabled[node] {
continue
}

// if the sriov is not enable in the kernel for intel nic the totalVF will be 0 so we skip the device
// That is not the case for Mellanox devices that will report 0 until we configure the sriov interfaces
// with the mstconfig package
if itf.Vendor == intelVendorID && itf.TotalVfs == 0 {
continue
}
filteredDevices := []*sriovv1.InterfaceExt{}
for _, device := range devices {
match, err := regexp.MatchString(sriovDeviceNameFilter, device.Name)
if err != nil {
return nil, err
}

return &itf, nil
if match {
filteredDevices = append(filteredDevices, device)
}
}
return nil, fmt.Errorf("unable to find sriov devices in node %s", node)

return filteredDevices, nil
}

// FindSriovDevices retrieves all valid sriov devices for the given node.
func (n *EnabledNodes) FindSriovDevices(node string) ([]*sriovv1.InterfaceExt, error) {
func (n *EnabledNodes) FindSriovDevicesIgnoreFilters(node string) ([]*sriovv1.InterfaceExt, error) {
devices := []*sriovv1.InterfaceExt{}
s, ok := n.States[node]
if !ok {
Expand Down
126 changes: 126 additions & 0 deletions test/util/cluster/cluster_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package cluster

import (
"os"
"testing"

"github.com/stretchr/testify/assert"

sriovv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
)

func init() {
sriovv1.InitNicIDMapFromList([]string{
"8086 158b 154c",
"15b3 1015 1016",
})
}

func TestFindSriovDevices(t *testing.T) {
nodes := &EnabledNodes{
Nodes: []string{"worker-0", "worker-1"},
States: map[string]sriovv1.SriovNetworkNodeState{
"worker-0": {
Status: sriovv1.SriovNetworkNodeStateStatus{
Interfaces: sriovv1.InterfaceExts{
makeConnectX4LX("eno1np0", "0000:19:00.0"),
makeConnectX4LX("eno1np1", "0000:19:00.1"),
makeSfp28("ens3f0", "0000:d8:00.0"),
makeSfp28("ens3f1", "0000:d8:00.0"),
},
},
},
"worker-1": {
Status: sriovv1.SriovNetworkNodeStateStatus{
Interfaces: sriovv1.InterfaceExts{
makeConnectX4LX("eno1np0", "0000:19:00.0"),
makeConnectX4LX("eno1np1", "0000:19:00.1"),
makeSfp28("ens3f0", "0000:d8:00.0"),
makeSfp28("ens3f1", "0000:d8:00.0"),
},
},
},
},
IsSecureBootEnabled: map[string]bool{
"worker-0": false,
"worker-1": true,
},
}

w0, err := nodes.FindSriovDevices("worker-0")
assert.NoError(t, err)

w0Names := extractNames(w0)
assert.Contains(t, w0Names, "eno1np0")
assert.Contains(t, w0Names, "eno1np1")
assert.Contains(t, w0Names, "ens3f0")
assert.Contains(t, w0Names, "ens3f1")

w1, err := nodes.FindSriovDevices("worker-1")
assert.NoError(t, err)

w1Names := extractNames(w1)
// worker-1 has SecureBoot enabled
assert.NotContains(t, w1Names, "eno1np0")
assert.NotContains(t, w1Names, "eno1np1")
assert.Contains(t, w1Names, "ens3f0")
assert.Contains(t, w1Names, "ens3f1")
}

func TestFindSriovDevicesFilteredByEnv(t *testing.T) {
nodes := &EnabledNodes{
Nodes: []string{"worker-0"},
States: map[string]sriovv1.SriovNetworkNodeState{
"worker-0": {
Status: sriovv1.SriovNetworkNodeStateStatus{
Interfaces: sriovv1.InterfaceExts{
makeConnectX4LX("eno1np0", "0000:19:00.0"),
makeConnectX4LX("eno1np1", "0000:19:00.1"),
},
},
},
},
IsSecureBootEnabled: map[string]bool{
"worker-0": false,
},
}

originalValue := os.Getenv("SRIOV_DEVICE_NAME_FILTER")
defer os.Setenv("SRIOV_DEVICE_NAME_FILTER", originalValue)

os.Setenv("SRIOV_DEVICE_NAME_FILTER", "eno1np1")
w0, err := nodes.FindSriovDevices("worker-0")
assert.NoError(t, err)
w0Names := extractNames(w0)
assert.NotContains(t, w0Names, "eno1np0")
assert.Contains(t, w0Names, "eno1np1")

os.Setenv("SRIOV_DEVICE_NAME_FILTER", "eno1*")
w0, err = nodes.FindSriovDevices("worker-0")
assert.NoError(t, err)
w0Names = extractNames(w0)
assert.Contains(t, w0Names, "eno1np0")
assert.Contains(t, w0Names, "eno1np1")
}

func makeConnectX4LX(name, pci string) sriovv1.InterfaceExt {
return sriovv1.InterfaceExt{
Vendor: "15b3", DeviceID: "1015", Driver: "mlx5_core",
Name: name, TotalVfs: 8, PciAddress: pci,
}
}

func makeSfp28(name, pci string) sriovv1.InterfaceExt {
return sriovv1.InterfaceExt{
Vendor: "8086", DeviceID: "158b", Driver: "i40e",
Name: name, TotalVfs: 64, PciAddress: pci,
}
}

func extractNames(in []*sriovv1.InterfaceExt) []string {
ret := make([]string, 0, len(in))
for _, intf := range in {
ret = append(ret, intf.Name)
}
return ret
}

0 comments on commit 5fbefa6

Please sign in to comment.