github.com/vishvananda/netlink@v1.3.0/devlink_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  	"syscall"
     8  
     9  	"github.com/vishvananda/netlink/nl"
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  // DevlinkDevEswitchAttr represents device's eswitch attributes
    14  type DevlinkDevEswitchAttr struct {
    15  	Mode       string
    16  	InlineMode string
    17  	EncapMode  string
    18  }
    19  
    20  // DevlinkDevAttrs represents device attributes
    21  type DevlinkDevAttrs struct {
    22  	Eswitch DevlinkDevEswitchAttr
    23  }
    24  
    25  // DevlinkDevice represents device and its attributes
    26  type DevlinkDevice struct {
    27  	BusName    string
    28  	DeviceName string
    29  	Attrs      DevlinkDevAttrs
    30  }
    31  
    32  // DevlinkPortFn represents port function and its attributes
    33  type DevlinkPortFn struct {
    34  	HwAddr  net.HardwareAddr
    35  	State   uint8
    36  	OpState uint8
    37  }
    38  
    39  // DevlinkPortFnSetAttrs represents attributes to set
    40  type DevlinkPortFnSetAttrs struct {
    41  	FnAttrs     DevlinkPortFn
    42  	HwAddrValid bool
    43  	StateValid  bool
    44  }
    45  
    46  // DevlinkPort represents port and its attributes
    47  type DevlinkPort struct {
    48  	BusName        string
    49  	DeviceName     string
    50  	PortIndex      uint32
    51  	PortType       uint16
    52  	NetdeviceName  string
    53  	NetdevIfIndex  uint32
    54  	RdmaDeviceName string
    55  	PortFlavour    uint16
    56  	Fn             *DevlinkPortFn
    57  }
    58  
    59  type DevLinkPortAddAttrs struct {
    60  	Controller      uint32
    61  	SfNumber        uint32
    62  	PortIndex       uint32
    63  	PfNumber        uint16
    64  	SfNumberValid   bool
    65  	PortIndexValid  bool
    66  	ControllerValid bool
    67  }
    68  
    69  // DevlinkDeviceInfo represents devlink info
    70  type DevlinkDeviceInfo struct {
    71  	Driver         string
    72  	SerialNumber   string
    73  	BoardID        string
    74  	FwApp          string
    75  	FwAppBoundleID string
    76  	FwAppName      string
    77  	FwBoundleID    string
    78  	FwMgmt         string
    79  	FwMgmtAPI      string
    80  	FwMgmtBuild    string
    81  	FwNetlist      string
    82  	FwNetlistBuild string
    83  	FwPsidAPI      string
    84  	FwUndi         string
    85  }
    86  
    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  
   250  // DevlinkParam represents parameter of the device
   251  type DevlinkParam struct {
   252  	Name      string
   253  	IsGeneric bool
   254  	Type      uint8 // possible values are in nl.DEVLINK_PARAM_TYPE_* constants
   255  	Values    []DevlinkParamValue
   256  }
   257  
   258  // DevlinkParamValue contains values of the parameter
   259  // Data field contains specific type which can be casted by unsing info from the DevlinkParam.Type field
   260  type DevlinkParamValue struct {
   261  	rawData []byte
   262  	Data    interface{}
   263  	CMODE   uint8 // possible values are in nl.DEVLINK_PARAM_CMODE_* constants
   264  }
   265  
   266  // parseAttributes parses provided Netlink Attributes and populates DevlinkParam, returns error if occured
   267  func (dlp *DevlinkParam) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
   268  	var valuesList [][]syscall.NetlinkRouteAttr
   269  	for _, attr := range attrs {
   270  		switch attr.Attr.Type {
   271  		case nl.DEVLINK_ATTR_PARAM:
   272  			nattrs, err := nl.ParseRouteAttr(attr.Value)
   273  			if err != nil {
   274  				return err
   275  			}
   276  			for _, nattr := range nattrs {
   277  				switch nattr.Attr.Type {
   278  				case nl.DEVLINK_ATTR_PARAM_NAME:
   279  					dlp.Name = nl.BytesToString(nattr.Value)
   280  				case nl.DEVLINK_ATTR_PARAM_GENERIC:
   281  					dlp.IsGeneric = true
   282  				case nl.DEVLINK_ATTR_PARAM_TYPE:
   283  					if len(nattr.Value) == 1 {
   284  						dlp.Type = nattr.Value[0]
   285  					}
   286  				case nl.DEVLINK_ATTR_PARAM_VALUES_LIST:
   287  					nnattrs, err := nl.ParseRouteAttr(nattr.Value)
   288  					if err != nil {
   289  						return err
   290  					}
   291  					valuesList = append(valuesList, nnattrs)
   292  				}
   293  			}
   294  		}
   295  	}
   296  	for _, valAttr := range valuesList {
   297  		v := DevlinkParamValue{}
   298  		if err := v.parseAttributes(valAttr, dlp.Type); err != nil {
   299  			return err
   300  		}
   301  		dlp.Values = append(dlp.Values, v)
   302  	}
   303  	return nil
   304  }
   305  
   306  func (dlpv *DevlinkParamValue) parseAttributes(attrs []syscall.NetlinkRouteAttr, paramType uint8) error {
   307  	for _, attr := range attrs {
   308  		nattrs, err := nl.ParseRouteAttr(attr.Value)
   309  		if err != nil {
   310  			return err
   311  		}
   312  		var rawData []byte
   313  		for _, nattr := range nattrs {
   314  			switch nattr.Attr.Type {
   315  			case nl.DEVLINK_ATTR_PARAM_VALUE_DATA:
   316  				rawData = nattr.Value
   317  			case nl.DEVLINK_ATTR_PARAM_VALUE_CMODE:
   318  				if len(nattr.Value) == 1 {
   319  					dlpv.CMODE = nattr.Value[0]
   320  				}
   321  			}
   322  		}
   323  		switch paramType {
   324  		case nl.DEVLINK_PARAM_TYPE_U8:
   325  			dlpv.Data = uint8(0)
   326  			if rawData != nil && len(rawData) == 1 {
   327  				dlpv.Data = uint8(rawData[0])
   328  			}
   329  		case nl.DEVLINK_PARAM_TYPE_U16:
   330  			dlpv.Data = uint16(0)
   331  			if rawData != nil {
   332  				dlpv.Data = native.Uint16(rawData)
   333  			}
   334  		case nl.DEVLINK_PARAM_TYPE_U32:
   335  			dlpv.Data = uint32(0)
   336  			if rawData != nil {
   337  				dlpv.Data = native.Uint32(rawData)
   338  			}
   339  		case nl.DEVLINK_PARAM_TYPE_STRING:
   340  			dlpv.Data = ""
   341  			if rawData != nil {
   342  				dlpv.Data = nl.BytesToString(rawData)
   343  			}
   344  		case nl.DEVLINK_PARAM_TYPE_BOOL:
   345  			dlpv.Data = rawData != nil
   346  		}
   347  	}
   348  	return nil
   349  }
   350  
   351  func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
   352  	devices := make([]*DevlinkDevice, 0, len(msgs))
   353  	for _, m := range msgs {
   354  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   355  		if err != nil {
   356  			return nil, err
   357  		}
   358  		dev := &DevlinkDevice{}
   359  		if err = dev.parseAttributes(attrs); err != nil {
   360  			return nil, err
   361  		}
   362  		devices = append(devices, dev)
   363  	}
   364  	return devices, nil
   365  }
   366  
   367  func eswitchStringToMode(modeName string) (uint16, error) {
   368  	if modeName == "legacy" {
   369  		return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
   370  	} else if modeName == "switchdev" {
   371  		return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
   372  	} else {
   373  		return 0xffff, fmt.Errorf("invalid switchdev mode")
   374  	}
   375  }
   376  
   377  func parseEswitchMode(mode uint16) string {
   378  	var eswitchMode = map[uint16]string{
   379  		nl.DEVLINK_ESWITCH_MODE_LEGACY:    "legacy",
   380  		nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
   381  	}
   382  	if eswitchMode[mode] == "" {
   383  		return "unknown"
   384  	} else {
   385  		return eswitchMode[mode]
   386  	}
   387  }
   388  
   389  func parseEswitchInlineMode(inlinemode uint8) string {
   390  	var eswitchInlineMode = map[uint8]string{
   391  		nl.DEVLINK_ESWITCH_INLINE_MODE_NONE:      "none",
   392  		nl.DEVLINK_ESWITCH_INLINE_MODE_LINK:      "link",
   393  		nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK:   "network",
   394  		nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
   395  	}
   396  	if eswitchInlineMode[inlinemode] == "" {
   397  		return "unknown"
   398  	} else {
   399  		return eswitchInlineMode[inlinemode]
   400  	}
   401  }
   402  
   403  func parseEswitchEncapMode(encapmode uint8) string {
   404  	var eswitchEncapMode = map[uint8]string{
   405  		nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE:  "disable",
   406  		nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
   407  	}
   408  	if eswitchEncapMode[encapmode] == "" {
   409  		return "unknown"
   410  	} else {
   411  		return eswitchEncapMode[encapmode]
   412  	}
   413  }
   414  
   415  func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
   416  	for _, a := range attrs {
   417  		switch a.Attr.Type {
   418  		case nl.DEVLINK_ATTR_BUS_NAME:
   419  			d.BusName = string(a.Value[:len(a.Value)-1])
   420  		case nl.DEVLINK_ATTR_DEV_NAME:
   421  			d.DeviceName = string(a.Value[:len(a.Value)-1])
   422  		case nl.DEVLINK_ATTR_ESWITCH_MODE:
   423  			d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
   424  		case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
   425  			d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
   426  		case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
   427  			d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
   428  		}
   429  	}
   430  	return nil
   431  }
   432  
   433  func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
   434  	m := msgs[0]
   435  	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   436  	if err != nil {
   437  		return
   438  	}
   439  	dev.parseAttributes(attrs)
   440  }
   441  
   442  func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
   443  	msg := &nl.Genlmsg{
   444  		Command: nl.DEVLINK_CMD_ESWITCH_GET,
   445  		Version: nl.GENL_DEVLINK_VERSION,
   446  	}
   447  	req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
   448  	req.AddData(msg)
   449  
   450  	b := make([]byte, len(dev.BusName)+1)
   451  	copy(b, dev.BusName)
   452  	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
   453  	req.AddData(data)
   454  
   455  	b = make([]byte, len(dev.DeviceName)+1)
   456  	copy(b, dev.DeviceName)
   457  	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
   458  	req.AddData(data)
   459  
   460  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   461  	if err != nil {
   462  		return
   463  	}
   464  	dev.parseEswitchAttrs(msgs)
   465  }
   466  
   467  // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
   468  // otherwise returns an error code.
   469  func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
   470  	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
   471  	if err != nil {
   472  		return nil, err
   473  	}
   474  	msg := &nl.Genlmsg{
   475  		Command: nl.DEVLINK_CMD_GET,
   476  		Version: nl.GENL_DEVLINK_VERSION,
   477  	}
   478  	req := h.newNetlinkRequest(int(f.ID),
   479  		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
   480  	req.AddData(msg)
   481  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   482  	if err != nil {
   483  		return nil, err
   484  	}
   485  	devices, err := parseDevLinkDeviceList(msgs)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  	for _, d := range devices {
   490  		h.getEswitchAttrs(f, d)
   491  	}
   492  	return devices, nil
   493  }
   494  
   495  // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
   496  // otherwise returns an error code.
   497  func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
   498  	return pkgHandle.DevLinkGetDeviceList()
   499  }
   500  
   501  func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
   502  	m := msgs[0]
   503  	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  	dev := &DevlinkDevice{}
   508  	if err = dev.parseAttributes(attrs); err != nil {
   509  		return nil, err
   510  	}
   511  	return dev, nil
   512  }
   513  
   514  func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
   515  	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
   516  	if err != nil {
   517  		return nil, nil, err
   518  	}
   519  
   520  	msg := &nl.Genlmsg{
   521  		Command: cmd,
   522  		Version: nl.GENL_DEVLINK_VERSION,
   523  	}
   524  	req := h.newNetlinkRequest(int(f.ID),
   525  		unix.NLM_F_REQUEST|unix.NLM_F_ACK)
   526  	req.AddData(msg)
   527  
   528  	b := make([]byte, len(bus)+1)
   529  	copy(b, bus)
   530  	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
   531  	req.AddData(data)
   532  
   533  	b = make([]byte, len(device)+1)
   534  	copy(b, device)
   535  	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
   536  	req.AddData(data)
   537  
   538  	return f, req, nil
   539  }
   540  
   541  // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
   542  // otherwise returns an error code.
   543  func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
   544  	f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
   545  	if err != nil {
   546  		return nil, err
   547  	}
   548  
   549  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   550  	if err != nil {
   551  		return nil, err
   552  	}
   553  	dev, err := parseDevlinkDevice(respmsg)
   554  	if err == nil {
   555  		h.getEswitchAttrs(f, dev)
   556  	}
   557  	return dev, err
   558  }
   559  
   560  // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
   561  // otherwise returns an error code.
   562  func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
   563  	return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
   564  }
   565  
   566  // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
   567  // returns an error code.
   568  // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
   569  // Equivalent to: `devlink dev eswitch set $dev mode legacy`
   570  func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
   571  	mode, err := eswitchStringToMode(NewMode)
   572  	if err != nil {
   573  		return err
   574  	}
   575  
   576  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
   577  	if err != nil {
   578  		return err
   579  	}
   580  
   581  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
   582  
   583  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   584  	return err
   585  }
   586  
   587  // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
   588  // returns an error code.
   589  // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
   590  // Equivalent to: `devlink dev eswitch set $dev mode legacy`
   591  func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
   592  	return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
   593  }
   594  
   595  func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
   596  	for _, a := range attrs {
   597  		switch a.Attr.Type {
   598  		case nl.DEVLINK_ATTR_BUS_NAME:
   599  			port.BusName = string(a.Value[:len(a.Value)-1])
   600  		case nl.DEVLINK_ATTR_DEV_NAME:
   601  			port.DeviceName = string(a.Value[:len(a.Value)-1])
   602  		case nl.DEVLINK_ATTR_PORT_INDEX:
   603  			port.PortIndex = native.Uint32(a.Value)
   604  		case nl.DEVLINK_ATTR_PORT_TYPE:
   605  			port.PortType = native.Uint16(a.Value)
   606  		case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
   607  			port.NetdeviceName = string(a.Value[:len(a.Value)-1])
   608  		case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
   609  			port.NetdevIfIndex = native.Uint32(a.Value)
   610  		case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
   611  			port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
   612  		case nl.DEVLINK_ATTR_PORT_FLAVOUR:
   613  			port.PortFlavour = native.Uint16(a.Value)
   614  		case nl.DEVLINK_ATTR_PORT_FUNCTION:
   615  			port.Fn = &DevlinkPortFn{}
   616  			for nested := range nl.ParseAttributes(a.Value) {
   617  				switch nested.Type {
   618  				case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
   619  					port.Fn.HwAddr = nested.Value[:]
   620  				case nl.DEVLINK_PORT_FN_ATTR_STATE:
   621  					port.Fn.State = uint8(nested.Value[0])
   622  				case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
   623  					port.Fn.OpState = uint8(nested.Value[0])
   624  				}
   625  			}
   626  		}
   627  	}
   628  	return nil
   629  }
   630  
   631  func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
   632  	ports := make([]*DevlinkPort, 0, len(msgs))
   633  	for _, m := range msgs {
   634  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   635  		if err != nil {
   636  			return nil, err
   637  		}
   638  		port := &DevlinkPort{}
   639  		if err = port.parseAttributes(attrs); err != nil {
   640  			return nil, err
   641  		}
   642  		ports = append(ports, port)
   643  	}
   644  	return ports, nil
   645  }
   646  
   647  // DevLinkGetPortList provides a pointer to devlink ports and nil error,
   648  // otherwise returns an error code.
   649  func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
   650  	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
   651  	if err != nil {
   652  		return nil, err
   653  	}
   654  	msg := &nl.Genlmsg{
   655  		Command: nl.DEVLINK_CMD_PORT_GET,
   656  		Version: nl.GENL_DEVLINK_VERSION,
   657  	}
   658  	req := h.newNetlinkRequest(int(f.ID),
   659  		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
   660  	req.AddData(msg)
   661  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   662  	if err != nil {
   663  		return nil, err
   664  	}
   665  	ports, err := parseDevLinkAllPortList(msgs)
   666  	if err != nil {
   667  		return nil, err
   668  	}
   669  	return ports, nil
   670  }
   671  
   672  // DevLinkGetPortList provides a pointer to devlink ports and nil error,
   673  // otherwise returns an error code.
   674  func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
   675  	return pkgHandle.DevLinkGetAllPortList()
   676  }
   677  
   678  func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
   679  	m := msgs[0]
   680  	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   681  	if err != nil {
   682  		return nil, err
   683  	}
   684  	port := &DevlinkPort{}
   685  	if err = port.parseAttributes(attrs); err != nil {
   686  		return nil, err
   687  	}
   688  	return port, nil
   689  }
   690  
   691  // DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
   692  // otherwise returns an error code.
   693  func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
   694  
   695  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
   696  	if err != nil {
   697  		return nil, err
   698  	}
   699  
   700  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
   701  
   702  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   703  	if err != nil {
   704  		return nil, err
   705  	}
   706  	port, err := parseDevlinkPortMsg(respmsg)
   707  	return port, err
   708  }
   709  
   710  // DevlinkGetDeviceResources returns devlink device resources
   711  func DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
   712  	return pkgHandle.DevlinkGetDeviceResources(bus, device)
   713  }
   714  
   715  // DevlinkGetDeviceResources returns devlink device resources
   716  func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
   717  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_RESOURCE_DUMP, bus, device)
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  
   722  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   723  	if err != nil {
   724  		return nil, err
   725  	}
   726  
   727  	var resources DevlinkResources
   728  	for _, m := range respmsg {
   729  		attrs, err := nl.ParseRouteAttrAsMap(m[nl.SizeofGenlmsg:])
   730  		if err != nil {
   731  			return nil, err
   732  		}
   733  		resources.parseAttributes(attrs)
   734  	}
   735  
   736  	return &resources, nil
   737  }
   738  
   739  // DevlinkGetDeviceParams returns parameters for devlink device
   740  // Equivalent to: `devlink dev param show <bus>/<device>`
   741  func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
   742  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
   743  	if err != nil {
   744  		return nil, err
   745  	}
   746  	req.Flags |= unix.NLM_F_DUMP
   747  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   748  	if err != nil {
   749  		return nil, err
   750  	}
   751  	var params []*DevlinkParam
   752  	for _, m := range respmsg {
   753  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   754  		if err != nil {
   755  			return nil, err
   756  		}
   757  		p := &DevlinkParam{}
   758  		if err := p.parseAttributes(attrs); err != nil {
   759  			return nil, err
   760  		}
   761  		params = append(params, p)
   762  	}
   763  
   764  	return params, nil
   765  }
   766  
   767  // DevlinkGetDeviceParams returns parameters for devlink device
   768  // Equivalent to: `devlink dev param show <bus>/<device>`
   769  func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
   770  	return pkgHandle.DevlinkGetDeviceParams(bus, device)
   771  }
   772  
   773  // DevlinkGetDeviceParamByName returns specific parameter for devlink device
   774  // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
   775  func (h *Handle) DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
   776  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
   777  	if err != nil {
   778  		return nil, err
   779  	}
   780  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
   781  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   782  	if err != nil {
   783  		return nil, err
   784  	}
   785  	if len(respmsg) == 0 {
   786  		return nil, fmt.Errorf("unexpected response")
   787  	}
   788  	attrs, err := nl.ParseRouteAttr(respmsg[0][nl.SizeofGenlmsg:])
   789  	if err != nil {
   790  		return nil, err
   791  	}
   792  	p := &DevlinkParam{}
   793  	if err := p.parseAttributes(attrs); err != nil {
   794  		return nil, err
   795  	}
   796  	return p, nil
   797  }
   798  
   799  // DevlinkGetDeviceParamByName returns specific parameter for devlink device
   800  // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
   801  func DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
   802  	return pkgHandle.DevlinkGetDeviceParamByName(bus, device, param)
   803  }
   804  
   805  // DevlinkSetDeviceParam set specific parameter for devlink device
   806  // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
   807  // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
   808  // value argument should have one of the following types: uint8, uint16, uint32, string, bool
   809  func (h *Handle) DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
   810  	// retrive the param type
   811  	p, err := h.DevlinkGetDeviceParamByName(bus, device, param)
   812  	if err != nil {
   813  		return fmt.Errorf("failed to get device param: %v", err)
   814  	}
   815  	paramType := p.Type
   816  
   817  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_SET, bus, device)
   818  	if err != nil {
   819  		return err
   820  	}
   821  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_TYPE, nl.Uint8Attr(paramType)))
   822  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
   823  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_CMODE, nl.Uint8Attr(cmode)))
   824  
   825  	var valueAsBytes []byte
   826  	switch paramType {
   827  	case nl.DEVLINK_PARAM_TYPE_U8:
   828  		v, ok := value.(uint8)
   829  		if !ok {
   830  			return fmt.Errorf("unepected value type required: uint8, actual: %T", value)
   831  		}
   832  		valueAsBytes = nl.Uint8Attr(v)
   833  	case nl.DEVLINK_PARAM_TYPE_U16:
   834  		v, ok := value.(uint16)
   835  		if !ok {
   836  			return fmt.Errorf("unepected value type required: uint16, actual: %T", value)
   837  		}
   838  		valueAsBytes = nl.Uint16Attr(v)
   839  	case nl.DEVLINK_PARAM_TYPE_U32:
   840  		v, ok := value.(uint32)
   841  		if !ok {
   842  			return fmt.Errorf("unepected value type required: uint32, actual: %T", value)
   843  		}
   844  		valueAsBytes = nl.Uint32Attr(v)
   845  	case nl.DEVLINK_PARAM_TYPE_STRING:
   846  		v, ok := value.(string)
   847  		if !ok {
   848  			return fmt.Errorf("unepected value type required: string, actual: %T", value)
   849  		}
   850  		valueAsBytes = nl.ZeroTerminated(v)
   851  	case nl.DEVLINK_PARAM_TYPE_BOOL:
   852  		v, ok := value.(bool)
   853  		if !ok {
   854  			return fmt.Errorf("unepected value type required: bool, actual: %T", value)
   855  		}
   856  		if v {
   857  			valueAsBytes = []byte{}
   858  		}
   859  	default:
   860  		return fmt.Errorf("unsupported parameter type: %d", paramType)
   861  	}
   862  	if valueAsBytes != nil {
   863  		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_DATA, valueAsBytes))
   864  	}
   865  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   866  	return err
   867  }
   868  
   869  // DevlinkSetDeviceParam set specific parameter for devlink device
   870  // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
   871  // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
   872  // value argument should have one of the following types: uint8, uint16, uint32, string, bool
   873  func DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
   874  	return pkgHandle.DevlinkSetDeviceParam(bus, device, param, cmode, value)
   875  }
   876  
   877  // DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
   878  // otherwise returns an error code.
   879  func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
   880  	return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
   881  }
   882  
   883  // DevLinkPortAdd adds a devlink port and returns a port on success
   884  // otherwise returns nil port and an error code.
   885  func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
   886  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
   887  	if err != nil {
   888  		return nil, err
   889  	}
   890  
   891  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
   892  
   893  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
   894  	if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
   895  		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
   896  	}
   897  	if Attrs.PortIndexValid {
   898  		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
   899  	}
   900  	if Attrs.ControllerValid {
   901  		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
   902  	}
   903  	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
   904  	if err != nil {
   905  		return nil, err
   906  	}
   907  	port, err := parseDevlinkPortMsg(respmsg)
   908  	return port, err
   909  }
   910  
   911  // DevLinkPortAdd adds a devlink port and returns a port on success
   912  // otherwise returns nil port and an error code.
   913  func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
   914  	return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
   915  }
   916  
   917  // DevLinkPortDel deletes a devlink port and returns success or error code.
   918  func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
   919  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
   920  	if err != nil {
   921  		return err
   922  	}
   923  
   924  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
   925  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   926  	return err
   927  }
   928  
   929  // DevLinkPortDel deletes a devlink port and returns success or error code.
   930  func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
   931  	return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
   932  }
   933  
   934  // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
   935  // It returns 0 on success or error code.
   936  func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
   937  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
   938  	if err != nil {
   939  		return err
   940  	}
   941  
   942  	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
   943  
   944  	fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
   945  
   946  	if FnAttrs.HwAddrValid {
   947  		fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
   948  	}
   949  
   950  	if FnAttrs.StateValid {
   951  		fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
   952  	}
   953  	req.AddData(fnAttr)
   954  
   955  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   956  	return err
   957  }
   958  
   959  // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
   960  // It returns 0 on success or error code.
   961  func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
   962  	return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
   963  }
   964  
   965  // devlinkInfoGetter is function that is responsible for getting devlink info message
   966  // this is introduced for test purpose
   967  type devlinkInfoGetter func(bus, device string) ([]byte, error)
   968  
   969  // DevlinkGetDeviceInfoByName returns devlink info for selected device,
   970  // otherwise returns an error code.
   971  // Equivalent to: `devlink dev info $dev`
   972  func (h *Handle) DevlinkGetDeviceInfoByName(Bus string, Device string, getInfoMsg devlinkInfoGetter) (*DevlinkDeviceInfo, error) {
   973  	info, err := h.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, getInfoMsg)
   974  	if err != nil {
   975  		return nil, err
   976  	}
   977  
   978  	return parseInfoData(info), nil
   979  }
   980  
   981  // DevlinkGetDeviceInfoByName returns devlink info for selected device,
   982  // otherwise returns an error code.
   983  // Equivalent to: `devlink dev info $dev`
   984  func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) {
   985  	return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg)
   986  }
   987  
   988  // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
   989  // otherwise returns an error code.
   990  // Equivalent to: `devlink dev info $dev`
   991  func (h *Handle) DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string, getInfoMsg devlinkInfoGetter) (map[string]string, error) {
   992  	response, err := getInfoMsg(Bus, Device)
   993  	if err != nil {
   994  		return nil, err
   995  	}
   996  
   997  	info, err := parseInfoMsg(response)
   998  	if err != nil {
   999  		return nil, err
  1000  	}
  1001  
  1002  	return info, nil
  1003  }
  1004  
  1005  // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
  1006  // otherwise returns an error code.
  1007  // Equivalent to: `devlink dev info $dev`
  1008  func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) {
  1009  	return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg)
  1010  }
  1011  
  1012  // GetDevlinkInfo returns devlink info for target device,
  1013  // otherwise returns an error code.
  1014  func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) {
  1015  	return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  1016  }
  1017  
  1018  // GetDevlinkInfoAsMap returns devlink info for target device as a map,
  1019  // otherwise returns an error code.
  1020  func (d *DevlinkDevice) GetDevlinkInfoAsMap() (map[string]string, error) {
  1021  	return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  1022  }
  1023  
  1024  func (h *Handle) getDevlinkInfoMsg(bus, device string) ([]byte, error) {
  1025  	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_INFO_GET, bus, device)
  1026  	if err != nil {
  1027  		return nil, err
  1028  	}
  1029  
  1030  	response, err := req.Execute(unix.NETLINK_GENERIC, 0)
  1031  	if err != nil {
  1032  		return nil, err
  1033  	}
  1034  
  1035  	if len(response) < 1 {
  1036  		return nil, fmt.Errorf("getDevlinkInfoMsg: message too short")
  1037  	}
  1038  
  1039  	return response[0], nil
  1040  }
  1041  
  1042  func parseInfoMsg(msg []byte) (map[string]string, error) {
  1043  	if len(msg) < nl.SizeofGenlmsg {
  1044  		return nil, fmt.Errorf("parseInfoMsg: message too short")
  1045  	}
  1046  
  1047  	info := make(map[string]string)
  1048  	err := collectInfoData(msg[nl.SizeofGenlmsg:], info)
  1049  
  1050  	if err != nil {
  1051  		return nil, err
  1052  	}
  1053  
  1054  	return info, nil
  1055  }
  1056  
  1057  func collectInfoData(msg []byte, data map[string]string) error {
  1058  	attrs, err := nl.ParseRouteAttr(msg)
  1059  	if err != nil {
  1060  		return err
  1061  	}
  1062  
  1063  	for _, attr := range attrs {
  1064  		switch attr.Attr.Type {
  1065  		case nl.DEVLINK_ATTR_INFO_DRIVER_NAME:
  1066  			data["driver"] = parseInfoValue(attr.Value)
  1067  		case nl.DEVLINK_ATTR_INFO_SERIAL_NUMBER:
  1068  			data["serialNumber"] = parseInfoValue(attr.Value)
  1069  		case nl.DEVLINK_ATTR_INFO_VERSION_RUNNING, nl.DEVLINK_ATTR_INFO_VERSION_FIXED,
  1070  			nl.DEVLINK_ATTR_INFO_VERSION_STORED:
  1071  			key, value, err := getNestedInfoData(attr.Value)
  1072  			if err != nil {
  1073  				return err
  1074  			}
  1075  			data[key] = value
  1076  		}
  1077  	}
  1078  
  1079  	if len(data) == 0 {
  1080  		return fmt.Errorf("collectInfoData: could not read attributes")
  1081  	}
  1082  
  1083  	return nil
  1084  }
  1085  
  1086  func getNestedInfoData(msg []byte) (string, string, error) {
  1087  	nestedAttrs, err := nl.ParseRouteAttr(msg)
  1088  
  1089  	var key, value string
  1090  
  1091  	if err != nil {
  1092  		return "", "", err
  1093  	}
  1094  
  1095  	if len(nestedAttrs) != 2 {
  1096  		return "", "", fmt.Errorf("getNestedInfoData: too few attributes in nested structure")
  1097  	}
  1098  
  1099  	for _, nestedAttr := range nestedAttrs {
  1100  		switch nestedAttr.Attr.Type {
  1101  		case nl.DEVLINK_ATTR_INFO_VERSION_NAME:
  1102  			key = parseInfoValue(nestedAttr.Value)
  1103  		case nl.DEVLINK_ATTR_INFO_VERSION_VALUE:
  1104  			value = parseInfoValue(nestedAttr.Value)
  1105  		}
  1106  	}
  1107  
  1108  	if key == "" {
  1109  		return "", "", fmt.Errorf("getNestedInfoData: key not found")
  1110  	}
  1111  
  1112  	if value == "" {
  1113  		return "", "", fmt.Errorf("getNestedInfoData: value not found")
  1114  	}
  1115  
  1116  	return key, value, nil
  1117  }
  1118  
  1119  func parseInfoData(data map[string]string) *DevlinkDeviceInfo {
  1120  	info := new(DevlinkDeviceInfo)
  1121  	for key, value := range data {
  1122  		switch key {
  1123  		case "driver":
  1124  			info.Driver = value
  1125  		case "serialNumber":
  1126  			info.SerialNumber = value
  1127  		case "board.id":
  1128  			info.BoardID = value
  1129  		case "fw.app":
  1130  			info.FwApp = value
  1131  		case "fw.app.bundle_id":
  1132  			info.FwAppBoundleID = value
  1133  		case "fw.app.name":
  1134  			info.FwAppName = value
  1135  		case "fw.bundle_id":
  1136  			info.FwBoundleID = value
  1137  		case "fw.mgmt":
  1138  			info.FwMgmt = value
  1139  		case "fw.mgmt.api":
  1140  			info.FwMgmtAPI = value
  1141  		case "fw.mgmt.build":
  1142  			info.FwMgmtBuild = value
  1143  		case "fw.netlist":
  1144  			info.FwNetlist = value
  1145  		case "fw.netlist.build":
  1146  			info.FwNetlistBuild = value
  1147  		case "fw.psid.api":
  1148  			info.FwPsidAPI = value
  1149  		case "fw.undi":
  1150  			info.FwUndi = value
  1151  		}
  1152  	}
  1153  	return info
  1154  }
  1155  
  1156  func parseInfoValue(value []byte) string {
  1157  	v := strings.ReplaceAll(string(value), "\x00", "")
  1158  	return strings.TrimSpace(v)
  1159  }