Skip to content

Commit 0e1b617

Browse files
committed
Merge branch 'master' into cpuinfo_darwin
2 parents b7b997c + a05af62 commit 0e1b617

File tree

5 files changed

+428
-3
lines changed

5 files changed

+428
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ go 1.21
44

55
require (
66
github.com/google/go-cmp v0.6.0
7-
golang.org/x/sync v0.9.0
7+
golang.org/x/sync v0.10.0
88
golang.org/x/sys v0.28.0
99
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
22
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3-
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
4-
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3+
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
4+
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
55
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
66
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

sysfs/net_class_aer.go

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Copyright 2024 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
//go:build linux
15+
// +build linux
16+
17+
package sysfs
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
"strconv"
23+
"strings"
24+
25+
"github.com/prometheus/procfs/internal/util"
26+
)
27+
28+
// CorrectableAerCounters contains values from /sys/class/net/<iface>/device/aer_dev_correctable
29+
// for single interface (iface).
30+
type CorrectableAerCounters struct {
31+
RxErr uint64
32+
BadTLP uint64
33+
BadDLLP uint64
34+
Rollover uint64
35+
Timeout uint64
36+
NonFatalErr uint64
37+
CorrIntErr uint64
38+
HeaderOF uint64
39+
}
40+
41+
// UncorrectableAerCounters contains values from /sys/class/net/<iface>/device/aer_dev_[non]fatal
42+
// for single interface (iface).
43+
type UncorrectableAerCounters struct {
44+
Undefined uint64
45+
DLP uint64
46+
SDES uint64
47+
TLP uint64
48+
FCP uint64
49+
CmpltTO uint64
50+
CmpltAbrt uint64
51+
UnxCmplt uint64
52+
RxOF uint64
53+
MalfTLP uint64
54+
ECRC uint64
55+
UnsupReq uint64
56+
ACSViol uint64
57+
UncorrIntErr uint64
58+
BlockedTLP uint64
59+
AtomicOpBlocked uint64
60+
TLPBlockedErr uint64
61+
PoisonTLPBlocked uint64
62+
}
63+
64+
// AerCounters contains AER counters from files in /sys/class/net/<iface>/device
65+
// for single interface (iface).
66+
type AerCounters struct {
67+
Name string // Interface name
68+
Correctable CorrectableAerCounters
69+
Fatal UncorrectableAerCounters
70+
NonFatal UncorrectableAerCounters
71+
}
72+
73+
// AllAerCounters is collection of AER counters for every interface (iface) in /sys/class/net.
74+
// The map keys are interface (iface) names.
75+
type AllAerCounters map[string]AerCounters
76+
77+
// AerCounters returns info for a single net interfaces (iface).
78+
func (fs FS) AerCountersByIface(devicePath string) (*AerCounters, error) {
79+
_, err := fs.NetClassByIface(devicePath)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
path := fs.sys.Path(netclassPath)
85+
counters, err := parseAerCounters(filepath.Join(path, devicePath))
86+
if err != nil {
87+
return nil, err
88+
}
89+
counters.Name = devicePath
90+
91+
return counters, nil
92+
}
93+
94+
// AerCounters returns AER counters for all net interfaces (iface) read from /sys/class/net/<iface>/device.
95+
func (fs FS) AerCounters() (AllAerCounters, error) {
96+
devices, err := fs.NetClassDevices()
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
path := fs.sys.Path(netclassPath)
102+
allAerCounters := AllAerCounters{}
103+
for _, devicePath := range devices {
104+
counters, err := parseAerCounters(filepath.Join(path, devicePath))
105+
if err != nil {
106+
return nil, err
107+
}
108+
counters.Name = devicePath
109+
allAerCounters[devicePath] = *counters
110+
}
111+
112+
return allAerCounters, nil
113+
}
114+
115+
// parseAerCounters scans predefined files in /sys/class/net/<iface>/device
116+
// directory and gets their contents.
117+
func parseAerCounters(devicePath string) (*AerCounters, error) {
118+
counters := AerCounters{}
119+
err := parseCorrectableAerCounters(devicePath, &counters.Correctable)
120+
if err != nil {
121+
return nil, err
122+
}
123+
err = parseUncorrectableAerCounters(devicePath, "fatal", &counters.Fatal)
124+
if err != nil {
125+
return nil, err
126+
}
127+
err = parseUncorrectableAerCounters(devicePath, "nonfatal", &counters.NonFatal)
128+
if err != nil {
129+
return nil, err
130+
}
131+
return &counters, nil
132+
}
133+
134+
// parseCorrectableAerCounters parses correctable error counters in
135+
// /sys/class/net/<iface>/device/aer_dev_correctable.
136+
func parseCorrectableAerCounters(devicePath string, counters *CorrectableAerCounters) error {
137+
path := filepath.Join(devicePath, "device", "aer_dev_correctable")
138+
value, err := util.SysReadFile(path)
139+
if err != nil {
140+
if canIgnoreError(err) {
141+
return nil
142+
}
143+
return fmt.Errorf("failed to read file %q: %w", path, err)
144+
}
145+
146+
for _, line := range strings.Split(string(value), "\n") {
147+
if line == "" {
148+
continue
149+
}
150+
fields := strings.Fields(line)
151+
if len(fields) != 2 {
152+
return fmt.Errorf("unexpected number of fields: %v", fields)
153+
}
154+
counterName := fields[0]
155+
value, err := strconv.ParseUint(fields[1], 10, 64)
156+
if err != nil {
157+
return fmt.Errorf("error parsing value for %s: %v", counterName, err)
158+
}
159+
160+
switch counterName {
161+
case "RxErr":
162+
counters.RxErr = value
163+
case "BadTLP":
164+
counters.BadTLP = value
165+
case "BadDLLP":
166+
counters.BadDLLP = value
167+
case "Rollover":
168+
counters.Rollover = value
169+
case "Timeout":
170+
counters.Timeout = value
171+
case "NonFatalErr":
172+
counters.NonFatalErr = value
173+
case "CorrIntErr":
174+
counters.CorrIntErr = value
175+
case "HeaderOF":
176+
counters.HeaderOF = value
177+
default:
178+
continue
179+
}
180+
}
181+
182+
return nil
183+
}
184+
185+
// parseUncorrectableAerCounters parses uncorrectable error counters in
186+
// /sys/class/net/<iface>/device/aer_dev_[non]fatal.
187+
func parseUncorrectableAerCounters(devicePath string, counterType string,
188+
counters *UncorrectableAerCounters) error {
189+
path := filepath.Join(devicePath, "device", "aer_dev_"+counterType)
190+
value, err := util.ReadFileNoStat(path)
191+
if err != nil {
192+
if canIgnoreError(err) {
193+
return nil
194+
}
195+
return fmt.Errorf("failed to read file %q: %w", path, err)
196+
}
197+
198+
for _, line := range strings.Split(string(value), "\n") {
199+
if line == "" {
200+
continue
201+
}
202+
fields := strings.Fields(line)
203+
if len(fields) != 2 {
204+
return fmt.Errorf("unexpected number of fields: %v", fields)
205+
}
206+
counterName := fields[0]
207+
value, err := strconv.ParseUint(fields[1], 10, 64)
208+
if err != nil {
209+
return fmt.Errorf("error parsing value for %s: %v", counterName, err)
210+
}
211+
212+
switch counterName {
213+
case "Undefined":
214+
counters.Undefined = value
215+
case "DLP":
216+
counters.DLP = value
217+
case "SDES":
218+
counters.SDES = value
219+
case "TLP":
220+
counters.TLP = value
221+
case "FCP":
222+
counters.FCP = value
223+
case "CmpltTO":
224+
counters.CmpltTO = value
225+
case "CmpltAbrt":
226+
counters.CmpltAbrt = value
227+
case "UnxCmplt":
228+
counters.UnxCmplt = value
229+
case "RxOF":
230+
counters.RxOF = value
231+
case "MalfTLP":
232+
counters.MalfTLP = value
233+
case "ECRC":
234+
counters.ECRC = value
235+
case "UnsupReq":
236+
counters.UnsupReq = value
237+
case "ACSViol":
238+
counters.ACSViol = value
239+
case "UncorrIntErr":
240+
counters.UncorrIntErr = value
241+
case "BlockedTLP":
242+
counters.BlockedTLP = value
243+
case "AtomicOpBlocked":
244+
counters.AtomicOpBlocked = value
245+
case "TLPBlockedErr":
246+
counters.TLPBlockedErr = value
247+
case "PoisonTLPBlocked":
248+
counters.PoisonTLPBlocked = value
249+
default:
250+
continue
251+
}
252+
}
253+
254+
return nil
255+
}

