Skip to contentSkip to conversation

XenAPI: Add Physical PCI Device (PPCI) Support

PATCH New Yosuke Iwamatsu 1 participant 1 message Jul 2, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 1/3 XenAPI: Add Physical PCI Device (PPCI) Support

Add support for PPCI class, which represents physical pci devices. This makes it possible for remote servers to get information about devices the host contains.

Here is the fields for PPCI class.
-----------------------------
(RO_run) host
domain
bus
slot
func
name
vendor_id
vendor_name
device_id
device_name
revision_id
class_code
class_name
subsystem_vendor_id
subsystem_vendor_name
subsystem_id
subsystem_name
driver
------------------------------

One thing to be noted; this patch uses 'lspci' command to obtain information (such as vendor_name, device_name, class_name etc) which we cannot get from sysfs. If 'lspci' command does not exist, these fields will be just left blank.

Regards,
-----------------------
Yosuke Iwamatsu
NEC Corporation

XenAPI: Add Physical PCI Device (PPCI) Support

tools/python/xen/util/pci.py +112 -3
diff -r 19970181d6a4 -r fdf409891cd6 tools/python/xen/util/pci.py
@@ -8,6 +8,8 @@ import sys
 import sys
 import os, os.path
 import resource
+import re
+import types
 
 PROC_MNT_PATH = '/proc/mounts'
 PROC_PCI_PATH = '/proc/bus/pci/devices'
@@ -22,6 +24,9 @@ SYSFS_PCI_DEV_DEVICE_PATH = '/device'
 SYSFS_PCI_DEV_DEVICE_PATH = '/device'
 SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
 SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
+SYSFS_PCI_DEV_CLASS_PATH = '/class'
+
+LSPCI_CMD = 'lspci'
 
 PCI_BAR_IO = 0x01
 PCI_BAR_IO_MASK = ~0x03
@@ -32,6 +37,9 @@ MSIX_BIR_MASK = 0x7
 MSIX_BIR_MASK = 0x7
 MSIX_SIZE_MASK = 0x7ff
 
+# Global variable to store information from lspci
+lspci_info = None
+
 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
 PAGE_SIZE = resource.getpagesize()
 PAGE_SHIFT = 0
@@ -45,6 +53,15 @@ def PCI_DEVFN(slot, func):
 def PCI_DEVFN(slot, func):
     return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 
+def parse_hex(val):
+    try:
+        if isinstance(val, types.StringTypes):
+            return int(val, 16)
+        else:
+            return val
+    except ValueError:
+        return None
+
 def find_sysfs_mnt():
     mounts_file = open(PROC_MNT_PATH,'r')
 
@@ -57,6 +74,61 @@ def find_sysfs_mnt():
             return sline[1]
 
     return None
+
+def get_all_pci_names():
+    try:
+        sysfs_mnt = find_sysfs_mnt()
+    except IOError, (errno, strerr):
+        raise PciDeviceParseError(('Failed to locate sysfs mount: %s (%d)' %
+            (PROC_PCI_PATH, strerr, errno)))
+
+    pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split()
+
+    return pci_names
+
+def get_all_pci_devices():
+    pci_devs = []
+    for pci_name in get_all_pci_names():
+        pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
+                r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
+                r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
+                r"(?P<func>[0-7])$", pci_name)
+        if pci_match is None:
+            raise PciDeviceParseError(('Failed to parse pci device name: %s' %
+                pci_name))
+        pci_dev_info = pci_match.groupdict('0')
+        domain = parse_hex(pci_dev_info['domain'])
+        bus = parse_hex(pci_dev_info['bus'])
+        slot = parse_hex(pci_dev_info['slot'])
+        func = parse_hex(pci_dev_info['func'])
+        try:
+            pci_dev = PciDevice(domain, bus, slot, func)
+        except:
+            continue
+        pci_devs.append(pci_dev)
+
+    return pci_devs
+
+def create_lspci_info():
+    global lspci_info
+    lspci_info = {}
+
+    # Execute 'lspci' command and parse the result.
+    # If the command does not exist, lspci_info will be kept blank ({}).
+    for paragraph in os.popen(LSPCI_CMD + ' -vmmD').read().split('\n\n'):
+        device_name = None
+        device_info = {}
+        for line in paragraph.split('\n'):
+            try:
+                (opt, value) = line.split(':\t')
+                if opt == 'Slot':
+                    device_name = value
+                else:
+                    device_info[opt] = value
+            except:
+                pass
+        if device_name is not None:
+            lspci_info[device_name] = device_info
 
 class PciDeviceNotFoundError(Exception):
     def __init__(self,domain,bus,slot,func):
@@ -92,7 +164,15 @@ class PciDevice:
         self.subdevice = None
         self.msix = 0
         self.msix_iomem = []
