# 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
|