Skip to content

Commit

Permalink
feat: add more hardware information to the link status resources
Browse files Browse the repository at this point in the history
The new fields will be used by the network device selector.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
  • Loading branch information
Unix4ever committed May 5, 2022
1 parent 2ff6db7 commit 5d52802
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
13 changes: 13 additions & 0 deletions internal/app/machined/pkg/controllers/network/link_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ func (ctrl *LinkStatusController) reconcile(ctx context.Context, r controller.Ru
status.Duplex = nethelpers.Duplex(ethtool.Unknown)
}

var deviceInfo *nethelpers.DeviceInfo

deviceInfo, err = nethelpers.GetDeviceInfo(link.Attributes.Name)
if err != nil {
logger.Warn("failure getting device information from /sys/class/net/*", zap.Error(err), zap.String("link", link.Attributes.Name))
}

if deviceInfo != nil {
status.BusPath = deviceInfo.BusPath
status.Driver = deviceInfo.Driver
status.PCIID = deviceInfo.PCIID
}

switch status.Kind {
case network.LinkKindVLAN:
if err = networkadapter.VLANSpec(&status.VLAN).Decode(link.Attributes.Info.Data); err != nil {
Expand Down
55 changes: 55 additions & 0 deletions internal/app/machined/pkg/controllers/network/link_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ package network_test

import (
"context"
"errors"
"fmt"
"log"
"math/rand"
"net"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -125,6 +127,59 @@ func (suite *LinkStatusSuite) assertNoInterface(id string) error {
return nil
}

func (suite *LinkStatusSuite) TestInterfaceHwInfo() {
errNoInterfaces := fmt.Errorf("no suitable interfaces found")

err := retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
)
suite.Require().NoError(err)

for _, res := range resources.Items {
spec := res.(*network.LinkStatus).TypedSpec() //nolint:errcheck,forcetypeassert

if !spec.Physical() {
continue
}

if spec.Type != nethelpers.LinkEther {
continue
}

emptyFields := []string{}

for key, value := range map[string]string{
"hw addr": spec.HardwareAddr.String(),
"driver": spec.Driver,
"bus path": spec.BusPath,
"PCI id": spec.PCIID,
} {
if value == "" {
emptyFields = append(emptyFields, key)
}
}

if len(emptyFields) > 0 {
return fmt.Errorf("the interface %s has the following fields empty: %s", res.Metadata().ID(), strings.Join(emptyFields, ", "))
}

return nil
}

return retry.ExpectedError(errNoInterfaces)
},
)

if errors.Is(err, errNoInterfaces) {
suite.T().Skip(err.Error())
}

suite.Require().NoError(err)
}

func (suite *LinkStatusSuite) TestLoopbackInterface() {
suite.Assert().NoError(
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
Expand Down
78 changes: 78 additions & 0 deletions pkg/machinery/nethelpers/device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package nethelpers

import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
)

// DeviceInfo contains device hardware information that can be read from /sys/.
type DeviceInfo struct {
BusPath string
PCIID string
Driver string
}

// GetDeviceInfo get additional device information by reading /sys/ directory.
//nolint:gocyclo
func GetDeviceInfo(deviceName string) (*DeviceInfo, error) {
path := filepath.Join("/sys/class/net/", deviceName, "/device/")

readFile := func(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}

res, err := ioutil.ReadAll(f)
if err != nil {
return "", err
}

return string(bytes.TrimSpace(res)), nil
}

_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return &DeviceInfo{}, nil
}

return nil, err
}

ueventContents, err := readFile(filepath.Join(path, "uevent"))
if err != nil {
return nil, err
}

if ueventContents == "" {
return &DeviceInfo{}, nil
}

device := &DeviceInfo{}

for _, line := range strings.Split(ueventContents, "\n") {
key, value, found := strings.Cut(line, "=")
if !found {
continue
}

switch key {
case "DRIVER":
device.Driver = value
case "PCI_ID":
device.PCIID = value
case "PCI_SLOT_NAME":
device.BusPath = value
}
}

return device, nil
}
3 changes: 3 additions & 0 deletions pkg/machinery/resources/network/link_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type LinkStatusSpec struct {
OperationalState nethelpers.OperationalState `yaml:"operationalState"`
Kind string `yaml:"kind"`
SlaveKind string `yaml:"slaveKind"`
BusPath string `yaml:"busPath,omitempty"`
PCIID string `yaml:"pciID,omitempty"`
Driver string `yaml:"driver,omitempty"`
// Fields coming from ethtool API.
LinkState bool `yaml:"linkState"`
SpeedMegabits int `yaml:"speedMbit,omitempty"`
Expand Down
31 changes: 31 additions & 0 deletions website/content/v1.1/learn-more/networking-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,37 @@ NODE NAMESPACE TYPE ID VERSION RESOLVERS
172.20.0.2 network ResolverStatus resolvers 2 ["8.8.8.8","1.1.1.1"]
```

```sh
$ talosctl get links -o yaml
node: 172.20.0.2
metadata:
namespace: network
type: LinkStatuses.net.talos.dev
id: eth0
version: 2
owner: network.LinkStatusController
phase: running
created: 2021-06-29T20:23:18Z
updated: 2021-06-29T20:23:18Z
spec:
index: 4
type: ether
linkIndex: 0
flags: UP,BROADCAST,RUNNING,MULTICAST,LOWER_UP
hardwareAddr: 4e:95:8e:8f:e4:47
broadcastAddr: ff:ff:ff:ff:ff:ff
mtu: 1500
queueDisc: pfifo_fast
operationalState: up
kind: ""
slaveKind: ""
driver: virtio_net
linkState: true
speedMbit: 4294967295
port: Other
duplex: Unknown
```

## Inspecting Configuration

The desired networking configuration is combined from multiple sources and presented
Expand Down

0 comments on commit 5d52802

Please sign in to comment.