+HEXADECIMAL = "[0-9a-zA-Z]"
+
+
+class PciAddress(object):
+ """Class to handle PCI addresses.
+
+ A PCI address could be written in two ways:
+ - Simple BDF notation:
+ 00:00.0 # bus:device.function
+ - With domain extension.
+ 0000:00:00.0 # domain:bus:device.function
+
+ Note: in Libvirt, 'device' is called 'slot'.
+
+ Reference: https://wiki.xenproject.org/wiki/
+ Bus:Device.Function_(BDF)_Notation
+ """
+ PCI_PATTERN_STR = (
+ r"((?P<domain>[0-9a-zA-Z]{4}):)?(?P<bus>[0-9a-zA-Z]{2}):"
+ r"(?P<slot>[0-9a-zA-Z]{2})\.(?P<function>[0-9a-zA-Z]{1})")
+
+ def __init__(self, address):
+ pci_pattern = re.compile(self.PCI_PATTERN_STR)
+ match = pci_pattern.search(address)
+ if not match:
+ raise ValueError('Invalid PCI address: {}'.format(address))
+
+ self._domain = (match.group('domain') or '0000').lower()
+ self._bus = match.group('bus').lower()
+ self._slot = match.group('slot').lower()
+ self._function = match.group('function').lower()
+ self.address = '{:0>4}:{:0>2}:{:0>2}.{:1}'.format(self.domain,
+ self.bus,
+ self.slot,
+ self.function)
+ self.match = match
+
+ def __repr__(self):
+ return self.address
+
+ @property
+ def domain(self):
+ return self._domain
+
+ @property
+ def bus(self):
+ return self._bus
+
+ @property
+ def slot(self):
+ return self._slot
+
+ @property
+ def function(self):
+ return self._function
+
+ def values(self):
+ return [self._domain, self._bus, self._slot, self._function]
+
+