Skip to content

Commit b851498

Browse files
adrianchirisvishvananda
authored andcommitted
feat: add additional devlink port attributes
Add the following devlink port attributes: PortNumber: the physical port number PfNumber: the PF number VfNumber: the VF number (index) SfNumber: the SF number (index) ControllerNumber: the controller number External: if set, indicates external controller Signed-off-by: adrianc <[email protected]>
1 parent 37e5aaf commit b851498

File tree

5 files changed

+327
-15
lines changed

5 files changed

+327
-15
lines changed

devlink_linux.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,21 @@ type DevlinkPortFnSetAttrs struct {
4646

4747
// DevlinkPort represents port and its attributes
4848
type DevlinkPort struct {
49-
BusName string
50-
DeviceName string
51-
PortIndex uint32
52-
PortType uint16
53-
NetdeviceName string
54-
NetdevIfIndex uint32
55-
RdmaDeviceName string
56-
PortFlavour uint16
57-
Fn *DevlinkPortFn
49+
BusName string
50+
DeviceName string
51+
PortIndex uint32
52+
PortType uint16
53+
NetdeviceName string
54+
NetdevIfIndex uint32
55+
RdmaDeviceName string
56+
PortFlavour uint16
57+
Fn *DevlinkPortFn
58+
PortNumber *uint32
59+
PfNumber *uint16
60+
VfNumber *uint16
61+
SfNumber *uint32
62+
ControllerNumber *uint32
63+
External *bool
5864
}
5965

6066
type DevLinkPortAddAttrs struct {
@@ -629,6 +635,24 @@ func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error
629635
port.Fn.OpState = uint8(nested.Value[0])
630636
}
631637
}
638+
case nl.DEVLINK_ATTR_PORT_NUMBER:
639+
val := native.Uint32(a.Value)
640+
port.PortNumber = &val
641+
case nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER:
642+
val := native.Uint16(a.Value)
643+
port.PfNumber = &val
644+
case nl.DEVLINK_ATTR_PORT_PCI_VF_NUMBER:
645+
val := native.Uint16(a.Value)
646+
port.VfNumber = &val
647+
case nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER:
648+
val := native.Uint32(a.Value)
649+
port.SfNumber = &val
650+
case nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER:
651+
val := native.Uint32(a.Value)
652+
port.ControllerNumber = &val
653+
case nl.DEVLINK_ATTR_PORT_EXTERNAL:
654+
val := uint8(a.Value[0]) != 0
655+
port.External = &val
632656
}
633657
}
634658
return nil

devlink_test.go

Lines changed: 269 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ package netlink
55

66
import (
77
"flag"
8+
"fmt"
89
"math/rand"
910
"net"
1011
"os"
1112
"strconv"
13+
"strings"
14+
"syscall"
1215
"testing"
1316

17+
"github.com/stretchr/testify/assert"
18+
1419
"github.com/vishvananda/netlink/nl"
1520
)
1621

@@ -49,6 +54,61 @@ func TestDevLinkSetEswitchMode(t *testing.T) {
4954
}
5055
}
5156

