debuggers.hg
changeset 17989:e65fe28b5288
XenAPI: Add Physical PCI Device (PPCI) Support
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Thu Jul 03 10:26:16 2008 +0100 (2008-07-03) |
parents | 3d5f28d6e777 |
children | 52a388ec09f8 |
files | tools/python/xen/util/pci.py tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/XendPPCI.py |
line diff
1.1 --- a/tools/python/xen/util/pci.py Wed Jul 02 17:28:27 2008 +0100 1.2 +++ b/tools/python/xen/util/pci.py Thu Jul 03 10:26:16 2008 +0100 1.3 @@ -8,6 +8,8 @@ 1.4 import sys 1.5 import os, os.path 1.6 import resource 1.7 +import re 1.8 +import types 1.9 1.10 PROC_MNT_PATH = '/proc/mounts' 1.11 PROC_PCI_PATH = '/proc/bus/pci/devices' 1.12 @@ -22,6 +24,9 @@ SYSFS_PCI_DEV_VENDOR_PATH = '/vendor' 1.13 SYSFS_PCI_DEV_DEVICE_PATH = '/device' 1.14 SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor' 1.15 SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device' 1.16 +SYSFS_PCI_DEV_CLASS_PATH = '/class' 1.17 + 1.18 +LSPCI_CMD = 'lspci' 1.19 1.20 PCI_BAR_IO = 0x01 1.21 PCI_BAR_IO_MASK = ~0x03 1.22 @@ -32,6 +37,9 @@ PCI_CAP_OFFSET = 0x34 1.23 MSIX_BIR_MASK = 0x7 1.24 MSIX_SIZE_MASK = 0x7ff 1.25 1.26 +# Global variable to store information from lspci 1.27 +lspci_info = None 1.28 + 1.29 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number 1.30 PAGE_SIZE = resource.getpagesize() 1.31 PAGE_SHIFT = 0 1.32 @@ -45,6 +53,15 @@ PAGE_MASK=~(PAGE_SIZE - 1) 1.33 def PCI_DEVFN(slot, func): 1.34 return ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 1.35 1.36 +def parse_hex(val): 1.37 + try: 1.38 + if isinstance(val, types.StringTypes): 1.39 + return int(val, 16) 1.40 + else: 1.41 + return val 1.42 + except ValueError: 1.43 + return None 1.44 + 1.45 def find_sysfs_mnt(): 1.46 mounts_file = open(PROC_MNT_PATH,'r') 1.47 1.48 @@ -58,6 +75,61 @@ def find_sysfs_mnt(): 1.49 1.50 return None 1.51 1.52 +def get_all_pci_names(): 1.53 + try: 1.54 + sysfs_mnt = find_sysfs_mnt() 1.55 + except IOError, (errno, strerr): 1.56 + raise PciDeviceParseError(('Failed to locate sysfs mount: %s (%d)' % 1.57 + (PROC_PCI_PATH, strerr, errno))) 1.58 + 1.59 + pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split() 1.60 + 1.61 + return pci_names 1.62 + 1.63 +def get_all_pci_devices(): 1.64 + pci_devs = [] 1.65 + for pci_name in get_all_pci_names(): 1.66 + pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \ 1.67 + r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \ 1.68 + r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \ 1.69 + r"(?P<func>[0-7])$", pci_name) 1.70 + if pci_match is None: 1.71 + raise PciDeviceParseError(('Failed to parse pci device name: %s' % 1.72 + pci_name)) 1.73 + pci_dev_info = pci_match.groupdict('0') 1.74 + domain = parse_hex(pci_dev_info['domain']) 1.75 + bus = parse_hex(pci_dev_info['bus']) 1.76 + slot = parse_hex(pci_dev_info['slot']) 1.77 + func = parse_hex(pci_dev_info['func']) 1.78 + try: 1.79 + pci_dev = PciDevice(domain, bus, slot, func) 1.80 + except: 1.81 + continue 1.82 + pci_devs.append(pci_dev) 1.83 + 1.84 + return pci_devs 1.85 + 1.86 +def create_lspci_info(): 1.87 + global lspci_info 1.88 + lspci_info = {} 1.89 + 1.90 + # Execute 'lspci' command and parse the result. 1.91 + # If the command does not exist, lspci_info will be kept blank ({}). 1.92 + for paragraph in os.popen(LSPCI_CMD + ' -vmmD').read().split('\n\n'): 1.93 + device_name = None 1.94 + device_info = {} 1.95 + for line in paragraph.split('\n'): 1.96 + try: 1.97 + (opt, value) = line.split(':\t') 1.98 + if opt == 'Slot': 1.99 + device_name = value 1.100 + else: 1.101 + device_info[opt] = value 1.102 + except: 1.103 + pass 1.104 + if device_name is not None: 1.105 + lspci_info[device_name] = device_info 1.106 + 1.107 class PciDeviceNotFoundError(Exception): 1.108 def __init__(self,domain,bus,slot,func): 1.109 self.domain = domain 1.110 @@ -92,7 +164,15 @@ class PciDevice: 1.111 self.subdevice = None 1.112 self.msix = 0 1.113 self.msix_iomem = [] 1.114 + self.revision = 0 1.115 + self.classcode = None 1.116 + self.vendorname = "" 1.117 + self.devicename = "" 1.118 + self.classname = "" 1.119 + self.subvendorname = "" 1.120 + self.subdevicename = "" 1.121 self.get_info_from_sysfs() 1.122 + self.get_info_from_lspci() 1.123 1.124 def find_capability(self, type): 1.125 try: 1.126 @@ -208,9 +288,8 @@ class PciDevice: 1.127 self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH 1.128 try: 1.129 self.driver = os.path.basename(os.readlink(path)) 1.130 - except IOError, (errno, strerr): 1.131 - raise PciDeviceParseError(('Failed to read %s: %s (%d)' % 1.132 - (path, strerr, errno))) 1.133 + except OSError, (errno, strerr): 1.134 + self.driver = "" 1.135 1.136 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ 1.137 self.name+SYSFS_PCI_DEV_VENDOR_PATH 1.138 @@ -244,6 +323,36 @@ class PciDevice: 1.139 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % 1.140 (path, strerr, errno))) 1.141 1.142 + path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ 1.143 + self.name+SYSFS_PCI_DEV_CLASS_PATH 1.144 + try: 1.145 + self.classcode = int(open(path,'r').readline(), 16) 1.146 + except IOError, (errno, strerr): 1.147 + raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % 1.148 + (path, strerr, errno))) 1.149 + 1.150 + return True 1.151 + 1.152 + def get_info_from_lspci(self): 1.153 + """ Get information such as vendor name, device name, class name, etc. 1.154 + Since we cannot obtain these data from sysfs, use 'lspci' command. 1.155 + """ 1.156 + global lspci_info 1.157 + 1.158 + if lspci_info is None: 1.159 + create_lspci_info() 1.160 + 1.161 + try: 1.162 + device_info = lspci_info[self.name] 1.163 + self.revision = int(device_info['Rev'], 16) 1.164 + self.vendorname = device_info['Vendor'] 1.165 + self.devicename = device_info['Device'] 1.166 + self.classname = device_info['Class'] 1.167 + self.subvendorname = device_info['SVendor'] 1.168 + self.subdevicename = device_info['SDevice'] 1.169 + except KeyError: 1.170 + pass 1.171 + 1.172 return True 1.173 1.174 def __str__(self):
2.1 --- a/tools/python/xen/xend/XendAPI.py Wed Jul 02 17:28:27 2008 +0100 2.2 +++ b/tools/python/xen/xend/XendAPI.py Thu Jul 03 10:26:16 2008 +0100 2.3 @@ -40,6 +40,7 @@ from XendPIFMetrics import XendPIFMetric 2.4 from XendVMMetrics import XendVMMetrics 2.5 from XendPIF import XendPIF 2.6 from XendPBD import XendPBD 2.7 +from XendPPCI import XendPPCI 2.8 from XendXSPolicy import XendXSPolicy, XendACMPolicy 2.9 2.10 from XendAPIConstants import * 2.11 @@ -476,7 +477,8 @@ classes = { 2.12 'PIF' : valid_object("PIF"), 2.13 'VM_metrics' : valid_object("VM_metrics"), 2.14 'PBD' : valid_object("PBD"), 2.15 - 'PIF_metrics' : valid_object("PIF_metrics") 2.16 + 'PIF_metrics' : valid_object("PIF_metrics"), 2.17 + 'PPCI' : valid_object("PPCI"), 2.18 } 2.19 2.20 autoplug_classes = { 2.21 @@ -485,6 +487,7 @@ autoplug_classes = { 2.22 'VM_metrics' : XendVMMetrics, 2.23 'PBD' : XendPBD, 2.24 'PIF_metrics' : XendPIFMetrics, 2.25 + 'PPCI' : XendPPCI, 2.26 'XSPolicy' : XendXSPolicy, 2.27 'ACMPolicy' : XendACMPolicy, 2.28 } 2.29 @@ -874,6 +877,7 @@ class XendAPI(object): 2.30 'resident_VMs', 2.31 'PBDs', 2.32 'PIFs', 2.33 + 'PPCIs', 2.34 'host_CPUs', 2.35 'cpu_configuration', 2.36 'metrics', 2.37 @@ -952,6 +956,8 @@ class XendAPI(object): 2.38 return xen_api_success(XendPBD.get_all()) 2.39 def host_get_PIFs(self, session, ref): 2.40 return xen_api_success(XendNode.instance().get_PIF_refs()) 2.41 + def host_get_PPCIs(self, session, ref): 2.42 + return xen_api_success(XendNode.instance().get_PPCI_refs()) 2.43 def host_get_host_CPUs(self, session, host_ref): 2.44 return xen_api_success(XendNode.instance().get_host_cpu_refs()) 2.45 def host_get_metrics(self, _, ref): 2.46 @@ -1027,7 +1033,8 @@ class XendAPI(object): 2.47 'sched_policy': node.get_vcpus_policy(), 2.48 'logging': {}, 2.49 'PIFs': XendPIF.get_all(), 2.50 - 'PBDs': XendPBD.get_all()} 2.51 + 'PBDs': XendPBD.get_all(), 2.52 + 'PPCIs': XendPPCI.get_all()} 2.53 return xen_api_success(record) 2.54 2.55 # class methods 2.56 @@ -1288,7 +1295,7 @@ class XendAPI(object): 2.57 def VM_get_consoles(self, session, vm_ref): 2.58 dom = XendDomain.instance().get_vm_by_uuid(vm_ref) 2.59 return xen_api_success(dom.get_consoles()) 2.60 - 2.61 + 2.62 def VM_get_tools_version(self, session, vm_ref): 2.63 dom = XendDomain.instance().get_vm_by_uuid(vm_ref) 2.64 return dom.get_tools_version()
3.1 --- a/tools/python/xen/xend/XendNode.py Wed Jul 02 17:28:27 2008 +0100 3.2 +++ b/tools/python/xen/xend/XendNode.py Thu Jul 03 10:26:16 2008 +0100 3.3 @@ -21,6 +21,7 @@ import socket 3.4 import xen.lowlevel.xc 3.5 3.6 from xen.util import Brctl 3.7 +from xen.util import pci as PciUtil 3.8 from xen.xend import XendAPIStore 3.9 3.10 import uuid, arch 3.11 @@ -35,6 +36,7 @@ from XendPIFMetrics import XendPIFMetric 3.12 from XendNetwork import * 3.13 from XendStateStore import XendStateStore 3.14 from XendMonitor import XendMonitor 3.15 +from XendPPCI import XendPPCI 3.16 3.17 class XendNode: 3.18 """XendNode - Represents a Domain 0 Host.""" 3.19 @@ -49,6 +51,7 @@ class XendNode: 3.20 * PIF_metrics 3.21 * network 3.22 * Storage Repository 3.23 + * PPCI 3.24 """ 3.25 3.26 self.xc = xen.lowlevel.xc.xc() 3.27 @@ -230,6 +233,41 @@ class XendNode: 3.28 except CreateUnspecifiedAttributeError: 3.29 log.warn("Error recreating PBD %s", pbd_uuid) 3.30 3.31 + 3.32 + # Initialise PPCIs 3.33 + saved_ppcis = self.state_store.load_state('ppci') 3.34 + saved_ppci_table = {} 3.35 + if saved_ppcis: 3.36 + for ppci_uuid, ppci_record in saved_ppcis.items(): 3.37 + try: 3.38 + saved_ppci_table[ppci_record['name']] = ppci_uuid 3.39 + except KeyError: 3.40 + pass 3.41 + 3.42 + for pci_dev in PciUtil.get_all_pci_devices(): 3.43 + ppci_record = { 3.44 + 'domain': pci_dev.domain, 3.45 + 'bus': pci_dev.bus, 3.46 + 'slot': pci_dev.slot, 3.47 + 'func': pci_dev.func, 3.48 + 'vendor_id': pci_dev.vendor, 3.49 + 'vendor_name': pci_dev.vendorname, 3.50 + 'device_id': pci_dev.device, 3.51 + 'device_name': pci_dev.devicename, 3.52 + 'revision_id': pci_dev.revision, 3.53 + 'class_code': pci_dev.classcode, 3.54 + 'class_name': pci_dev.classname, 3.55 + 'subsystem_vendor_id': pci_dev.subvendor, 3.56 + 'subsystem_vendor_name': pci_dev.subvendorname, 3.57 + 'subsystem_id': pci_dev.subdevice, 3.58 + 'subsystem_name': pci_dev.subdevicename, 3.59 + 'driver': pci_dev.driver 3.60 + } 3.61 + # If saved uuid exists, use it. Otherwise create one. 3.62 + ppci_uuid = saved_ppci_table.get(pci_dev.name, uuid.createString()) 3.63 + XendPPCI(ppci_uuid, ppci_record) 3.64 + 3.65 + 3.66 ## def network_destroy(self, net_uuid): 3.67 ## del self.networks[net_uuid] 3.68 ## self.save_networks() 3.69 @@ -272,6 +310,15 @@ class XendNode: 3.70 ## self.save_PIFs() 3.71 3.72 3.73 + def get_PPCI_refs(self): 3.74 + return XendPPCI.get_all() 3.75 + 3.76 + def get_ppci_by_uuid(self, ppci_uuid): 3.77 + if ppci_uuid in self.get_PPCI_refs(): 3.78 + return ppci_uuid 3.79 + return None 3.80 + 3.81 + 3.82 def save(self): 3.83 # save state 3.84 host_record = {self.uuid: {'name_label':self.name, 3.85 @@ -284,6 +331,7 @@ class XendNode: 3.86 self.save_networks() 3.87 self.save_PBDs() 3.88 self.save_SRs() 3.89 + self.save_PPCIs() 3.90 3.91 def save_PIFs(self): 3.92 pif_records = dict([(pif_uuid, XendAPIStore.get( 3.93 @@ -308,6 +356,12 @@ class XendNode: 3.94 for k, v in self.srs.items()]) 3.95 self.state_store.save_state('sr', sr_records) 3.96 3.97 + def save_PPCIs(self): 3.98 + ppci_records = dict([(ppci_uuid, XendAPIStore.get( 3.99 + ppci_uuid, "PPCI").get_record()) 3.100 + for ppci_uuid in XendPPCI.get_all()]) 3.101 + self.state_store.save_state('ppci', ppci_records) 3.102 + 3.103 def shutdown(self): 3.104 return 0 3.105
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/tools/python/xen/xend/XendPPCI.py Thu Jul 03 10:26:16 2008 +0100 4.3 @@ -0,0 +1,158 @@ 4.4 +#============================================================================ 4.5 +# This library is free software; you can redistribute it and/or 4.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public 4.7 +# License as published by the Free Software Foundation. 4.8 +# 4.9 +# This library is distributed in the hope that it will be useful, 4.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of 4.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 4.12 +# Lesser General Public License for more details. 4.13 +# 4.14 +# You should have received a copy of the GNU Lesser General Public 4.15 +# License along with this library; if not, write to the Free Software 4.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4.17 +#============================================================================ 4.18 +# Copyright (c) 2008 NEC Corporation 4.19 +# Yosuke Iwamatsu <y-iwamatsu at ab jp nec com> 4.20 +#============================================================================ 4.21 + 4.22 +from xen.xend.XendBase import XendBase 4.23 +from xen.xend.XendBase import XendAPIStore 4.24 +from xen.xend import uuid as genuuid 4.25 + 4.26 +class XendPPCI(XendBase): 4.27 + """Representation of a physical PCI device.""" 4.28 + 4.29 + def getClass(self): 4.30 + return "PPCI" 4.31 + 4.32 + def getAttrRO(self): 4.33 + attrRO = ['host', 4.34 + 'domain', 4.35 + 'bus', 4.36 + 'slot', 4.37 + 'func', 4.38 + 'name', 4.39 + 'vendor_id', 4.40 + 'vendor_name', 4.41 + 'device_id', 4.42 + 'device_name', 4.43 + 'revision_id', 4.44 + 'class_code', 4.45 + 'class_name', 4.46 + 'subsystem_vendor_id', 4.47 + 'subsystem_vendor_name', 4.48 + 'subsystem_id', 4.49 + 'subsystem_name', 4.50 + 'driver'] 4.51 + return XendBase.getAttrRO() + attrRO 4.52 + 4.53 + def getAttrRW(self): 4.54 + attrRW = [] 4.55 + return XendBase.getAttrRW() + attrRW 4.56 + 4.57 + def getAttrInst(self): 4.58 + attrInst = [] 4.59 + return XendBase.getAttrInst() + attrInst 4.60 + 4.61 + def getMethods(self): 4.62 + methods = [] 4.63 + return XendBase.getMethods() + methods 4.64 + 4.65 + def getFuncs(self): 4.66 + funcs = [] 4.67 + return XendBase.getFuncs() + funcs 4.68 + 4.69 + getClass = classmethod(getClass) 4.70 + getAttrRO = classmethod(getAttrRO) 4.71 + getAttrRW = classmethod(getAttrRW) 4.72 + getAttrInst = classmethod(getAttrInst) 4.73 + getMethods = classmethod(getMethods) 4.74 + getFuncs = classmethod(getFuncs) 4.75 + 4.76 + def get_by_sbdf(self, domain, bus, slot, func): 4.77 + for ppci in XendAPIStore.get_all("PPCI"): 4.78 + if ppci.get_domain() == int(domain, 16) and \ 4.79 + ppci.get_bus() == int(bus, 16) and \ 4.80 + ppci.get_slot() == int(slot, 16) and \ 4.81 + ppci.get_func() == int(func, 16): 4.82 + return ppci.get_uuid() 4.83 + return None 4.84 + 4.85 + get_by_sbdf = classmethod(get_by_sbdf) 4.86 + 4.87 + def __init__(self, uuid, record): 4.88 + self.domain = record['domain'] 4.89 + self.bus = record['bus'] 4.90 + self.slot = record['slot'] 4.91 + self.func = record['func'] 4.92 + self.vendor_id = record['vendor_id'] 4.93 + self.vendor_name = record['vendor_name'] 4.94 + self.device_id = record['device_id'] 4.95 + self.device_name = record['device_name'] 4.96 + self.revision_id = record['revision_id'] 4.97 + self.class_code = record['class_code'] 4.98 + self.class_name = record['class_name'] 4.99 + self.subsystem_vendor_id = record['subsystem_vendor_id'] 4.100 + self.subsystem_vendor_name = record['subsystem_vendor_name'] 4.101 + self.subsystem_id = record['subsystem_id'] 4.102 + self.subsystem_name = record['subsystem_name'] 4.103 + self.driver = record['driver'] 4.104 + XendBase.__init__(self, uuid, record) 4.105 + 4.106 + def get_host(self): 4.107 + from xen.xend import XendNode 4.108 + return XendNode.instance().get_uuid() 4.109 + 4.110 + def get_domain(self): 4.111 + return self.domain 4.112 + 4.113 + def get_bus(self): 4.114 + return self.bus 4.115 + 4.116 + def get_slot(self): 4.117 + return self.slot 4.118 + 4.119 + def get_func(self): 4.120 + return self.func 4.121 + 4.122 + def get_name(self): 4.123 + return "%04x:%02x:%02x.%01x" % (self.domain, self.bus, self.slot, 4.124 + self.func) 4.125 + 4.126 + def get_vendor_id(self): 4.127 + return self.vendor_id 4.128 + 4.129 + def get_vendor_name(self): 4.130 + return self.vendor_name 4.131 + 4.132 + def get_device_id(self): 4.133 + return self.device_id 4.134 + 4.135 + def get_device_name(self): 4.136 + return self.device_name 4.137 + 4.138 + def get_class_code(self): 4.139 + return self.class_code 4.140 + 4.141 + def get_class_name(self): 4.142 + return self.class_name 4.143 + 4.144 + def get_revision_id(self): 4.145 + return self.revision_id 4.146 + 4.147 + def get_subsystem_vendor_id(self): 4.148 + return self.subsystem_vendor_id 4.149 + 4.150 + def get_subsystem_vendor_name(self): 4.151 + return self.subsystem_vendor_name 4.152 + 4.153 + def get_subsystem_id(self): 4.154 + return self.subsystem_id 4.155 + 4.156 + def get_subsystem_name(self): 4.157 + return self.subsystem_name 4.158 + 4.159 + def get_driver(self): 4.160 + return self.driver 4.161 +