fix(pcie): stop misclassifying same-vendor non-GPU devices as GPUs

matchesGPUVendor (sat_overlay.go) matched any PCIe DeviceClass containing
the substring "Controller" instead of the actual GPU classes, so a
same-vendor non-GPU device (e.g. an NVIDIA-branded NIC/storage controller)
with a degraded PCIe link surfaced as a pcie:gpu:<vendor> alarm on the
Hardware Summary/webui.

isGPUDevice (app_format.go) had the same bug via a different path: an
"any NVIDIA-vendor device is a GPU" fallback that could inflate the
"GPU: N x <model>" audit summary line with non-GPU companion devices
(NVSwitch/NVLink bridges, etc).

Both now defer to collector.IsGPUClass (exported from the previously
unexported isGPUClass), the canonical exact-match classifier already used
by amdgpu.go — removing the duplicated/incorrect class checks instead of
reimplementing them. Also dedup two more locally-duplicated classifiers
within webui (which doesn't import collector by convention): NIC-class
matching (pages.go/page_topo.go) and GPU-class matching in
page_validate.go now share one copy per package instead of being
reimplemented per file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-08-17 12:50:50 +03:00
co-authored by Claude Sonnet 5
parent 4ac9863353
commit e3697c0a11
10 changed files with 92 additions and 28 deletions
+32
View File
@@ -391,6 +391,38 @@ func TestWritePCIeGPUStatusesToDBSurfacesLinkSpeedDegradation(t *testing.T) {
}
}
// TestWritePCIeGPUStatusesToDBIgnoresNonGPUSameVendorDevice guards the bug
// where a PCIe link-speed degradation on a non-GPU device that merely shares
// the GPU's PCI vendor ID (e.g. an NVIDIA-branded NIC/storage/NVLink-bridge
// companion device) was misclassified as a GPU fault and surfaced as a
// pcie:gpu:<vendor> alarm, because matchesGPUVendor matched any class
// containing the substring "Controller" instead of the actual GPU classes.
func TestWritePCIeGPUStatusesToDBIgnoresNonGPUSameVendorDevice(t *testing.T) {
db, err := OpenComponentStatusDB(filepath.Join(t.TempDir(), "component-status.json"))
if err != nil {
t.Fatal(err)
}
class := "NetworkController"
vendor := 0x10de // collector.NvidiaVendorID
status := "Warning"
desc := "PCIe link speed degraded: running at Gen1, capable of Gen5"
devices := []schema.HardwarePCIeDevice{
{
HardwareComponentStatus: schema.HardwareComponentStatus{Status: &status, ErrorDescription: &desc},
DeviceClass: &class,
VendorID: &vendor,
BDF: strPtr("0000:02:00.0"),
},
}
writePCIeGPUStatusesToDB(db, devices)
if _, ok := db.Get("pcie:gpu:nvidia"); ok {
t.Fatal("expected non-GPU same-vendor device to not write pcie:gpu:nvidia")
}
}
func TestRunNCCLTestsPassesSelectedGPUs(t *testing.T) {
t.Parallel()