diff --git a/README.md b/README.md index 410e36e9..c14d08af 100644 --- a/README.md +++ b/README.md @@ -715,6 +715,20 @@ Each `ghw.NIC` struct contains the following fields: * `ghw.NIC.PCIAddress` is the PCI device address of the device backing the NIC. this is not-nil only if the backing device is indeed a PCI device; more backing devices (e.g. USB) will be added in future versions. +* `ghw.NIC.Speed` is a string showing the current link speed. This + field will be present even if ethtool is not available. +* `ghw.NIC.Duplex` is a string showing the current link duplex. This + field will be present even if ethtool is not available. +* `ghw.NIC.SupportedLinkModes` is a string slice containing a list of + supported link modes +* `ghw.NIC.SupportedPorts` is a string slice containing the list of + supported port types (MII, TP, FIBRE) +* `ghw.NIC.SupportedFECModes` is a string slice containing a list of + supported FEC Modes. +* `ghw.NIC.AdvertisedLinkModes` is a string slice containing the + link modes being advertised during auto negotiation. +* `ghw.NIC.AdvertisedFECModes` is a string slice containing the FEC + modes advertised during auto negotiation. The `ghw.NICCapability` struct contains the following fields: diff --git a/pkg/net/net.go b/pkg/net/net.go index dfc1dc52..2d7855a0 100644 --- a/pkg/net/net.go +++ b/pkg/net/net.go @@ -21,11 +21,20 @@ type NICCapability struct { } type NIC struct { - Name string `json:"name"` - MacAddress string `json:"mac_address"` - IsVirtual bool `json:"is_virtual"` - Capabilities []*NICCapability `json:"capabilities"` - PCIAddress *string `json:"pci_address,omitempty"` + Name string `json:"name"` + MacAddress string `json:"mac_address"` + IsVirtual bool `json:"is_virtual"` + Capabilities []*NICCapability `json:"capabilities"` + PCIAddress *string `json:"pci_address,omitempty"` + Speed string `json:"speed"` + Duplex string `json:"duplex"` + SupportedLinkModes []string `json:"supported_link_modes,omitempty"` + SupportedPorts []string `json:"supported_ports,omitempty"` + SupportedFECModes []string `json:"supported_fec_modes,omitempty"` + AdvertisedLinkModes []string `json:"advertised_link_modes,omitempty"` + AdvertisedFECModes []string `json:"advertised_fec_modes,omitempty"` + SupportedWakeOnModes []string `json:"supported_wake_on_modes,omitempty"` + AdvertisedWakeOnModes []string `json:"advertised_wake_on_modes,omitempty"` // TODO(fromani): add other hw addresses (USB) when we support them } diff --git a/pkg/net/net_linux.go b/pkg/net/net_linux.go index 6d4300f8..ee4ba09c 100644 --- a/pkg/net/net_linux.go +++ b/pkg/net/net_linux.go @@ -68,7 +68,7 @@ func nics(ctx *context.Context) []*NIC { mac := netDeviceMacAddress(paths, filename) nic.MacAddress = mac if etAvailable { - nic.Capabilities = netDeviceCapabilities(ctx, filename) + nic.netDeviceParseEthtool(ctx, filename) } else { nic.Capabilities = []*NICCapability{} } @@ -106,19 +106,29 @@ func ethtoolInstalled() bool { return err == nil } -func netDeviceCapabilities(ctx *context.Context, dev string) []*NICCapability { - caps := make([]*NICCapability, 0) +func (n *NIC) netDeviceParseEthtool(ctx *context.Context, dev string) { var out bytes.Buffer path, _ := exec.LookPath("ethtool") // Get auto-negotiation and pause-frame-use capabilities from "ethtool" (with no options) + // Populate Speed, Duplex, SupportedLinkModes, SupportedPorts, SupportedFECModes, + // AdvertisedLinkModes, and AdvertisedFECModes attributes from "ethtool" output. cmd := exec.Command(path, dev) cmd.Stdout = &out err := cmd.Run() if err == nil { m := parseNicAttrEthtool(&out) - caps = append(caps, autoNegCap(m)) - caps = append(caps, pauseFrameUseCap(m)) + n.Capabilities = append(n.Capabilities, autoNegCap(m)) + n.Capabilities = append(n.Capabilities, pauseFrameUseCap(m)) + + // Update NIC Attributes with ethtool output + n.Speed = strings.Join(m["Speed"], "") + n.Duplex = strings.Join(m["Duplex"], "") + n.SupportedLinkModes = m["Supported link modes"] + n.SupportedPorts = m["Supported ports"] + n.SupportedFECModes = m["Supported FEC modes"] + n.AdvertisedLinkModes = m["Advertised link modes"] + n.AdvertisedFECModes = m["Advertised FEC modes"] } else { msg := fmt.Sprintf("could not grab NIC link info for %s: %s", dev, err) ctx.Warn(msg) @@ -154,7 +164,7 @@ func netDeviceCapabilities(ctx *context.Context, dev string) []*NICCapability { scanner.Scan() for scanner.Scan() { line := strings.TrimPrefix(scanner.Text(), "\t") - caps = append(caps, netParseEthtoolFeature(line)) + n.Capabilities = append(n.Capabilities, netParseEthtoolFeature(line)) } } else { @@ -162,7 +172,6 @@ func netDeviceCapabilities(ctx *context.Context, dev string) []*NICCapability { ctx.Warn(msg) } - return caps } diff --git a/pkg/net/net_linux_test.go b/pkg/net/net_linux_test.go index 6da777e4..6539b091 100644 --- a/pkg/net/net_linux_test.go +++ b/pkg/net/net_linux_test.go @@ -66,7 +66,7 @@ func TestParseNicAttrEthtool(t *testing.T) { tests := []struct { input string - expected []*NICCapability + expected *NIC }{ { input: `Settings for eth0: @@ -96,16 +96,35 @@ func TestParseNicAttrEthtool(t *testing.T) { drv probe link Link detected: yes `, - expected: []*NICCapability{ - { - Name: "auto-negotiation", - IsEnabled: true, - CanEnable: true, + expected: &NIC{ + Speed: "1000Mb/s", + Duplex: "Full", + SupportedPorts: []string{"TP"}, + AdvertisedLinkModes: []string{ + "10baseT/Half", + "10baseT/Full", + "100baseT/Half", + "100baseT/Full", + "1000baseT/Full", }, - { - Name: "pause-frame-use", - IsEnabled: false, - CanEnable: false, + SupportedLinkModes: []string{ + "10baseT/Half", + "10baseT/Full", + "100baseT/Half", + "100baseT/Full", + "1000baseT/Full", + }, + Capabilities: []*NICCapability{ + { + Name: "auto-negotiation", + IsEnabled: true, + CanEnable: true, + }, + { + Name: "pause-frame-use", + IsEnabled: false, + CanEnable: false, + }, }, }, }, @@ -113,9 +132,16 @@ func TestParseNicAttrEthtool(t *testing.T) { for x, test := range tests { m := parseNicAttrEthtool(bytes.NewBufferString(test.input)) - actual := make([]*NICCapability, 0) - actual = append(actual, autoNegCap(m)) - actual = append(actual, pauseFrameUseCap(m)) + actual := &NIC{} + actual.Speed = strings.Join(m["Speed"], "") + actual.Duplex = strings.Join(m["Duplex"], "") + actual.SupportedLinkModes = m["Supported link modes"] + actual.SupportedPorts = m["Supported ports"] + actual.SupportedFECModes = m["Supported FEC modes"] + actual.AdvertisedLinkModes = m["Advertised link modes"] + actual.AdvertisedFECModes = m["Advertised FEC modes"] + actual.Capabilities = append(actual.Capabilities, autoNegCap(m)) + actual.Capabilities = append(actual.Capabilities, pauseFrameUseCap(m)) if !reflect.DeepEqual(test.expected, actual) { t.Fatalf("In test %d\nExpected:\n%+v\nActual:\n%+v\n", x, test.expected, actual) }