Skip to content

Commit 36b61ad

Browse files
adrianchirisaboch
authored andcommitted
Add support to get devlink resources
- Update nl package with new netlink attribute types and consts - Define structs to model devlink device resources - Add DevlinkGetDeviceResources method to return device resources - Add basic test Signed-off-by: adrianc <[email protected]>
1 parent 2bbba08 commit 36b61ad

File tree

3 files changed

+265
-30
lines changed

3 files changed

+265
-30
lines changed

devlink_linux.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,169 @@ type DevlinkDeviceInfo struct {
8484
FwUndi string
8585
}
8686

87+
// DevlinkResource represents a device resource
88+
type DevlinkResource struct {
89+
Name string
90+
ID uint64
91+
Size uint64
92+
SizeNew uint64
93+
SizeMin uint64
94+
SizeMax uint64
95+
SizeGranularity uint64
96+
PendingChange bool
97+
Unit uint8
98+
SizeValid bool
99+
OCCValid bool
100+
OCCSize uint64
101+
Parent *DevlinkResource
102+
Children []DevlinkResource
103+
}
104+
105+
// parseAttributes parses provided Netlink Attributes and populates DevlinkResource, returns error if occured
106+
func (dlr *DevlinkResource) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
107+
var attr syscall.NetlinkRouteAttr
108+
var ok bool
109+
110+
// mandatory attributes
111+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_ID]
112+
if !ok {
113+
return fmt.Errorf("missing resource id")
114+
}
115+
dlr.ID = native.Uint64(attr.Value)
116+
117+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_NAME]
118+
if !ok {
119+
return fmt.Errorf("missing resource name")
120+
}
121+
dlr.Name = nl.BytesToString(attr.Value)
122+
123+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE]
124+
if !ok {
125+
return fmt.Errorf("missing resource size")
126+
}
127+
dlr.Size = native.Uint64(attr.Value)
128+
129+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_GRAN]
130+
if !ok {
131+
return fmt.Errorf("missing resource size granularity")
132+
}
133+
dlr.SizeGranularity = native.Uint64(attr.Value)
134+
135+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_UNIT]
136+
if !ok {
137+
return fmt.Errorf("missing resource unit")
138+
}
139+
dlr.Unit = uint8(attr.Value[0])
140+
141+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MIN]
142+
if !ok {
143+
return fmt.Errorf("missing resource size min")
144+
}
145+
dlr.SizeMin = native.Uint64(attr.Value)
146+
147+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MAX]
148+
if !ok {
149+
return fmt.Errorf("missing resource size max")
150+
}
151+
dlr.SizeMax = native.Uint64(attr.Value)
152+
153+
// optional attributes
154+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_OCC]
155+
if ok {
156+
dlr.OCCSize = native.Uint64(attr.Value)
157+
dlr.OCCValid = true
158+
}
159+
160+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_VALID]
161+
if ok {
162+
dlr.SizeValid = uint8(attr.Value[0]) != 0
163+
}
164+
165+
dlr.SizeNew = dlr.Size
166+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_NEW]
167+
if ok {
168+
dlr.SizeNew = native.Uint64(attr.Value)
169+
}
170+
171+
dlr.PendingChange = dlr.Size != dlr.SizeNew
172+
173+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
174+
if ok {
175+
// handle nested resoruces recursively
176+
subResources, err := nl.ParseRouteAttr(attr.Value)
177+
if err != nil {
178+
return err
179+
}
180+
181+
for _, subresource := range subResources {
182+
resource := DevlinkResource{Parent: dlr}
183+
attrs, err := nl.ParseRouteAttrAsMap(subresource.Value)
184+
if err != nil {
185+
return err
186+
}
187+
err = resource.parseAttributes(attrs)
188+
if err != nil {
189+
return fmt.Errorf("failed to parse child resource, parent:%s. %w", dlr.Name, err)
190+
}
191+
dlr.Children = append(dlr.Children, resource)
192+
}
193+
}
194+
return nil
195+
}
196+
197+
// DevlinkResources represents all devlink resources of a devlink device
198+
type DevlinkResources struct {
199+
Bus string
200+
Device string
201+
Resources []DevlinkResource
202+
}
203+
204+
// parseAttributes parses provided Netlink Attributes and populates DevlinkResources, returns error if occured
205+
func (dlrs *DevlinkResources) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
206+
var attr syscall.NetlinkRouteAttr
207+
var ok bool
208+
209+
// Bus
210+
attr, ok = attrs[nl.DEVLINK_ATTR_BUS_NAME]
211+
if !ok {
212+
return fmt.Errorf("missing bus name")
213+
}
214+
dlrs.Bus = nl.BytesToString(attr.Value)
215+
216+
// Device
217+
attr, ok = attrs[nl.DEVLINK_ATTR_DEV_NAME]
218+
if !ok {
219+
return fmt.Errorf("missing device name")
220+
}
221+
dlrs.Device = nl.BytesToString(attr.Value)
222+
223+
// Resource List
224+
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
225+
if !ok {
226+
return fmt.Errorf("missing resource list")
227+
}
228+
229+
resourceAttrs, err := nl.ParseRouteAttr(attr.Value)
230+
if err != nil {
231+
return err
232+
}
233+
234+
for _, resourceAttr := range resourceAttrs {
235+
resource := DevlinkResource{}
236+
attrs, err := nl.ParseRouteAttrAsMap(resourceAttr.Value)
237+
if err != nil {
238+
return err
239+
}
240+
err = resource.parseAttributes(attrs)
241+
if err != nil {
242+
return fmt.Errorf("failed to parse root resoruces, %w", err)
243+
}
244+
dlrs.Resources = append(dlrs.Resources, resource)
245+
}
246+
247+
return nil
248+
}
249+
87250
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
88251
devices := make([]*DevlinkDevice, 0, len(msgs))
89252
for _, m := range msgs {
@@ -443,6 +606,35 @@ func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint
443606
return port, err
444607
}
445608

