The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7327
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
From 34b5ea2314c2e1a9df4abc0911bbc1c1a77aaa5d Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@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.brau...@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.brau...@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.brau...@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 +}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel