feat: improve inspur parsing and pci.ids integration

This commit is contained in:
2026-02-17 18:09:36 +03:00
parent b33cca5fcc
commit 758fa66282
26 changed files with 43567 additions and 247 deletions

View File

@@ -1,12 +1,27 @@
package pciids
import (
"bufio"
_ "embed"
"fmt"
"os"
"strconv"
"strings"
"sync"
)
var (
//go:embed pci.ids
embeddedPCIIDs string
loadOnce sync.Once
vendors map[int]string
devices map[string]string
)
// VendorName returns vendor name by PCI Vendor ID
func VendorName(vendorID int) string {
loadPCIIDs()
if name, ok := vendors[vendorID]; ok {
return name
}
@@ -15,6 +30,7 @@ func VendorName(vendorID int) string {
// DeviceName returns device name by Vendor ID and Device ID
func DeviceName(vendorID, deviceID int) string {
loadPCIIDs()
key := fmt.Sprintf("%04x:%04x", vendorID, deviceID)
if name, ok := devices[key]; ok {
return name
@@ -46,7 +62,6 @@ func VendorNameFromString(s string) string {
} else if c >= 'a' && c <= 'f' {
id = id*16 + int(c-'a'+10)
} else {
// Not a valid hex string, return original
return ""
}
}
@@ -54,124 +69,99 @@ func VendorNameFromString(s string) string {
return VendorName(id)
}
// Common PCI Vendor IDs
// Source: https://pci-ids.ucw.cz/
var vendors = map[int]string{
// Storage controllers and SSDs
0x1E0F: "KIOXIA",
0x144D: "Samsung Electronics",
0x1C5C: "SK Hynix",
0x15B7: "SanDisk (Western Digital)",
0x1179: "Toshiba",
0x8086: "Intel",
0x1344: "Micron Technology",
0x126F: "Silicon Motion",
0x1987: "Phison Electronics",
0x1CC1: "ADATA Technology",
0x2646: "Kingston Technology",
0x1E95: "Solid State Storage Technology",
0x025E: "Solidigm",
0x1D97: "Shenzhen Longsys Electronics",
0x1E4B: "MAXIO Technology",
func loadPCIIDs() {
loadOnce.Do(func() {
vendors = make(map[int]string)
devices = make(map[string]string)
// Network adapters
0x15B3: "Mellanox Technologies",
0x14E4: "Broadcom",
0x10EC: "Realtek Semiconductor",
0x1077: "QLogic",
0x19A2: "Emulex",
0x1137: "Cisco Systems",
0x1924: "Solarflare Communications",
0x177D: "Cavium",
0x1D6A: "Aquantia",
0x1FC9: "Tehuti Networks",
0x18D4: "Chelsio Communications",
parsePCIIDs(strings.NewReader(embeddedPCIIDs), vendors, devices)
// GPU / Graphics
0x10DE: "NVIDIA",
0x1002: "AMD/ATI",
0x102B: "Matrox Electronics",
0x1A03: "ASPEED Technology",
// Storage controllers (RAID/HBA)
0x1000: "LSI Logic / Broadcom",
0x9005: "Adaptec / Microsemi",
0x1028: "Dell",
0x103C: "Hewlett-Packard",
0x17D3: "Areca Technology",
0x1CC4: "Union Memory",
// Server vendors
0x1014: "IBM",
0x15D9: "Supermicro",
0x8088: "Inspur",
// Other common
0x1022: "AMD",
0x1106: "VIA Technologies",
0x10B5: "PLX Technology",
0x1B21: "ASMedia Technology",
0x1B4B: "Marvell Technology",
0x197B: "JMicron Technology",
for _, path := range candidatePCIIDsPaths() {
f, err := os.Open(path)
if err != nil {
continue
}
parsePCIIDs(f, vendors, devices)
_ = f.Close()
}
})
}
// Device IDs (vendor:device -> name)
var devices = map[string]string{
// NVIDIA GPUs (0x10DE)
"10de:26b9": "L40S 48GB",
"10de:26b1": "L40 48GB",
"10de:2684": "RTX 4090",
"10de:2704": "RTX 4080",
"10de:2782": "RTX 4070 Ti",
"10de:2786": "RTX 4070",
"10de:27b8": "RTX 4060 Ti",
"10de:2882": "RTX 4060",
"10de:2204": "RTX 3090",
"10de:2208": "RTX 3080 Ti",
"10de:2206": "RTX 3080",
"10de:2484": "RTX 3070",
"10de:2503": "RTX 3060",
"10de:20b0": "A100 80GB",
"10de:20b2": "A100 40GB",
"10de:20f1": "A10",
"10de:2236": "A10G",
"10de:25b6": "A16",
"10de:20b5": "A30",
"10de:20b7": "A30X",
"10de:1db4": "V100 32GB",
"10de:1db1": "V100 16GB",
"10de:1e04": "RTX 2080 Ti",
"10de:1e07": "RTX 2080",
"10de:1f02": "RTX 2070",
"10de:26ba": "L40S-PCIE-48G",
"10de:2330": "H100 80GB PCIe",
"10de:2331": "H100 80GB SXM5",
"10de:2322": "H100 NVL",
"10de:2324": "H200",
func candidatePCIIDsPaths() []string {
paths := []string{
"pci.ids",
"/usr/share/hwdata/pci.ids",
"/usr/share/misc/pci.ids",
"/opt/homebrew/share/pciids/pci.ids",
}
// AMD GPUs (0x1002)
"1002:744c": "Instinct MI250X",
"1002:7408": "Instinct MI100",
"1002:73a5": "RX 6950 XT",
"1002:73bf": "RX 6900 XT",
"1002:73df": "RX 6700 XT",
"1002:7480": "RX 7900 XTX",
"1002:7483": "RX 7900 XT",
// ASPEED (0x1A03) - BMC VGA
"1a03:2000": "AST2500 VGA",
"1a03:1150": "AST2600 VGA",
// Intel GPUs
"8086:56c0": "Data Center GPU Flex 170",
"8086:56c1": "Data Center GPU Flex 140",
// Mellanox/NVIDIA NICs (0x15B3)
"15b3:1017": "ConnectX-5 100GbE",
"15b3:1019": "ConnectX-5 Ex",
"15b3:101b": "ConnectX-6",
"15b3:101d": "ConnectX-6 Dx",
"15b3:101f": "ConnectX-6 Lx",
"15b3:1021": "ConnectX-7",
"15b3:a2d6": "ConnectX-4 Lx",
// Env paths have highest priority, so they are applied last.
if env := strings.TrimSpace(os.Getenv("LOGPILE_PCI_IDS_PATH")); env != "" {
for _, p := range strings.Split(env, string(os.PathListSeparator)) {
p = strings.TrimSpace(p)
if p != "" {
paths = append(paths, p)
}
}
}
return paths
}
func parsePCIIDs(r interface{ Read([]byte) (int, error) }, outVendors map[int]string, outDevices map[string]string) {
scanner := bufio.NewScanner(r)
currentVendor := -1
for scanner.Scan() {
line := scanner.Text()
if line == "" || strings.HasPrefix(line, "#") {
continue
}
// Subdevice line (tab-tab) - ignored for now
if strings.HasPrefix(line, "\t\t") {
continue
}
// Device line
if strings.HasPrefix(line, "\t") {
if currentVendor < 0 {
continue
}
trimmed := strings.TrimLeft(line, "\t")
fields := strings.Fields(trimmed)
if len(fields) < 2 {
continue
}
deviceID, err := strconv.ParseInt(fields[0], 16, 32)
if err != nil {
continue
}
name := strings.TrimSpace(trimmed[len(fields[0]):])
if name == "" {
continue
}
key := fmt.Sprintf("%04x:%04x", currentVendor, int(deviceID))
outDevices[key] = name
continue
}
// Vendor line
fields := strings.Fields(line)
if len(fields) < 2 {
currentVendor = -1
continue
}
vendorID, err := strconv.ParseInt(fields[0], 16, 32)
if err != nil {
currentVendor = -1
continue
}
name := strings.TrimSpace(line[len(fields[0]):])
if name == "" {
currentVendor = -1
continue
}
currentVendor = int(vendorID)
outVendors[currentVendor] = name
}
}