debuggers.hg
changeset 17990:52a388ec09f8
XenAPI: Add Direct PCI Device (DPCI) Assignment 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:27:12 2008 +0100 (2008-07-03) |
parents | e65fe28b5288 |
children | 20215b87d0f3 |
files | tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDPCI.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendError.py tools/python/xen/xend/server/pciif.py |
line diff
1.1 --- a/tools/python/xen/xend/XendAPI.py Thu Jul 03 10:26:16 2008 +0100 1.2 +++ b/tools/python/xen/xend/XendAPI.py Thu Jul 03 10:27:12 2008 +0100 1.3 @@ -41,6 +41,7 @@ from XendVMMetrics import XendVMMetrics 1.4 from XendPIF import XendPIF 1.5 from XendPBD import XendPBD 1.6 from XendPPCI import XendPPCI 1.7 +from XendDPCI import XendDPCI 1.8 from XendXSPolicy import XendXSPolicy, XendACMPolicy 1.9 1.10 from XendAPIConstants import * 1.11 @@ -479,6 +480,7 @@ classes = { 1.12 'PBD' : valid_object("PBD"), 1.13 'PIF_metrics' : valid_object("PIF_metrics"), 1.14 'PPCI' : valid_object("PPCI"), 1.15 + 'DPCI' : valid_object("DPCI") 1.16 } 1.17 1.18 autoplug_classes = { 1.19 @@ -488,6 +490,7 @@ autoplug_classes = { 1.20 'PBD' : XendPBD, 1.21 'PIF_metrics' : XendPIFMetrics, 1.22 'PPCI' : XendPPCI, 1.23 + 'DPCI' : XendDPCI, 1.24 'XSPolicy' : XendXSPolicy, 1.25 'ACMPolicy' : XendACMPolicy, 1.26 } 1.27 @@ -1154,6 +1157,7 @@ class XendAPI(object): 1.28 'VIFs', 1.29 'VBDs', 1.30 'VTPMs', 1.31 + 'DPCIs', 1.32 'tools_version', 1.33 'domid', 1.34 'is_control_domain', 1.35 @@ -1296,6 +1300,10 @@ class XendAPI(object): 1.36 dom = XendDomain.instance().get_vm_by_uuid(vm_ref) 1.37 return xen_api_success(dom.get_consoles()) 1.38 1.39 + def VM_get_DPCIs(self, session, vm_ref): 1.40 + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) 1.41 + return xen_api_success(dom.get_dpcis()) 1.42 + 1.43 def VM_get_tools_version(self, session, vm_ref): 1.44 dom = XendDomain.instance().get_vm_by_uuid(vm_ref) 1.45 return dom.get_tools_version() 1.46 @@ -1675,6 +1683,7 @@ class XendAPI(object): 1.47 'VIFs': xeninfo.get_vifs(), 1.48 'VBDs': xeninfo.get_vbds(), 1.49 'VTPMs': xeninfo.get_vtpms(), 1.50 + 'DPCIs': xeninfo.get_dpcis(), 1.51 'PV_bootloader': xeninfo.info.get('PV_bootloader'), 1.52 'PV_kernel': xeninfo.info.get('PV_kernel'), 1.53 'PV_ramdisk': xeninfo.info.get('PV_ramdisk'),
2.1 --- a/tools/python/xen/xend/XendConfig.py Thu Jul 03 10:26:16 2008 +0100 2.2 +++ b/tools/python/xen/xend/XendConfig.py Thu Jul 03 10:27:12 2008 +0100 2.3 @@ -24,6 +24,8 @@ from xen.xend import sxp 2.4 from xen.xend import uuid 2.5 from xen.xend import XendOptions 2.6 from xen.xend import XendAPIStore 2.7 +from xen.xend.XendPPCI import XendPPCI 2.8 +from xen.xend.XendDPCI import XendDPCI 2.9 from xen.xend.XendError import VmError 2.10 from xen.xend.XendDevices import XendDevices 2.11 from xen.xend.PrettyPrint import prettyprintstring 2.12 @@ -773,6 +775,11 @@ class XendConfig(dict): 2.13 """ 2.14 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg)) 2.15 2.16 + # _parse_sxp() below will call device_add() and construct devices. 2.17 + # Some devices (currently only pci) may require VM's uuid, so 2.18 + # setup self['uuid'] beforehand. 2.19 + self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString()) 2.20 + 2.21 cfg = self._parse_sxp(sxp_cfg) 2.22 2.23 for key, typ in XENAPI_CFG_TYPES.items(): 2.24 @@ -1209,42 +1216,35 @@ class XendConfig(dict): 2.25 dev_type = sxp.name(config) 2.26 dev_info = {} 2.27 2.28 - # Parsing the device SXP's. In most cases, the SXP looks 2.29 - # like this: 2.30 - # 2.31 - # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]] 2.32 - # 2.33 - # However, for PCI devices it looks like this: 2.34 - # 2.35 - # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]] 2.36 - # 2.37 - # It seems the reasoning for this difference is because 2.38 - # pciif.py needs all the PCI device configurations at 2.39 - # the same time when creating the devices. 2.40 - # 2.41 - # To further complicate matters, Xen 2.0 configuration format 2.42 - # uses the following for pci device configuration: 2.43 - # 2.44 - # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]] 2.45 - 2.46 if dev_type == 'pci': 2.47 pci_devs_uuid = sxp.child_value(config, 'uuid', 2.48 uuid.createString()) 2.49 - pci_devs = [] 2.50 - for pci_dev in sxp.children(config, 'dev'): 2.51 - pci_dev_info = {} 2.52 - for opt_val in pci_dev[1:]: 2.53 - try: 2.54 - opt, val = opt_val 2.55 - pci_dev_info[opt] = val 2.56 - except TypeError: 2.57 - pass 2.58 - pci_devs.append(pci_dev_info) 2.59 + 2.60 + pci_dict = self.pci_convert_sxp_to_dict(config) 2.61 + pci_devs = pci_dict['devs'] 2.62 + 2.63 + # create XenAPI DPCI objects. 2.64 + for pci_dev in pci_devs: 2.65 + dpci_uuid = pci_dev.get('uuid') 2.66 + ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], 2.67 + pci_dev['bus'], 2.68 + pci_dev['slot'], 2.69 + pci_dev['func']) 2.70 + if ppci_uuid is None: 2.71 + continue 2.72 + dpci_record = { 2.73 + 'VM': self['uuid'], 2.74 + 'PPCI': ppci_uuid, 2.75 + 'hotplug_slot': pci_dev.get('vslot', 0) 2.76 + } 2.77 + XendDPCI(dpci_uuid, dpci_record) 2.78 + 2.79 target['devices'][pci_devs_uuid] = (dev_type, 2.80 {'devs': pci_devs, 2.81 'uuid': pci_devs_uuid}) 2.82 2.83 log.debug("XendConfig: reading device: %s" % pci_devs) 2.84 + 2.85 return pci_devs_uuid 2.86 2.87 for opt_val in config[1:]: 2.88 @@ -1482,6 +1482,76 @@ class XendConfig(dict): 2.89 2.90 return '' 2.91 2.92 + def pci_convert_sxp_to_dict(self, dev_sxp): 2.93 + """Convert pci device sxp to dict 2.94 + @param dev_sxp: device configuration 2.95 + @type dev_sxp: SXP object (parsed config) 2.96 + @return: dev_config 2.97 + @rtype: dictionary 2.98 + """ 2.99 + # Parsing the device SXP's. In most cases, the SXP looks 2.100 + # like this: 2.101 + # 2.102 + # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]] 2.103 + # 2.104 + # However, for PCI devices it looks like this: 2.105 + # 2.106 + # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2]]] 2.107 + # 2.108 + # It seems the reasoning for this difference is because 2.109 + # pciif.py needs all the PCI device configurations at 2.110 + # the same time when creating the devices. 2.111 + # 2.112 + # To further complicate matters, Xen 2.0 configuration format 2.113 + # uses the following for pci device configuration: 2.114 + # 2.115 + # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]] 2.116 + 2.117 + # For PCI device hotplug support, the SXP of PCI devices is 2.118 + # extendend like this: 2.119 + # 2.120 + # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2], 2.121 + # [vslt, 0]], 2.122 + # [state, 'Initialising']]] 2.123 + # 2.124 + # 'vslt' shows the virtual hotplug slot number which the PCI device 2.125 + # is inserted in. This is only effective for HVM domains. 2.126 + # 2.127 + # state 'Initialising' indicates that the device is being attached, 2.128 + # while state 'Closing' indicates that the device is being detached. 2.129 + # 2.130 + # The Dict looks like this: 2.131 + # 2.132 + # { devs: [{domain: 0, bus: 0, slot: 1, func: 2, vslt: 0}], 2.133 + # states: ['Initialising'] } 2.134 + 2.135 + dev_config = {} 2.136 + 2.137 + pci_devs = [] 2.138 + for pci_dev in sxp.children(dev_sxp, 'dev'): 2.139 + pci_dev_info = {} 2.140 + for opt_val in pci_dev[1:]: 2.141 + try: 2.142 + opt, val = opt_val 2.143 + pci_dev_info[opt] = val 2.144 + except TypeError: 2.145 + pass 2.146 + # append uuid for each pci device. 2.147 + dpci_uuid = pci_dev_info.get('uuid', uuid.createString()) 2.148 + pci_dev_info['uuid'] = dpci_uuid 2.149 + pci_devs.append(pci_dev_info) 2.150 + dev_config['devs'] = pci_devs 2.151 + 2.152 + pci_states = [] 2.153 + for pci_state in sxp.children(dev_sxp, 'state'): 2.154 + try: 2.155 + pci_states.append(pci_state[1]) 2.156 + except IndexError: 2.157 + raise XendError("Error reading state while parsing pci sxp") 2.158 + dev_config['states'] = pci_states 2.159 + 2.160 + return dev_config 2.161 + 2.162 def console_add(self, protocol, location, other_config = {}): 2.163 dev_uuid = uuid.createString() 2.164 if protocol == 'vt100': 2.165 @@ -1556,16 +1626,29 @@ class XendConfig(dict): 2.166 dev_type, dev_info = self['devices'][dev_uuid] 2.167 2.168 if dev_type == 'pci': # Special case for pci 2.169 - pci_devs = [] 2.170 - for pci_dev in sxp.children(config, 'dev'): 2.171 - pci_dev_info = {} 2.172 - for opt_val in pci_dev[1:]: 2.173 - try: 2.174 - opt, val = opt_val 2.175 - pci_dev_info[opt] = val 2.176 - except TypeError: 2.177 - pass 2.178 - pci_devs.append(pci_dev_info) 2.179 + pci_dict = self.pci_convert_sxp_to_dict(config) 2.180 + pci_devs = pci_dict['devs'] 2.181 + 2.182 + # destroy existing XenAPI DPCI objects 2.183 + for dpci_uuid in XendDPCI.get_by_VM(self['uuid']): 2.184 + XendAPIStore.deregister(dpci_uuid, "DPCI") 2.185 + 2.186 + # create XenAPI DPCI objects. 2.187 + for pci_dev in pci_devs: 2.188 + dpci_uuid = pci_dev.get('uuid') 2.189 + ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'], 2.190 + pci_dev['bus'], 2.191 + pci_dev['slot'], 2.192 + pci_dev['func']) 2.193 + if ppci_uuid is None: 2.194 + continue 2.195 + dpci_record = { 2.196 + 'VM': self['uuid'], 2.197 + 'PPCI': ppci_uuid, 2.198 + 'hotplug_slot': pci_dev.get('vslot', 0) 2.199 + } 2.200 + XendDPCI(dpci_uuid, dpci_record) 2.201 + 2.202 self['devices'][dev_uuid] = (dev_type, 2.203 {'devs': pci_devs, 2.204 'uuid': dev_uuid})
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/tools/python/xen/xend/XendDPCI.py Thu Jul 03 10:27:12 2008 +0100 3.3 @@ -0,0 +1,154 @@ 3.4 +#============================================================================ 3.5 +# This library is free software; you can redistribute it and/or 3.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public 3.7 +# License as published by the Free Software Foundation. 3.8 +# 3.9 +# This library is distributed in the hope that it will be useful, 3.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of 3.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 3.12 +# Lesser General Public License for more details. 3.13 +# 3.14 +# You should have received a copy of the GNU Lesser General Public 3.15 +# License along with this library; if not, write to the Free Software 3.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 3.17 +#============================================================================ 3.18 +# Copyright (c) 2008 NEC Corporation 3.19 +# Yosuke Iwamatsu <y-iwamatsu at ab jp nec com> 3.20 +#============================================================================ 3.21 + 3.22 +from xen.xend.XendBase import XendBase 3.23 +from xen.xend.XendPPCI import XendPPCI 3.24 +from xen.xend import XendAPIStore 3.25 +from xen.xend import uuid as genuuid 3.26 + 3.27 +import XendDomain, XendNode 3.28 + 3.29 +from XendError import * 3.30 +from XendTask import XendTask 3.31 +from XendLogging import log 3.32 + 3.33 +class XendDPCI(XendBase): 3.34 + """Representation of a passthrough PCI device.""" 3.35 + 3.36 + def getClass(self): 3.37 + return "DPCI" 3.38 + 3.39 + def getAttrRO(self): 3.40 + attrRO = ['virtual_domain', 3.41 + 'virtual_bus', 3.42 + 'virtual_slot', 3.43 + 'virtual_func', 3.44 + 'virtual_name', 3.45 + 'VM', 3.46 + 'PPCI', 3.47 + 'hotplug_slot'] 3.48 + return XendBase.getAttrRO() + attrRO 3.49 + 3.50 + def getAttrRW(self): 3.51 + attrRW = [] 3.52 + return XendBase.getAttrRW() + attrRW 3.53 + 3.54 + def getAttrInst(self): 3.55 + attrInst = ['VM', 3.56 + 'PPCI', 3.57 + 'hotplug_slot'] 3.58 + return XendBase.getAttrInst() + attrInst 3.59 + 3.60 + def getMethods(self): 3.61 + methods = ['destroy'] 3.62 + return XendBase.getMethods() + methods 3.63 + 3.64 + def getFuncs(self): 3.65 + funcs = ['create'] 3.66 + return XendBase.getFuncs() + funcs 3.67 + 3.68 + getClass = classmethod(getClass) 3.69 + getAttrRO = classmethod(getAttrRO) 3.70 + getAttrRW = classmethod(getAttrRW) 3.71 + getAttrInst = classmethod(getAttrInst) 3.72 + getMethods = classmethod(getMethods) 3.73 + getFuncs = classmethod(getFuncs) 3.74 + 3.75 + def create(self, dpci_struct): 3.76 + 3.77 + # Check if VM is valid 3.78 + xendom = XendDomain.instance() 3.79 + if not xendom.is_valid_vm(dpci_struct['VM']): 3.80 + raise InvalidHandleError('VM', dpci_struct['VM']) 3.81 + dom = xendom.get_vm_by_uuid(dpci_struct['VM']) 3.82 + 3.83 + # Check if PPCI is valid 3.84 + xennode = XendNode.instance() 3.85 + ppci_uuid = xennode.get_ppci_by_uuid(dpci_struct['PPCI']) 3.86 + if not ppci_uuid: 3.87 + raise InvalidHandleError('PPCI', dpci_struct['PPCI']) 3.88 + for existing_dpci in XendAPIStore.get_all('DPCI'): 3.89 + if ppci_uuid == existing_dpci.get_PPCI(): 3.90 + raise DirectPCIError("Device is in use") 3.91 + 3.92 + # Assign PPCI to VM 3.93 + try: 3.94 + dpci_ref = XendTask.log_progress(0, 100, dom.create_dpci, 3.95 + dpci_struct) 3.96 + except XendError, e: 3.97 + raise DirectPCIError("Failed to assign device") 3.98 + 3.99 + # TODO: Retrive virtual pci device infomation. 3.100 + 3.101 + return dpci_ref 3.102 + 3.103 + create = classmethod(create) 3.104 + 3.105 + def get_by_VM(cls, VM_ref): 3.106 + result = [] 3.107 + for dpci in XendAPIStore.get_all("DPCI"): 3.108 + if dpci.get_VM() == VM_ref: 3.109 + result.append(dpci.get_uuid()) 3.110 + return result 3.111 + 3.112 + get_by_VM = classmethod(get_by_VM) 3.113 + 3.114 + def __init__(self, uuid, record): 3.115 + XendBase.__init__(self, uuid, record) 3.116 + 3.117 + self.virtual_domain = -1 3.118 + self.virtual_bus = -1 3.119 + self.virtual_slot = -1 3.120 + self.virtual_func = -1 3.121 + 3.122 + self.VM = record['VM'] 3.123 + self.PPCI = record['PPCI'] 3.124 + self.hotplug_slot = record['hotplug_slot'] 3.125 + 3.126 + def destroy(self): 3.127 + xendom = XendDomain.instance() 3.128 + dom = xendom.get_vm_by_uuid(self.get_VM()) 3.129 + if not dom: 3.130 + raise InvalidHandleError("VM", self.get_VM()) 3.131 + XendTask.log_progress(0, 100, dom.destroy_dpci, self.get_uuid()) 3.132 + 3.133 + def get_virtual_domain(self): 3.134 + return self.virtual_domain 3.135 + 3.136 + def get_virtual_bus(self): 3.137 + return self.virtual_bus 3.138 + 3.139 + def get_virtual_slot(self): 3.140 + return self.virtual_slot 3.141 + 3.142 + def get_virtual_func(self): 3.143 + return self.virtual_func 3.144 + 3.145 + def get_virtual_name(self): 3.146 + return "%04x:%02x:%02x.%01x" % (self.virtual_domain, self.virtual_bus, 3.147 + self.virtual_slot, self.virtual_func) 3.148 + 3.149 + def get_VM(self): 3.150 + return self.VM 3.151 + 3.152 + def get_PPCI(self): 3.153 + return self.PPCI 3.154 + 3.155 + def get_hotplug_slot(self): 3.156 + return self.hotplug_slot 3.157 +
4.1 --- a/tools/python/xen/xend/XendDomain.py Thu Jul 03 10:26:16 2008 +0100 4.2 +++ b/tools/python/xen/xend/XendDomain.py Thu Jul 03 10:27:12 2008 +0100 4.3 @@ -478,6 +478,8 @@ class XendDomain: 4.4 4.5 if domid in self.domains: 4.6 del self.domains[domid] 4.7 + 4.8 + info.destroy_xapi_device_instances() 4.9 else: 4.10 log.warning("Attempted to remove non-existent domain.") 4.11 4.12 @@ -1091,6 +1093,7 @@ class XendDomain: 4.13 self._managed_domain_unregister(dominfo) 4.14 self._remove_domain(dominfo) 4.15 XendDevices.destroy_device_state(dominfo) 4.16 + dominfo.destroy_xapi_device_instances() 4.17 4.18 4.19 def domain_configure(self, config):
5.1 --- a/tools/python/xen/xend/XendDomainInfo.py Thu Jul 03 10:26:16 2008 +0100 5.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Thu Jul 03 10:27:12 2008 +0100 5.3 @@ -55,6 +55,10 @@ from xen.xend.XendAPIConstants import * 5.4 5.5 from xen.xend.XendVMMetrics import XendVMMetrics 5.6 5.7 +from xen.xend.XendPPCI import XendPPCI 5.8 +from xen.xend.XendDPCI import XendDPCI 5.9 +from xen.xend import XendAPIStore 5.10 + 5.11 MIGRATE_TIMEOUT = 30.0 5.12 BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp' 5.13 5.14 @@ -642,50 +646,7 @@ class XendDomainInfo: 5.15 xen.xend.XendDomain.instance().managed_config_save(self) 5.16 return self.getDeviceController(dev_type).sxpr(devid) 5.17 5.18 - def pci_convert_sxp_to_dict(self, dev_sxp): 5.19 - """Convert pci device sxp to dict 5.20 - @param dev_sxp: device configuration 5.21 - @type dev_sxp: SXP object (parsed config) 5.22 - @return: dev_config 5.23 - @rtype: dictionary 5.24 - """ 5.25 - # In reconfigure phase, config of PCI device looks like below: 5.26 - # 5.27 - # sxp: 5.28 - # [device, [pci, [dev, [domain, '0x0'], [bus, '0x0'], [slot, '0x0'], 5.29 - # [func, '0x0'], [vslt, '0x0']], 5.30 - # [state, 'Initialising']]] 5.31 - # 5.32 - # dict: 5.33 - # {devs: [{domain: '0x0', bus: '0x0', slot: '0x0', func: '0x0', 5.34 - # vslt: '0x0'}], 5.35 - # states: ['Initialising']} 5.36 - # 5.37 - # state 'Initialising' means the device is being attached. 5.38 - # state 'Closing' means the device is being detached. 5.39 - 5.40 - dev_config = {} 5.41 - pci_devs = [] 5.42 - for pci_dev in sxp.children(dev_sxp, 'dev'): 5.43 - pci_dev_info = {} 5.44 - for opt_val in pci_dev[1:]: 5.45 - try: 5.46 - opt, val = opt_val 5.47 - pci_dev_info[opt] = val 5.48 - except TypeError: 5.49 - pass 5.50 - pci_devs.append(pci_dev_info) 5.51 - dev_config['devs'] = pci_devs 5.52 - pci_states = [] 5.53 - for pci_state in sxp.children(dev_sxp, 'state'): 5.54 - try: 5.55 - pci_states.append(pci_state[1]) 5.56 - except IndexError: 5.57 - raise XendError("Error reading state while parsing pci sxp") 5.58 - dev_config['states'] = pci_states 5.59 - 5.60 - return dev_config 5.61 - 5.62 + 5.63 def pci_device_configure(self, dev_sxp, devid = 0): 5.64 """Configure an existing pci device. 5.65 5.66 @@ -711,7 +672,7 @@ class XendDomainInfo: 5.67 raise XendError("Cannot detach when pci platform does not exist") 5.68 5.69 pci_dev = sxp.children(dev_sxp, 'dev')[0] 5.70 - dev_config = self.pci_convert_sxp_to_dict(dev_sxp) 5.71 + dev_config = self.info.pci_convert_sxp_to_dict(dev_sxp) 5.72 dev = dev_config['devs'][0] 5.73 5.74 # Do HVM specific processing 5.75 @@ -785,6 +746,8 @@ class XendDomainInfo: 5.76 self.destroyDevice('pci', devid) 5.77 del self.info['devices'][dev_uuid] 5.78 5.79 + xen.xend.XendDomain.instance().managed_config_save(self) 5.80 + 5.81 return True 5.82 5.83 def device_configure(self, dev_sxp, devid = None): 5.84 @@ -3169,6 +3132,9 @@ class XendDomainInfo: 5.85 def get_vtpms(self): 5.86 return self.info.get('vtpm_refs', []) 5.87 5.88 + def get_dpcis(self): 5.89 + return XendDPCI.get_by_VM(self.info.get('uuid')) 5.90 + 5.91 def create_vbd(self, xenapi_vbd, vdi_image_path): 5.92 """Create a VBD using a VDI from XendStorageRepository. 5.93 5.94 @@ -3292,6 +3258,64 @@ class XendDomainInfo: 5.95 def set_console_other_config(self, console_uuid, other_config): 5.96 self.info.console_update(console_uuid, 'other_config', other_config) 5.97 5.98 + def create_dpci(self, xenapi_pci): 5.99 + """Create pci device from the passed struct in Xen API format. 5.100 + 5.101 + @param xenapi_pci: DPCI struct from Xen API 5.102 + @rtype: bool 5.103 + #@rtype: string 5.104 + @return: True if successfully created device 5.105 + #@return: UUID 5.106 + """ 5.107 + 5.108 + dpci_uuid = uuid.createString() 5.109 + 5.110 + # Convert xenapi to sxp 5.111 + ppci = XendAPIStore.get(xenapi_pci.get('PPCI'), 'PPCI') 5.112 + 5.113 + target_pci_sxp = \ 5.114 + ['pci', 5.115 + ['dev', 5.116 + ['domain', '0x%02x' % ppci.get_domain()], 5.117 + ['bus', '0x%02x' % ppci.get_bus()], 5.118 + ['slot', '0x%02x' % ppci.get_slot()], 5.119 + ['func', '0x%1x' % ppci.get_func()], 5.120 + ['vslt', '0x%02x' % xenapi_pci.get('hotplug_slot')], 5.121 + ['uuid', dpci_uuid] 5.122 + ], 5.123 + ['state', 'Initialising'] 5.124 + ] 5.125 + 5.126 + if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING: 5.127 + 5.128 + old_pci_sxp = self._getDeviceInfo_pci(0) 5.129 + 5.130 + if old_pci_sxp is None: 5.131 + dev_uuid = self.info.device_add('pci', cfg_sxp = target_pci_sxp) 5.132 + if not dev_uuid: 5.133 + raise XendError('Failed to create device') 5.134 + 5.135 + else: 5.136 + new_pci_sxp = ['pci'] 5.137 + for existing_dev in sxp.children(old_pci_sxp, 'dev'): 5.138 + new_pci_sxp.append(existing_dev) 5.139 + new_pci_sxp.append(sxp.child0(target_pci_sxp, 'dev')) 5.140 + 5.141 + dev_uuid = sxp.child_value(old_pci_sxp, 'uuid') 5.142 + self.info.device_update(dev_uuid, new_pci_sxp) 5.143 + 5.144 + xen.xend.XendDomain.instance().managed_config_save(self) 5.145 + 5.146 + else: 5.147 + try: 5.148 + self.device_configure(target_pci_sxp) 5.149 + 5.150 + except Exception, exn: 5.151 + raise XendError('Failed to create device') 5.152 + 5.153 + return dpci_uuid 5.154 + 5.155 + 5.156 def destroy_device_by_uuid(self, dev_type, dev_uuid): 5.157 if dev_uuid not in self.info['devices']: 5.158 raise XendError('Device does not exist') 5.159 @@ -3318,6 +3342,63 @@ class XendDomainInfo: 5.160 5.161 def destroy_vtpm(self, dev_uuid): 5.162 self.destroy_device_by_uuid('vtpm', dev_uuid) 5.163 + 5.164 + def destroy_dpci(self, dev_uuid): 5.165 + 5.166 + dpci = XendAPIStore.get(dev_uuid, 'DPCI') 5.167 + ppci = XendAPIStore.get(dpci.get_PPCI(), 'PPCI') 5.168 + 5.169 + old_pci_sxp = self._getDeviceInfo_pci(0) 5.170 + dev_uuid = sxp.child_value(old_pci_sxp, 'uuid') 5.171 + target_dev = None 5.172 + new_pci_sxp = ['pci'] 5.173 + for dev in sxp.children(old_pci_sxp, 'dev'): 5.174 + domain = int(sxp.child_value(dev, 'domain'), 16) 5.175 + bus = int(sxp.child_value(dev, 'bus'), 16) 5.176 + slot = int(sxp.child_value(dev, 'slot'), 16) 5.177 + func = int(sxp.child_value(dev, 'func'), 16) 5.178 + name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) 5.179 + if ppci.get_name() == name: 5.180 + target_dev = dev 5.181 + else: 5.182 + new_pci_sxp.append(dev) 5.183 + 5.184 + if target_dev is None: 5.185 + raise XendError('Failed to destroy device') 5.186 + 5.187 + target_pci_sxp = ['pci', target_dev, ['state', 'Closing']] 5.188 + 5.189 + if self._stateGet() != XEN_API_VM_POWER_STATE_RUNNING: 5.190 + 5.191 + self.info.device_update(dev_uuid, new_pci_sxp) 5.192 + if len(sxp.children(new_pci_sxp, 'dev')) == 0: 5.193 + del self.info['devices'][dev_uuid] 5.194 + xen.xend.XendDomain.instance().managed_config_save(self) 5.195 + 5.196 + else: 5.197 + try: 5.198 + self.device_configure(target_pci_sxp) 5.199 + 5.200 + except Exception, exn: 5.201 + raise XendError('Failed to destroy device') 5.202 + 5.203 + def destroy_xapi_device_instances(self): 5.204 + """Destroy Xen-API device instances stored in XendAPIStore. 5.205 + """ 5.206 + # Xen-API classes based on XendBase have their instances stored 5.207 + # in XendAPIStore. Cleanup these virtual device instances here 5.208 + # if they are supposed to be destroyed when the parent domain is dead. 5.209 + # 5.210 + # Most of the virtual devices (vif, vbd, vfb, etc) are not based on 5.211 + # XendBase and there's no need to remove them from XendAPIStore. 5.212 + 5.213 + from xen.xend import XendDomain 5.214 + if XendDomain.instance().is_valid_vm(self.info.get('uuid')): 5.215 + # domain still exists. 5.216 + return 5.217 + 5.218 + for dpci_uuid in XendDPCI.get_by_VM(self.info.get('uuid')): 5.219 + XendAPIStore.deregister(dpci_uuid, "DPCI") 5.220 5.221 def has_device(self, dev_class, dev_uuid): 5.222 return (dev_uuid in self.info['%s_refs' % dev_class.lower()])
6.1 --- a/tools/python/xen/xend/XendError.py Thu Jul 03 10:26:16 2008 +0100 6.2 +++ b/tools/python/xen/xend/XendError.py Thu Jul 03 10:27:12 2008 +0100 6.3 @@ -175,6 +175,17 @@ class NetworkError(XendAPIError): 6.4 def __str__(self): 6.5 return 'NETWORK_ERROR: %s %s' % (self.error, self.network) 6.6 6.7 +class DirectPCIError(XendAPIError): 6.8 + def __init__(self, error): 6.9 + XendAPIError.__init__(self) 6.10 + self.error = error 6.11 + 6.12 + def get_api_error(self): 6.13 + return ['DIRECT_PCI_ERROR', self.error] 6.14 + 6.15 + def __str__(self): 6.16 + return 'DIRECT_PCI_ERROR: %s' % self.error 6.17 + 6.18 from xen.util.xsconstants import xserr2string 6.19 6.20 class SecurityError(XendAPIError):
7.1 --- a/tools/python/xen/xend/server/pciif.py Thu Jul 03 10:26:16 2008 +0100 7.2 +++ b/tools/python/xen/xend/server/pciif.py Thu Jul 03 10:27:12 2008 +0100 7.3 @@ -76,6 +76,7 @@ class PciController(DevController): 7.4 7.5 back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \ 7.6 (domain, bus, slot, func) 7.7 + back['uuid-%i' % pcidevid] = pci_config.get('uuid', '') 7.8 pcidevid += 1 7.9 7.10 if vslots != "": 7.11 @@ -101,6 +102,7 @@ class PciController(DevController): 7.12 try: 7.13 dev = back['dev-%i' % i] 7.14 state = states[i] 7.15 + uuid = back['uuid-%i' %i] 7.16 except: 7.17 raise XendError('Error reading config') 7.18 7.19 @@ -121,6 +123,7 @@ class PciController(DevController): 7.20 self.writeBackend(devid, 'dev-%i' % (num_olddevs + i), dev) 7.21 self.writeBackend(devid, 'state-%i' % (num_olddevs + i), 7.22 str(xenbusState['Initialising'])) 7.23 + self.writeBackend(devid, 'uuid-%i' % (num_olddevs + i), uuid) 7.24 self.writeBackend(devid, 'num_devs', str(num_olddevs + i + 1)) 7.25 7.26 # Update vslots 7.27 @@ -141,7 +144,7 @@ class PciController(DevController): 7.28 raise XendError('Device %s is not connected' % dev) 7.29 7.30 # Update vslots 7.31 - if back['vslots'] is not None: 7.32 + if back.get('vslots') is not None: 7.33 vslots = old_vslots 7.34 for vslt in back['vslots'].split(';'): 7.35 if vslt != '': 7.36 @@ -186,6 +189,9 @@ class PciController(DevController): 7.37 'slot': '0x%(slot)s' % pci_dev_info, 7.38 'func': '0x%(func)s' % pci_dev_info} 7.39 7.40 + # Per device uuid info 7.41 + dev_dict['uuid'] = self.readBackend(devid, 'uuid-%d' % i) 7.42 + 7.43 #append vslot info 7.44 if vslots is not None: 7.45 try: 7.46 @@ -442,6 +448,7 @@ class PciController(DevController): 7.47 self.removeBackend(devid, 'dev-%i' % i) 7.48 self.removeBackend(devid, 'vdev-%i' % i) 7.49 self.removeBackend(devid, 'state-%i' % i) 7.50 + self.removeBackend(devid, 'uuid-%i' % i) 7.51 else: 7.52 if new_num_devs != i: 7.53 tmpdev = self.readBackend(devid, 'dev-%i' % i) 7.54 @@ -455,6 +462,9 @@ class PciController(DevController): 7.55 tmpstate = self.readBackend(devid, 'state-%i' % i) 7.56 self.writeBackend(devid, 'state-%i' % new_num_devs, tmpstate) 7.57 self.removeBackend(devid, 'state-%i' % i) 7.58 + tmpuuid = self.readBackend(devid, 'uuid-%i' % i) 7.59 + self.writeBackend(devid, 'uuid-%i' % new_num_devs, tmpuuid) 7.60 + self.removeBackend(devid, 'uuid-%i' % i) 7.61 new_num_devs = new_num_devs + 1 7.62 7.63 self.writeBackend(devid, 'num_devs', str(new_num_devs))