package sysfs import ( "fmt" "io/ioutil" "path" "path/filepath" "strconv" "strings" ) const ( sysFsPCIDevicesPath = "/sys/bus/pci/devices/" ) type PCIDevice struct { NumaNode int ID string Device, Vendor uint64 SubVendor, SubDevice uint64 Class uint64 MSIs []int } func ScanPCIDevices() []PCIDevice { devices, err := ioutil.ReadDir(sysFsPCIDevicesPath) if err != nil { panic(err) } pciDevices := []PCIDevice{} for _, device := range devices { dpath := filepath.Join(sysFsPCIDevicesPath, device.Name()) pcid, err := NewPCIDevice(dpath, device.Name()) if err != nil { panic(err) } pciDevices = append(pciDevices, pcid) } return pciDevices } func getPCIDeviceClass(path string) (uint64, error) { return ContentUint64(filepath.Join(path, "class")) } func getPCIDeviceVendor(path string) (uint64, error) { return ContentUint64(filepath.Join(path, "vendor")) } func getPCIDeviceId(path string) (uint64, error) { return ContentUint64(filepath.Join(path, "device")) } func getPCIDeviceSubsystemDevice(path string) (uint64, error) { return ContentUint64(filepath.Join(path, "subsystem_device")) } func getPCIDeviceSubsystemVendor(path string) (uint64, error) { return ContentUint64(filepath.Join(path, "subsystem_vendor")) } func getPCIDeviceNumaNode(path string) int { content, err := ioutil.ReadFile(filepath.Join(path, "numa_node")) if err != nil { panic(err) } nodeNum, err := strconv.Atoi(strings.TrimSpace(string(content))) if err != nil { panic(err) } return nodeNum } func getPCIDeviceMSIx(p string) []int { g := fmt.Sprintf("%s/*", filepath.Join(p, "msi_irqs")) files, err := filepath.Glob(g) if err != nil { panic(err) } if len(files) == 0 { return []int{} } msix := []int{} for _, f := range files { content, err := ioutil.ReadFile(f) if err != nil { panic(err) } if strings.TrimSpace(string(content)) == "msix" { base := path.Base(f) v, err := strconv.Atoi(base) if err != nil { panic(err) } msix = append(msix, v) } } return msix } func NewPCIDevice(path, name string) (PCIDevice, error) { nodeNum := getPCIDeviceNumaNode(path) device, err := getPCIDeviceId(path) if err != nil { return PCIDevice{}, err } vendor, err := getPCIDeviceVendor(path) if err != nil { return PCIDevice{}, err } subvendor, err := getPCIDeviceSubsystemVendor(path) if err != nil { return PCIDevice{}, err } subdevice, err := getPCIDeviceSubsystemDevice(path) if err != nil { return PCIDevice{}, err } deviceClass, err := getPCIDeviceClass(path) if err != nil { return PCIDevice{}, err } msix := getPCIDeviceMSIx(path) return PCIDevice{ ID: name, Device: device, Class: deviceClass, NumaNode: nodeNum, Vendor: vendor, SubVendor: subvendor, SubDevice: subdevice, MSIs: msix, }, nil }