diff --git a/devlink_linux.go b/devlink_linux.go index ef20a1f..0db166f 100644 --- a/devlink_linux.go +++ b/devlink_linux.go @@ -47,6 +47,16 @@ type DevlinkPort struct { 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) { devices := make([]*DevlinkDevice, 0, len(msgs)) for _, m := range msgs { @@ -411,3 +421,54 @@ 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) +} diff --git a/devlink_test.go b/devlink_test.go index 47e845d..3364636 100644 --- a/devlink_test.go +++ b/devlink_test.go @@ -4,6 +4,7 @@ package netlink import ( "testing" + "flag" ) func TestDevLinkGetDeviceList(t *testing.T) { @@ -53,21 +54,43 @@ 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) - if p.Fn != nil { - t.Log("function attributes = " , *p.Fn) - } + 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) } } + +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") +} diff --git a/nl/devlink_linux.go b/nl/devlink_linux.go index f98ee69..2410922 100644 --- a/nl/devlink_linux.go +++ b/nl/devlink_linux.go @@ -11,23 +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_PORT_FUNCTION = 145 + 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 (