Files
netlink/devlink_test.go
Vishvananda Abrams d79d27a836 remove testify deps
2025-08-27 20:37:11 +00:00

769 lines
24 KiB
Go

//go:build linux
// +build linux
package netlink
import (
"flag"
"fmt"
"math/rand"
"net"
"os"
"strconv"
"strings"
"syscall"
"testing"
"github.com/vishvananda/netlink/nl"
)
func TestDevLinkGetDeviceList(t *testing.T) {
minKernelRequired(t, 4, 12)
setUpNetlinkTestWithKModule(t, "devlink")
_, err := DevLinkGetDeviceList()
if err != nil {
t.Fatal(err)
}
}
func TestDevLinkGetDeviceByName(t *testing.T) {
minKernelRequired(t, 4, 12)
setUpNetlinkTestWithKModule(t, "devlink")
_, err := DevLinkGetDeviceByName("foo", "bar")
if err != nil {
t.Fatal(err)
}
}
func TestDevLinkSetEswitchMode(t *testing.T) {
minKernelRequired(t, 4, 12)
setUpNetlinkTestWithKModule(t, "devlink")
dev, err := DevLinkGetDeviceByName("foo", "bar")
if err != nil {
t.Fatal(err)
}
err = DevLinkSetEswitchMode(dev, "switchdev")
if err != nil {
t.Fatal(err)
}
err = DevLinkSetEswitchMode(dev, "legacy")
if err != nil {
t.Fatal(err)
}
}
func logPort(t *testing.T, port *DevlinkPort) {
type field struct {
key string
value string
}
fields := []field{}
fields = append(fields, field{key: "bus", value: port.BusName})
fields = append(fields, field{key: "device", value: port.DeviceName})
fields = append(fields, field{key: "port_index", value: strconv.Itoa(int(port.PortIndex))})
fields = append(fields, field{key: "port_type", value: strconv.Itoa(int(port.PortType))})
fields = append(fields, field{key: "port_flavour", value: strconv.Itoa(int(port.PortFlavour))})
fields = append(fields, field{key: "netdev_name", value: port.NetdeviceName})
fields = append(fields, field{key: "netdev_index", value: strconv.Itoa(int(port.NetdevIfIndex))})
fields = append(fields, field{key: "rdma_dev_name", value: port.RdmaDeviceName})
if port.Fn != nil {
fields = append(fields, field{key: "hw_addr", value: port.Fn.HwAddr.String()})
fields = append(fields, field{key: "state", value: strconv.Itoa(int(port.Fn.State))})
fields = append(fields, field{key: "op_state", value: strconv.Itoa(int(port.Fn.OpState))})
}
if port.PortNumber != nil {
fields = append(fields, field{key: "port_number", value: strconv.Itoa(int(*port.PortNumber))})
}
if port.PfNumber != nil {
fields = append(fields, field{key: "pf_number", value: strconv.Itoa(int(*port.PfNumber))})
}
if port.VfNumber != nil {
fields = append(fields, field{key: "vf_number", value: strconv.Itoa(int(*port.VfNumber))})
}
if port.SfNumber != nil {
fields = append(fields, field{key: "sf_number", value: strconv.Itoa(int(*port.SfNumber))})
}
if port.ControllerNumber != nil {
fields = append(fields, field{key: "controller_number", value: strconv.Itoa(int(*port.ControllerNumber))})
}
if port.External != nil {
fields = append(fields, field{key: "external", value: strconv.FormatBool(*port.External)})
}
fieldsStr := []string{}
for _, field := range fields {
fieldsStr = append(fieldsStr, fmt.Sprintf("%s=%s", field.key, field.value))
}
t.Log(strings.Join(fieldsStr, " "))
}
func TestDevLinkGetAllPortList(t *testing.T) {
minKernelRequired(t, 5, 4)
ports, err := DevLinkGetAllPortList()
if err != nil {
t.Fatal(err)
}
t.Log("devlink port count = ", len(ports))
for _, port := range ports {
logPort(t, port)
}
}
func TestDevLinkAddDelSfPort(t *testing.T) {
var addAttrs DevLinkPortAddAttrs
minKernelRequired(t, 5, 13)
if bus == "" || device == "" {
t.Log("devlink bus and device are empty, skipping test")
return
}
dev, err := DevLinkGetDeviceByName(bus, device)
if err != nil {
t.Fatal(err)
return
}
addAttrs.SfNumberValid = true
addAttrs.SfNumber = uint32(sfnum)
addAttrs.PfNumber = 0
port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs)
if err2 != nil {
t.Fatal(err2)
return
}
t.Log(*port)
if port.Fn != nil {
t.Log("function attributes = ", *port.Fn)
}
err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex)
if err2 != nil {
t.Fatal(err2)
}
}
func TestDevLinkSfPortFnSet(t *testing.T) {
var addAttrs DevLinkPortAddAttrs
var stateAttr DevlinkPortFnSetAttrs
minKernelRequired(t, 5, 12)
if bus == "" || device == "" {
t.Log("devlink bus and device are empty, skipping test")
return
}
dev, err := DevLinkGetDeviceByName(bus, device)
if err != nil {
t.Fatal(err)
return
}
addAttrs.SfNumberValid = true
addAttrs.SfNumber = uint32(sfnum)
addAttrs.PfNumber = 0
port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs)
if err2 != nil {
t.Fatal(err2)
return
}
t.Log(*port)
if port.Fn != nil {
t.Log("function attributes = ", *port.Fn)
}
macAttr := DevlinkPortFnSetAttrs{
FnAttrs: DevlinkPortFn{
HwAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
HwAddrValid: true,
}
err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, macAttr)
if err2 != nil {
t.Log("function mac set err = ", err2)
}
stateAttr.FnAttrs.State = 1
stateAttr.StateValid = true
err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, stateAttr)
if err2 != nil {
t.Log("function state set err = ", err2)
}
port, err3 := DevLinkGetPortByIndex(dev.BusName, dev.DeviceName, port.PortIndex)
if err3 == nil {
t.Log(*port)
t.Log(*port.Fn)
}
err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex)
if err2 != nil {
t.Fatal(err2)
}
}
var bus string
var device string
var sfnum uint
func init() {
flag.StringVar(&bus, "bus", "", "devlink device bus name")
flag.StringVar(&device, "device", "", "devlink device devicename")
flag.UintVar(&sfnum, "sfnum", 0, "devlink port sfnumber")
}
func TestDevlinkGetDeviceInfoByNameAsMap(t *testing.T) {
info, err := pkgHandle.DevlinkGetDeviceInfoByNameAsMap("pci", "0000:00:00.0", mockDevlinkInfoGetter)
if err != nil {
t.Fatal(err)
}
testInfo := devlinkTestInfoParesd()
for k, v := range info {
if testInfo[k] != v {
t.Fatal("Value", v, "retrieved for key", k, "is not equal to", testInfo[k])
}
}
}
func TestDevlinkGetDeviceInfoByName(t *testing.T) {
info, err := pkgHandle.DevlinkGetDeviceInfoByName("pci", "0000:00:00.0", mockDevlinkInfoGetter)
if err != nil {
t.Fatal(err)
}
testInfo := parseInfoData(devlinkTestInfoParesd())
if !areInfoStructsEqual(info, testInfo) {
t.Fatal("Info structures are not equal")
}
}
func TestDevlinkGetDeviceInfoByNameAsMapFail(t *testing.T) {
_, err := pkgHandle.DevlinkGetDeviceInfoByNameAsMap("pci", "0000:00:00.0", mockDevlinkInfoGetterEmpty)
if err == nil {
t.Fatal()
}
}
func TestDevlinkGetDeviceInfoByNameFail(t *testing.T) {
_, err := pkgHandle.DevlinkGetDeviceInfoByName("pci", "0000:00:00.0", mockDevlinkInfoGetterEmpty)
if err == nil {
t.Fatal()
}
}
func mockDevlinkInfoGetter(bus, device string) ([]byte, error) {
return devlinkInfo(), nil
}
func mockDevlinkInfoGetterEmpty(bus, device string) ([]byte, error) {
return []byte{}, nil
}
func devlinkInfo() []byte {
return []byte{51, 1, 0, 0, 8, 0, 1, 0, 112, 99, 105, 0, 17, 0, 2, 0, 48,
48, 48, 48, 58, 56, 52, 58, 48, 48, 46, 48, 0, 0, 0, 0, 8, 0, 98, 0,
105, 99, 101, 0, 28, 0, 99, 0, 51, 48, 45, 56, 57, 45, 97, 51, 45,
102, 102, 45, 102, 102, 45, 99, 97, 45, 48, 53, 45, 54, 56, 0, 36,
0, 100, 0, 13, 0, 103, 0, 98, 111, 97, 114, 100, 46, 105, 100, 0, 0,
0, 0, 15, 0, 104, 0, 75, 56, 53, 53, 56, 53, 45, 48, 48, 48, 0, 0,
28, 0, 101, 0, 12, 0, 103, 0, 102, 119, 46, 109, 103, 109, 116, 0,
10, 0, 104, 0, 53, 46, 52, 46, 53, 0, 0, 0, 28, 0, 101, 0, 16, 0,
103, 0, 102, 119, 46, 109, 103, 109, 116, 46, 97, 112, 105, 0, 8, 0,
104, 0, 49, 46, 55, 0, 40, 0, 101, 0, 18, 0, 103, 0, 102, 119, 46,
109, 103, 109, 116, 46, 98, 117, 105, 108, 100, 0, 0, 0, 15, 0, 104,
0, 48, 120, 51, 57, 49, 102, 55, 54, 52, 48, 0, 0, 32, 0, 101, 0,
12, 0, 103, 0, 102, 119, 46, 117, 110, 100, 105, 0, 13, 0, 104, 0,
49, 46, 50, 56, 57, 56, 46, 48, 0, 0, 0, 0, 32, 0, 101, 0, 16, 0,
103, 0, 102, 119, 46, 112, 115, 105, 100, 46, 97, 112, 105, 0, 9, 0,
104, 0, 50, 46, 52, 50, 0, 0, 0, 0, 40, 0, 101, 0, 17, 0, 103, 0,
102, 119, 46, 98, 117, 110, 100, 108, 101, 95, 105, 100, 0, 0, 0, 0,
15, 0, 104, 0, 48, 120, 56, 48, 48, 48, 55, 48, 54, 98, 0, 0, 48, 0,
101, 0, 16, 0, 103, 0, 102, 119, 46, 97, 112, 112, 46, 110, 97, 109,
101, 0, 27, 0, 104, 0, 73, 67, 69, 32, 79, 83, 32, 68, 101, 102, 97,
117, 108, 116, 32, 80, 97, 99, 107, 97, 103, 101, 0, 0, 32, 0, 101,
0, 11, 0, 103, 0, 102, 119, 46, 97, 112, 112, 0, 0, 13, 0, 104, 0,
49, 46, 51, 46, 50, 52, 46, 48, 0, 0, 0, 0, 44, 0, 101, 0, 21, 0,
103, 0, 102, 119, 46, 97, 112, 112, 46, 98, 117, 110, 100, 108,
101, 95, 105, 100, 0, 0, 0, 0, 15, 0, 104, 0, 48, 120, 99, 48, 48,
48, 48, 48, 48, 49, 0, 0, 44, 0, 101, 0, 15, 0, 103, 0, 102, 119,
46, 110, 101, 116, 108, 105, 115, 116, 0, 0, 21, 0, 104, 0, 50, 46,
52, 48, 46, 50, 48, 48, 48, 45, 51, 46, 49, 54, 46, 48, 0, 0, 0, 0,
44, 0, 101, 0, 21, 0, 103, 0, 102, 119, 46, 110, 101, 116, 108, 105,
115, 116, 46, 98, 117, 105, 108, 100, 0, 0, 0, 0, 15, 0, 104, 0, 48,
120, 54, 55, 54, 97, 52, 56, 57, 100, 0, 0}
}
func devlinkTestInfoParesd() map[string]string {
return map[string]string{
"board.id": "K85585-000",
"fw.app": "1.3.24.0",
"fw.app.bundle_id": "0xc0000001",
"fw.app.name": "ICE OS Default Package",
"fw.bundle_id": "0x8000706b",
"fw.mgmt": "5.4.5",
"fw.mgmt.api": "1.7",
"fw.mgmt.build": "0x391f7640",
"fw.netlist": "2.40.2000-3.16.0",
"fw.netlist.build": "0x676a489d",
"fw.psid.api": "2.42",
"fw.undi": "1.2898.0",
"driver": "ice",
"serialNumber": "30-89-a3-ff-ff-ca-05-68",
}
}
func areInfoStructsEqual(first *DevlinkDeviceInfo, second *DevlinkDeviceInfo) bool {
if first.FwApp != second.FwApp || first.FwAppBoundleID != second.FwAppBoundleID ||
first.FwAppName != second.FwAppName || first.FwBoundleID != second.FwBoundleID ||
first.FwMgmt != second.FwMgmt || first.FwMgmtAPI != second.FwMgmtAPI ||
first.FwMgmtBuild != second.FwMgmtBuild || first.FwNetlist != second.FwNetlist ||
first.FwNetlistBuild != second.FwNetlistBuild || first.FwPsidAPI != second.FwPsidAPI ||
first.BoardID != second.BoardID || first.FwUndi != second.FwUndi ||
first.Driver != second.Driver || first.SerialNumber != second.SerialNumber {
return false
}
return true
}
func TestDevlinkGetDeviceResources(t *testing.T) {
minKernelRequired(t, 5, 11)
tearDown := setUpNetlinkTestWithKModule(t, "devlink")
defer tearDown()
if bus == "" || device == "" {
//TODO: setup netdevsim device instead of getting device from flags
t.Log("devlink bus and device are empty, skipping test")
t.SkipNow()
}
res, err := DevlinkGetDeviceResources(bus, device)
if err != nil {
t.Fatalf("failed to get device(%s/%s) resources. %s", bus, device, err)
}
if res.Bus != bus || res.Device != device {
t.Fatalf("missmatching bus/device")
}
t.Logf("Resources: %+v", res)
}
// devlink device parameters can be tested with netdevsim
// function will create netdevsim/netdevsim<random_id> virtual device that can be used for testing
// netdevsim module should be loaded to run devlink param tests
func setupDevlinkDeviceParamTest(t *testing.T) (string, string, func()) {
t.Helper()
skipUnlessRoot(t)
skipUnlessKModuleLoaded(t, "netdevsim")
testDevID := strconv.Itoa(1000 + rand.Intn(1000))
err := os.WriteFile("/sys/bus/netdevsim/new_device", []byte(testDevID), 0755)
if err != nil {
t.Fatalf("can't create netdevsim test device %s: %v", testDevID, err)
}
return "netdevsim", "netdevsim" + testDevID, func() {
_ = os.WriteFile("/sys/bus/netdevsim/del_device", []byte(testDevID), 0755)
}
}
func TestDevlinkGetDeviceParams(t *testing.T) {
busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t)
defer cleanupFunc()
params, err := DevlinkGetDeviceParams(busName, deviceName)
if err != nil {
t.Fatalf("failed to get device(%s/%s) parameters. %s", busName, deviceName, err)
}
if len(params) == 0 {
t.Fatal("parameters list is empty")
}
for _, p := range params {
validateDeviceParams(t, p)
}
}
func TestDevlinkGetDeviceParamByName(t *testing.T) {
busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t)
defer cleanupFunc()
param, err := DevlinkGetDeviceParamByName(busName, deviceName, "max_macs")
if err != nil {
t.Fatalf("failed to get device(%s/%s) parameter max_macs. %s", busName, deviceName, err)
}
validateDeviceParams(t, param)
}
func TestDevlinkSetDeviceParam(t *testing.T) {
busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t)
defer cleanupFunc()
err := DevlinkSetDeviceParam(busName, deviceName, "max_macs", nl.DEVLINK_PARAM_CMODE_DRIVERINIT, uint32(8))
if err != nil {
t.Fatalf("failed to set max_macs for device(%s/%s): %s", busName, deviceName, err)
}
param, err := DevlinkGetDeviceParamByName(busName, deviceName, "max_macs")
if err != nil {
t.Fatalf("failed to get device(%s/%s) parameter max_macs. %s", busName, deviceName, err)
}
validateDeviceParams(t, param)
v, ok := param.Values[0].Data.(uint32)
if !ok {
t.Fatalf("unexpected value")
}
if v != uint32(8) {
t.Fatalf("value not set")
}
}
func validateDeviceParams(t *testing.T, p *DevlinkParam) {
if p.Name == "" {
t.Fatal("Name field not set")
}
if p.Name == "max_macs" && !p.IsGeneric {
t.Fatal("IsGeneric should be true for generic parameter")
}
// test1 is a driver-specific parameter in netdevsim device, check should
// also path on HW devices
if p.Name == "test1" && p.IsGeneric {
t.Fatal("IsGeneric should be false for driver-specific parameter")
}
switch p.Type {
case nl.DEVLINK_PARAM_TYPE_U8,
nl.DEVLINK_PARAM_TYPE_U16,
nl.DEVLINK_PARAM_TYPE_U32,
nl.DEVLINK_PARAM_TYPE_STRING,
nl.DEVLINK_PARAM_TYPE_BOOL:
default:
t.Fatal("Type has unexpected value")
}
if len(p.Values) == 0 {
t.Fatal("Values are not set")
}
for _, v := range p.Values {
switch v.CMODE {
case nl.DEVLINK_PARAM_CMODE_RUNTIME,
nl.DEVLINK_PARAM_CMODE_DRIVERINIT,
nl.DEVLINK_PARAM_CMODE_PERMANENT:
default:
t.Fatal("CMODE has unexpected value")
}
if p.Name == "max_macs" {
_, ok := v.Data.(uint32)
if !ok {
t.Fatalf("value max_macs has wrong type: %T, expected: uint32", v.Data)
}
}
if p.Name == "test1" {
_, ok := v.Data.(bool)
if !ok {
t.Fatalf("value test1 has wrong type: %T, expected: bool", v.Data)
}
}
}
}
func testGetDevlinkPortCommonAttrs() []*nl.RtAttr {
nlAttrs := []*nl.RtAttr{}
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, nl.ZeroTerminated("pci")),
nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, nl.ZeroTerminated("0000:08:00.0")),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(131071)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_TYPE, nl.Uint16Attr(nl.DEVLINK_PORT_TYPE_ETH)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NETDEV_NAME, nl.ZeroTerminated("eth0")),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX, nl.Uint32Attr(5)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_IBDEV_NAME, nl.ZeroTerminated("rdma0")),
)
return nlAttrs
}
func testAddDevlinkPortPhysicalAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PHYSICAL)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NUMBER, nl.Uint32Attr(1)),
)
return nlAttrs
}
func testAddDevlinkPortPfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_PF)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(1)),
)
return nlAttrs
}
func testAddDevlinkPortVfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_VF)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(0)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_VF_NUMBER, nl.Uint16Attr(4)),
)
nlAttrs = testAddDevlinkPortFnAttrs(nlAttrs)
return nlAttrs
}
func testAddDevlinkPortSfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_SF)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(0)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(123)),
)
nlAttrs = testAddDevlinkPortFnAttrs(nlAttrs)
return nlAttrs
}
func testNlAttrsToNetlinkRouteAttrs(nlAttrs []*nl.RtAttr) []syscall.NetlinkRouteAttr {
attrs := []syscall.NetlinkRouteAttr{}
for _, attr := range nlAttrs {
attrs = append(attrs, syscall.NetlinkRouteAttr{Attr: syscall.RtAttr(attr.RtAttr), Value: attr.Data})
}
return attrs
}
func testAddDevlinkPortFnAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
hwAddr, _ := net.ParseMAC("00:11:22:33:44:55")
hwAddrAttr := nl.NewRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(hwAddr))
raw := hwAddrAttr.Serialize()
nlAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION, raw)
return append(nlAttrs, nlAttr)
}
func testAddDevlinkPortControllerAttrs(nlAttrs []*nl.RtAttr, controllerNumber uint32, external bool) []*nl.RtAttr {
extVal := uint8(0)
if external {
extVal = 1
}
nlAttrs = append(nlAttrs,
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(controllerNumber)),
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_EXTERNAL, nl.Uint8Attr(extVal)),
)
return nlAttrs
}
func testAssertCommonAttrs(t *testing.T, port *DevlinkPort) {
if port.BusName != "pci" {
t.Errorf("expected BusName to be 'pci', got %s", port.BusName)
}
if port.DeviceName != "0000:08:00.0" {
t.Errorf("expected DeviceName to be '0000:08:00.0', got %s", port.DeviceName)
}
if port.PortIndex != uint32(131071) {
t.Errorf("expected PortIndex to be 131071, got %d", port.PortIndex)
}
if port.PortType != uint16(nl.DEVLINK_PORT_TYPE_ETH) {
t.Errorf("expected PortType to be %d, got %d", nl.DEVLINK_PORT_TYPE_ETH, port.PortType)
}
if port.NetdeviceName != "eth0" {
t.Errorf("expected NetdeviceName to be 'eth0', got %s", port.NetdeviceName)
}
if port.NetdevIfIndex != uint32(5) {
t.Errorf("expected NetdevIfIndex to be 5, got %d", port.NetdevIfIndex)
}
if port.RdmaDeviceName != "rdma0" {
t.Errorf("expected RdmaDeviceName to be 'rdma0', got %s", port.RdmaDeviceName)
}
}
func TestDevlinkPortParseAttributes(t *testing.T) {
t.Run("flavor physical", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortPhysicalAttrs(nlAttrs)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
testAssertCommonAttrs(t, port)
if port.PortFlavour != uint16(nl.DEVLINK_PORT_FLAVOUR_PHYSICAL) {
t.Errorf("expected PortFlavour to be %d, got %d", nl.DEVLINK_PORT_FLAVOUR_PHYSICAL, port.PortFlavour)
}
if *port.PortNumber != uint32(1) {
t.Errorf("expected PortNumber to be 1, got %d", *port.PortNumber)
}
if port.Fn != nil {
t.Errorf("expected Fn to be nil, got %v", port.Fn)
}
if port.PfNumber != nil {
t.Errorf("expected PfNumber to be nil, got %v", port.PfNumber)
}
if port.VfNumber != nil {
t.Errorf("expected VfNumber to be nil, got %v", port.VfNumber)
}
if port.SfNumber != nil {
t.Errorf("expected SfNumber to be nil, got %v", port.SfNumber)
}
if port.ControllerNumber != nil {
t.Errorf("expected ControllerNumber to be nil, got %v", port.ControllerNumber)
}
if port.External != nil {
t.Errorf("expected External to be nil, got %v", port.External)
}
})
t.Run("flavor pcipf", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortPfAttrs(nlAttrs)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
testAssertCommonAttrs(t, port)
if port.PortFlavour != uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_PF) {
t.Errorf("expected PortFlavour to be %d, got %d", nl.DEVLINK_PORT_FLAVOUR_PCI_PF, port.PortFlavour)
}
if *port.PfNumber != uint16(1) {
t.Errorf("expected PfNumber to be 1, got %d", *port.PfNumber)
}
if port.Fn != nil {
t.Errorf("expected Fn to be nil, got %v", port.Fn)
}
if port.PortNumber != nil {
t.Errorf("expected PortNumber to be nil, got %v", port.PortNumber)
}
if port.VfNumber != nil {
t.Errorf("expected VfNumber to be nil, got %v", port.VfNumber)
}
if port.SfNumber != nil {
t.Errorf("expected SfNumber to be nil, got %v", port.SfNumber)
}
if port.ControllerNumber != nil {
t.Errorf("expected ControllerNumber to be nil, got %v", port.ControllerNumber)
}
if port.External != nil {
t.Errorf("expected External to be nil, got %v", port.External)
}
})
t.Run("flavor pcivf", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
testAssertCommonAttrs(t, port)
if port.PortFlavour != uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_VF) {
t.Errorf("expected PortFlavour to be %d, got %d", nl.DEVLINK_PORT_FLAVOUR_PCI_VF, port.PortFlavour)
}
if *port.PfNumber != uint16(0) {
t.Errorf("expected PfNumber to be 0, got %d", *port.PfNumber)
}
if *port.VfNumber != uint16(4) {
t.Errorf("expected VfNumber to be 4, got %d", *port.VfNumber)
}
if port.Fn.HwAddr.String() != "00:11:22:33:44:55" {
t.Errorf("expected HwAddr to be '00:11:22:33:44:55', got %s", port.Fn.HwAddr.String())
}
if port.PortNumber != nil {
t.Errorf("expected PortNumber to be nil, got %v", port.PortNumber)
}
if port.SfNumber != nil {
t.Errorf("expected SfNumber to be nil, got %v", port.SfNumber)
}
if port.ControllerNumber != nil {
t.Errorf("expected ControllerNumber to be nil, got %v", port.ControllerNumber)
}
if port.External != nil {
t.Errorf("expected External to be nil, got %v", port.External)
}
})
t.Run("flavor pcisf", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortSfAttrs(nlAttrs)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
testAssertCommonAttrs(t, port)
if port.PortFlavour != uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_SF) {
t.Errorf("expected PortFlavour to be %d, got %d", nl.DEVLINK_PORT_FLAVOUR_PCI_SF, port.PortFlavour)
}
if *port.PfNumber != uint16(0) {
t.Errorf("expected PfNumber to be 0, got %d", *port.PfNumber)
}
if *port.SfNumber != uint32(123) {
t.Errorf("expected SfNumber to be 123, got %d", *port.SfNumber)
}
if port.Fn.HwAddr.String() != "00:11:22:33:44:55" {
t.Errorf("expected HwAddr to be '00:11:22:33:44:55', got %s", port.Fn.HwAddr.String())
}
if port.PortNumber != nil {
t.Errorf("expected PortNumber to be nil, got %v", port.PortNumber)
}
if port.VfNumber != nil {
t.Errorf("expected VfNumber to be nil, got %v", port.VfNumber)
}
if port.ControllerNumber != nil {
t.Errorf("expected ControllerNumber to be nil, got %v", port.ControllerNumber)
}
if port.External != nil {
t.Errorf("expected External to be nil, got %v", port.External)
}
})
t.Run("port with controller - external false", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
nlAttrs = testAddDevlinkPortControllerAttrs(nlAttrs, 0, false)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if *port.ControllerNumber != uint32(0) {
t.Errorf("expected ControllerNumber to be 0, got %d", *port.ControllerNumber)
}
if *port.External != false {
t.Errorf("expected External to be false, got %t", *port.External)
}
})
t.Run("port with controller - external true", func(t *testing.T) {
nlAttrs := testGetDevlinkPortCommonAttrs()
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
nlAttrs = testAddDevlinkPortControllerAttrs(nlAttrs, 1, true)
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
port := &DevlinkPort{}
err := port.parseAttributes(attrs)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if *port.ControllerNumber != uint32(1) {
t.Errorf("expected ControllerNumber to be 1, got %d", *port.ControllerNumber)
}
if *port.External != true {
t.Errorf("expected External to be true, got %t", *port.External)
}
})
}