mirror of https://github.com/vishvananda/netlink
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 <adrianc@nvidia.com>
This commit is contained in:
parent
2bbba08be2
commit
36b61ad22c
192
devlink_linux.go
192
devlink_linux.go
|
@ -84,6 +84,169 @@ type DevlinkDeviceInfo struct {
|
||||||
FwUndi string
|
FwUndi string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DevlinkResource represents a device resource
|
||||||
|
type DevlinkResource struct {
|
||||||
|
Name string
|
||||||
|
ID uint64
|
||||||
|
Size uint64
|
||||||
|
SizeNew uint64
|
||||||
|
SizeMin uint64
|
||||||
|
SizeMax uint64
|
||||||
|
SizeGranularity uint64
|
||||||
|
PendingChange bool
|
||||||
|
Unit uint8
|
||||||
|
SizeValid bool
|
||||||
|
OCCValid bool
|
||||||
|
OCCSize uint64
|
||||||
|
Parent *DevlinkResource
|
||||||
|
Children []DevlinkResource
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseAttributes parses provided Netlink Attributes and populates DevlinkResource, returns error if occured
|
||||||
|
func (dlr *DevlinkResource) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
|
||||||
|
var attr syscall.NetlinkRouteAttr
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
// mandatory attributes
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_ID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource id")
|
||||||
|
}
|
||||||
|
dlr.ID = native.Uint64(attr.Value)
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_NAME]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource name")
|
||||||
|
}
|
||||||
|
dlr.Name = nl.BytesToString(attr.Value)
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource size")
|
||||||
|
}
|
||||||
|
dlr.Size = native.Uint64(attr.Value)
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_GRAN]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource size granularity")
|
||||||
|
}
|
||||||
|
dlr.SizeGranularity = native.Uint64(attr.Value)
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_UNIT]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource unit")
|
||||||
|
}
|
||||||
|
dlr.Unit = uint8(attr.Value[0])
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MIN]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource size min")
|
||||||
|
}
|
||||||
|
dlr.SizeMin = native.Uint64(attr.Value)
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MAX]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource size max")
|
||||||
|
}
|
||||||
|
dlr.SizeMax = native.Uint64(attr.Value)
|
||||||
|
|
||||||
|
// optional attributes
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_OCC]
|
||||||
|
if ok {
|
||||||
|
dlr.OCCSize = native.Uint64(attr.Value)
|
||||||
|
dlr.OCCValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_VALID]
|
||||||
|
if ok {
|
||||||
|
dlr.SizeValid = uint8(attr.Value[0]) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
dlr.SizeNew = dlr.Size
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_NEW]
|
||||||
|
if ok {
|
||||||
|
dlr.SizeNew = native.Uint64(attr.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
dlr.PendingChange = dlr.Size != dlr.SizeNew
|
||||||
|
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
|
||||||
|
if ok {
|
||||||
|
// handle nested resoruces recursively
|
||||||
|
subResources, err := nl.ParseRouteAttr(attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subresource := range subResources {
|
||||||
|
resource := DevlinkResource{Parent: dlr}
|
||||||
|
attrs, err := nl.ParseRouteAttrAsMap(subresource.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = resource.parseAttributes(attrs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse child resource, parent:%s. %w", dlr.Name, err)
|
||||||
|
}
|
||||||
|
dlr.Children = append(dlr.Children, resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DevlinkResources represents all devlink resources of a devlink device
|
||||||
|
type DevlinkResources struct {
|
||||||
|
Bus string
|
||||||
|
Device string
|
||||||
|
Resources []DevlinkResource
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseAttributes parses provided Netlink Attributes and populates DevlinkResources, returns error if occured
|
||||||
|
func (dlrs *DevlinkResources) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
|
||||||
|
var attr syscall.NetlinkRouteAttr
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
// Bus
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_BUS_NAME]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing bus name")
|
||||||
|
}
|
||||||
|
dlrs.Bus = nl.BytesToString(attr.Value)
|
||||||
|
|
||||||
|
// Device
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_DEV_NAME]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing device name")
|
||||||
|
}
|
||||||
|
dlrs.Device = nl.BytesToString(attr.Value)
|
||||||
|
|
||||||
|
// Resource List
|
||||||
|
attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing resource list")
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceAttrs, err := nl.ParseRouteAttr(attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, resourceAttr := range resourceAttrs {
|
||||||
|
resource := DevlinkResource{}
|
||||||
|
attrs, err := nl.ParseRouteAttrAsMap(resourceAttr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = resource.parseAttributes(attrs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse root resoruces, %w", err)
|
||||||
|
}
|
||||||
|
dlrs.Resources = append(dlrs.Resources, resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
|
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
|
||||||
devices := make([]*DevlinkDevice, 0, len(msgs))
|
devices := make([]*DevlinkDevice, 0, len(msgs))
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
|
@ -443,6 +606,35 @@ func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint
|
||||||
return port, err
|
return port, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DevlinkGetDeviceResources returns devlink device resources
|
||||||
|
func DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
|
||||||
|
return pkgHandle.DevlinkGetDeviceResources(bus, device)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DevlinkGetDeviceResources returns devlink device resources
|
||||||
|
func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
|
||||||
|
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_RESOURCE_DUMP, bus, device)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources DevlinkResources
|
||||||
|
for _, m := range respmsg {
|
||||||
|
attrs, err := nl.ParseRouteAttrAsMap(m[nl.SizeofGenlmsg:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resources.parseAttributes(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
|
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
|
||||||
// otherwise returns an error code.
|
// otherwise returns an error code.
|
||||||
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
|
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build linux
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package netlink
|
package netlink
|
||||||
|
@ -262,3 +263,26 @@ func areInfoStructsEqual(first *DevlinkDeviceInfo, second *DevlinkDeviceInfo) bo
|
||||||
}
|
}
|
||||||
return true
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -9,39 +9,54 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DEVLINK_CMD_GET = 1
|
DEVLINK_CMD_GET = 1
|
||||||
DEVLINK_CMD_PORT_GET = 5
|
DEVLINK_CMD_PORT_GET = 5
|
||||||
DEVLINK_CMD_PORT_SET = 6
|
DEVLINK_CMD_PORT_SET = 6
|
||||||
DEVLINK_CMD_PORT_NEW = 7
|
DEVLINK_CMD_PORT_NEW = 7
|
||||||
DEVLINK_CMD_PORT_DEL = 8
|
DEVLINK_CMD_PORT_DEL = 8
|
||||||
DEVLINK_CMD_ESWITCH_GET = 29
|
DEVLINK_CMD_ESWITCH_GET = 29
|
||||||
DEVLINK_CMD_ESWITCH_SET = 30
|
DEVLINK_CMD_ESWITCH_SET = 30
|
||||||
DEVLINK_CMD_INFO_GET = 51
|
DEVLINK_CMD_RESOURCE_DUMP = 36
|
||||||
|
DEVLINK_CMD_INFO_GET = 51
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DEVLINK_ATTR_BUS_NAME = 1
|
DEVLINK_ATTR_BUS_NAME = 1
|
||||||
DEVLINK_ATTR_DEV_NAME = 2
|
DEVLINK_ATTR_DEV_NAME = 2
|
||||||
DEVLINK_ATTR_PORT_INDEX = 3
|
DEVLINK_ATTR_PORT_INDEX = 3
|
||||||
DEVLINK_ATTR_PORT_TYPE = 4
|
DEVLINK_ATTR_PORT_TYPE = 4
|
||||||
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
|
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
|
||||||
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
|
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
|
||||||
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
|
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
|
||||||
DEVLINK_ATTR_ESWITCH_MODE = 25
|
DEVLINK_ATTR_ESWITCH_MODE = 25
|
||||||
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
|
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
|
||||||
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
|
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
|
||||||
DEVLINK_ATTR_PORT_FLAVOUR = 77
|
DEVLINK_ATTR_RESOURCE_LIST = 63 /* nested */
|
||||||
DEVLINK_ATTR_INFO_DRIVER_NAME = 98
|
DEVLINK_ATTR_RESOURCE = 64 /* nested */
|
||||||
DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99
|
DEVLINK_ATTR_RESOURCE_NAME = 65 /* string */
|
||||||
DEVLINK_ATTR_INFO_VERSION_FIXED = 100
|
DEVLINK_ATTR_RESOURCE_ID = 66 /* u64 */
|
||||||
DEVLINK_ATTR_INFO_VERSION_RUNNING = 101
|
DEVLINK_ATTR_RESOURCE_SIZE = 67 /* u64 */
|
||||||
DEVLINK_ATTR_INFO_VERSION_STORED = 102
|
DEVLINK_ATTR_RESOURCE_SIZE_NEW = 68 /* u64 */
|
||||||
DEVLINK_ATTR_INFO_VERSION_NAME = 103
|
DEVLINK_ATTR_RESOURCE_SIZE_VALID = 69 /* u8 */
|
||||||
DEVLINK_ATTR_INFO_VERSION_VALUE = 104
|
DEVLINK_ATTR_RESOURCE_SIZE_MIN = 70 /* u64 */
|
||||||
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
|
DEVLINK_ATTR_RESOURCE_SIZE_MAX = 71 /* u64 */
|
||||||
DEVLINK_ATTR_PORT_FUNCTION = 145
|
DEVLINK_ATTR_RESOURCE_SIZE_GRAN = 72 /* u64 */
|
||||||
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
|
DEVLINK_ATTR_RESOURCE_UNIT = 73 /* u8 */
|
||||||
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
|
DEVLINK_ATTR_RESOURCE_OCC = 74 /* u64 */
|
||||||
|
DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID = 75 /* u64 */
|
||||||
|
DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS = 76 /* u64 */
|
||||||
|
DEVLINK_ATTR_PORT_FLAVOUR = 77
|
||||||
|
DEVLINK_ATTR_INFO_DRIVER_NAME = 98
|
||||||
|
DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99
|
||||||
|
DEVLINK_ATTR_INFO_VERSION_FIXED = 100
|
||||||
|
DEVLINK_ATTR_INFO_VERSION_RUNNING = 101
|
||||||
|
DEVLINK_ATTR_INFO_VERSION_STORED = 102
|
||||||
|
DEVLINK_ATTR_INFO_VERSION_NAME = 103
|
||||||
|
DEVLINK_ATTR_INFO_VERSION_VALUE = 104
|
||||||
|
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
|
||||||
|
DEVLINK_ATTR_PORT_FUNCTION = 145
|
||||||
|
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
|
||||||
|
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -94,3 +109,7 @@ const (
|
||||||
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
|
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
|
||||||
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
|
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DEVLINK_RESOURCE_UNIT_ENTRY uint8 = 0
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue