[lxc-devel] [lxd/master] ethtool: resources/ethtool: implement ETHTOOL_GLINKSETTINGS
brauner on Github
lxc-bot at linuxcontainers.org
Thu May 7 14:37:48 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200507/b06a5c89/attachment.bin>
-------------- next part --------------
From 34b5ea2314c2e1a9df4abc0911bbc1c1a77aaa5d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 6 May 2020 09:33:56 +0200
Subject: [PATCH 1/2] ethtool: add ethtoolGset() helper
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/resources/network_ethtool.go | 88 ++++++++++++++++++--------------
1 file changed, 49 insertions(+), 39 deletions(-)
diff --git a/lxd/resources/network_ethtool.go b/lxd/resources/network_ethtool.go
index ce3d00fb52..c910045f06 100644
--- a/lxd/resources/network_ethtool.go
+++ b/lxd/resources/network_ethtool.go
@@ -144,51 +144,14 @@ func ethtoolAddCardInfo(name string, info *api.ResourcesNetworkCard) error {
return nil
}
-func ethtoolAddPortInfo(info *api.ResourcesNetworkCardPort) error {
- // Open FD
- ethtoolFd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
- if err != nil {
- return errors.Wrap(err, "Failed to open IPPROTO_IP socket")
- }
- defer unix.Close(ethtoolFd)
-
- // Prepare the request struct
- req := ethtoolReq{}
- copy(req.name[:], []byte(info.ID))
-
- // Try to get MAC address
- ethPermaddr := ethtoolPermAddr{
- cmd: 0x00000020,
- size: 32,
- }
- req.data = uintptr(unsafe.Pointer(ðPermaddr))
-
- _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
- if errno == 0 {
- hwaddr := net.HardwareAddr(ethPermaddr.data[0:ethPermaddr.size])
- info.Address = hwaddr.String()
- }
-
- // Link state
- ethGlink := ethtoolValue{
- cmd: 0x0000000a,
- }
- req.data = uintptr(unsafe.Pointer(ðGlink))
-
- _, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
- if errno != 0 {
- return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GLINK")
- }
-
- info.LinkDetected = ethGlink.data == 1
-
+func ethtoolGset(ethtoolFd int, req *ethtoolReq, info *api.ResourcesNetworkCardPort) error {
// Interface info
ethCmd := ethtoolCmd{
cmd: 0x00000001,
}
req.data = uintptr(unsafe.Pointer(ðCmd))
- _, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
if errno != 0 {
return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GSET")
}
@@ -255,3 +218,50 @@ func ethtoolAddPortInfo(info *api.ResourcesNetworkCardPort) error {
return nil
}
+
+func ethtoolAddPortInfo(info *api.ResourcesNetworkCardPort) error {
+ // Open FD
+ ethtoolFd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
+ if err != nil {
+ return errors.Wrap(err, "Failed to open IPPROTO_IP socket")
+ }
+ defer unix.Close(ethtoolFd)
+
+ // Prepare the request struct
+ req := ethtoolReq{}
+ copy(req.name[:], []byte(info.ID))
+
+ // Try to get MAC address
+ ethPermaddr := ethtoolPermAddr{
+ cmd: 0x00000020,
+ size: 32,
+ }
+ req.data = uintptr(unsafe.Pointer(ðPermaddr))
+
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
+ if errno == 0 {
+ hwaddr := net.HardwareAddr(ethPermaddr.data[0:ethPermaddr.size])
+ info.Address = hwaddr.String()
+ }
+
+ // Link state
+ ethGlink := ethtoolValue{
+ cmd: 0x0000000a,
+ }
+ req.data = uintptr(unsafe.Pointer(ðGlink))
+
+ _, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
+ if errno != 0 {
+ return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GLINK")
+ }
+
+ info.LinkDetected = ethGlink.data == 1
+
+ // Interface info
+ err = ethtoolGset(ethtoolFd, &req, info)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
From ca655d798a128b623de650ffa655f443ab8e84c8 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 7 May 2020 16:36:02 +0200
Subject: [PATCH 2/2] resources/ethtool: implement ETHTOOL_GLINKSETTINGS
Closes: #7307.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/resources/network_ethtool.go | 131 ++++++++++++++++++++++++++++++-
lxd/resources/utils.go | 4 +
2 files changed, 132 insertions(+), 3 deletions(-)
diff --git a/lxd/resources/network_ethtool.go b/lxd/resources/network_ethtool.go
index c910045f06..35f9738a26 100644
--- a/lxd/resources/network_ethtool.go
+++ b/lxd/resources/network_ethtool.go
@@ -117,6 +117,34 @@ type ethtoolValue struct {
data uint32
}
+const EthtoolLinkModeMaskMaxKernelNu32 = 127 // SCHAR_MAX
+type ethtoolLinkSettings struct {
+ cmd uint32
+ speed uint32
+ duplex uint8
+ port uint8
+ phyAddress uint8
+ autoneg uint8
+ mdioSupport uint8
+ ethTpMdix uint8
+ ethTpMdixCtrl uint8
+ linkModeMasksNwords int8
+ transceiver uint8
+ reserved1 [3]uint8
+ reserved [7]uint32
+ linkModeMasks [0]uint32
+ linkModeData [3 * EthtoolLinkModeMaskMaxKernelNu32]uint32
+ // __u32 map_supported[link_mode_masks_nwords];
+ // __u32 map_advertising[link_mode_masks_nwords];
+ // __u32 map_lp_advertising[link_mode_masks_nwords];
+}
+
+type ethtoolLinkModeMaps struct {
+ mapSupported []uint32
+ mapAdvertising []uint32
+ mapLpAdvertising []uint32
+}
+
func ethtoolAddCardInfo(name string, info *api.ResourcesNetworkCard) error {
// Open FD
ethtoolFd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
@@ -151,7 +179,7 @@ func ethtoolGset(ethtoolFd int, req *ethtoolReq, info *api.ResourcesNetworkCardP
}
req.data = uintptr(unsafe.Pointer(ðCmd))
- _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(&req)))
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(req)))
if errno != 0 {
return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GSET")
}
@@ -219,6 +247,103 @@ func ethtoolGset(ethtoolFd int, req *ethtoolReq, info *api.ResourcesNetworkCardP
return nil
}
+func ethtoolLink(ethtoolFd int, req *ethtoolReq, info *api.ResourcesNetworkCardPort) error {
+ // Interface info
+ ethLinkSettings := ethtoolLinkSettings{
+ cmd: 0x0000004c,
+ }
+ req.data = uintptr(unsafe.Pointer(ðLinkSettings))
+
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(req)))
+ if errno != 0 {
+ return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GLINKSETTINGS")
+ }
+
+ if ethLinkSettings.linkModeMasksNwords >= 0 || ethLinkSettings.cmd != 0x0000004c {
+ return errors.Wrap(unix.Errno(unix.EINVAL), "Failed to ETHTOOL_GLINKSETTINGS")
+ }
+
+ /* got the real ecmd.req.link_mode_masks_nwords,
+ * now send the real request
+ */
+ ethLinkSettings.cmd = 0x0000004c
+ ethLinkSettings.linkModeMasksNwords = -ethLinkSettings.linkModeMasksNwords
+ _, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(ethtoolFd), unix.SIOCETHTOOL, uintptr(unsafe.Pointer(req)))
+ if errno != 0 {
+ return errors.Wrap(unix.Errno(errno), "Failed to ETHTOOL_GLINKSETTINGS")
+ }
+
+ if ethLinkSettings.linkModeMasksNwords <= 0 || ethLinkSettings.cmd != 0x0000004c {
+ return errors.Wrap(unix.Errno(unix.EINVAL), "Failed to ETHTOOL_GLINKSETTINGS")
+ }
+
+ ethLinkModeMap := ethtoolLinkModeMaps{}
+ ethLinkModeMap.mapSupported = append(ethLinkModeMap.mapSupported, ethLinkSettings.linkModeData[:4*ethLinkSettings.linkModeMasksNwords]...)
+ offset := ethLinkSettings.linkModeMasksNwords
+ ethLinkModeMap.mapAdvertising = append(ethLinkModeMap.mapAdvertising, ethLinkSettings.linkModeData[offset:4*ethLinkSettings.linkModeMasksNwords]...)
+ offset += ethLinkSettings.linkModeMasksNwords
+ ethLinkModeMap.mapLpAdvertising = append(ethLinkModeMap.mapLpAdvertising, ethLinkSettings.linkModeData[offset:4*ethLinkSettings.linkModeMasksNwords]...)
+
+ // Link negotiation
+ info.AutoNegotiation = ethLinkSettings.autoneg == 1
+
+ if info.LinkDetected {
+ // Link duplex
+ if ethLinkSettings.duplex == 0x00 {
+ info.LinkDuplex = "half"
+ } else if ethLinkSettings.duplex == 0x01 {
+ info.LinkDuplex = "full"
+ }
+
+ // Link speed
+ info.LinkSpeed = uint64(ethLinkSettings.speed)
+ }
+
+ // Transceiver
+ if ethLinkSettings.transceiver == 0x00 {
+ info.TransceiverType = "internal"
+ } else if ethLinkSettings.transceiver == 0x01 {
+ info.TransceiverType = "external"
+ }
+
+ // Port
+ if ethLinkSettings.port == 0x00 {
+ info.PortType = "twisted pair"
+ } else if ethLinkSettings.port == 0x01 {
+ info.PortType = "AUI"
+ } else if ethLinkSettings.port == 0x02 {
+ info.PortType = "media-independent"
+ } else if ethLinkSettings.port == 0x03 {
+ info.PortType = "fibre"
+ } else if ethLinkSettings.port == 0x04 {
+ info.PortType = "BNC"
+ } else if ethLinkSettings.port == 0x05 {
+ info.PortType = "direct attach"
+ } else if ethLinkSettings.port == 0xef {
+ info.PortType = "none"
+ } else if ethLinkSettings.port == 0xff {
+ info.PortType = "other"
+ }
+
+ // Supported modes
+ info.SupportedModes = []string{}
+ for _, mode := range ethtoolModes {
+ if hasBitField(ethLinkModeMap.mapSupported, mode.bit) {
+ info.SupportedModes = append(info.SupportedModes, mode.name)
+ }
+ }
+
+ // Supported ports
+ info.SupportedPorts = []string{}
+ for _, port := range ethtoolPorts {
+ if hasBitField(ethLinkModeMap.mapSupported, port.bit) {
+ info.SupportedPorts = append(info.SupportedPorts, port.name)
+ }
+ }
+
+ return nil
+}
+
func ethtoolAddPortInfo(info *api.ResourcesNetworkCardPort) error {
// Open FD
ethtoolFd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
@@ -258,9 +383,9 @@ func ethtoolAddPortInfo(info *api.ResourcesNetworkCardPort) error {
info.LinkDetected = ethGlink.data == 1
// Interface info
- err = ethtoolGset(ethtoolFd, &req, info)
+ err = ethtoolLink(ethtoolFd, &req, info)
if err != nil {
- return err
+ return ethtoolGset(ethtoolFd, &req, info)
}
return nil
diff --git a/lxd/resources/utils.go b/lxd/resources/utils.go
index 49019e185e..8290b5c6ab 100644
--- a/lxd/resources/utils.go
+++ b/lxd/resources/utils.go
@@ -88,3 +88,7 @@ func hasBit(n uint32, pos uint) bool {
val := n & (1 << pos)
return (val > 0)
}
+
+func hasBitField(n []uint32, bit uint) bool {
+ return (n[bit/32] & (1 << (bit % 32))) != 0
+}
More information about the lxc-devel
mailing list