57+
func logPort(t *testing.T, port *DevlinkPort) {
58+
type field struct {
59+
key string
60+
value string
61+
}
62+
63+
fields := []field{}
64+
65+
fields = append(fields, field{key: "bus", value: port.BusName})
66+
fields = append(fields, field{key: "device", value: port.DeviceName})
67+
fields = append(fields, field{key: "port_index", value: strconv.Itoa(int(port.PortIndex))})
68+
fields = append(fields, field{key: "port_type", value: strconv.Itoa(int(port.PortType))})
69+
fields = append(fields, field{key: "port_flavour", value: strconv.Itoa(int(port.PortFlavour))})
70+
fields = append(fields, field{key: "netdev_name", value: port.NetdeviceName})
71+
fields = append(fields, field{key: "netdev_index", value: strconv.Itoa(int(port.NetdevIfIndex))})
72+
fields = append(fields, field{key: "rdma_dev_name", value: port.RdmaDeviceName})
73+
74+
if port.Fn != nil {
75+
fields = append(fields, field{key: "hw_addr", value: port.Fn.HwAddr.String()})
76+
fields = append(fields, field{key: "state", value: strconv.Itoa(int(port.Fn.State))})
77+
fields = append(fields, field{key: "op_state", value: strconv.Itoa(int(port.Fn.OpState))})
78+
}
79+
80+
if port.PortNumber != nil {
81+
fields = append(fields, field{key: "port_number", value: strconv.Itoa(int(*port.PortNumber))})
82+
}
83+
84+
if port.PfNumber != nil {
85+
fields = append(fields, field{key: "pf_number", value: strconv.Itoa(int(*port.PfNumber))})
86+
}
87+
88+
if port.VfNumber != nil {
89+
fields = append(fields, field{key: "vf_number", value: strconv.Itoa(int(*port.VfNumber))})
90+
}
91+
92+
if port.SfNumber != nil {
93+
fields = append(fields, field{key: "sf_number", value: strconv.Itoa(int(*port.SfNumber))})
94+
}
95+
96+
if port.ControllerNumber != nil {
97+
fields = append(fields, field{key: "controller_number", value: strconv.Itoa(int(*port.ControllerNumber))})
98+
}
99+
100+
if port.External != nil {
101+
fields = append(fields, field{key: "external", value: strconv.FormatBool(*port.External)})
102+
}
103+
104+
fieldsStr := []string{}
105+
for _, field := range fields {
106+
fieldsStr = append(fieldsStr, fmt.Sprintf("%s=%s", field.key, field.value))
107+
}
108+
109+
t.Log(strings.Join(fieldsStr, " "))
110+
}
111+
52112
func TestDevLinkGetAllPortList(t *testing.T) {
53113
minKernelRequired(t, 5, 4)
54114
ports, err := DevLinkGetAllPortList()
@@ -57,7 +117,7 @@ func TestDevLinkGetAllPortList(t *testing.T) {
57117
}
58118
t.Log("devlink port count = ", len(ports))
59119
for _, port := range ports {
60-
t.Log(*port)
120+
logPort(t, port)
61121
}
62122
}
63123

