| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175 |
- package netlink
- import (
- "errors"
- "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
- }
- // 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
- }
- // DevlinkParam represents parameter of the device
- type DevlinkParam struct {
- Name string
- IsGeneric bool
- Type uint8 // possible values are in nl.DEVLINK_PARAM_TYPE_* constants
- Values []DevlinkParamValue
- }
- // DevlinkParamValue contains values of the parameter
- // Data field contains specific type which can be casted by unsing info from the DevlinkParam.Type field
- type DevlinkParamValue struct {
- rawData []byte
- Data interface{}
- CMODE uint8 // possible values are in nl.DEVLINK_PARAM_CMODE_* constants
- }
- // parseAttributes parses provided Netlink Attributes and populates DevlinkParam, returns error if occured
- func (dlp *DevlinkParam) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
- var valuesList [][]syscall.NetlinkRouteAttr
- for _, attr := range attrs {
- switch attr.Attr.Type {
- case nl.DEVLINK_ATTR_PARAM:
- nattrs, err := nl.ParseRouteAttr(attr.Value)
- if err != nil {
- return err
- }
- for _, nattr := range nattrs {
- switch nattr.Attr.Type {
- case nl.DEVLINK_ATTR_PARAM_NAME:
- dlp.Name = nl.BytesToString(nattr.Value)
- case nl.DEVLINK_ATTR_PARAM_GENERIC:
- dlp.IsGeneric = true
- case nl.DEVLINK_ATTR_PARAM_TYPE:
- if len(nattr.Value) == 1 {
- dlp.Type = nattr.Value[0]
- }
- case nl.DEVLINK_ATTR_PARAM_VALUES_LIST:
- nnattrs, err := nl.ParseRouteAttr(nattr.Value)
- if err != nil {
- return err
- }
- valuesList = append(valuesList, nnattrs)
- }
- }
- }
- }
- for _, valAttr := range valuesList {
- v := DevlinkParamValue{}
- if err := v.parseAttributes(valAttr, dlp.Type); err != nil {
- return err
- }
- dlp.Values = append(dlp.Values, v)
- }
- return nil
- }
- func (dlpv *DevlinkParamValue) parseAttributes(attrs []syscall.NetlinkRouteAttr, paramType uint8) error {
- for _, attr := range attrs {
- nattrs, err := nl.ParseRouteAttr(attr.Value)
- if err != nil {
- return err
- }
- var rawData []byte
- for _, nattr := range nattrs {
- switch nattr.Attr.Type {
- case nl.DEVLINK_ATTR_PARAM_VALUE_DATA:
- rawData = nattr.Value
- case nl.DEVLINK_ATTR_PARAM_VALUE_CMODE:
- if len(nattr.Value) == 1 {
- dlpv.CMODE = nattr.Value[0]
- }
- }
- }
- switch paramType {
- case nl.DEVLINK_PARAM_TYPE_U8:
- dlpv.Data = uint8(0)
- if rawData != nil && len(rawData) == 1 {
- dlpv.Data = uint8(rawData[0])
- }
- case nl.DEVLINK_PARAM_TYPE_U16:
- dlpv.Data = uint16(0)
- if rawData != nil {
- dlpv.Data = native.Uint16(rawData)
- }
- case nl.DEVLINK_PARAM_TYPE_U32:
- dlpv.Data = uint32(0)
- if rawData != nil {
- dlpv.Data = native.Uint32(rawData)
- }
- case nl.DEVLINK_PARAM_TYPE_STRING:
- dlpv.Data = ""
- if rawData != nil {
- dlpv.Data = nl.BytesToString(rawData)
- }
- case nl.DEVLINK_PARAM_TYPE_BOOL:
- dlpv.Data = rawData != nil
- }
- }
- return nil
- }
- 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.
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- devices, err := parseDevLinkDeviceList(msgs)
- if err != nil {
- return nil, err
- }
- for _, d := range devices {
- h.getEswitchAttrs(f, d)
- }
- return devices, executeErr
- }
- // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
- // otherwise returns an error code.
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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.
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- ports, err := parseDevLinkAllPortList(msgs)
- if err != nil {
- return nil, err
- }
- return ports, executeErr
- }
- // DevLinkGetPortList provides a pointer to devlink ports and nil error,
- // otherwise returns an error code.
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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
- }
- // 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
- }
- // DevlinkGetDeviceParams returns parameters for devlink device
- // Equivalent to: `devlink dev param show <bus>/<device>`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
- _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
- if err != nil {
- return nil, err
- }
- req.Flags |= unix.NLM_F_DUMP
- respmsg, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- var params []*DevlinkParam
- for _, m := range respmsg {
- attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
- if err != nil {
- return nil, err
- }
- p := &DevlinkParam{}
- if err := p.parseAttributes(attrs); err != nil {
- return nil, err
- }
- params = append(params, p)
- }
- return params, executeErr
- }
- // DevlinkGetDeviceParams returns parameters for devlink device
- // Equivalent to: `devlink dev param show <bus>/<device>`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
- return pkgHandle.DevlinkGetDeviceParams(bus, device)
- }
- // DevlinkGetDeviceParamByName returns specific parameter for devlink device
- // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
- func (h *Handle) DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
- _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
- if err != nil {
- return nil, err
- }
- req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
- respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
- if err != nil {
- return nil, err
- }
- if len(respmsg) == 0 {
- return nil, fmt.Errorf("unexpected response")
- }
- attrs, err := nl.ParseRouteAttr(respmsg[0][nl.SizeofGenlmsg:])
- if err != nil {
- return nil, err
- }
- p := &DevlinkParam{}
- if err := p.parseAttributes(attrs); err != nil {
- return nil, err
- }
- return p, nil
- }
- // DevlinkGetDeviceParamByName returns specific parameter for devlink device
- // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
- func DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
- return pkgHandle.DevlinkGetDeviceParamByName(bus, device, param)
- }
- // DevlinkSetDeviceParam set specific parameter for devlink device
- // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
- // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
- // value argument should have one of the following types: uint8, uint16, uint32, string, bool
- func (h *Handle) DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
- // retrive the param type
- p, err := h.DevlinkGetDeviceParamByName(bus, device, param)
- if err != nil {
- return fmt.Errorf("failed to get device param: %v", err)
- }
- paramType := p.Type
- _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_SET, bus, device)
- if err != nil {
- return err
- }
- req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_TYPE, nl.Uint8Attr(paramType)))
- req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
- req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_CMODE, nl.Uint8Attr(cmode)))
- var valueAsBytes []byte
- switch paramType {
- case nl.DEVLINK_PARAM_TYPE_U8:
- v, ok := value.(uint8)
- if !ok {
- return fmt.Errorf("unepected value type required: uint8, actual: %T", value)
- }
- valueAsBytes = nl.Uint8Attr(v)
- case nl.DEVLINK_PARAM_TYPE_U16:
- v, ok := value.(uint16)
- if !ok {
- return fmt.Errorf("unepected value type required: uint16, actual: %T", value)
- }
- valueAsBytes = nl.Uint16Attr(v)
- case nl.DEVLINK_PARAM_TYPE_U32:
- v, ok := value.(uint32)
- if !ok {
- return fmt.Errorf("unepected value type required: uint32, actual: %T", value)
- }
- valueAsBytes = nl.Uint32Attr(v)
- case nl.DEVLINK_PARAM_TYPE_STRING:
- v, ok := value.(string)
- if !ok {
- return fmt.Errorf("unepected value type required: string, actual: %T", value)
- }
- valueAsBytes = nl.ZeroTerminated(v)
- case nl.DEVLINK_PARAM_TYPE_BOOL:
- v, ok := value.(bool)
- if !ok {
- return fmt.Errorf("unepected value type required: bool, actual: %T", value)
- }
- if v {
- valueAsBytes = []byte{}
- }
- default:
- return fmt.Errorf("unsupported parameter type: %d", paramType)
- }
- if valueAsBytes != nil {
- req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_DATA, valueAsBytes))
- }
- _, err = req.Execute(unix.NETLINK_GENERIC, 0)
- return err
- }
- // DevlinkSetDeviceParam set specific parameter for devlink device
- // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
- // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
- // value argument should have one of the following types: uint8, uint16, uint32, string, bool
- func DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
- return pkgHandle.DevlinkSetDeviceParam(bus, device, param, cmode, value)
- }
- // 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)
- }
|