Skip to content

Commit

Permalink
eSwitch: e2e test for Switchdev mode
Browse files Browse the repository at this point in the history
Add a basic test to loop over all available
devices and test if setting `eSwitchMode: switchdev` works.

Signed-off-by: Andrea Panattoni <apanatto@redhat.com>
  • Loading branch information
zeeke committed Aug 28, 2024
1 parent 34dcef5 commit ec85651
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 2 deletions.
9 changes: 7 additions & 2 deletions test/conformance/tests/test_sriov_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,7 @@ func findMainSriovDevice(executorPod *corev1.Pod, sriovDevices []*sriovv1.Interf
stdout, _, err = pod.ExecCommand(clients, executorPod, "ip", "link", "show", device.Name)
Expect(err).ToNot(HaveOccurred())
Expect(len(stdout)).Should(Not(Equal(0)), "Unable to query link state")

if strings.Contains(stdout, "state DOWN") {
continue // The interface is not active
}
Expand All @@ -1830,6 +1831,7 @@ func findMainSriovDevice(executorPod *corev1.Pod, sriovDevices []*sriovv1.Interf
return device
}
}

return nil
}

Expand Down Expand Up @@ -2124,7 +2126,7 @@ func createVanillaNetworkPolicy(node string, sriovInfos *cluster.EnabledNodes, n
})))
}

func runCommandOnConfigDaemon(nodeName string, command ...string) (string, string, error) {
func getConfigDaemonPod(nodeName string) *corev1.Pod {
pods := &corev1.PodList{}
label, err := labels.Parse("app=sriov-network-config-daemon")
Expect(err).ToNot(HaveOccurred())
Expand All @@ -2133,8 +2135,11 @@ func runCommandOnConfigDaemon(nodeName string, command ...string) (string, strin
err = clients.List(context.Background(), pods, &runtimeclient.ListOptions{Namespace: operatorNamespace, LabelSelector: label, FieldSelector: field})
Expect(err).ToNot(HaveOccurred())
Expect(len(pods.Items)).To(Equal(1))
return &pods.Items[0]
}

output, errOutput, err := pod.ExecCommand(clients, &pods.Items[0], command...)
func runCommandOnConfigDaemon(nodeName string, command ...string) (string, string, error) {
output, errOutput, err := pod.ExecCommand(clients, getConfigDaemonPod(nodeName), command...)
return output, errOutput, err
}

Expand Down
103 changes: 103 additions & 0 deletions test/conformance/tests/test_switchdev.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package tests

import (
"context"
"fmt"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

sriovv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/cluster"
"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/discovery"
"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/namespaces"
"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/network"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("[sriov] Switchdev", Ordered, func() {

BeforeAll(func() {
if cluster.VirtualCluster() {
Skip("IGB driver does not support switchdev driver model")
}

err := namespaces.Create(namespaces.Test, clients)
Expect(err).ToNot(HaveOccurred())

err = namespaces.Clean(operatorNamespace, namespaces.Test, clients, discovery.Enabled())
Expect(err).ToNot(HaveOccurred())

WaitForSRIOVStable()
})

It("create switchdev policies on supported devices", func() {
sriovInfos, err := cluster.DiscoverSriov(clients, operatorNamespace)
Expect(err).ToNot(HaveOccurred())
Expect(len(sriovInfos.Nodes)).ToNot(BeZero())

testNode, interfaces, err := sriovInfos.FindSriovDevicesAndNode()
Expect(err).ToNot(HaveOccurred())

// Avoid testing against primary NIC
interfaces, err = findUnusedSriovDevices(testNode, interfaces)
Expect(err).ToNot(HaveOccurred())

// Avoid testing the same NIC model more than once
interfaces = filterDuplicateNICModels(interfaces)

By(fmt.Sprintf("Testing on node %s, %d devices found", testNode, len(interfaces)))

for _, intf := range interfaces {
if !doesInterfaceSupportSwitchdev(intf) {
continue
}

By("Testing device " + intf.Name + " on node " + testNode)
resourceName := "swtichdev" + intf.Name
_, err = network.CreateSriovPolicy(clients, "test-switchdev-policy-", operatorNamespace, intf.Name, testNode, 8, resourceName, "netdevice", func(snnp *sriovv1.SriovNetworkNodePolicy) {
snnp.Spec.EswitchMode = "switchdev"
})
Expect(err).ToNot(HaveOccurred())

WaitForSRIOVStable()

Eventually(func() int64 {
testedNode, err := clients.CoreV1Interface.Nodes().Get(context.Background(), testNode, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
resNum := testedNode.Status.Allocatable[corev1.ResourceName("openshift.io/"+resourceName)]
capacity, _ := resNum.AsInt64()
return capacity
}, 10*time.Minute, time.Second).Should(Equal(int64(8)))
}
})
})

func doesInterfaceSupportSwitchdev(intf *sriovv1.InterfaceExt) bool {
if intf.Driver == "mlx5_core" {
return true
}

if intf.Driver == "ice" {
return true
}

return false
}

func filterDuplicateNICModels(devices []*sriovv1.InterfaceExt) []*sriovv1.InterfaceExt {
foundVendorAndModels := map[string]bool{}
ret := []*sriovv1.InterfaceExt{}

for _, device := range devices {
vendorAndDevice := device.Vendor + "_" + device.DeviceID
if _, value := foundVendorAndModels[vendorAndDevice]; !value {
ret = append(ret, device)
foundVendorAndModels[vendorAndDevice] = true
}
}
return ret
}
27 changes: 27 additions & 0 deletions test/util/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,33 @@ func (n *EnabledNodes) FindSriovDevices(node string) ([]*sriovv1.InterfaceExt, e
return filteredDevices, nil
}

// FindSriovDevicesAndNode retrieves the node with the most number of SRIOV devices after filtering by `SRIOV_NODE_AND_DEVICE_NAME_FILTER` environment variable.
func (n *EnabledNodes) FindSriovDevicesAndNode() (string, []*sriovv1.InterfaceExt, error) {
errs := []error{}

retNode := ""
retDevices := []*sriovv1.InterfaceExt{}

for _, node := range n.Nodes {
devices, err := n.FindSriovDevices(node)
if err != nil {
errs = append(errs, err)
continue
}

if len(devices) > len(retDevices) {
retNode = node
retDevices = devices
}
}

if len(retDevices) == 0 {
return "", nil, fmt.Errorf("can't find any SR-IOV devices in cluster's nodes: %w", errors.Join(errs...))
}

return retNode, retDevices, nil
}

// FindSriovDevicesIgnoreFilters retrieves all valid sriov devices for the given node.
func (n *EnabledNodes) FindSriovDevicesIgnoreFilters(node string) ([]*sriovv1.InterfaceExt, error) {
devices := []*sriovv1.InterfaceExt{}
Expand Down

0 comments on commit ec85651

Please sign in to comment.