@@ -401,3 +461,211 @@ func validateDeviceParams(t *testing.T, p *DevlinkParam) {
401461
}
402462
}
403463
}
464+
465+
func testGetDevlinkPortCommonAttrs() []*nl.RtAttr {
466+
nlAttrs := []*nl.RtAttr{}
467+
nlAttrs = append(nlAttrs,
468+
nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, nl.ZeroTerminated("pci")),
469+
nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, nl.ZeroTerminated("0000:08:00.0")),
470+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(131071)),
471+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_TYPE, nl.Uint16Attr(nl.DEVLINK_PORT_TYPE_ETH)),
472+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NETDEV_NAME, nl.ZeroTerminated("eth0")),
473+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX, nl.Uint32Attr(5)),
474+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_IBDEV_NAME, nl.ZeroTerminated("rdma0")),
475+
)
476+
477+
return nlAttrs
478+
}
479+
480+
func testAddDevlinkPortPhysicalAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
481+
nlAttrs = append(nlAttrs,
482+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PHYSICAL)),
483+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_NUMBER, nl.Uint32Attr(1)),
484+
)
485+
486+
return nlAttrs
487+
}
488+
489+
func testAddDevlinkPortPfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
490+
nlAttrs = append(nlAttrs,
491+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_PF)),
492+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(1)),
493+
)
494+
495+
return nlAttrs
496+
}
497+
498+
func testAddDevlinkPortVfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
499+
nlAttrs = append(nlAttrs,
500+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_VF)),
501+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(0)),
502+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_VF_NUMBER, nl.Uint16Attr(4)),
503+
)
504+
505+
nlAttrs = testAddDevlinkPortFnAttrs(nlAttrs)
506+
return nlAttrs
507+
}
508+
509+
func testAddDevlinkPortSfAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
510+
nlAttrs = append(nlAttrs,
511+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(nl.DEVLINK_PORT_FLAVOUR_PCI_SF)),
512+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(0)),
513+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(123)),
514+
)
515+
516+
nlAttrs = testAddDevlinkPortFnAttrs(nlAttrs)
517+
return nlAttrs
518+
}
519+
520+
func testNlAttrsToNetlinkRouteAttrs(nlAttrs []*nl.RtAttr) []syscall.NetlinkRouteAttr {
521+
attrs := []syscall.NetlinkRouteAttr{}
522+
for _, attr := range nlAttrs {
523+
attrs = append(attrs, syscall.NetlinkRouteAttr{Attr: syscall.RtAttr(attr.RtAttr), Value: attr.Data})
524+
}
525+
return attrs
526+
}
527+
528+
func testAddDevlinkPortFnAttrs(nlAttrs []*nl.RtAttr) []*nl.RtAttr {
529+
hwAddr, _ := net.ParseMAC("00:11:22:33:44:55")
530+
hwAddrAttr := nl.NewRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(hwAddr))
531+
raw := hwAddrAttr.Serialize()
532+
533+
nlAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION, raw)
534+
return append(nlAttrs, nlAttr)
535+
}
536+
537+
func testAddDevlinkPortControllerAttrs(nlAttrs []*nl.RtAttr, controllerNumber uint32, external bool) []*nl.RtAttr {
538+
extVal := uint8(0)
539+
if external {
540+
extVal = 1
541+
}
542+
543+
nlAttrs = append(nlAttrs,
544+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(controllerNumber)),
545+
nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_EXTERNAL, nl.Uint8Attr(extVal)),
546+
)
547+
548+
return nlAttrs
549+
}
550+
func testAssertCommonAttrs(t *testing.T, port *DevlinkPort) {
551+
assert.Equal(t, "pci", port.BusName)
552+
assert.Equal(t, "0000:08:00.0", port.DeviceName)
553+
assert.Equal(t, uint32(131071), port.PortIndex)
554+
assert.Equal(t, uint16(nl.DEVLINK_PORT_TYPE_ETH), port.PortType)
555+
assert.Equal(t, "eth0", port.NetdeviceName)
556+
assert.Equal(t, uint32(5), port.NetdevIfIndex)
557+
assert.Equal(t, "rdma0", port.RdmaDeviceName)
558+
}
559+
560+
func TestDevlinkPortParseAttributes(t *testing.T) {
561+
t.Run("flavor physical", func(t *testing.T) {
562+
nlAttrs := testGetDevlinkPortCommonAttrs()
563+
nlAttrs = testAddDevlinkPortPhysicalAttrs(nlAttrs)
564+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
565+
566+
port := &DevlinkPort{}
567+
err := port.parseAttributes(attrs)
568+
assert.NoError(t, err)
569+
570+
testAssertCommonAttrs(t, port)
571+
assert.Equal(t, uint16(nl.DEVLINK_PORT_FLAVOUR_PHYSICAL), port.PortFlavour)
572+
assert.Equal(t, uint32(1), *port.PortNumber)
573+
574+
assert.Nil(t, port.Fn)
575+
assert.Nil(t, port.PfNumber)
576+
assert.Nil(t, port.VfNumber)
577+
assert.Nil(t, port.SfNumber)
578+
assert.Nil(t, port.ControllerNumber)
579+
assert.Nil(t, port.External)
580+
})
581+
582+
t.Run("flavor pcipf", func(t *testing.T) {
583+
nlAttrs := testGetDevlinkPortCommonAttrs()
584+
nlAttrs = testAddDevlinkPortPfAttrs(nlAttrs)
585+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
586+
587+
port := &DevlinkPort{}
588+
err := port.parseAttributes(attrs)
589+
assert.NoError(t, err)
590+
591+
testAssertCommonAttrs(t, port)
592+
assert.Equal(t, uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_PF), port.PortFlavour)
593+
assert.Equal(t, uint16(1), *port.PfNumber)
594+
595+
assert.Nil(t, port.Fn)
596+
assert.Nil(t, port.PortNumber)
597+
assert.Nil(t, port.VfNumber)
598+
assert.Nil(t, port.SfNumber)
599+
assert.Nil(t, port.ControllerNumber)
600+
assert.Nil(t, port.External)
601+
})
602+
t.Run("flavor pcivf", func(t *testing.T) {
603+
nlAttrs := testGetDevlinkPortCommonAttrs()
604+
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
605+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
606+
607+
port := &DevlinkPort{}
608+
err := port.parseAttributes(attrs)
609+
assert.NoError(t, err)
610+
611+
testAssertCommonAttrs(t, port)
612+
assert.Equal(t, uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_VF), port.PortFlavour)
613+
assert.Equal(t, uint16(0), *port.PfNumber)
614+
assert.Equal(t, uint16(4), *port.VfNumber)
615+
assert.Equal(t, "00:11:22:33:44:55", port.Fn.HwAddr.String())
616+
617+
assert.Nil(t, port.PortNumber)
618+
assert.Nil(t, port.SfNumber)
619+
assert.Nil(t, port.ControllerNumber)
620+
assert.Nil(t, port.External)
621+
})
622+
623+
t.Run("flavor pcisf", func(t *testing.T) {
624+
nlAttrs := testGetDevlinkPortCommonAttrs()
625+
nlAttrs = testAddDevlinkPortSfAttrs(nlAttrs)
626+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
627+
628+
port := &DevlinkPort{}
629+
err := port.parseAttributes(attrs)
630+
assert.NoError(t, err)
631+
632+
testAssertCommonAttrs(t, port)
633+
assert.Equal(t, uint16(nl.DEVLINK_PORT_FLAVOUR_PCI_SF), port.PortFlavour)
634+
assert.Equal(t, uint16(0), *port.PfNumber)
635+
assert.Equal(t, uint32(123), *port.SfNumber)
636+
assert.Equal(t, "00:11:22:33:44:55", port.Fn.HwAddr.String())
637+
638+
assert.Nil(t, port.PortNumber)
639+
assert.Nil(t, port.VfNumber)
640+
assert.Nil(t, port.ControllerNumber)
641+
assert.Nil(t, port.External)
642+
})
643+
644+
t.Run("port with controller - external false", func(t *testing.T) {
645+
nlAttrs := testGetDevlinkPortCommonAttrs()
646+
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
647+
nlAttrs = testAddDevlinkPortControllerAttrs(nlAttrs, 0, false)
648+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
649+
650+
port := &DevlinkPort{}
651+
err := port.parseAttributes(attrs)
652+
assert.NoError(t, err)
653+
654+
assert.Equal(t, uint32(0), *port.ControllerNumber)
655+
assert.Equal(t, false, *port.External)
656+
})
657+
658+
t.Run("port with controller - external true", func(t *testing.T) {
659+
nlAttrs := testGetDevlinkPortCommonAttrs()
660+
nlAttrs = testAddDevlinkPortVfAttrs(nlAttrs)
661+
nlAttrs = testAddDevlinkPortControllerAttrs(nlAttrs, 1, true)
662+
attrs := testNlAttrsToNetlinkRouteAttrs(nlAttrs)
663+
664+
port := &DevlinkPort{}
665+
err := port.parseAttributes(attrs)
666+
assert.NoError(t, err)
667+
668+
assert.Equal(t, uint32(1), *port.ControllerNumber)
669+
assert.Equal(t, true, *port.External)
670+
})
671+
}

go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ module github.com/vishvananda/netlink
33
go 1.23
44

55
require (
6+
github.com/stretchr/testify v1.10.0
67
github.com/vishvananda/netns v0.0.5
78
golang.org/x/sys v0.10.0
89
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/pmezard/go-difflib v1.0.0 // indirect
14+
gopkg.in/yaml.v3 v3.0.1 // indirect
15+
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
17
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
28
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
39
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
410
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
11+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
12+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
13+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
14+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)