Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 121 additions & 2 deletions devlink_linux.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package netlink

import (
"syscall"

"fmt"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
"net"
"syscall"
)

// DevlinkDevEswitchAttr represents device's eswitch attributes
Expand All @@ -27,6 +27,20 @@ type DevlinkDevice struct {
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
Expand All @@ -37,6 +51,17 @@ type DevlinkPort struct {
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
}

func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
Expand Down Expand Up @@ -302,6 +327,18 @@ func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error
port.RdmaDeviceName = string(a.Value)
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
Expand Down Expand Up @@ -391,3 +428,85 @@ func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint
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 == true {
fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
}

if FnAttrs.StateValid == true {
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)
}
102 changes: 92 additions & 10 deletions devlink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package netlink

import (
"flag"
"net"
"testing"
)

Expand Down Expand Up @@ -53,18 +55,98 @@ func TestDevLinkGetAllPortList(t *testing.T) {
}
}

func TestDevLinkGetPortByIndex(t *testing.T) {
minKernelRequired(t, 5, 4)
ports, err := DevLinkGetAllPortList()
func TestDevLinkAddDelSfPort(t *testing.T) {
var addAttrs DevLinkPortAddAttrs
minKernelRequired(t, 5, 13)
if bus == "" || device == "" {
t.Log("devlink bus and device are empty, skipping test")
return
}

dev, err := DevLinkGetDeviceByName(bus, device)
if err != nil {
t.Fatal(err)
return
}
t.Log("devlink port count = ", len(ports))
for _, port := range ports {
p, err2 := DevLinkGetPortByIndex(port.BusName, port.DeviceName, port.PortIndex)
if err2 != nil {
t.Fatal(err)
}
t.Log(*p)
addAttrs.SfNumberValid = true
addAttrs.SfNumber = uint32(sfnum)
addAttrs.PfNumber = 0
port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs)
if err2 != nil {
t.Fatal(err2)
return
}
t.Log(*port)
if port.Fn != nil {
t.Log("function attributes = ", *port.Fn)
}
err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex)
if err2 != nil {
t.Fatal(err2)
}
}

func TestDevLinkSfPortFnSet(t *testing.T) {
var addAttrs DevLinkPortAddAttrs
var stateAttr DevlinkPortFnSetAttrs

minKernelRequired(t, 5, 12)
if bus == "" || device == "" {
t.Log("devlink bus and device are empty, skipping test")
return
}

dev, err := DevLinkGetDeviceByName(bus, device)
if err != nil {
t.Fatal(err)
return
}
addAttrs.SfNumberValid = true
addAttrs.SfNumber = uint32(sfnum)
addAttrs.PfNumber = 0
port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs)
if err2 != nil {
t.Fatal(err2)
return
}
t.Log(*port)
if port.Fn != nil {
t.Log("function attributes = ", *port.Fn)
}
macAttr := DevlinkPortFnSetAttrs{
FnAttrs: DevlinkPortFn{
HwAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
HwAddrValid: true,
}
err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, macAttr)
if err2 != nil {
t.Log("function mac set err = ", err2)
}
stateAttr.FnAttrs.State = 1
stateAttr.StateValid = true
err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, stateAttr)
if err2 != nil {
t.Log("function state set err = ", err2)
}

port, err3 := DevLinkGetPortByIndex(dev.BusName, dev.DeviceName, port.PortIndex)
if err3 == nil {
t.Log(*port)
t.Log(*port.Fn)
}
err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex)
if err2 != nil {
t.Fatal(err2)
}
}

var bus string
var device string
var sfnum uint

func init() {
flag.StringVar(&bus, "bus", "", "devlink device bus name")
flag.StringVar(&device, "device", "", "devlink device devicename")
flag.UintVar(&sfnum, "sfnum", 0, "devlink port sfnumber")
}
47 changes: 36 additions & 11 deletions nl/devlink_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,29 @@ const (
const (
DEVLINK_CMD_GET = 1
DEVLINK_CMD_PORT_GET = 5
DEVLINK_CMD_PORT_SET = 6
DEVLINK_CMD_PORT_NEW = 7
DEVLINK_CMD_PORT_DEL = 8
DEVLINK_CMD_ESWITCH_GET = 29
DEVLINK_CMD_ESWITCH_SET = 30
)

const (
DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
DEVLINK_ATTR_PORT_FUNCTION = 145
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
)

const (
Expand All @@ -53,6 +60,8 @@ const (
DEVLINK_PORT_FLAVOUR_PCI_PF = 3
DEVLINK_PORT_FLAVOUR_PCI_VF = 4
DEVLINK_PORT_FLAVOUR_VIRTUAL = 5
DEVLINK_PORT_FLAVOUR_UNUSED = 6
DEVLINK_PORT_FLAVOUR_PCI_SF = 7
)

const (
Expand All @@ -61,3 +70,19 @@ const (
DEVLINK_PORT_TYPE_ETH = 2
DEVLINK_PORT_TYPE_IB = 3
)

const (
DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 1
DEVLINK_PORT_FN_ATTR_STATE = 2
DEVLINK_PORT_FN_ATTR_OPSTATE = 3
)

const (
DEVLINK_PORT_FN_STATE_INACTIVE = 0
DEVLINK_PORT_FN_STATE_ACTIVE = 1
)

const (
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
)