Skip to content

Commit 5d52802

Browse files
committed
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>
1 parent 2ff6db7 commit 5d52802

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

internal/app/machined/pkg/controllers/network/link_status.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,19 @@ func (ctrl *LinkStatusController) reconcile(ctx context.Context, r controller.Ru
213213
status.Duplex = nethelpers.Duplex(ethtool.Unknown)
214214
}
215215

216+
var deviceInfo *nethelpers.DeviceInfo
217+
218+
deviceInfo, err = nethelpers.GetDeviceInfo(link.Attributes.Name)
219+
if err != nil {
220+
logger.Warn("failure getting device information from /sys/class/net/*", zap.Error(err), zap.String("link", link.Attributes.Name))
221+
}
222+
223+
if deviceInfo != nil {
224+
status.BusPath = deviceInfo.BusPath
225+
status.Driver = deviceInfo.Driver
226+
status.PCIID = deviceInfo.PCIID
227+
}
228+
216229
switch status.Kind {
217230
case network.LinkKindVLAN:
218231
if err = networkadapter.VLANSpec(&status.VLAN).Decode(link.Attributes.Info.Data); err != nil {

internal/app/machined/pkg/controllers/network/link_status_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ package network_test
77

88
import (
99
"context"
10+
"errors"
1011
"fmt"
1112
"log"
1213
"math/rand"
1314
"net"
15+
"strings"
1416
"sync"
1517
"testing"
1618
"time"
@@ -125,6 +127,59 @@ func (suite *LinkStatusSuite) assertNoInterface(id string) error {
125127
return nil
126128
}
127129

130+
func (suite *LinkStatusSuite) TestInterfaceHwInfo() {
131+
errNoInterfaces := fmt.Errorf("no suitable interfaces found")
132+
133+
err := retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
134+
func() error {
135+
resources, err := suite.state.List(
136+
suite.ctx,
137+
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
138+
)
139+
suite.Require().NoError(err)
140+
141+
for _, res := range resources.Items {
142+
spec := res.(*network.LinkStatus).TypedSpec() //nolint:errcheck,forcetypeassert
143+
144+
if !spec.Physical() {
145+
continue
146+
}
147+
148+
if spec.Type != nethelpers.LinkEther {
149+
continue
150+
}
151+
152+
emptyFields := []string{}
153+
154+
for key, value := range map[string]string{
155+
"hw addr": spec.HardwareAddr.String(),
156+
"driver": spec.Driver,
157+
"bus path": spec.BusPath,
158+
"PCI id": spec.PCIID,
159+
} {
160+
if value == "" {
161+
emptyFields = append(emptyFields, key)
162+
}
163+
}
164+
165+
if len(emptyFields) > 0 {
166+
return fmt.Errorf("the interface %s has the following fields empty: %s", res.Metadata().ID(), strings.Join(emptyFields, ", "))
167+
}
168+
169+
return nil
170+
}
171+
172+
return retry.ExpectedError(errNoInterfaces)
173+
},
174+
)
175+
176+
if errors.Is(err, errNoInterfaces) {
177+
suite.T().Skip(err.Error())
178+
}
179+
180+
suite.Require().NoError(err)
181+
}
182+
128183
func (suite *LinkStatusSuite) TestLoopbackInterface() {
129184
suite.Assert().NoError(
130185
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(

pkg/machinery/nethelpers/device.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package nethelpers
6+
7+
import (
8+
"bytes"
9+
"io/ioutil"
10+
"os"
11+
"path/filepath"
12+
"strings"
13+
)
14+
15+
// DeviceInfo contains device hardware information that can be read from /sys/.
16+
type DeviceInfo struct {
17+
BusPath string
18+
PCIID string
19+
Driver string
20+
}
21+
22+
// GetDeviceInfo get additional device information by reading /sys/ directory.
23+
//nolint:gocyclo
24+
func GetDeviceInfo(deviceName string) (*DeviceInfo, error) {
25+
path := filepath.Join("/sys/class/net/", deviceName, "/device/")
26+
27+
readFile := func(path string) (string, error) {
28+
f, err := os.Open(path)
29+
if err != nil {
30+
return "", err
31+
}
32+
33+
res, err := ioutil.ReadAll(f)
34+
if err != nil {
35+
return "", err
36+
}
37+
38+
return string(bytes.TrimSpace(res)), nil
39+
}
40+
41+
_, err := os.Stat(path)
42+
if err != nil {
43+
if os.IsNotExist(err) {
44+
return &DeviceInfo{}, nil
45+
}
46+
47+
return nil, err
48+
}
49+
50+
ueventContents, err := readFile(filepath.Join(path, "uevent"))
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
if ueventContents == "" {
56+
return &DeviceInfo{}, nil
57+
}
58+
59+
device := &DeviceInfo{}
60+
61+
for _, line := range strings.Split(ueventContents, "\n") {
62+
key, value, found := strings.Cut(line, "=")
63+
if !found {
64+
continue
65+
}
66+
67+
switch key {
68+
case "DRIVER":
69+
device.Driver = value
70+
case "PCI_ID":
71+
device.PCIID = value
72+
case "PCI_SLOT_NAME":
73+
device.BusPath = value
74+
}
75+
}
76+
77+
return device, nil
78+
}

pkg/machinery/resources/network/link_status.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ type LinkStatusSpec struct {
3434
OperationalState nethelpers.OperationalState `yaml:"operationalState"`
3535
Kind string `yaml:"kind"`
3636
SlaveKind string `yaml:"slaveKind"`
37+
BusPath string `yaml:"busPath,omitempty"`
38+
PCIID string `yaml:"pciID,omitempty"`
39+
Driver string `yaml:"driver,omitempty"`
3740
// Fields coming from ethtool API.
3841
LinkState bool `yaml:"linkState"`
3942
SpeedMegabits int `yaml:"speedMbit,omitempty"`

website/content/v1.1/learn-more/networking-resources.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,37 @@ NODE NAMESPACE TYPE ID VERSION RESOLVERS
9999
172.20.0.2 network ResolverStatus resolvers 2 ["8.8.8.8","1.1.1.1"]
100100
```
101101

102+
```sh
103+
$ talosctl get links -o yaml
104+
node: 172.20.0.2
105+
metadata:
106+
namespace: network
107+
type: LinkStatuses.net.talos.dev
108+
id: eth0
109+
version: 2
110+
owner: network.LinkStatusController
111+
phase: running
112+
created: 2021-06-29T20:23:18Z
113+
updated: 2021-06-29T20:23:18Z
114+
spec:
115+
index: 4
116+
type: ether
117+
linkIndex: 0
118+
flags: UP,BROADCAST,RUNNING,MULTICAST,LOWER_UP
119+
hardwareAddr: 4e:95:8e:8f:e4:47
120+
broadcastAddr: ff:ff:ff:ff:ff:ff
121+
mtu: 1500
122+
queueDisc: pfifo_fast
123+
operationalState: up
124+
kind: ""
125+
slaveKind: ""
126+
driver: virtio_net
127+
linkState: true
128+
speedMbit: 4294967295
129+
port: Other
130+
duplex: Unknown
131+
```
132+
102133
## Inspecting Configuration
103134

104135
The desired networking configuration is combined from multiple sources and presented

0 commit comments

Comments
 (0)