mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
XenAPI: Add Direct PCI Device (DPCI) Assignment Support
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
This commit is contained in:
1 parent
5a940c0997
commit
8e65d32968
7 files changed
+434
-83
No files matched your search
@@ -41,6 +41,7 @@ from XendVMMetrics import XendVMMetrics
|
||||
from XendPIF import XendPIF
|
||||
from XendPBD import XendPBD
|
||||
from XendPPCI import XendPPCI
|
||||
from XendDPCI import XendDPCI
|
||||
from XendXSPolicy import XendXSPolicy, XendACMPolicy
|
||||
|
||||
from XendAPIConstants import *
|
||||
@@ -479,6 +480,7 @@ classes = {
|
||||
'PBD' : valid_object("PBD"),
|
||||
'PIF_metrics' : valid_object("PIF_metrics"),
|
||||
'PPCI' : valid_object("PPCI"),
|
||||
'DPCI' : valid_object("DPCI")
|
||||
}
|
||||
|
||||
autoplug_classes = {
|
||||
@@ -488,6 +490,7 @@ autoplug_classes = {
|
||||
'PBD' : XendPBD,
|
||||
'PIF_metrics' : XendPIFMetrics,
|
||||
'PPCI' : XendPPCI,
|
||||
'DPCI' : XendDPCI,
|
||||
'XSPolicy' : XendXSPolicy,
|
||||
'ACMPolicy' : XendACMPolicy,
|
||||
}
|
||||
@@ -1154,6 +1157,7 @@ class XendAPI(object):
|
||||
'VIFs',
|
||||
'VBDs',
|
||||
'VTPMs',
|
||||
'DPCIs',
|
||||
'tools_version',
|
||||
'domid',
|
||||
'is_control_domain',
|
||||
@@ -1296,6 +1300,10 @@ class XendAPI(object):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_success(dom.get_consoles())
|
||||
|
||||
def VM_get_DPCIs(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return xen_api_success(dom.get_dpcis())
|
||||
|
||||
def VM_get_tools_version(self, session, vm_ref):
|
||||
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
|
||||
return dom.get_tools_version()
|
||||
@@ -1675,6 +1683,7 @@ class XendAPI(object):
|
||||
'VIFs': xeninfo.get_vifs(),
|
||||
'VBDs': xeninfo.get_vbds(),
|
||||
'VTPMs': xeninfo.get_vtpms(),
|
||||
'DPCIs': xeninfo.get_dpcis(),
|
||||
'PV_bootloader': xeninfo.info.get('PV_bootloader'),
|
||||
'PV_kernel': xeninfo.info.get('PV_kernel'),
|
||||
'PV_ramdisk': xeninfo.info.get('PV_ramdisk'),
|
||||
|
||||
@@ -24,6 +24,8 @@ from xen.xend import sxp
|
||||
from xen.xend import uuid
|
||||
from xen.xend import XendOptions
|
||||
from xen.xend import XendAPIStore
|
||||
from xen.xend.XendPPCI import XendPPCI
|
||||
from xen.xend.XendDPCI import XendDPCI
|
||||
from xen.xend.XendError import VmError
|
||||
from xen.xend.XendDevices import XendDevices
|
||||
from xen.xend.PrettyPrint import prettyprintstring
|
||||
@@ -773,6 +775,11 @@ class XendConfig(dict):
|
||||
"""
|
||||
log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
|
||||
|
||||
# _parse_sxp() below will call device_add() and construct devices.
|
||||
# Some devices (currently only pci) may require VM's uuid, so
|
||||
# setup self['uuid'] beforehand.
|
||||
self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString())
|
||||
|
||||
cfg = self._parse_sxp(sxp_cfg)
|
||||
|
||||
for key, typ in XENAPI_CFG_TYPES.items():
|
||||
@@ -1209,42 +1216,35 @@ class XendConfig(dict):
|
||||
dev_type = sxp.name(config)
|
||||
dev_info = {}
|
||||
|
||||
# Parsing the device SXP's. In most cases, the SXP looks
|
||||
# like this:
|
||||
#
|
||||
# [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
|
||||
#
|
||||
# However, for PCI devices it looks like this:
|
||||
#
|
||||
# [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
|
||||
#
|
||||
# It seems the reasoning for this difference is because
|
||||
# pciif.py needs all the PCI device configurations at
|
||||
# the same time when creating the devices.
|
||||
#
|
||||
# To further complicate matters, Xen 2.0 configuration format
|
||||
# uses the following for pci device configuration:
|
||||
#
|
||||
# [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
|
||||
|
||||
if dev_type == 'pci':
|
||||
pci_devs_uuid = sxp.child_value(config, 'uuid',
|
||||
uuid.createString())
|
||||
pci_devs = []
|
||||
for pci_dev in sxp.children(config, 'dev'):
|
||||
pci_dev_info = {}
|
||||
for opt_val in pci_dev[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
pci_dev_info[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
pci_devs.append(pci_dev_info)
|
||||
|
||||
pci_dict = self.pci_convert_sxp_to_dict(config)
|
||||
pci_devs = pci_dict['devs']
|
||||
|
||||
# create XenAPI DPCI objects.
|
||||
for pci_dev in pci_devs:
|
||||
dpci_uuid = pci_dev.get('uuid')
|
||||
ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
|
||||
pci_dev['bus'],
|
||||
pci_dev['slot'],
|
||||
pci_dev['func'])
|
||||
if ppci_uuid is None:
|
||||
continue
|
||||
dpci_record = {
|
||||
'VM': self['uuid'],
|
||||
'PPCI': ppci_uuid,
|
||||
'hotplug_slot': pci_dev.get('vslot', 0)
|
||||
}
|
||||
XendDPCI(dpci_uuid, dpci_record)
|
||||
|
||||
target['devices'][pci_devs_uuid] = (dev_type,
|
||||
{'devs': pci_devs,
|
||||
'uuid': pci_devs_uuid})
|
||||
|
||||
log.debug("XendConfig: reading device: %s" % pci_devs)
|
||||
|
||||
return pci_devs_uuid
|
||||
|
||||
for opt_val in config[1:]:
|
||||
@@ -1482,6 +1482,76 @@ class XendConfig(dict):
|
||||
|
||||
return ''
|
||||
|
||||
def pci_convert_sxp_to_dict(self, dev_sxp):
|
||||
"""Convert pci device sxp to dict
|
||||
@param dev_sxp: device configuration
|
||||
@type dev_sxp: SXP object (parsed config)
|
||||
@return: dev_config
|
||||
@rtype: dictionary
|
||||
"""
|
||||
# Parsing the device SXP's. In most cases, the SXP looks
|
||||
# like this:
|
||||
#
|
||||
# [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
|
||||
#
|
||||
# However, for PCI devices it looks like this:
|
||||
#
|
||||
# [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2]]]
|
||||
#
|
||||
# It seems the reasoning for this difference is because
|
||||
# pciif.py needs all the PCI device configurations at
|
||||
# the same time when creating the devices.
|
||||
#
|
||||
# To further complicate matters, Xen 2.0 configuration format
|
||||
# uses the following for pci device configuration:
|
||||
#
|
||||
# [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
|
||||
|
||||
# For PCI device hotplug support, the SXP of PCI devices is
|
||||
# extendend like this:
|
||||
#
|
||||
# [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2],
|
||||
# [vslt, 0]],
|
||||
# [state, 'Initialising']]]
|
||||
#
|
||||
# 'vslt' shows the virtual hotplug slot number which the PCI device
|
||||
# is inserted in. This is only effective for HVM domains.
|
||||
#
|
||||
# state 'Initialising' indicates that the device is being attached,
|
||||
# while state 'Closing' indicates that the device is being detached.
|
||||
#
|
||||
# The Dict looks like this:
|
||||
#
|
||||
# { devs: [{domain: 0, bus: 0, slot: 1, func: 2, vslt: 0}],
|
||||
# states: ['Initialising'] }
|
||||
|
||||
dev_config = {}
|
||||
|
||||
pci_devs = []
|
||||
for pci_dev in sxp.children(dev_sxp, 'dev'):
|
||||
pci_dev_info = {}
|
||||
for opt_val in pci_dev[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
pci_dev_info[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
# append uuid for each pci device.
|
||||
dpci_uuid = pci_dev_info.get('uuid', uuid.createString())
|
||||
pci_dev_info['uuid'] = dpci_uuid
|
||||
pci_devs.append(pci_dev_info)
|
||||
dev_config['devs'] = pci_devs
|
||||
|
||||
pci_states = []
|
||||
for pci_state in sxp.children(dev_sxp, 'state'):
|
||||
try:
|
||||
pci_states.append(pci_state[1])
|
||||
except IndexError:
|
||||
raise XendError("Error reading state while parsing pci sxp")
|
||||
dev_config['states'] = pci_states
|
||||
|
||||
return dev_config
|
||||
|
||||
def console_add(self, protocol, location, other_config = {}):
|
||||
dev_uuid = uuid.createString()
|
||||
if protocol == 'vt100':
|
||||
@@ -1556,16 +1626,29 @@ class XendConfig(dict):
|
||||
dev_type, dev_info = self['devices'][dev_uuid]
|
||||
|
||||
if dev_type == 'pci': # Special case for pci
|
||||
pci_devs = []
|
||||
for pci_dev in sxp.children(config, 'dev'):
|
||||
pci_dev_info = {}
|
||||
for opt_val in pci_dev[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
pci_dev_info[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
pci_devs.append(pci_dev_info)
|
||||
pci_dict = self.pci_convert_sxp_to_dict(config)
|
||||
pci_devs = pci_dict['devs']
|
||||
|
||||
# destroy existing XenAPI DPCI objects
|
||||
for dpci_uuid in XendDPCI.get_by_VM(self['uuid']):
|
||||
XendAPIStore.deregister(dpci_uuid, "DPCI")
|
||||
|
||||
# create XenAPI DPCI objects.
|
||||
for pci_dev in pci_devs:
|
||||
dpci_uuid = pci_dev.get('uuid')
|
||||
ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
|
||||
pci_dev['bus'],
|
||||
pci_dev['slot'],
|
||||
pci_dev['func'])
|
||||
if ppci_uuid is None:
|
||||
continue
|
||||
dpci_record = {
|
||||
'VM': self['uuid'],
|
||||
'PPCI': ppci_uuid,
|
||||
'hotplug_slot': pci_dev.get('vslot', 0)
|
||||
}
|
||||
XendDPCI(dpci_uuid, dpci_record)
|
||||
|
||||
self['devices'][dev_uuid] = (dev_type,
|
||||
{'devs': pci_devs,
|
||||
'uuid': dev_uuid})
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
#============================================================================
|
||||
# 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.XendPPCI import XendPPCI
|
||||
from xen.xend import XendAPIStore
|
||||
from xen.xend import uuid as genuuid
|
||||
|
||||
import XendDomain, XendNode
|
||||
|
||||
from XendError import *
|
||||
from XendTask import XendTask
|
||||
from XendLogging import log
|
||||
|
||||
class XendDPCI(XendBase):
|
||||
"""Representation of a passthrough PCI device."""
|
||||
|
||||
def getClass(self):
|
||||
return "DPCI"
|
||||
|
||||
def getAttrRO(self):
|
||||
attrRO = ['virtual_domain',
|
||||
'virtual_bus',
|
||||
'virtual_slot',
|
||||
'virtual_func',
|
||||
'virtual_name',
|
||||
'VM',
|
||||
'PPCI',
|
||||
'hotplug_slot']
|
||||
return XendBase.getAttrRO() + attrRO
|
||||
|
||||
def getAttrRW(self):
|
||||
attrRW = []
|
||||
return XendBase.getAttrRW() + attrRW
|
||||
|
||||
def getAttrInst(self):
|
||||
attrInst = ['VM',
|
||||
'PPCI',
|
||||
'hotplug_slot']
|
||||
return XendBase.getAttrInst() + attrInst
|
||||
|
||||
def getMethods(self):
|
||||
methods = ['destroy']
|
||||
return XendBase.getMethods() + methods
|
||||
|
||||
def getFuncs(self):
|
||||
funcs = ['create']
|
||||
return XendBase.getFuncs() + funcs
|
||||
|
||||
getClass = classmethod(getClass)
|
||||
getAttrRO = classmethod(getAttrRO)
|
||||
getAttrRW = classmethod(getAttrRW)
|
||||
getAttrInst = classmethod(getAttrInst)
|
||||
getMethods = classmethod(getMethods)
|
||||
getFuncs = classmethod(getFuncs)
|
||||
|
||||
def create(self, dpci_struct):
|
||||
|
||||
# Check if VM is valid
|
||||
xendom = XendDomain.instance()
|
||||
if not xendom.is_valid_vm(dpci_struct['VM']):
|
||||
raise InvalidHandleError('VM', dpci_struct['VM'])
|
||||
dom = xendom.get_vm_by_uuid(dpci_struct['VM'])
|
||||
|
||||
# Check if PPCI is valid
|
||||
xennode = XendNode.instance()
|
||||
ppci_uuid = xennode.get_ppci_by_uuid(dpci_struct['PPCI'])
|
||||
if not ppci_uuid:
|
||||
raise InvalidHandleError('PPCI', dpci_struct['PPCI'])
|
||||
for existing_dpci in XendAPIStore.get_all('DPCI'):
|
||||
if ppci_uuid == existing_dpci.get_PPCI():
|
||||
raise DirectPCIError("Device is in use")
|
||||
|
||||
# Assign PPCI to VM
|
||||
try:
|
||||
dpci_ref = XendTask.log_progress(0, 100, dom.create_dpci,
|
||||
dpci_struct)
|
||||
except XendError, e:
|
||||
raise DirectPCIError("Failed to assign device")
|
||||
|
||||
# TODO: Retrive virtual pci device infomation.
|
||||
|
||||
return dpci_ref
|
||||
|
||||
create = classmethod(create)
|
||||
|
||||
def get_by_VM(cls, VM_ref):
|
||||
result = []
|
||||
for dpci in XendAPIStore.get_all("DPCI"):
|
||||
if dpci.get_VM() == VM_ref:
|
||||
result.append(dpci.get_uuid())
|
||||
return result
|
||||
|
||||
get_by_VM = classmethod(get_by_VM)
|
||||
|
||||
def __init__(self, uuid, record):
|
||||
XendBase.__init__(self, uuid, record)
|
||||
|
||||
self.virtual_domain = -1
|
||||
self.virtual_bus = -1
|
||||
self.virtual_slot = -1
|
||||
self.virtual_func = -1
|
||||
|
||||
self.VM = record['VM']
|
||||
self.PPCI = record['PPCI']
|
||||
self.hotplug_slot = record['hotplug_slot']
|
||||
|
||||
def destroy(self):
|
||||
xendom = XendDomain.instance()
|
||||
dom = xendom.get_vm_by_uuid(self.get_VM())
|
||||
if not dom:
|
||||
raise InvalidHandleError("VM", self.get_VM())
|
||||
XendTask.log_progress(0, 100, dom.destroy_dpci, self.get_uuid())
|
||||
|
||||
def get_virtual_domain(self):
|
||||
return self.virtual_domain
|
||||
|
||||
def get_virtual_bus(self):
|
||||
return self.virtual_bus
|
||||
|
||||
def get_virtual_slot(self):
|
||||
return self.virtual_slot
|
||||
|
||||
def get_virtual_func(self):
|
||||
return self.virtual_func
|
||||
|
||||
def get_virtual_name(self):
|
||||
return "%04x:%02x:%02x.%01x" % (self.virtual_domain, self.virtual_bus,
|
||||
self.virtual_slot, self.virtual_func)
|
||||
|
||||
def get_VM(self):
|
||||
return self.VM
|
||||
|
||||
def get_PPCI(self):
|
||||
return self.PPCI
|
||||
|
||||
def get_hotplug_slot(self):
|
||||
return self.hotplug_slot
|
||||
|
||||
@@ -478,6 +478,8 @@ class XendDomain:
|
||||
|
||||
if domid in self.domains:
|
||||
del self.domains[domid]
|
||||
|
||||
info.destroy_xapi_device_instances()
|
||||
else:
|
||||
log.warning("Attempted to remove non-existent domain.")
|
||||
|
||||
@@ -1091,6 +1093,7 @@ class XendDomain:
|
||||
self._managed_domain_unregister(dominfo)
|
||||
self._remove_domain(dominfo)
|
||||
XendDevices.destroy_device_state(dominfo)
|
||||
dominfo.destroy_xapi_device_instances()
|
||||
|
||||
|
||||
def domain_configure(self, config):
|
||||
|
||||
@@ -55,6 +55,10 @@ from xen.xend.XendAPIConstants import *
|
||||
|
||||
from xen.xend.XendVMMetrics import XendVMMetrics
|
||||
|
||||
from xen.xend.XendPPCI import XendPPCI
|
||||
from xen.xend.XendDPCI import XendDPCI
|
||||
from xen.xend import XendAPIStore
|
||||
|
||||
MIGRATE_TIMEOUT = 30.0
|
||||
BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp'
|
||||
|
||||
@@ -642,50 +646,7 @@ class XendDomainInfo:
|
||||
xen.xend.XendDomain.instance().managed_config_save(self)
|
||||
return self.getDeviceController(dev_type).sxpr(devid)
|
||||
|
||||
def pci_convert_sxp_to_dict(self, dev_sxp):
|
||||
"""Convert pci device sxp to dict
|
||||
@param dev_sxp: device configuration
|
||||
@type dev_sxp: SXP object (parsed config)
|
||||
@return: dev_config
|
||||
@rtype: dictionary
|
||||
"""
|
||||
# In reconfigure phase, config of PCI device looks like below:
|
||||
#
|
||||
# sxp:
|
||||
# [device, [pci, [dev, [domain, '0x0'], [bus, '0x0'], [slot, '0x0'],
|
||||
# [func, '0x0'], [vslt, '0x0']],
|
||||
# [state, 'Initialising']]]
|
||||
#
|
||||
# dict:
|
||||
# {devs: [{domain: '0x0', bus: '0x0', slot: '0x0', func: '0x0',
|
||||
# vslt: '0x0'}],
|
||||
# states: ['Initialising']}
|
||||
#
|
||||
# state 'Initialising' means the device is being attached.
|
||||
# state 'Closing' means the device is being detached.
|
||||
|
||||
dev_config = {}
|
||||
pci_devs = []
|
||||
for pci_dev in sxp.children(dev_sxp, 'dev'):
|
||||
pci_dev_info = {}
|
||||
for opt_val in pci_dev[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
pci_dev_info[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
pci_devs.append(pci_dev_info)
|
||||
dev_config['devs'] = pci_devs
|
||||
pci_states = []
|
||||
for pci_state in sxp.children(dev_sxp, 'state'):
|
||||
try:
|
||||
pci_states.append(pci_state[1])
|
||||
except IndexError:
|
||||
raise XendError("Error reading state while parsing pci sxp")
|
||||
dev_config['states'] = pci_states
|
||||
|
||||
return dev_config
|
||||
|
||||
def pci_device_configure(self, dev_sxp, devid = 0):
|
||||
"""Configure an existing pci device.
|
||||
|
||||
@@ -711,7 +672,7 @@ class XendDomainInfo:
|
||||
raise XendError("Cannot detach when pci platform does not exist")
|
||||
|
||||
pci_dev = sxp.children(dev_sxp, 'dev')[0]
|
||||
dev_config = self.pci_convert_sxp_to_dict(dev_sxp)
|
||||
dev_config = self.info.pci_convert_sxp_to_dict(dev_sxp)
|
||||
dev = dev_config['devs'][0]
|
||||
|
||||
# Do HVM specific processing
|
||||
@@ -785,6 +746,8 @@ class XendDomainInfo:
|
||||
self.destroyDevice('pci', devid)
|
||||
del self.info['devices'][dev_uuid]
|
||||
|
||||
xen.xend.XendDomain.instance().managed_config_save(self)
|
||||
|
||||
return True
|
||||
|
||||
def device_configure(self, dev_sxp, devid = None):
|
||||
@@ -3169,6 +3132,9 @@ class XendDomainInfo:
|
||||
def get_vtpms(self):
|
||||
return self.info.get('vtpm_refs', [])
|
||||
|
||||
def get_dpcis(self):
|
||||
return XendDPCI.get_by_VM(self.info.get('uuid'))
|
||||
|
||||
def create_vbd(self, xenapi_vbd, vdi_image_path):
|
||||
"""Create a VBD using a VDI from XendStorageRepository.
|
||||
|
||||
@@ -3292,6 +3258,64 @@ class XendDomainInfo:
|
||||
def set_console_other_config(self, console_uuid, other_config):
|
||||
self.info.console_update(console_uuid, 'other_config', other_config)
|
||||
|
||||
def create_dpci(self, xenapi_pci):
|
||||
"""Create pci device from the passed struct in Xen API format.
|
||||
|
||||
@param xenapi_pci: DPCI struct from Xen API
|
||||
@rtype: bool
|
||||
#@rtype: string
|
||||
@return: True if successfully created device
|
||||
#@return: UUID
|
||||
"""
|
||||
|
||||
dpci_uuid = uuid.createString()
|
||||
|
||||
# Convert xenapi to sxp
|
||||
ppci = XendAPIStore.get(xenapi_pci.get('PPCI'), 'PPCI')
|
||||
|
||||
target_pci_sxp = \
|
||||
['pci',
|
||||
['dev',
|
||||
['domain', '0x%02x' % ppci.get_domain()],
|
||||
['bus', '0x%02x' % ppci.get_bus()],
|
||||
['slot', '0x%02x' % ppci.get_slot()],
|
||||
['func', '0x%1x' % ppci.get_func()],
|
||||
['vslt', '0x%02x' % xenapi_pci.get('hotplug_slot')],
|
||||
['uuid', dpci_uuid]
|
||||
],
|
||||
['state', 'Initialising']
|
||||
]
|
||||
|
||||
if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING:
|
||||
|
||||
old_pci_sxp = self._getDeviceInfo_pci(0)
|
||||
|
||||
if old_pci_sxp is None:
|
||||
dev_uuid = self.info.device_add('pci', cfg_sxp = target_pci_sxp)
|
||||
if not dev_uuid:
|
||||
raise XendError('Failed to create device')
|
||||
|
||||
else:
|
||||
new_pci_sxp = ['pci']
|
||||
for existing_dev in sxp.children(old_pci_sxp, 'dev'):
|
||||
new_pci_sxp.append(existing_dev)
|
||||
new_pci_sxp.append(sxp.child0(target_pci_sxp, 'dev'))
|
||||
|
||||
dev_uuid = sxp.child_value(old_pci_sxp, 'uuid')
|
||||
self.info.device_update(dev_uuid, new_pci_sxp)
|
||||
|
||||
xen.xend.XendDomain.instance().managed_config_save(self)
|
||||
|
||||
else:
|
||||
try:
|
||||
self.device_configure(target_pci_sxp)
|
||||
|
||||
except Exception, exn:
|
||||
raise XendError('Failed to create device')
|
||||
|
||||
return dpci_uuid
|
||||
|
||||
|
||||
def destroy_device_by_uuid(self, dev_type, dev_uuid):
|
||||
if dev_uuid not in self.info['devices']:
|
||||
raise XendError('Device does not exist')
|
||||
@@ -3318,6 +3342,63 @@ class XendDomainInfo:
|
||||
|
||||
def destroy_vtpm(self, dev_uuid):
|
||||
self.destroy_device_by_uuid('vtpm', dev_uuid)
|
||||
|
||||
def destroy_dpci(self, dev_uuid):
|
||||
|
||||
dpci = XendAPIStore.get(dev_uuid, 'DPCI')
|
||||
ppci = XendAPIStore.get(dpci.get_PPCI(), 'PPCI')
|
||||
|
||||
old_pci_sxp = self._getDeviceInfo_pci(0)
|
||||
dev_uuid = sxp.child_value(old_pci_sxp, 'uuid')
|
||||
target_dev = None
|
||||
new_pci_sxp = ['pci']
|
||||
for dev in sxp.children(old_pci_sxp, 'dev'):
|
||||
domain = int(sxp.child_value(dev, 'domain'), 16)
|
||||
bus = int(sxp.child_value(dev, 'bus'), 16)
|
||||
slot = int(sxp.child_value(dev, 'slot'), 16)
|
||||
func = int(sxp.child_value(dev, 'func'), 16)
|
||||
name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
|
||||
if ppci.get_name() == name:
|
||||
target_dev = dev
|
||||
else:
|
||||
new_pci_sxp.append(dev)
|
||||
|
||||
if target_dev is None:
|
||||
raise XendError('Failed to destroy device')
|
||||
|
||||
target_pci_sxp = ['pci', target_dev, ['state', 'Closing']]
|
||||
|
||||
if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING:
|
||||
|
||||
self.info.device_update(dev_uuid, new_pci_sxp)
|
||||
if len(sxp.children(new_pci_sxp, 'dev')) == 0:
|
||||
del self.info['devices'][dev_uuid]
|
||||
xen.xend.XendDomain.instance().managed_config_save(self)
|
||||
|
||||
else:
|
||||
try:
|
||||
self.device_configure(target_pci_sxp)
|
||||
|
||||
except Exception, exn:
|
||||
raise XendError('Failed to destroy device')
|
||||
|
||||
def destroy_xapi_device_instances(self):
|
||||
"""Destroy Xen-API device instances stored in XendAPIStore.
|
||||
"""
|
||||
# Xen-API classes based on XendBase have their instances stored
|
||||
# in XendAPIStore. Cleanup these virtual device instances here
|
||||
# if they are supposed to be destroyed when the parent domain is dead.
|
||||
#
|
||||
# Most of the virtual devices (vif, vbd, vfb, etc) are not based on
|
||||
# XendBase and there's no need to remove them from XendAPIStore.
|
||||
|
||||
from xen.xend import XendDomain
|
||||
if XendDomain.instance().is_valid_vm(self.info.get('uuid')):
|
||||
# domain still exists.
|
||||
return
|
||||
|
||||
for dpci_uuid in XendDPCI.get_by_VM(self.info.get('uuid')):
|
||||
XendAPIStore.deregister(dpci_uuid, "DPCI")
|
||||
|
||||
def has_device(self, dev_class, dev_uuid):
|
||||
return (dev_uuid in self.info['%s_refs' % dev_class.lower()])
|
||||
|
||||
@@ -175,6 +175,17 @@ class NetworkError(XendAPIError):
|
||||
def __str__(self):
|
||||
return 'NETWORK_ERROR: %s %s' % (self.error, self.network)
|
||||
|
||||
class DirectPCIError(XendAPIError):
|
||||
def __init__(self, error):
|
||||
XendAPIError.__init__(self)
|
||||
self.error = error
|
||||
|
||||
def get_api_error(self):
|
||||
return ['DIRECT_PCI_ERROR', self.error]
|
||||
|
||||
def __str__(self):
|
||||
return 'DIRECT_PCI_ERROR: %s' % self.error
|
||||
|
||||
from xen.util.xsconstants import xserr2string
|
||||
|
||||
class SecurityError(XendAPIError):
|
||||
|
||||
@@ -76,6 +76,7 @@ class PciController(DevController):
|
||||
|
||||
back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
|
||||
(domain, bus, slot, func)
|
||||
back['uuid-%i' % pcidevid] = pci_config.get('uuid', '')
|
||||
pcidevid += 1
|
||||
|
||||
if vslots != "":
|
||||
@@ -101,6 +102,7 @@ class PciController(DevController):
|
||||
try:
|
||||
dev = back['dev-%i' % i]
|
||||
state = states[i]
|
||||
uuid = back['uuid-%i' %i]
|
||||
except:
|
||||
raise XendError('Error reading config')
|
||||
|
||||
@@ -121,6 +123,7 @@ class PciController(DevController):
|
||||
self.writeBackend(devid, 'dev-%i' % (num_olddevs + i), dev)
|
||||
self.writeBackend(devid, 'state-%i' % (num_olddevs + i),
|
||||
str(xenbusState['Initialising']))
|
||||
self.writeBackend(devid, 'uuid-%i' % (num_olddevs + i), uuid)
|
||||
self.writeBackend(devid, 'num_devs', str(num_olddevs + i + 1))
|
||||
|
||||
# Update vslots
|
||||
@@ -141,7 +144,7 @@ class PciController(DevController):
|
||||
raise XendError('Device %s is not connected' % dev)
|
||||
|
||||
# Update vslots
|
||||
if back['vslots'] is not None:
|
||||
if back.get('vslots') is not None:
|
||||
vslots = old_vslots
|
||||
for vslt in back['vslots'].split(';'):
|
||||
if vslt != '':
|
||||
@@ -186,6 +189,9 @@ class PciController(DevController):
|
||||
'slot': '0x%(slot)s' % pci_dev_info,
|
||||
'func': '0x%(func)s' % pci_dev_info}
|
||||
|
||||
# Per device uuid info
|
||||
dev_dict['uuid'] = self.readBackend(devid, 'uuid-%d' % i)
|
||||
|
||||
#append vslot info
|
||||
if vslots is not None:
|
||||
try:
|
||||
@@ -442,6 +448,7 @@ class PciController(DevController):
|
||||
self.removeBackend(devid, 'dev-%i' % i)
|
||||
self.removeBackend(devid, 'vdev-%i' % i)
|
||||
self.removeBackend(devid, 'state-%i' % i)
|
||||
self.removeBackend(devid, 'uuid-%i' % i)
|
||||
else:
|
||||
if new_num_devs != i:
|
||||
tmpdev = self.readBackend(devid, 'dev-%i' % i)
|
||||
@@ -455,6 +462,9 @@ class PciController(DevController):
|
||||
tmpstate = self.readBackend(devid, 'state-%i' % i)
|
||||
self.writeBackend(devid, 'state-%i' % new_num_devs, tmpstate)
|
||||
self.removeBackend(devid, 'state-%i' % i)
|
||||
tmpuuid = self.readBackend(devid, 'uuid-%i' % i)
|
||||
self.writeBackend(devid, 'uuid-%i' % new_num_devs, tmpuuid)
|
||||
self.removeBackend(devid, 'uuid-%i' % i)
|
||||
new_num_devs = new_num_devs + 1
|
||||
|
||||
self.writeBackend(devid, 'num_devs', str(new_num_devs))
|
||||
|
||||