From c0a6b978d6b581b354593c9b27577c90665bd51d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:11:33 +0000 Subject: [PATCH 1/3] Bump golang.org/x/sync from 0.8.0 to 0.9.0 Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.8.0 to 0.9.0. - [Commits](https://github.com/golang/sync/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f1337ebe..f0f076b0 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.21 require ( github.com/google/go-cmp v0.6.0 - golang.org/x/sync v0.8.0 + golang.org/x/sync v0.9.0 golang.org/x/sys v0.26.0 ) diff --git a/go.sum b/go.sum index 2149e39b..5e6aa650 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From 82ce1c1d1e89853a5c8363978b26f8a6e804cb19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:49:13 +0100 Subject: [PATCH 2/3] Bump golang.org/x/sys from 0.26.0 to 0.28.0 (#688) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.26.0 to 0.28.0. - [Commits](https://github.com/golang/sys/compare/v0.26.0...v0.28.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f0f076b0..89c02f9c 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.21 require ( github.com/google/go-cmp v0.6.0 golang.org/x/sync v0.9.0 - golang.org/x/sys v0.26.0 + golang.org/x/sys v0.28.0 ) diff --git a/go.sum b/go.sum index 5e6aa650..0bd13908 100644 --- a/go.sum +++ b/go.sum @@ -2,5 +2,5 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From 24ab3d8d880d820115eef19f7b0c2c38fffd6a25 Mon Sep 17 00:00:00 2001 From: dasturiasArista <dasturias@arista.com> Date: Sat, 21 Dec 2024 11:45:11 -0800 Subject: [PATCH 3/3] feat: Read PCIE AER counters class/net (#686) * feat: Read PCIE AER counters class/net Linux provides AER counters in the path /sys/class/net/<iface>/device/ This is split amoung 3 different files: aer_dev_correctable aer_dev_fatal aer_dev_nonfatal --------- Signed-off-by: Diego Asturias <dasturias@arista.com> --- sysfs/net_class_aer.go | 255 ++++++++++++++++++++++++++++++++++++ sysfs/net_class_aer_test.go | 111 ++++++++++++++++ testdata/fixtures.ttar | 59 +++++++++ 3 files changed, 425 insertions(+) create mode 100644 sysfs/net_class_aer.go create mode 100644 sysfs/net_class_aer_test.go diff --git a/sysfs/net_class_aer.go b/sysfs/net_class_aer.go new file mode 100644 index 00000000..c99539c6 --- /dev/null +++ b/sysfs/net_class_aer.go @@ -0,0 +1,255 @@ +// Copyright 2024 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux +// +build linux + +package sysfs + +import ( + "fmt" + "path/filepath" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// CorrectableAerCounters contains values from /sys/class/net/<iface>/device/aer_dev_correctable +// for single interface (iface). +type CorrectableAerCounters struct { + RxErr uint64 + BadTLP uint64 + BadDLLP uint64 + Rollover uint64 + Timeout uint64 + NonFatalErr uint64 + CorrIntErr uint64 + HeaderOF uint64 +} + +// UncorrectableAerCounters contains values from /sys/class/net/<iface>/device/aer_dev_[non]fatal +// for single interface (iface). +type UncorrectableAerCounters struct { + Undefined uint64 + DLP uint64 + SDES uint64 + TLP uint64 + FCP uint64 + CmpltTO uint64 + CmpltAbrt uint64 + UnxCmplt uint64 + RxOF uint64 + MalfTLP uint64 + ECRC uint64 + UnsupReq uint64 + ACSViol uint64 + UncorrIntErr uint64 + BlockedTLP uint64 + AtomicOpBlocked uint64 + TLPBlockedErr uint64 + PoisonTLPBlocked uint64 +} + +// AerCounters contains AER counters from files in /sys/class/net/<iface>/device +// for single interface (iface). +type AerCounters struct { + Name string // Interface name + Correctable CorrectableAerCounters + Fatal UncorrectableAerCounters + NonFatal UncorrectableAerCounters +} + +// AllAerCounters is collection of AER counters for every interface (iface) in /sys/class/net. +// The map keys are interface (iface) names. +type AllAerCounters map[string]AerCounters + +// AerCounters returns info for a single net interfaces (iface). +func (fs FS) AerCountersByIface(devicePath string) (*AerCounters, error) { + _, err := fs.NetClassByIface(devicePath) + if err != nil { + return nil, err + } + + path := fs.sys.Path(netclassPath) + counters, err := parseAerCounters(filepath.Join(path, devicePath)) + if err != nil { + return nil, err + } + counters.Name = devicePath + + return counters, nil +} + +// AerCounters returns AER counters for all net interfaces (iface) read from /sys/class/net/<iface>/device. +func (fs FS) AerCounters() (AllAerCounters, error) { + devices, err := fs.NetClassDevices() + if err != nil { + return nil, err + } + + path := fs.sys.Path(netclassPath) + allAerCounters := AllAerCounters{} + for _, devicePath := range devices { + counters, err := parseAerCounters(filepath.Join(path, devicePath)) + if err != nil { + return nil, err + } + counters.Name = devicePath + allAerCounters[devicePath] = *counters + } + + return allAerCounters, nil +} + +// parseAerCounters scans predefined files in /sys/class/net/<iface>/device +// directory and gets their contents. +func parseAerCounters(devicePath string) (*AerCounters, error) { + counters := AerCounters{} + err := parseCorrectableAerCounters(devicePath, &counters.Correctable) + if err != nil { + return nil, err + } + err = parseUncorrectableAerCounters(devicePath, "fatal", &counters.Fatal) + if err != nil { + return nil, err + } + err = parseUncorrectableAerCounters(devicePath, "nonfatal", &counters.NonFatal) + if err != nil { + return nil, err + } + return &counters, nil +} + +// parseCorrectableAerCounters parses correctable error counters in +// /sys/class/net/<iface>/device/aer_dev_correctable. +func parseCorrectableAerCounters(devicePath string, counters *CorrectableAerCounters) error { + path := filepath.Join(devicePath, "device", "aer_dev_correctable") + value, err := util.SysReadFile(path) + if err != nil { + if canIgnoreError(err) { + return nil + } + return fmt.Errorf("failed to read file %q: %w", path, err) + } + + for _, line := range strings.Split(string(value), "\n") { + if line == "" { + continue + } + fields := strings.Fields(line) + if len(fields) != 2 { + return fmt.Errorf("unexpected number of fields: %v", fields) + } + counterName := fields[0] + value, err := strconv.ParseUint(fields[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing value for %s: %v", counterName, err) + } + + switch counterName { + case "RxErr": + counters.RxErr = value + case "BadTLP": + counters.BadTLP = value + case "BadDLLP": + counters.BadDLLP = value + case "Rollover": + counters.Rollover = value + case "Timeout": + counters.Timeout = value + case "NonFatalErr": + counters.NonFatalErr = value + case "CorrIntErr": + counters.CorrIntErr = value + case "HeaderOF": + counters.HeaderOF = value + default: + continue + } + } + + return nil +} + +// parseUncorrectableAerCounters parses uncorrectable error counters in +// /sys/class/net/<iface>/device/aer_dev_[non]fatal. +func parseUncorrectableAerCounters(devicePath string, counterType string, + counters *UncorrectableAerCounters) error { + path := filepath.Join(devicePath, "device", "aer_dev_"+counterType) + value, err := util.ReadFileNoStat(path) + if err != nil { + if canIgnoreError(err) { + return nil + } + return fmt.Errorf("failed to read file %q: %w", path, err) + } + + for _, line := range strings.Split(string(value), "\n") { + if line == "" { + continue + } + fields := strings.Fields(line) + if len(fields) != 2 { + return fmt.Errorf("unexpected number of fields: %v", fields) + } + counterName := fields[0] + value, err := strconv.ParseUint(fields[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing value for %s: %v", counterName, err) + } + + switch counterName { + case "Undefined": + counters.Undefined = value + case "DLP": + counters.DLP = value + case "SDES": + counters.SDES = value + case "TLP": + counters.TLP = value + case "FCP": + counters.FCP = value + case "CmpltTO": + counters.CmpltTO = value + case "CmpltAbrt": + counters.CmpltAbrt = value + case "UnxCmplt": + counters.UnxCmplt = value + case "RxOF": + counters.RxOF = value + case "MalfTLP": + counters.MalfTLP = value + case "ECRC": + counters.ECRC = value + case "UnsupReq": + counters.UnsupReq = value + case "ACSViol": + counters.ACSViol = value + case "UncorrIntErr": + counters.UncorrIntErr = value + case "BlockedTLP": + counters.BlockedTLP = value + case "AtomicOpBlocked": + counters.AtomicOpBlocked = value + case "TLPBlockedErr": + counters.TLPBlockedErr = value + case "PoisonTLPBlocked": + counters.PoisonTLPBlocked = value + default: + continue + } + } + + return nil +} diff --git a/sysfs/net_class_aer_test.go b/sysfs/net_class_aer_test.go new file mode 100644 index 00000000..2d75265a --- /dev/null +++ b/sysfs/net_class_aer_test.go @@ -0,0 +1,111 @@ +// Copyright 2024 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux +// +build linux + +package sysfs + +import ( + "reflect" + "testing" +) + +func TestAerCountersByIface(t *testing.T) { + fs, err := NewFS(sysTestFixtures) + if err != nil { + t.Fatal(err) + } + + _, err = fs.AerCountersByIface("non-existent") + if err == nil { + t.Fatal("expected error, have none") + } + + device, err := fs.AerCountersByIface("eth0") + if err != nil { + t.Fatal(err) + } + + if device.Name != "eth0" { + t.Errorf("Found unexpected device, want %s, have %s", "eth0", device.Name) + } +} + +func TestAerCounters(t *testing.T) { + fs, err := NewFS(sysTestFixtures) + if err != nil { + t.Fatal(err) + } + + ac, _ := fs.AerCounters() + aerCounters := AllAerCounters{ + "eth0": AerCounters{ + Name: "eth0", + Correctable: CorrectableAerCounters{ + RxErr: 1, + BadTLP: 2, + BadDLLP: 3, + Rollover: 4, + Timeout: 5, + NonFatalErr: 6, + CorrIntErr: 7, + HeaderOF: 8, + }, + Fatal: UncorrectableAerCounters{ + Undefined: 10, + DLP: 11, + SDES: 12, + TLP: 13, + FCP: 14, + CmpltTO: 15, + CmpltAbrt: 16, + UnxCmplt: 17, + RxOF: 18, + MalfTLP: 19, + ECRC: 20, + UnsupReq: 21, + ACSViol: 22, + UncorrIntErr: 23, + BlockedTLP: 24, + AtomicOpBlocked: 25, + TLPBlockedErr: 26, + PoisonTLPBlocked: 27, + }, + NonFatal: UncorrectableAerCounters{ + Undefined: 30, + DLP: 31, + SDES: 32, + TLP: 33, + FCP: 34, + CmpltTO: 35, + CmpltAbrt: 36, + UnxCmplt: 37, + RxOF: 38, + MalfTLP: 39, + ECRC: 40, + UnsupReq: 41, + ACSViol: 42, + UncorrIntErr: 43, + BlockedTLP: 44, + AtomicOpBlocked: 45, + TLPBlockedErr: 46, + PoisonTLPBlocked: 47, + }, + }, + } + + if !reflect.DeepEqual(aerCounters, ac) { + t.Errorf("Result not correct: want %v, have %v", aerCounters, ac) + } +} diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index 07137af8..dfbcd345 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -13267,6 +13267,65 @@ Mode: 644 Directory: fixtures/sys/devices/pci0000:00/0000:00:1f.6 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/aer_dev_correctable +Lines: 9 +RxErr 1 +BadTLP 2 +BadDLLP 3 +Rollover 4 +Timeout 5 +NonFatalErr 6 +CorrIntErr 7 +HeaderOF 8 +TOTAL_ERR_COR 9 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/aer_dev_fatal +Lines: 19 +Undefined 10 +DLP 11 +SDES 12 +TLP 13 +FCP 14 +CmpltTO 15 +CmpltAbrt 16 +UnxCmplt 17 +RxOF 18 +MalfTLP 19 +ECRC 20 +UnsupReq 21 +ACSViol 22 +UncorrIntErr 23 +BlockedTLP 24 +AtomicOpBlocked 25 +TLPBlockedErr 26 +PoisonTLPBlocked 27 +TOTAL_ERR_FATAL 28 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/aer_dev_nonfatal +Lines: 19 +Undefined 30 +DLP 31 +SDES 32 +TLP 33 +FCP 34 +CmpltTO 35 +CmpltAbrt 36 +UnxCmplt 37 +RxOF 38 +MalfTLP 39 +ECRC 40 +UnsupReq 41 +ACSViol 42 +UncorrIntErr 43 +BlockedTLP 44 +AtomicOpBlocked 45 +TLPBlockedErr 46 +PoisonTLPBlocked 47 +TOTAL_ERR_FATAL 48 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/ari_enabled Lines: 1 0