feat: improve inspur parsing and pci.ids integration
This commit is contained in:
217
internal/parser/vendors/inspur/pcie.go
vendored
217
internal/parser/vendors/inspur/pcie.go
vendored
@@ -3,36 +3,38 @@ package inspur
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.mchus.pro/mchus/logpile/internal/models"
|
||||
"git.mchus.pro/mchus/logpile/internal/parser/vendors/pciids"
|
||||
)
|
||||
|
||||
// PCIeRESTInfo represents the RESTful PCIE Device info structure
|
||||
type PCIeRESTInfo []struct {
|
||||
ID int `json:"id"`
|
||||
Present int `json:"present"`
|
||||
Enable int `json:"enable"`
|
||||
Status int `json:"status"`
|
||||
VendorID int `json:"vendor_id"`
|
||||
VendorName string `json:"vendor_name"`
|
||||
DeviceID int `json:"device_id"`
|
||||
DeviceName string `json:"device_name"`
|
||||
BusNum int `json:"bus_num"`
|
||||
DevNum int `json:"dev_num"`
|
||||
FuncNum int `json:"func_num"`
|
||||
MaxLinkWidth int `json:"max_link_width"`
|
||||
MaxLinkSpeed int `json:"max_link_speed"`
|
||||
CurrentLinkWidth int `json:"current_link_width"`
|
||||
CurrentLinkSpeed int `json:"current_link_speed"`
|
||||
Slot int `json:"slot"`
|
||||
Location string `json:"location"`
|
||||
DeviceLocator string `json:"DeviceLocator"`
|
||||
DevType int `json:"dev_type"`
|
||||
DevSubtype int `json:"dev_subtype"`
|
||||
PartNum string `json:"part_num"`
|
||||
SerialNum string `json:"serial_num"`
|
||||
FwVer string `json:"fw_ver"`
|
||||
ID int `json:"id"`
|
||||
Present int `json:"present"`
|
||||
Enable int `json:"enable"`
|
||||
Status int `json:"status"`
|
||||
VendorID int `json:"vendor_id"`
|
||||
VendorName string `json:"vendor_name"`
|
||||
DeviceID int `json:"device_id"`
|
||||
DeviceName string `json:"device_name"`
|
||||
BusNum int `json:"bus_num"`
|
||||
DevNum int `json:"dev_num"`
|
||||
FuncNum int `json:"func_num"`
|
||||
MaxLinkWidth int `json:"max_link_width"`
|
||||
MaxLinkSpeed int `json:"max_link_speed"`
|
||||
CurrentLinkWidth int `json:"current_link_width"`
|
||||
CurrentLinkSpeed int `json:"current_link_speed"`
|
||||
Slot int `json:"slot"`
|
||||
Location string `json:"location"`
|
||||
DeviceLocator string `json:"DeviceLocator"`
|
||||
DevType int `json:"dev_type"`
|
||||
DevSubtype int `json:"dev_subtype"`
|
||||
PartNum string `json:"part_num"`
|
||||
SerialNum string `json:"serial_num"`
|
||||
FwVer string `json:"fw_ver"`
|
||||
}
|
||||
|
||||
// ParsePCIeDevices parses RESTful PCIE Device info from devicefrusdr.log
|
||||
@@ -73,9 +75,27 @@ func ParsePCIeDevices(content []byte) []models.PCIeDevice {
|
||||
|
||||
// Determine device class based on dev_type
|
||||
deviceClass := determineDeviceClass(pcie.DevType, pcie.DevSubtype, pcie.DeviceName)
|
||||
_, pciDeviceName := pciids.DeviceInfo(pcie.VendorID, pcie.DeviceID)
|
||||
|
||||
// Build BDF string
|
||||
bdf := fmt.Sprintf("%04x/%02x/%02x/%02x", 0, pcie.BusNum, pcie.DevNum, pcie.FuncNum)
|
||||
// Build BDF string in canonical form (bb:dd.f)
|
||||
bdf := formatBDF(pcie.BusNum, pcie.DevNum, pcie.FuncNum)
|
||||
|
||||
partNumber := strings.TrimSpace(pcie.PartNum)
|
||||
if partNumber == "" {
|
||||
partNumber = sanitizePCIeDeviceName(pcie.DeviceName)
|
||||
}
|
||||
if partNumber == "" {
|
||||
partNumber = normalizeModelLabel(pciDeviceName)
|
||||
}
|
||||
if isGenericPCIeClass(deviceClass) {
|
||||
if resolved := normalizeModelLabel(pciDeviceName); resolved != "" {
|
||||
deviceClass = resolved
|
||||
}
|
||||
}
|
||||
manufacturer := strings.TrimSpace(pcie.VendorName)
|
||||
if manufacturer == "" {
|
||||
manufacturer = normalizeModelLabel(pciids.VendorName(pcie.VendorID))
|
||||
}
|
||||
|
||||
device := models.PCIeDevice{
|
||||
Slot: pcie.Location,
|
||||
@@ -83,12 +103,12 @@ func ParsePCIeDevices(content []byte) []models.PCIeDevice {
|
||||
DeviceID: pcie.DeviceID,
|
||||
BDF: bdf,
|
||||
DeviceClass: deviceClass,
|
||||
Manufacturer: pcie.VendorName,
|
||||
Manufacturer: manufacturer,
|
||||
LinkWidth: pcie.CurrentLinkWidth,
|
||||
LinkSpeed: currentSpeed,
|
||||
MaxLinkWidth: pcie.MaxLinkWidth,
|
||||
MaxLinkSpeed: maxSpeed,
|
||||
PartNumber: strings.TrimSpace(pcie.PartNum),
|
||||
PartNumber: partNumber,
|
||||
SerialNumber: strings.TrimSpace(pcie.SerialNum),
|
||||
}
|
||||
|
||||
@@ -98,6 +118,149 @@ func ParsePCIeDevices(content []byte) []models.PCIeDevice {
|
||||
return devices
|
||||
}
|
||||
|
||||
var rawHexDeviceNameRegex = regexp.MustCompile(`(?i)^0x[0-9a-f]+$`)
|
||||
|
||||
func sanitizePCIeDeviceName(name string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.EqualFold(name, "N/A") {
|
||||
return ""
|
||||
}
|
||||
if rawHexDeviceNameRegex.MatchString(name) {
|
||||
return ""
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// MergePCIeDevices enriches base devices (from asset.json) with detailed RESTful PCIe data.
|
||||
// Matching is done by BDF first, then by slot fallback.
|
||||
func MergePCIeDevices(base []models.PCIeDevice, rest []models.PCIeDevice) []models.PCIeDevice {
|
||||
if len(rest) == 0 {
|
||||
return base
|
||||
}
|
||||
if len(base) == 0 {
|
||||
return append([]models.PCIeDevice(nil), rest...)
|
||||
}
|
||||
|
||||
type ref struct {
|
||||
index int
|
||||
}
|
||||
byBDF := make(map[string]ref, len(base))
|
||||
bySlot := make(map[string]ref, len(base))
|
||||
|
||||
for i := range base {
|
||||
bdf := normalizePCIeBDF(base[i].BDF)
|
||||
if bdf != "" {
|
||||
byBDF[bdf] = ref{index: i}
|
||||
}
|
||||
slot := strings.ToLower(strings.TrimSpace(base[i].Slot))
|
||||
if slot != "" {
|
||||
bySlot[slot] = ref{index: i}
|
||||
}
|
||||
}
|
||||
|
||||
for _, detailed := range rest {
|
||||
idx := -1
|
||||
if bdf := normalizePCIeBDF(detailed.BDF); bdf != "" {
|
||||
if found, ok := byBDF[bdf]; ok {
|
||||
idx = found.index
|
||||
}
|
||||
}
|
||||
if idx == -1 {
|
||||
slot := strings.ToLower(strings.TrimSpace(detailed.Slot))
|
||||
if slot != "" {
|
||||
if found, ok := bySlot[slot]; ok {
|
||||
idx = found.index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idx == -1 {
|
||||
base = append(base, detailed)
|
||||
newIdx := len(base) - 1
|
||||
if bdf := normalizePCIeBDF(detailed.BDF); bdf != "" {
|
||||
byBDF[bdf] = ref{index: newIdx}
|
||||
}
|
||||
if slot := strings.ToLower(strings.TrimSpace(detailed.Slot)); slot != "" {
|
||||
bySlot[slot] = ref{index: newIdx}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
enrichPCIeDevice(&base[idx], detailed)
|
||||
}
|
||||
|
||||
return base
|
||||
}
|
||||
|
||||
func enrichPCIeDevice(dst *models.PCIeDevice, src models.PCIeDevice) {
|
||||
if dst == nil {
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(dst.Slot) == "" {
|
||||
dst.Slot = src.Slot
|
||||
}
|
||||
if strings.TrimSpace(dst.BDF) == "" {
|
||||
dst.BDF = src.BDF
|
||||
}
|
||||
if dst.VendorID == 0 {
|
||||
dst.VendorID = src.VendorID
|
||||
}
|
||||
if dst.DeviceID == 0 {
|
||||
dst.DeviceID = src.DeviceID
|
||||
}
|
||||
if strings.TrimSpace(dst.Manufacturer) == "" {
|
||||
dst.Manufacturer = src.Manufacturer
|
||||
}
|
||||
if strings.TrimSpace(dst.SerialNumber) == "" {
|
||||
dst.SerialNumber = src.SerialNumber
|
||||
}
|
||||
if strings.TrimSpace(dst.PartNumber) == "" {
|
||||
dst.PartNumber = src.PartNumber
|
||||
}
|
||||
if strings.TrimSpace(dst.LinkSpeed) == "" || strings.EqualFold(strings.TrimSpace(dst.LinkSpeed), "unknown") {
|
||||
dst.LinkSpeed = src.LinkSpeed
|
||||
}
|
||||
if strings.TrimSpace(dst.MaxLinkSpeed) == "" || strings.EqualFold(strings.TrimSpace(dst.MaxLinkSpeed), "unknown") {
|
||||
dst.MaxLinkSpeed = src.MaxLinkSpeed
|
||||
}
|
||||
if dst.LinkWidth == 0 {
|
||||
dst.LinkWidth = src.LinkWidth
|
||||
}
|
||||
if dst.MaxLinkWidth == 0 {
|
||||
dst.MaxLinkWidth = src.MaxLinkWidth
|
||||
}
|
||||
if isGenericPCIeClass(dst.DeviceClass) && !isGenericPCIeClass(src.DeviceClass) {
|
||||
dst.DeviceClass = src.DeviceClass
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePCIeBDF(bdf string) string {
|
||||
bdf = strings.TrimSpace(strings.ToLower(bdf))
|
||||
if bdf == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.Contains(bdf, "/") {
|
||||
parts := strings.Split(bdf, "/")
|
||||
if len(parts) == 4 {
|
||||
return fmt.Sprintf("%s:%s.%s", parts[1], parts[2], parts[3])
|
||||
}
|
||||
}
|
||||
return bdf
|
||||
}
|
||||
|
||||
func isGenericPCIeClass(class string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(class)) {
|
||||
case "", "unknown", "other", "bridge", "network", "storage", "sas", "sata", "display", "vga", "3d controller", "serial bus":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// determineDeviceClass maps device type to human-readable class
|
||||
func determineDeviceClass(devType, devSubtype int, deviceName string) string {
|
||||
// dev_type mapping:
|
||||
|
||||
Reference in New Issue
Block a user