helper function to standardize the PCIBusID device attribute for DRA drivers

Signed-off-by: Varun Ramachandra Sekar <vsekar@nvidia.com>
This commit is contained in:
Varun Ramachandra Sekar
2025-10-14 11:24:14 -07:00
parent 3955220f84
commit 4d1ed68946
3 changed files with 100 additions and 7 deletions

View File

@@ -30,6 +30,13 @@ const (
// referring to a PCIe (Peripheral Component Interconnect Express) Root Complex.
// This attribute can be used to identify devices that share the same PCIe Root Complex.
StandardDeviceAttributePCIeRoot resourceapi.QualifiedName = StandardDeviceAttributePrefix + "pcieRoot"
// StandardDeviceAttributePCIBusID is a standard device attribute name
// which describes the PCI Bus address of the PCI device.
// The value is a string value in the extended BDF notation (Domain:Bus:Device.Function),
// referring to a PCI (Peripheral Component Interconnect) device.
// This attribute can be used to identify PCI devices.
StandardDeviceAttributePCIBusID resourceapi.QualifiedName = StandardDeviceAttributePrefix + "pciBusID"
)
// DeviceAttribute represents a device attribute name and its value

View File

@@ -34,13 +34,8 @@ import (
//
// ref: https://wiki.xenproject.org/wiki/Bus:Device.Function_(BDF)_Notation
func GetPCIeRootAttributeByPCIBusID(pciBusID string) (DeviceAttribute, error) {
if pciBusID == "" {
return DeviceAttribute{}, fmt.Errorf("PCI Bus ID cannot be empty")
}
bdfRegexp := regexp.MustCompile(`^([0-9a-f]{4}):([0-9a-f]{2}):([0-9a-f]{2})\.([0-9a-f]{1})$`)
if !bdfRegexp.MatchString(pciBusID) {
return DeviceAttribute{}, fmt.Errorf("invalid PCI Bus ID format: %s", pciBusID)
if err := verifyPCIBDFFormat(pciBusID); err != nil {
return DeviceAttribute{}, err
}
pcieRoot, err := resolvePCIeRoot(pciBusID)
@@ -100,3 +95,39 @@ func resolvePCIeRoot(pciBusID string) (string, error) {
return pcieRootPart, nil
}
// GetPCIBusIDAttribute returns a DeviceAttribute with the PCI Bus Address("<domain>:<bus>:<device>.<function>")
// of a PCI device as a string value.
//
// It returns an error if the PCI Bus ID is empty or is not in
// extended BDF (Domain:Bus:Device.Function) format, e.g., "0123:45:1e.7"
//
// ref: https://wiki.xenproject.org/wiki/Bus:Device.Function_(BDF)_Notation
func GetPCIBusIDAttribute(pciBusID string) (DeviceAttribute, error) {
if err := verifyPCIBDFFormat(pciBusID); err != nil {
return DeviceAttribute{}, err
}
attr := DeviceAttribute{
Name: StandardDeviceAttributePCIBusID,
Value: resourceapi.DeviceAttribute{StringValue: &pciBusID},
}
return attr, nil
}
// verifyPCIBDFFormat verifies that the PCI Bus ID is in extended BDF (Domain:Bus:Device.Function) format.
//
// ref: https://wiki.xenproject.org/wiki/Bus:Device.Function_(BDF)_Notation
func verifyPCIBDFFormat(pciBusID string) error {
if pciBusID == "" {
return fmt.Errorf("PCI Bus ID cannot be empty")
}
bdfRegexp := regexp.MustCompile(`^([0-9a-f]{4}):([0-9a-f]{2}):([0-9a-f]{2})\.([0-9a-f]{1})$`)
if !bdfRegexp.MatchString(pciBusID) {
return fmt.Errorf("invalid PCI Bus ID format: %s", pciBusID)
}
return nil
}

View File

@@ -136,6 +136,61 @@ func TestGetPCIeRootAttributePCIBusID(t *testing.T) {
}
}
func TestGetPCIBusIDAttribute(t *testing.T) {
pciBusID := "0000:02:00.0"
expectedAttribute := DeviceAttribute{
Name: StandardDeviceAttributePCIBusID,
Value: resourceapi.DeviceAttribute{StringValue: ptr.To(pciBusID)},
}
tests := map[string]struct {
address string
expectedAttribute *DeviceAttribute
expectsError bool
expectedErrMsg string
}{
"valid": {
address: pciBusID,
expectedAttribute: &expectedAttribute,
expectsError: false,
},
"invalid empty PCI Bus ID": {
address: "",
expectedAttribute: nil,
expectsError: true,
expectedErrMsg: "PCI Bus ID cannot be empty",
},
"invalid PCI Bus ID format": {
address: "invalid-pci-id",
expectedAttribute: nil,
expectsError: true,
expectedErrMsg: "invalid PCI Bus ID format: invalid-pci-id",
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
got, err := GetPCIBusIDAttribute(test.address)
if test.expectsError {
if err == nil {
t.Errorf("Expected error but got none")
return
}
if !strings.Contains(err.Error(), test.expectedErrMsg) {
t.Errorf("Expected error message to contain %q, got %q", test.expectedErrMsg, err.Error())
return
}
return
}
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, *test.expectedAttribute) {
t.Errorf("Expected attribute %v, got %v", test.expectedAttribute, got)
}
})
}
}
func touchFile(t *testing.T, path string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {