mirror of
https://github.com/vishvananda/netlink.git
synced 2025-09-27 04:05:59 +08:00
Support for devlink info command
This commit is contained in:

committed by
Vish (Ishaya) Abrams

parent
74e723f230
commit
b10eb8fe5c
215
devlink_linux.go
215
devlink_linux.go
@@ -3,6 +3,7 @@ package netlink
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
@@ -65,6 +66,24 @@ type DevLinkPortAddAttrs struct {
|
||||
ControllerValid bool
|
||||
}
|
||||
|
||||
// DevlinkDeviceInfo represents devlink info
|
||||
type DevlinkDeviceInfo struct {
|
||||
Driver string
|
||||
SerialNumber string
|
||||
BoardID string
|
||||
FwApp string
|
||||
FwAppBoundleID string
|
||||
FwAppName string
|
||||
FwBoundleID string
|
||||
FwMgmt string
|
||||
FwMgmtAPI string
|
||||
FwMgmtBuild string
|
||||
FwNetlist string
|
||||
FwNetlistBuild string
|
||||
FwPsidAPI string
|
||||
FwUndi string
|
||||
}
|
||||
|
||||
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
|
||||
devices := make([]*DevlinkDevice, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
@@ -511,3 +530,199 @@ func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, F
|
||||
func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
|
||||
return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
|
||||
}
|
||||
|
||||
// devlinkInfoGetter is function that is responsible for getting devlink info message
|
||||
// this is introduced for test purpose
|
||||
type devlinkInfoGetter func(bus, device string) ([]byte, error)
|
||||
|
||||
// DevlinkGetDeviceInfoByName returns devlink info for selected device,
|
||||
// otherwise returns an error code.
|
||||
// Equivalent to: `devlink dev info $dev`
|
||||
func (h *Handle) DevlinkGetDeviceInfoByName(Bus string, Device string, getInfoMsg devlinkInfoGetter) (*DevlinkDeviceInfo, error) {
|
||||
info, err := h.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, getInfoMsg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseInfoData(info), nil
|
||||
}
|
||||
|
||||
// DevlinkGetDeviceInfoByName returns devlink info for selected device,
|
||||
// otherwise returns an error code.
|
||||
// Equivalent to: `devlink dev info $dev`
|
||||
func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) {
|
||||
return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg)
|
||||
}
|
||||
|
||||
// DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
|
||||
// otherwise returns an error code.
|
||||
// Equivalent to: `devlink dev info $dev`
|
||||
func (h *Handle) DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string, getInfoMsg devlinkInfoGetter) (map[string]string, error) {
|
||||
response, err := getInfoMsg(Bus, Device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := parseInfoMsg(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
|
||||
// otherwise returns an error code.
|
||||
// Equivalent to: `devlink dev info $dev`
|
||||
func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) {
|
||||
return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg)
|
||||
}
|
||||
|
||||
// GetDevlinkInfo returns devlink info for target device,
|
||||
// otherwise returns an error code.
|
||||
func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) {
|
||||
return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
|
||||
}
|
||||
|
||||
// GetDevlinkInfoAsMap returns devlink info for target device as a map,
|
||||
// otherwise returns an error code.
|
||||
func (d *DevlinkDevice) GetDevlinkInfoAsMap() (map[string]string, error) {
|
||||
return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
|
||||
}
|
||||
|
||||
func (h *Handle) getDevlinkInfoMsg(bus, device string) ([]byte, error) {
|
||||
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_INFO_GET, bus, device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(response) < 1 {
|
||||
return nil, fmt.Errorf("getDevlinkInfoMsg: message too short")
|
||||
}
|
||||
|
||||
return response[0], nil
|
||||
}
|
||||
|
||||
func parseInfoMsg(msg []byte) (map[string]string, error) {
|
||||
if len(msg) < nl.SizeofGenlmsg {
|
||||
return nil, fmt.Errorf("parseInfoMsg: message too short")
|
||||
}
|
||||
|
||||
info := make(map[string]string)
|
||||
err := collectInfoData(msg[nl.SizeofGenlmsg:], info)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func collectInfoData(msg []byte, data map[string]string) error {
|
||||
attrs, err := nl.ParseRouteAttr(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case nl.DEVLINK_ATTR_INFO_DRIVER_NAME:
|
||||
data["driver"] = parseInfoValue(attr.Value)
|
||||
case nl.DEVLINK_ATTR_INFO_SERIAL_NUMBER:
|
||||
data["serialNumber"] = parseInfoValue(attr.Value)
|
||||
case nl.DEVLINK_ATTR_INFO_VERSION_RUNNING, nl.DEVLINK_ATTR_INFO_VERSION_FIXED,
|
||||
nl.DEVLINK_ATTR_INFO_VERSION_STORED:
|
||||
key, value, err := getNestedInfoData(attr.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return fmt.Errorf("collectInfoData: could not read attributes")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNestedInfoData(msg []byte) (string, string, error) {
|
||||
nestedAttrs, err := nl.ParseRouteAttr(msg)
|
||||
|
||||
var key, value string
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if len(nestedAttrs) != 2 {
|
||||
return "", "", fmt.Errorf("getNestedInfoData: too few attributes in nested structure")
|
||||
}
|
||||
|
||||
for _, nestedAttr := range nestedAttrs {
|
||||
switch nestedAttr.Attr.Type {
|
||||
case nl.DEVLINK_ATTR_INFO_VERSION_NAME:
|
||||
key = parseInfoValue(nestedAttr.Value)
|
||||
case nl.DEVLINK_ATTR_INFO_VERSION_VALUE:
|
||||
value = parseInfoValue(nestedAttr.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if key == "" {
|
||||
return "", "", fmt.Errorf("getNestedInfoData: key not found")
|
||||
}
|
||||
|
||||
if value == "" {
|
||||
return "", "", fmt.Errorf("getNestedInfoData: value not found")
|
||||
}
|
||||
|
||||
return key, value, nil
|
||||
}
|
||||
|
||||
func parseInfoData(data map[string]string) *DevlinkDeviceInfo {
|
||||
info := new(DevlinkDeviceInfo)
|
||||
for key, value := range data {
|
||||
switch key {
|
||||
case "driver":
|
||||
info.Driver = value
|
||||
case "serialNumber":
|
||||
info.SerialNumber = value
|
||||
case "board.id":
|
||||
info.BoardID = value
|
||||
case "fw.app":
|
||||
info.FwApp = value
|
||||
case "fw.app.bundle_id":
|
||||
info.FwAppBoundleID = value
|
||||
case "fw.app.name":
|
||||
info.FwAppName = value
|
||||
case "fw.bundle_id":
|
||||
info.FwBoundleID = value
|
||||
case "fw.mgmt":
|
||||
info.FwMgmt = value
|
||||
case "fw.mgmt.api":
|
||||
info.FwMgmtAPI = value
|
||||
case "fw.mgmt.build":
|
||||
info.FwMgmtBuild = value
|
||||
case "fw.netlist":
|
||||
info.FwNetlist = value
|
||||
case "fw.netlist.build":
|
||||
info.FwNetlistBuild = value
|
||||
case "fw.psid.api":
|
||||
info.FwPsidAPI = value
|
||||
case "fw.undi":
|
||||
info.FwUndi = value
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func parseInfoValue(value []byte) string {
|
||||
v := strings.ReplaceAll(string(value), "\x00", "")
|
||||
return strings.TrimSpace(v)
|
||||
}
|
||||
|
Reference in New Issue
Block a user