729 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			729 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package netlink
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"strings"
 | 
						|
	"syscall"
 | 
						|
 | 
						|
	"github.com/vishvananda/netlink/nl"
 | 
						|
	"golang.org/x/sys/unix"
 | 
						|
)
 | 
						|
 | 
						|
// DevlinkDevEswitchAttr represents device's eswitch attributes
 | 
						|
type DevlinkDevEswitchAttr struct {
 | 
						|
	Mode       string
 | 
						|
	InlineMode string
 | 
						|
	EncapMode  string
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkDevAttrs represents device attributes
 | 
						|
type DevlinkDevAttrs struct {
 | 
						|
	Eswitch DevlinkDevEswitchAttr
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkDevice represents device and its attributes
 | 
						|
type DevlinkDevice struct {
 | 
						|
	BusName    string
 | 
						|
	DeviceName string
 | 
						|
	Attrs      DevlinkDevAttrs
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkPortFn represents port function and its attributes
 | 
						|
type DevlinkPortFn struct {
 | 
						|
	HwAddr  net.HardwareAddr
 | 
						|
	State   uint8
 | 
						|
	OpState uint8
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkPortFnSetAttrs represents attributes to set
 | 
						|
type DevlinkPortFnSetAttrs struct {
 | 
						|
	FnAttrs     DevlinkPortFn
 | 
						|
	HwAddrValid bool
 | 
						|
	StateValid  bool
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkPort represents port and its attributes
 | 
						|
type DevlinkPort struct {
 | 
						|
	BusName        string
 | 
						|
	DeviceName     string
 | 
						|
	PortIndex      uint32
 | 
						|
	PortType       uint16
 | 
						|
	NetdeviceName  string
 | 
						|
	NetdevIfIndex  uint32
 | 
						|
	RdmaDeviceName string
 | 
						|
	PortFlavour    uint16
 | 
						|
	Fn             *DevlinkPortFn
 | 
						|
}
 | 
						|
 | 
						|
type DevLinkPortAddAttrs struct {
 | 
						|
	Controller      uint32
 | 
						|
	SfNumber        uint32
 | 
						|
	PortIndex       uint32
 | 
						|
	PfNumber        uint16
 | 
						|
	SfNumberValid   bool
 | 
						|
	PortIndexValid  bool
 | 
						|
	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 {
 | 
						|
		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		dev := &DevlinkDevice{}
 | 
						|
		if err = dev.parseAttributes(attrs); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		devices = append(devices, dev)
 | 
						|
	}
 | 
						|
	return devices, nil
 | 
						|
}
 | 
						|
 | 
						|
func eswitchStringToMode(modeName string) (uint16, error) {
 | 
						|
	if modeName == "legacy" {
 | 
						|
		return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
 | 
						|
	} else if modeName == "switchdev" {
 | 
						|
		return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
 | 
						|
	} else {
 | 
						|
		return 0xffff, fmt.Errorf("invalid switchdev mode")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func parseEswitchMode(mode uint16) string {
 | 
						|
	var eswitchMode = map[uint16]string{
 | 
						|
		nl.DEVLINK_ESWITCH_MODE_LEGACY:    "legacy",
 | 
						|
		nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
 | 
						|
	}
 | 
						|
	if eswitchMode[mode] == "" {
 | 
						|
		return "unknown"
 | 
						|
	} else {
 | 
						|
		return eswitchMode[mode]
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func parseEswitchInlineMode(inlinemode uint8) string {
 | 
						|
	var eswitchInlineMode = map[uint8]string{
 | 
						|
		nl.DEVLINK_ESWITCH_INLINE_MODE_NONE:      "none",
 | 
						|
		nl.DEVLINK_ESWITCH_INLINE_MODE_LINK:      "link",
 | 
						|
		nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK:   "network",
 | 
						|
		nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
 | 
						|
	}
 | 
						|
	if eswitchInlineMode[inlinemode] == "" {
 | 
						|
		return "unknown"
 | 
						|
	} else {
 | 
						|
		return eswitchInlineMode[inlinemode]
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func parseEswitchEncapMode(encapmode uint8) string {
 | 
						|
	var eswitchEncapMode = map[uint8]string{
 | 
						|
		nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE:  "disable",
 | 
						|
		nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
 | 
						|
	}
 | 
						|
	if eswitchEncapMode[encapmode] == "" {
 | 
						|
		return "unknown"
 | 
						|
	} else {
 | 
						|
		return eswitchEncapMode[encapmode]
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
 | 
						|
	for _, a := range attrs {
 | 
						|
		switch a.Attr.Type {
 | 
						|
		case nl.DEVLINK_ATTR_BUS_NAME:
 | 
						|
			d.BusName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_DEV_NAME:
 | 
						|
			d.DeviceName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_ESWITCH_MODE:
 | 
						|
			d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
 | 
						|
		case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
 | 
						|
			d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
 | 
						|
		case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
 | 
						|
			d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
 | 
						|
	m := msgs[0]
 | 
						|
	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
 | 
						|
	if err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	dev.parseAttributes(attrs)
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
 | 
						|
	msg := &nl.Genlmsg{
 | 
						|
		Command: nl.DEVLINK_CMD_ESWITCH_GET,
 | 
						|
		Version: nl.GENL_DEVLINK_VERSION,
 | 
						|
	}
 | 
						|
	req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
 | 
						|
	req.AddData(msg)
 | 
						|
 | 
						|
	b := make([]byte, len(dev.BusName)+1)
 | 
						|
	copy(b, dev.BusName)
 | 
						|
	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
 | 
						|
	req.AddData(data)
 | 
						|
 | 
						|
	b = make([]byte, len(dev.DeviceName)+1)
 | 
						|
	copy(b, dev.DeviceName)
 | 
						|
	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
 | 
						|
	req.AddData(data)
 | 
						|
 | 
						|
	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	dev.parseEswitchAttrs(msgs)
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 | 
						|
	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	msg := &nl.Genlmsg{
 | 
						|
		Command: nl.DEVLINK_CMD_GET,
 | 
						|
		Version: nl.GENL_DEVLINK_VERSION,
 | 
						|
	}
 | 
						|
	req := h.newNetlinkRequest(int(f.ID),
 | 
						|
		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
 | 
						|
	req.AddData(msg)
 | 
						|
	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	devices, err := parseDevLinkDeviceList(msgs)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, d := range devices {
 | 
						|
		h.getEswitchAttrs(f, d)
 | 
						|
	}
 | 
						|
	return devices, nil
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 | 
						|
	return pkgHandle.DevLinkGetDeviceList()
 | 
						|
}
 | 
						|
 | 
						|
func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
 | 
						|
	m := msgs[0]
 | 
						|
	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	dev := &DevlinkDevice{}
 | 
						|
	if err = dev.parseAttributes(attrs); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return dev, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
 | 
						|
	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	msg := &nl.Genlmsg{
 | 
						|
		Command: cmd,
 | 
						|
		Version: nl.GENL_DEVLINK_VERSION,
 | 
						|
	}
 | 
						|
	req := h.newNetlinkRequest(int(f.ID),
 | 
						|
		unix.NLM_F_REQUEST|unix.NLM_F_ACK)
 | 
						|
	req.AddData(msg)
 | 
						|
 | 
						|
	b := make([]byte, len(bus)+1)
 | 
						|
	copy(b, bus)
 | 
						|
	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
 | 
						|
	req.AddData(data)
 | 
						|
 | 
						|
	b = make([]byte, len(device)+1)
 | 
						|
	copy(b, device)
 | 
						|
	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
 | 
						|
	req.AddData(data)
 | 
						|
 | 
						|
	return f, req, nil
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
 | 
						|
	f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	dev, err := parseDevlinkDevice(respmsg)
 | 
						|
	if err == nil {
 | 
						|
		h.getEswitchAttrs(f, dev)
 | 
						|
	}
 | 
						|
	return dev, err
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
 | 
						|
	return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
 | 
						|
// returns an error code.
 | 
						|
// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
 | 
						|
// Equivalent to: `devlink dev eswitch set $dev mode legacy`
 | 
						|
func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
 | 
						|
	mode, err := eswitchStringToMode(NewMode)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
 | 
						|
 | 
						|
	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
 | 
						|
// returns an error code.
 | 
						|
// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
 | 
						|
// Equivalent to: `devlink dev eswitch set $dev mode legacy`
 | 
						|
func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
 | 
						|
	return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
 | 
						|
}
 | 
						|
 | 
						|
func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
 | 
						|
	for _, a := range attrs {
 | 
						|
		switch a.Attr.Type {
 | 
						|
		case nl.DEVLINK_ATTR_BUS_NAME:
 | 
						|
			port.BusName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_DEV_NAME:
 | 
						|
			port.DeviceName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_PORT_INDEX:
 | 
						|
			port.PortIndex = native.Uint32(a.Value)
 | 
						|
		case nl.DEVLINK_ATTR_PORT_TYPE:
 | 
						|
			port.PortType = native.Uint16(a.Value)
 | 
						|
		case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
 | 
						|
			port.NetdeviceName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
 | 
						|
			port.NetdevIfIndex = native.Uint32(a.Value)
 | 
						|
		case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
 | 
						|
			port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
 | 
						|
		case nl.DEVLINK_ATTR_PORT_FLAVOUR:
 | 
						|
			port.PortFlavour = native.Uint16(a.Value)
 | 
						|
		case nl.DEVLINK_ATTR_PORT_FUNCTION:
 | 
						|
			port.Fn = &DevlinkPortFn{}
 | 
						|
			for nested := range nl.ParseAttributes(a.Value) {
 | 
						|
				switch nested.Type {
 | 
						|
				case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
 | 
						|
					port.Fn.HwAddr = nested.Value[:]
 | 
						|
				case nl.DEVLINK_PORT_FN_ATTR_STATE:
 | 
						|
					port.Fn.State = uint8(nested.Value[0])
 | 
						|
				case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
 | 
						|
					port.Fn.OpState = uint8(nested.Value[0])
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
 | 
						|
	ports := make([]*DevlinkPort, 0, len(msgs))
 | 
						|
	for _, m := range msgs {
 | 
						|
		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		port := &DevlinkPort{}
 | 
						|
		if err = port.parseAttributes(attrs); err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		ports = append(ports, port)
 | 
						|
	}
 | 
						|
	return ports, nil
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
 | 
						|
	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	msg := &nl.Genlmsg{
 | 
						|
		Command: nl.DEVLINK_CMD_PORT_GET,
 | 
						|
		Version: nl.GENL_DEVLINK_VERSION,
 | 
						|
	}
 | 
						|
	req := h.newNetlinkRequest(int(f.ID),
 | 
						|
		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
 | 
						|
	req.AddData(msg)
 | 
						|
	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	ports, err := parseDevLinkAllPortList(msgs)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return ports, nil
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
 | 
						|
	return pkgHandle.DevLinkGetAllPortList()
 | 
						|
}
 | 
						|
 | 
						|
func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
 | 
						|
	m := msgs[0]
 | 
						|
	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	port := &DevlinkPort{}
 | 
						|
	if err = port.parseAttributes(attrs); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return port, nil
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
 | 
						|
 | 
						|
	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
 | 
						|
 | 
						|
	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	port, err := parseDevlinkPortMsg(respmsg)
 | 
						|
	return port, err
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
 | 
						|
// otherwise returns an error code.
 | 
						|
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
 | 
						|
	return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkPortAdd adds a devlink port and returns a port on success
 | 
						|
// otherwise returns nil port and an error code.
 | 
						|
func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
 | 
						|
	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
 | 
						|
	if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
 | 
						|
		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
 | 
						|
	}
 | 
						|
	if Attrs.PortIndexValid {
 | 
						|
		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
 | 
						|
	}
 | 
						|
	if Attrs.ControllerValid {
 | 
						|
		req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
 | 
						|
	}
 | 
						|
	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	port, err := parseDevlinkPortMsg(respmsg)
 | 
						|
	return port, err
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkPortAdd adds a devlink port and returns a port on success
 | 
						|
// otherwise returns nil port and an error code.
 | 
						|
func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
 | 
						|
	return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkPortDel deletes a devlink port and returns success or error code.
 | 
						|
func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
 | 
						|
	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
 | 
						|
	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// DevLinkPortDel deletes a devlink port and returns success or error code.
 | 
						|
func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
 | 
						|
	return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
 | 
						|
// It returns 0 on success or error code.
 | 
						|
func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
 | 
						|
	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
 | 
						|
 | 
						|
	fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
 | 
						|
 | 
						|
	if FnAttrs.HwAddrValid {
 | 
						|
		fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
 | 
						|
	}
 | 
						|
 | 
						|
	if FnAttrs.StateValid {
 | 
						|
		fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
 | 
						|
	}
 | 
						|
	req.AddData(fnAttr)
 | 
						|
 | 
						|
	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
 | 
						|
// It returns 0 on success or error code.
 | 
						|
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)
 | 
						|
}
 |