mirror of
https://github.com/vishvananda/netlink
synced 2024-12-18 12:44:55 +00:00
332a6983d9
This patch adds very basic support for getting information about devlink devices which are typically PCI devices which exposes Networking switch or legacy devices. This information includes bus name, device name and eswitch modes. This is done through devlink family of commands via generic netlink sockets provided by Linux kernel. DevlinkDevice represents a devlink device which is identified by bus name and device name (unlike interface index for netdevices). It contains the DevlinkDevAttrs device attributes. Currently only eswitch attributes are queried. In future more attributes such as port, shared buffer, traffic class will be added. Signed-off-by: Parav Pandit <parav@mellanox.com>
168 lines
4.2 KiB
Go
168 lines
4.2 KiB
Go
package netlink
|
|
|
|
import (
|
|
"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
|
|
}
|
|
|
|
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 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)
|
|
case nl.DEVLINK_ATTR_DEV_NAME:
|
|
d.DeviceName = string(a.Value)
|
|
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))
|
|
copy(b, dev.BusName)
|
|
data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
|
|
req.AddData(data)
|
|
|
|
b = make([]byte, len(dev.DeviceName))
|
|
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()
|
|
}
|