609+
// DevlinkGetDeviceResources returns devlink device resources
610+
func DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
611+
return pkgHandle.DevlinkGetDeviceResources(bus, device)
612+
}
613+
614+
// DevlinkGetDeviceResources returns devlink device resources
615+
func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
616+
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_RESOURCE_DUMP, bus, device)
617+
if err != nil {
618+
return nil, err
619+
}
620+
621+
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
622+
if err != nil {
623+
return nil, err
624+
}
625+
626+
var resources DevlinkResources
627+
for _, m := range respmsg {
628+
attrs, err := nl.ParseRouteAttrAsMap(m[nl.SizeofGenlmsg:])
629+
if err != nil {
630+
return nil, err
631+
}
632+
resources.parseAttributes(attrs)
633+
}
634+
635+
return &resources, nil
636+
}
637+
446638
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
447639
// otherwise returns an error code.
448640
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {

devlink_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build linux
12
// +build linux
23

34
package netlink
@@ -262,3 +263,26 @@ func areInfoStructsEqual(first *DevlinkDeviceInfo, second *DevlinkDeviceInfo) bo
262263
}
263264
return true
264265
}
266+
267+
func TestDevlinkGetDeviceResources(t *testing.T) {
268+
minKernelRequired(t, 5, 11)
269+
tearDown := setUpNetlinkTestWithKModule(t, "devlink")
270+
defer tearDown()
271+
272+
if bus == "" || device == "" {
273+
//TODO: setup netdevsim device instead of getting device from flags
274+
t.Log("devlink bus and device are empty, skipping test")
275+
t.SkipNow()
276+
}
277+
278+
res, err := DevlinkGetDeviceResources(bus, device)
279+
if err != nil {
280+
t.Fatalf("failed to get device(%s/%s) resources. %s", bus, device, err)
281+
}
282+
283+
if res.Bus != bus || res.Device != device {
284+
t.Fatalf("missmatching bus/device")
285+
}
286+
287+
t.Logf("Resources: %+v", res)
288+
}

nl/devlink_linux.go

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,54 @@ const (
99
)
1010

