mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-22 13:01:38 +02:00
feat: add more hardware information to the link status resources
The new fields will be used by the network device selector. Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
This commit is contained in:
parent
2ff6db749a
commit
5d52802001
@ -213,6 +213,19 @@ func (ctrl *LinkStatusController) reconcile(ctx context.Context, r controller.Ru
|
|||||||
status.Duplex = nethelpers.Duplex(ethtool.Unknown)
|
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 {
|
switch status.Kind {
|
||||||
case network.LinkKindVLAN:
|
case network.LinkKindVLAN:
|
||||||
if err = networkadapter.VLANSpec(&status.VLAN).Decode(link.Attributes.Info.Data); err != nil {
|
if err = networkadapter.VLANSpec(&status.VLAN).Decode(link.Attributes.Info.Data); err != nil {
|
||||||
|
@ -7,10 +7,12 @@ package network_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -125,6 +127,59 @@ func (suite *LinkStatusSuite) assertNoInterface(id string) error {
|
|||||||
return nil
|
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() {
|
func (suite *LinkStatusSuite) TestLoopbackInterface() {
|
||||||
suite.Assert().NoError(
|
suite.Assert().NoError(
|
||||||
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||||
|
78
pkg/machinery/nethelpers/device.go
Normal file
78
pkg/machinery/nethelpers/device.go
Normal file
@ -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
|
||||||
|
}
|
@ -34,6 +34,9 @@ type LinkStatusSpec struct {
|
|||||||
OperationalState nethelpers.OperationalState `yaml:"operationalState"`
|
OperationalState nethelpers.OperationalState `yaml:"operationalState"`
|
||||||
Kind string `yaml:"kind"`
|
Kind string `yaml:"kind"`
|
||||||
SlaveKind string `yaml:"slaveKind"`
|
SlaveKind string `yaml:"slaveKind"`
|
||||||
|
BusPath string `yaml:"busPath,omitempty"`
|
||||||
|
PCIID string `yaml:"pciID,omitempty"`
|
||||||
|
Driver string `yaml:"driver,omitempty"`
|
||||||
// Fields coming from ethtool API.
|
// Fields coming from ethtool API.
|
||||||
LinkState bool `yaml:"linkState"`
|
LinkState bool `yaml:"linkState"`
|
||||||
SpeedMegabits int `yaml:"speedMbit,omitempty"`
|
SpeedMegabits int `yaml:"speedMbit,omitempty"`
|
||||||
|
@ -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"]
|
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
|
## Inspecting Configuration
|
||||||
|
|
||||||
The desired networking configuration is combined from multiple sources and presented
|
The desired networking configuration is combined from multiple sources and presented
|
||||||
|
Loading…
x
Reference in New Issue
Block a user