[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] XenAPI: Add Physical PCI Device (PPCI) Support
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1215077176 -3600 # Node ID e65fe28b52887ffe61750474835cbd0afe8ccd48 # Parent 3d5f28d6e77711d3b5adb8fd75cd05fe0537302d XenAPI: Add Physical PCI Device (PPCI) Support Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@xxxxxxxxxxxxx> --- tools/python/xen/util/pci.py | 115 ++++++++++++++++++++++++++- tools/python/xen/xend/XendAPI.py | 13 ++- tools/python/xen/xend/XendNode.py | 54 ++++++++++++ tools/python/xen/xend/XendPPCI.py | 158 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+), 6 deletions(-) diff -r 3d5f28d6e777 -r e65fe28b5288 tools/python/xen/util/pci.py --- a/tools/python/xen/util/pci.py Wed Jul 02 17:28:27 2008 +0100 +++ b/tools/python/xen/util/pci.py Thu Jul 03 10:26:16 2008 +0100 @@ -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 diff -r 3d5f28d6e777 -r e65fe28b5288 tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Wed Jul 02 17:28:27 2008 +0100 +++ b/tools/python/xen/xend/XendAPI.py Thu Jul 03 10:26:16 2008 +0100 @@ -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() diff -r 3d5f28d6e777 -r e65fe28b5288 tools/python/xen/xend/XendNode.py --- a/tools/python/xen/xend/XendNode.py Wed Jul 02 17:28:27 2008 +0100 +++ b/tools/python/xen/xend/XendNode.py Thu Jul 03 10:26:16 2008 +0100 @@ -21,6 +21,7 @@ import xen.lowlevel.xc import xen.lowlevel.xc from xen.util import Brctl +from xen.util import pci as PciUtil from xen.xend import XendAPIStore import uuid, arch @@ -35,6 +36,7 @@ from XendNetwork import * from XendNetwork import * from XendStateStore import XendStateStore from XendMonitor import XendMonitor +from XendPPCI import XendPPCI class XendNode: """XendNode - Represents a Domain 0 Host.""" @@ -49,6 +51,7 @@ class XendNode: * PIF_metrics * network * Storage Repository + * PPCI """ self.xc = xen.lowlevel.xc.xc() @@ -230,6 +233,41 @@ class XendNode: except CreateUnspecifiedAttributeError: log.warn("Error recreating PBD %s", pbd_uuid) + + # Initialise PPCIs + saved_ppcis = self.state_store.load_state('ppci') + saved_ppci_table = {} + if saved_ppcis: + for ppci_uuid, ppci_record in saved_ppcis.items(): + try: + saved_ppci_table[ppci_record['name']] = ppci_uuid + except KeyError: + pass + + for pci_dev in PciUtil.get_all_pci_devices(): + ppci_record = { + 'domain': pci_dev.domain, + 'bus': pci_dev.bus, + 'slot': pci_dev.slot, + 'func': pci_dev.func, + 'vendor_id': pci_dev.vendor, + 'vendor_name': pci_dev.vendorname, + 'device_id': pci_dev.device, + 'device_name': pci_dev.devicename, + 'revision_id': pci_dev.revision, + 'class_code': pci_dev.classcode, + 'class_name': pci_dev.classname, + 'subsystem_vendor_id': pci_dev.subvendor, + 'subsystem_vendor_name': pci_dev.subvendorname, + 'subsystem_id': pci_dev.subdevice, + 'subsystem_name': pci_dev.subdevicename, + 'driver': pci_dev.driver + } + # If saved uuid exists, use it. Otherwise create one. + ppci_uuid = saved_ppci_table.get(pci_dev.name, uuid.createString()) + XendPPCI(ppci_uuid, ppci_record) + + ## def network_destroy(self, net_uuid): ## del self.networks[net_uuid] ## self.save_networks() @@ -270,6 +308,15 @@ class XendNode: ## del self.pifs[pif_uuid] ## self.save_PIFs() + + + def get_PPCI_refs(self): + return XendPPCI.get_all() + + def get_ppci_by_uuid(self, ppci_uuid): + if ppci_uuid in self.get_PPCI_refs(): + return ppci_uuid + return None def save(self): @@ -284,6 +331,7 @@ class XendNode: self.save_networks() self.save_PBDs() self.save_SRs() + self.save_PPCIs() def save_PIFs(self): pif_records = dict([(pif_uuid, XendAPIStore.get( @@ -307,6 +355,12 @@ class XendNode: sr_records = dict([(k, v.get_record(transient = False)) for k, v in self.srs.items()]) self.state_store.save_state('sr', sr_records) + + def save_PPCIs(self): + ppci_records = dict([(ppci_uuid, XendAPIStore.get( + ppci_uuid, "PPCI").get_record()) + for ppci_uuid in XendPPCI.get_all()]) + self.state_store.save_state('ppci', ppci_records) def shutdown(self): return 0 diff -r 3d5f28d6e777 -r e65fe28b5288 tools/python/xen/xend/XendPPCI.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendPPCI.py Thu Jul 03 10:26:16 2008 +0100 @@ -0,0 +1,158 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (c) 2008 NEC Corporation +# Yosuke Iwamatsu <y-iwamatsu at ab jp nec com> +#============================================================================ + +from xen.xend.XendBase import XendBase +from xen.xend.XendBase import XendAPIStore +from xen.xend import uuid as genuuid + +class XendPPCI(XendBase): + """Representation of a physical PCI device.""" + + def getClass(self): + return "PPCI" + + def getAttrRO(self): + attrRO = ['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'] + return XendBase.getAttrRO() + attrRO + + def getAttrRW(self): + attrRW = [] + return XendBase.getAttrRW() + attrRW + + def getAttrInst(self): + attrInst = [] + return XendBase.getAttrInst() + attrInst + + def getMethods(self): + methods = [] + return XendBase.getMethods() + methods + + def getFuncs(self): + funcs = [] + return XendBase.getFuncs() + funcs + + getClass = classmethod(getClass) + getAttrRO = classmethod(getAttrRO) + getAttrRW = classmethod(getAttrRW) + getAttrInst = classmethod(getAttrInst) + getMethods = classmethod(getMethods) + getFuncs = classmethod(getFuncs) + + def get_by_sbdf(self, domain, bus, slot, func): + for ppci in XendAPIStore.get_all("PPCI"): + if ppci.get_domain() == int(domain, 16) and \ + ppci.get_bus() == int(bus, 16) and \ + ppci.get_slot() == int(slot, 16) and \ + ppci.get_func() == int(func, 16): + return ppci.get_uuid() + return None + + get_by_sbdf = classmethod(get_by_sbdf) + + def __init__(self, uuid, record): + self.domain = record['domain'] + self.bus = record['bus'] + self.slot = record['slot'] + self.func = record['func'] + self.vendor_id = record['vendor_id'] + self.vendor_name = record['vendor_name'] + self.device_id = record['device_id'] + self.device_name = record['device_name'] + self.revision_id = record['revision_id'] + self.class_code = record['class_code'] + self.class_name = record['class_name'] + self.subsystem_vendor_id = record['subsystem_vendor_id'] + self.subsystem_vendor_name = record['subsystem_vendor_name'] + self.subsystem_id = record['subsystem_id'] + self.subsystem_name = record['subsystem_name'] + self.driver = record['driver'] + XendBase.__init__(self, uuid, record) + + def get_host(self): + from xen.xend import XendNode + return XendNode.instance().get_uuid() + + def get_domain(self): + return self.domain + + def get_bus(self): + return self.bus + + def get_slot(self): + return self.slot + + def get_func(self): + return self.func + + def get_name(self): + return "%04x:%02x:%02x.%01x" % (self.domain, self.bus, self.slot, + self.func) + + def get_vendor_id(self): + return self.vendor_id + + def get_vendor_name(self): + return self.vendor_name + + def get_device_id(self): + return self.device_id + + def get_device_name(self): + return self.device_name + + def get_class_code(self): + return self.class_code + + def get_class_name(self): + return self.class_name + + def get_revision_id(self): + return self.revision_id + + def get_subsystem_vendor_id(self): + return self.subsystem_vendor_id + + def get_subsystem_vendor_name(self): + return self.subsystem_vendor_name + + def get_subsystem_id(self): + return self.subsystem_id + + def get_subsystem_name(self): + return self.subsystem_name + + def get_driver(self): + return self.driver + _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |