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(&ethPermaddr))
-
-       _, _, 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(&ethGlink))
-
-       _, _, 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(&ethCmd))
 
-       _, _, 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(&ethPermaddr))
+
+       _, _, 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(&ethGlink))
+
+       _, _, 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(&ethCmd))
 
-       _, _, 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(&ethLinkSettings))
+
+       _, _, 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

Reply via email to