1111
const (
12-
DEVLINK_CMD_GET = 1
13-
DEVLINK_CMD_PORT_GET = 5
14-
DEVLINK_CMD_PORT_SET = 6
15-
DEVLINK_CMD_PORT_NEW = 7
16-
DEVLINK_CMD_PORT_DEL = 8
17-
DEVLINK_CMD_ESWITCH_GET = 29
18-
DEVLINK_CMD_ESWITCH_SET = 30
19-
DEVLINK_CMD_INFO_GET = 51
12+
DEVLINK_CMD_GET = 1
13+
DEVLINK_CMD_PORT_GET = 5
14+
DEVLINK_CMD_PORT_SET = 6
15+
DEVLINK_CMD_PORT_NEW = 7
16+
DEVLINK_CMD_PORT_DEL = 8
17+
DEVLINK_CMD_ESWITCH_GET = 29
18+
DEVLINK_CMD_ESWITCH_SET = 30
19+
DEVLINK_CMD_RESOURCE_DUMP = 36
20+
DEVLINK_CMD_INFO_GET = 51
2021
)
2122

2223
const (
23-
DEVLINK_ATTR_BUS_NAME = 1
24-
DEVLINK_ATTR_DEV_NAME = 2
25-
DEVLINK_ATTR_PORT_INDEX = 3
26-
DEVLINK_ATTR_PORT_TYPE = 4
27-
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
28-
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
29-
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
30-
DEVLINK_ATTR_ESWITCH_MODE = 25
31-
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
32-
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
33-
DEVLINK_ATTR_PORT_FLAVOUR = 77
34-
DEVLINK_ATTR_INFO_DRIVER_NAME = 98
35-
DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99
36-
DEVLINK_ATTR_INFO_VERSION_FIXED = 100
37-
DEVLINK_ATTR_INFO_VERSION_RUNNING = 101
38-
DEVLINK_ATTR_INFO_VERSION_STORED = 102
39-
DEVLINK_ATTR_INFO_VERSION_NAME = 103
40-
DEVLINK_ATTR_INFO_VERSION_VALUE = 104
41-
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
42-
DEVLINK_ATTR_PORT_FUNCTION = 145
43-
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
44-
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
24+
DEVLINK_ATTR_BUS_NAME = 1
25+
DEVLINK_ATTR_DEV_NAME = 2
26+
DEVLINK_ATTR_PORT_INDEX = 3
27+
DEVLINK_ATTR_PORT_TYPE = 4
28+
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
29+
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
30+
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
31+
DEVLINK_ATTR_ESWITCH_MODE = 25
32+
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
33+
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
34+
DEVLINK_ATTR_RESOURCE_LIST = 63 /* nested */
35+
DEVLINK_ATTR_RESOURCE = 64 /* nested */
36+
DEVLINK_ATTR_RESOURCE_NAME = 65 /* string */
37+
DEVLINK_ATTR_RESOURCE_ID = 66 /* u64 */
38+
DEVLINK_ATTR_RESOURCE_SIZE = 67 /* u64 */
39+
DEVLINK_ATTR_RESOURCE_SIZE_NEW = 68 /* u64 */
40+
DEVLINK_ATTR_RESOURCE_SIZE_VALID = 69 /* u8 */
41+
DEVLINK_ATTR_RESOURCE_SIZE_MIN = 70 /* u64 */
42+
DEVLINK_ATTR_RESOURCE_SIZE_MAX = 71 /* u64 */
43+
DEVLINK_ATTR_RESOURCE_SIZE_GRAN = 72 /* u64 */
44+
DEVLINK_ATTR_RESOURCE_UNIT = 73 /* u8 */
45+
DEVLINK_ATTR_RESOURCE_OCC = 74 /* u64 */
46+
DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID = 75 /* u64 */
47+
DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS = 76 /* u64 */
48+
DEVLINK_ATTR_PORT_FLAVOUR = 77
49+
DEVLINK_ATTR_INFO_DRIVER_NAME = 98
50+
DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99
51+
DEVLINK_ATTR_INFO_VERSION_FIXED = 100
52+
DEVLINK_ATTR_INFO_VERSION_RUNNING = 101
53+
DEVLINK_ATTR_INFO_VERSION_STORED = 102
54+
DEVLINK_ATTR_INFO_VERSION_NAME = 103
55+
DEVLINK_ATTR_INFO_VERSION_VALUE = 104
56+
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
57+
DEVLINK_ATTR_PORT_FUNCTION = 145
58+
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
59+
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
4560
)
4661

4762
const (
@@ -94,3 +109,7 @@ const (
94109
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
95110
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
96111
)
112+
113+
const (
114+
DEVLINK_RESOURCE_UNIT_ENTRY uint8 = 0
115+
)

0 commit comments

Comments
 (0)