From aac6274b98f2167742e9fd82a21e3d9c65af2fa9 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 2 Mar 2026 15:04:44 +0100 Subject: [PATCH 1/9] feat: add MEIClass for Management Engine Interface Signed-off-by: Michal Gorlas --- sysfs/class_mei.go | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 sysfs/class_mei.go diff --git a/sysfs/class_mei.go b/sysfs/class_mei.go new file mode 100644 index 00000000..10c0fc64 --- /dev/null +++ b/sysfs/class_mei.go @@ -0,0 +1,77 @@ +package sysfs + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/prometheus/procfs/internal/util" +) + +const meiClassPath = "class/mei/mei0" + +type MEIClass struct { + Dev *string + DevState *string + FWStatus *string + FWVersion *string + HBMVersion *string + HBMVersionDrv *string + Kind *string + Trc *string + TxQueueLimit *string +} + +// MEIClass returns Management Engine Interface (DMI) information read from /sys/class/mei/. +func (fs FS) MEIClass() (*MEIClass, error) { + path := fs.sys.Path(meiClassPath) + + files, err := os.ReadDir(path) + if err != nil { + return nil, fmt.Errorf("failed to read directory %q: %w", path, err) + } + + var mei MEIClass + for _, f := range files { + if !f.Type().IsRegular() { + continue + } + + name := f.Name() + if name == "uevent" { + continue + } + + filename := filepath.Join(path, name) + value, err := util.SysReadFile(filename) + if err != nil { + if os.IsPermission(err) { + continue + } + return nil, fmt.Errorf("failed to read file %q: %w", filename, err) + } + + switch name { + case "dev": + mei.Dev = &value + case "dev_state": + mei.DevState = &value + case "fw_status": + mei.FWStatus = &value + case "fw_ver": + mei.FWVersion = &value + case "hbm_ver": + mei.HBMVersion = &value + case "hbm_ver_drv": + mei.HBMVersionDrv = &value + case "kind": + mei.Kind = &value + case "trc": + mei.Trc = &value + case "tx_queue_limit": + mei.TxQueueLimit = &value + } + } + + return &mei, nil +} From d737c00521512b073f195e2d21fb2c76190671c6 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 2 Mar 2026 15:21:40 +0100 Subject: [PATCH 2/9] feat(testdata): update fixtures with sample mei data Signed-off-by: Michal Gorlas --- testdata/fixtures.ttar | 65 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index 844757c9..30d0ad3e 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -6338,6 +6338,71 @@ Lines: 1 4: ACTIVE Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/mei +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/mei/mei0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/dev +Lines: 1 +244:0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/dev_state +Lines: 1 +ENABLEDEOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/fw_status +Lines: 6 +90000245 +00110500 +00000020 +00000000 +02F41F03 +40000000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/fw_ver +Lines: 3 +0:18.0.5.2098 +0:18.0.5.2098 +0:18.0.5.2098 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/hbm_ver +Lines: 1 +2.2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/hbm_ver_drv +Lines: 1 +2.2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/kind +Lines: 1 +mei +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/trc +Lines: 1 +00000889 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/tx_queue_limit +Lines: 1 +50 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/mei/mei0/uevent +Lines: 3 +MAJOR=244 +MINOR=0 +DEVNAME=mei0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/sys/class/net Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From aabbd89c66890d5c2ba2f6eceb14401ed96916df Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 2 Mar 2026 16:01:03 +0100 Subject: [PATCH 3/9] fix: remove perms check for mei Signed-off-by: Michal Gorlas --- sysfs/class_mei.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sysfs/class_mei.go b/sysfs/class_mei.go index 10c0fc64..f961d325 100644 --- a/sysfs/class_mei.go +++ b/sysfs/class_mei.go @@ -45,9 +45,7 @@ func (fs FS) MEIClass() (*MEIClass, error) { filename := filepath.Join(path, name) value, err := util.SysReadFile(filename) if err != nil { - if os.IsPermission(err) { - continue - } + // no check for perms since all files (well apart from tx_queue_limit) are 0444 return nil, fmt.Errorf("failed to read file %q: %w", filename, err) } From 49da672fef96f62bf3533624ff686c45ec306d3a Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 2 Mar 2026 16:01:33 +0100 Subject: [PATCH 4/9] feat: add test for MEIClass Signed-off-by: Michal Gorlas --- sysfs/class_mei_test.go | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 sysfs/class_mei_test.go diff --git a/sysfs/class_mei_test.go b/sysfs/class_mei_test.go new file mode 100644 index 00000000..f4d22ebc --- /dev/null +++ b/sysfs/class_mei_test.go @@ -0,0 +1,60 @@ +// Copyright 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 + +package sysfs + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestMEIClass(t *testing.T) { + fs, err := NewFS(sysTestFixtures) + if err != nil { + t.Fatal(err) + } + + got, err := fs.MEIClass() + if err != nil { + t.Fatal(err) + } + + dev := "244:0" + devState := "ENABLED" + fwStatus := "90000245\n00110500\n00000020\n00000000\n02F41F03\n40000000" + fwVer := "0:18.0.5.2098\n0:18.0.5.2098\n0:18.0.5.2098" + hbmVer := "2.2" + hbmVerDrv := "2.2" + kind := "mei" + trc := "00000889" + txQueueLimit := "50" + + want := &MEIClass{ + Dev: &dev, + DevState: &devState, + FWStatus: &fwStatus, + FWVersion: &fwVer, + HBMVersion: &hbmVer, + HBMVersionDrv: &hbmVerDrv, + Kind: &kind, + Trc: &trc, + TxQueueLimit: &txQueueLimit, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Fatalf("unexpected DMI class (-want +got):\n%s", diff) + } +} From dbef2583d3e0b23e01271c4de6ab658b966341c2 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 20 Apr 2026 20:26:35 +0200 Subject: [PATCH 5/9] chore: add license header and buildtag Signed-off-by: Michal Gorlas --- sysfs/class_mei.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sysfs/class_mei.go b/sysfs/class_mei.go index f961d325..4ad88394 100644 --- a/sysfs/class_mei.go +++ b/sysfs/class_mei.go @@ -1,3 +1,18 @@ +// Copyright 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 + package sysfs import ( From 284ee4027531255dc145e089c356af0cf71187c5 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 20 Apr 2026 20:29:35 +0200 Subject: [PATCH 6/9] fix(mei): remove leftover DMI mentions Signed-off-by: Michal Gorlas --- sysfs/class_mei.go | 2 +- sysfs/class_mei_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sysfs/class_mei.go b/sysfs/class_mei.go index 4ad88394..1da868c3 100644 --- a/sysfs/class_mei.go +++ b/sysfs/class_mei.go @@ -37,7 +37,7 @@ type MEIClass struct { TxQueueLimit *string } -// MEIClass returns Management Engine Interface (DMI) information read from /sys/class/mei/. +// MEIClass returns Management Engine Interface (MEI) information read from /sys/class/mei/. func (fs FS) MEIClass() (*MEIClass, error) { path := fs.sys.Path(meiClassPath) diff --git a/sysfs/class_mei_test.go b/sysfs/class_mei_test.go index f4d22ebc..ab00a885 100644 --- a/sysfs/class_mei_test.go +++ b/sysfs/class_mei_test.go @@ -55,6 +55,6 @@ func TestMEIClass(t *testing.T) { } if diff := cmp.Diff(want, got); diff != "" { - t.Fatalf("unexpected DMI class (-want +got):\n%s", diff) + t.Fatalf("unexpected MEI class (-want +got):\n%s", diff) } } From 6db76d845d6fda419ea5a18f827692fd024cff96 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 20 Apr 2026 21:26:55 +0200 Subject: [PATCH 7/9] fix(testdata): remove trailing whitespace in dev_state Signed-off-by: Michal Gorlas --- testdata/fixtures.ttar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index 30d0ad3e..d9e0734d 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -6351,7 +6351,7 @@ Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/mei/mei0/dev_state Lines: 1 -ENABLEDEOF +ENABLED Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/mei/mei0/fw_status From b1edfb4574e7cdf24db1cc20ad0924ac198f40cd Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 20 Apr 2026 21:29:56 +0200 Subject: [PATCH 8/9] feat: add support for multiple MEI's Signed-off-by: Michal Gorlas --- sysfs/class_mei.go | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sysfs/class_mei.go b/sysfs/class_mei.go index 1da868c3..672fe758 100644 --- a/sysfs/class_mei.go +++ b/sysfs/class_mei.go @@ -23,9 +23,10 @@ import ( "github.com/prometheus/procfs/internal/util" ) -const meiClassPath = "class/mei/mei0" +const meiClassPath = "class/mei" -type MEIClass struct { +type MEIDev struct { + Name *string Dev *string DevState *string FWStatus *string @@ -37,16 +38,41 @@ type MEIClass struct { TxQueueLimit *string } +type MEIClass map[string]MEIDev + // MEIClass returns Management Engine Interface (MEI) information read from /sys/class/mei/. func (fs FS) MEIClass() (*MEIClass, error) { path := fs.sys.Path(meiClassPath) + subdirs, err := os.ReadDir(path) + if err != nil { + return nil, fmt.Errorf("failed to list MEI devices at %q: %w", path, err) + } + + mei := make(MEIClass, len(subdirs)) + for _, d := range subdirs { + dev, err := fs.parseMEI(d.Name()) + if err != nil { + return nil, err + } + + mei[*dev.Name] = *dev + } + + return &mei, nil +} + +func (fs FS) parseMEI(meiDev string) (*MEIDev, error) { + path := fs.sys.Path(meiClassPath, meiDev) + files, err := os.ReadDir(path) if err != nil { return nil, fmt.Errorf("failed to read directory %q: %w", path, err) } - var mei MEIClass + var mei MEIDev + mei.Name = &meiDev + for _, f := range files { if !f.Type().IsRegular() { continue @@ -60,7 +86,10 @@ func (fs FS) MEIClass() (*MEIClass, error) { filename := filepath.Join(path, name) value, err := util.SysReadFile(filename) if err != nil { - // no check for perms since all files (well apart from tx_queue_limit) are 0444 + if os.IsPermission(err) { + continue + } + return nil, fmt.Errorf("failed to read file %q: %w", filename, err) } From 926c835fddeb6a12a4a4d3803aacfa60b63fa652 Mon Sep 17 00:00:00 2001 From: Michal Gorlas Date: Mon, 20 Apr 2026 21:30:43 +0200 Subject: [PATCH 9/9] feat: update test for MEIClass Signed-off-by: Michal Gorlas --- sysfs/class_mei_test.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/sysfs/class_mei_test.go b/sysfs/class_mei_test.go index ab00a885..5ff16ad7 100644 --- a/sysfs/class_mei_test.go +++ b/sysfs/class_mei_test.go @@ -32,6 +32,7 @@ func TestMEIClass(t *testing.T) { t.Fatal(err) } + name := "mei0" dev := "244:0" devState := "ENABLED" fwStatus := "90000245\n00110500\n00000020\n00000000\n02F41F03\n40000000" @@ -43,15 +44,18 @@ func TestMEIClass(t *testing.T) { txQueueLimit := "50" want := &MEIClass{ - Dev: &dev, - DevState: &devState, - FWStatus: &fwStatus, - FWVersion: &fwVer, - HBMVersion: &hbmVer, - HBMVersionDrv: &hbmVerDrv, - Kind: &kind, - Trc: &trc, - TxQueueLimit: &txQueueLimit, + "mei0": MEIDev{ + Name: &name, + Dev: &dev, + DevState: &devState, + FWStatus: &fwStatus, + FWVersion: &fwVer, + HBMVersion: &hbmVer, + HBMVersionDrv: &hbmVerDrv, + Kind: &kind, + Trc: &trc, + TxQueueLimit: &txQueueLimit, + }, } if diff := cmp.Diff(want, got); diff != "" {