ia64/xen-unstable

changeset 17955:52a388ec09f8

XenAPI: Add Direct PCI Device (DPCI) Assignment Support

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