XenAPI: Add Physical PCI Device (PPCI) Support

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
This commit is contained in:
Keir Fraser committed 2008-07-03 10:26:16 +01:00
1 parent fec35adc86
commit 5a940c0997
4 files changed
+334 -6

No files matched your search

+112 -3
View File
@@ -8,6 +8,8 @@
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_VENDOR_PATH = '/vendor'
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 @@ PCI_CAP_OFFSET = 0x34
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 @@ PAGE_MASK=~(PAGE_SIZE - 1)
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')
@@ -58,6 +75,61 @@ def find_sysfs_mnt():
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):
self.domain = domain
@@ -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
@@ -244,6 +323,36 @@ class PciDevice:
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
def __str__(self):
+10 -3
View File
@@ -40,6 +40,7 @@ from XendPIFMetrics import XendPIFMetrics
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()
+54
View File
@@ -21,6 +21,7 @@ import socket
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 XendPIFMetrics import XendPIFMetrics
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()
@@ -272,6 +310,15 @@ class XendNode:
## 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):
# save state
host_record = {self.uuid: {'name_label':self.name,
@@ -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(
@@ -308,6 +356,12 @@ class XendNode:
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
+158
View File
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.