sysfs/net_class_aer_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2024 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
//go:build linux
15+
// +build linux
16+
17+
package sysfs
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
)
23+
24+
func TestAerCountersByIface(t *testing.T) {
25+
fs, err := NewFS(sysTestFixtures)
26+
if err != nil {
27+
t.Fatal(err)
28+
}
29+
30+
_, err = fs.AerCountersByIface("non-existent")
31+
if err == nil {
32+
t.Fatal("expected error, have none")
33+
}
34+
35+
device, err := fs.AerCountersByIface("eth0")
36+
if err != nil {
37+
t.Fatal(err)
38+
}
39+
40+
if device.Name != "eth0" {
41+
t.Errorf("Found unexpected device, want %s, have %s", "eth0", device.Name)
42+
}
43+
}
44+
45+
func TestAerCounters(t *testing.T) {
46+
fs, err := NewFS(sysTestFixtures)
47+
if err != nil {
48+
t.Fatal(err)
49+
}
50+
51+
ac, _ := fs.AerCounters()
52+
aerCounters := AllAerCounters{
53+
"eth0": AerCounters{
54+
Name: "eth0",
55+
Correctable: CorrectableAerCounters{
56+
RxErr: 1,
57+
BadTLP: 2,
58+
BadDLLP: 3,
59+
Rollover: 4,
60+
Timeout: 5,
61+
NonFatalErr: 6,
62+
CorrIntErr: 7,
63+
HeaderOF: 8,
64+
},
65+
Fatal: UncorrectableAerCounters{
66+
Undefined: 10,
67+
DLP: 11,
68+
SDES: 12,
69+
TLP: 13,
70+
FCP: 14,
71+
CmpltTO: 15,
72+
CmpltAbrt: 16,
73+
UnxCmplt: 17,
74+
RxOF: 18,
75+
MalfTLP: 19,
76+
ECRC: 20,
77+
UnsupReq: 21,
78+
ACSViol: 22,
79+
UncorrIntErr: 23,
80+
BlockedTLP: 24,
81+
AtomicOpBlocked: 25,
82+
TLPBlockedErr: 26,
83+
PoisonTLPBlocked: 27,
84+
},
85+
NonFatal: UncorrectableAerCounters{
86+
Undefined: 30,
87+
DLP: 31,
88+
SDES: 32,
89+
TLP: 33,
90+
FCP: 34,
91+
CmpltTO: 35,
92+
CmpltAbrt: 36,
93+
UnxCmplt: 37,
94+
RxOF: 38,
95+
MalfTLP: 39,
96+
ECRC: 40,
97+
UnsupReq: 41,
98+
ACSViol: 42,
99+
UncorrIntErr: 43,
100+
BlockedTLP: 44,
101+
AtomicOpBlocked: 45,
102+
TLPBlockedErr: 46,
103+
PoisonTLPBlocked: 47,
104+
},
105+
},
106+
}
107+
108+
if !reflect.DeepEqual(aerCounters, ac) {
109+
t.Errorf("Result not correct: want %v, have %v", aerCounters, ac)
110+
}
111+
}

0 commit comments

Comments
 (0)