+        self.revision = 0
+        self.classcode = None
+        self.vendorname = ""
+        self.devicename = ""
+        self.classname = ""
+        self.subvendorname = ""
+        self.subdevicename = ""
         self.get_info_from_sysfs()
+        self.get_info_from_lspci()
 
     def find_capability(self, type):
         try:
@@ -208,9 +288,8 @@ class PciDevice:
                 self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
         try:
             self.driver = os.path.basename(os.readlink(path))
-        except IOError, (errno, strerr):
-            raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
-                (path, strerr, errno)))
+        except OSError, (errno, strerr):
+            self.driver = ""
 
         path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
                 self.name+SYSFS_PCI_DEV_VENDOR_PATH
@@ -243,6 +322,36 @@ class PciDevice:
         except IOError, (errno, strerr):
             raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
                 (path, strerr, errno)))
+
+        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+                self.name+SYSFS_PCI_DEV_CLASS_PATH
+        try:
+            self.classcode = int(open(path,'r').readline(), 16)
+        except IOError, (errno, strerr):
+            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+                (path, strerr, errno)))
+
+        return True
+
+    def get_info_from_lspci(self):
+        """ Get information such as vendor name, device name, class name, etc.
+        Since we cannot obtain these data from sysfs, use 'lspci' command.
+        """
+        global lspci_info
+
+        if lspci_info is None:
+            create_lspci_info()
+
+        try:
+            device_info = lspci_info[self.name]
+            self.revision = int(device_info['Rev'], 16)
+            self.vendorname = device_info['Vendor']
+            self.devicename = device_info['Device']
+            self.classname = device_info['Class']
+            self.subvendorname = device_info['SVendor']
+            self.subdevicename = device_info['SDevice']
+        except KeyError:
+            pass
 
         return True
 
tools/python/xen/xend/XendAPI.py +10 -3
diff -r 19970181d6a4 -r fdf409891cd6 tools/python/xen/xend/XendAPI.py
@@ -40,6 +40,7 @@ from XendVMMetrics import XendVMMetrics
 from XendVMMetrics import XendVMMetrics
 from XendPIF import XendPIF
 from XendPBD import XendPBD
+from XendPPCI import XendPPCI
 from XendXSPolicy import XendXSPolicy, XendACMPolicy
 
 from XendAPIConstants import *
@@ -476,7 +477,8 @@ classes = {
     'PIF'          : valid_object("PIF"),
     'VM_metrics'   : valid_object("VM_metrics"),
     'PBD'          : valid_object("PBD"),
-    'PIF_metrics'  : valid_object("PIF_metrics")
+    'PIF_metrics'  : valid_object("PIF_metrics"),
+    'PPCI'         : valid_object("PPCI"),
 }
 
 autoplug_classes = {
@@ -485,6 +487,7 @@ autoplug_classes = {
     'VM_metrics'  : XendVMMetrics,
     'PBD'         : XendPBD,
     'PIF_metrics' : XendPIFMetrics,
+    'PPCI'        : XendPPCI,
     'XSPolicy'    : XendXSPolicy,
     'ACMPolicy'   : XendACMPolicy,
 }
@@ -874,6 +877,7 @@ class XendAPI(object):
                     'resident_VMs',
                     'PBDs',
                     'PIFs',
+                    'PPCIs',
                     'host_CPUs',
                     'cpu_configuration',
                     'metrics',
@@ -952,6 +956,8 @@ class XendAPI(object):
         return xen_api_success(XendPBD.get_all())
     def host_get_PIFs(self, session, ref):
         return xen_api_success(XendNode.instance().get_PIF_refs())
+    def host_get_PPCIs(self, session, ref):
+        return xen_api_success(XendNode.instance().get_PPCI_refs())
     def host_get_host_CPUs(self, session, host_ref):
         return xen_api_success(XendNode.instance().get_host_cpu_refs())
     def host_get_metrics(self, _, ref):
@@ -1027,7 +1033,8 @@ class XendAPI(object):
                   'sched_policy': node.get_vcpus_policy(),
                   'logging': {},
                   'PIFs': XendPIF.get_all(),
-                  'PBDs': XendPBD.get_all()}
+                  'PBDs': XendPBD.get_all(),
+                  'PPCIs': XendPPCI.get_all()}
         return xen_api_success(record)
 
     # class methods
@@ -1288,7 +1295,7 @@ class XendAPI(object):
     def VM_get_consoles(self, session, vm_ref):
         dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
         return xen_api_success(dom.get_consoles())
-    
+
     def VM_get_tools_version(self, session, vm_ref):
         dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
         return dom.get_tools_version()
tools/python/xen/xend/XendNode.py +54 -0

96 lines not on this page · raw message

tools/python/xen/xend/XendPPCI.py new file +158 -0

158 lines not on this page · raw message

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel