Exemple #1
0
    def allocate(self, instance):
        ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                       fields.PciDeviceStatus.CLAIMED)
        if self.status not in ok_statuses:
            raise exception.PciDeviceInvalidStatus(
                compute_node_id=self.compute_node_id,
                address=self.address,
                status=self.status,
                hopestatus=ok_statuses)
        if (self.status == fields.PciDeviceStatus.CLAIMED
                and self.instance_uuid != instance['uuid']):
            raise exception.PciDeviceInvalidOwner(
                compute_node_id=self.compute_node_id,
                address=self.address,
                owner=self.instance_uuid,
                hopeowner=instance['uuid'])

        self.status = fields.PciDeviceStatus.ALLOCATED
        self.instance_uuid = instance['uuid']

        # Notes(yjiang5): remove this check when instance object for
        # compute manager is finished
        if isinstance(instance, dict):
            if 'pci_devices' not in instance:
                instance['pci_devices'] = []
            instance['pci_devices'].append(copy.copy(self))
        else:
            instance.pci_devices.objects.append(copy.copy(self))
Exemple #2
0
 def free(self, instance=None):
     ok_statuses = (fields.PciDeviceStatus.ALLOCATED,
                    fields.PciDeviceStatus.CLAIMED)
     if self.status not in ok_statuses:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=self.compute_node_id,
             address=self.address,
             status=self.status,
             hopestatus=ok_statuses)
     if instance and self.instance_uuid != instance['uuid']:
         raise exception.PciDeviceInvalidOwner(
             compute_node_id=self.compute_node_id,
             address=self.address,
             owner=self.instance_uuid,
             hopeowner=instance['uuid'])
     old_status = self.status
     self.status = fields.PciDeviceStatus.AVAILABLE
     self.instance_uuid = None
     self.request_id = None
     if old_status == fields.PciDeviceStatus.ALLOCATED and instance:
         # Notes(yjiang5): remove this check when instance object for
         # compute manager is finished
         existed = next(
             (dev for dev in instance['pci_devices'] if dev.id == self.id))
         if isinstance(instance, dict):
             instance['pci_devices'].remove(existed)
         else:
             instance.pci_devices.objects.remove(existed)
Exemple #3
0
    def remove(self):
        # We allow removal of a device is if it is unused. It can be unused
        # either by being in available state or being in a state that shows
        # that the parent or child device blocks the consumption of this device
        expected_states = [
            fields.PciDeviceStatus.AVAILABLE,
            fields.PciDeviceStatus.UNAVAILABLE,
            fields.PciDeviceStatus.UNCLAIMABLE,
        ]
        if self.status not in expected_states:
            raise exception.PciDeviceInvalidStatus(
                compute_node_id=self.compute_node_id,
                address=self.address,
                status=self.status,
                hopestatus=expected_states)
        # Just to be on the safe side, do not allow removal of device that has
        # an owner even if the state of the device suggests that it is not
        # owned.
        if 'instance_uuid' in self and self.instance_uuid is not None:
            raise exception.PciDeviceInvalidOwner(
                compute_node_id=self.compute_node_id,
                address=self.address,
                owner=self.instance_uuid,
                hopeowner=None,
            )

        self.status = fields.PciDeviceStatus.REMOVED
        self.instance_uuid = None
        self.request_id = None
Exemple #4
0
    def allocate(self, instance):
        ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                       fields.PciDeviceStatus.CLAIMED)
        parent_ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                              fields.PciDeviceStatus.UNCLAIMABLE,
                              fields.PciDeviceStatus.UNAVAILABLE)
        dependants_ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                                  fields.PciDeviceStatus.UNCLAIMABLE)
        if self.status not in ok_statuses:
            raise exception.PciDeviceInvalidStatus(
                compute_node_id=self.compute_node_id,
                address=self.address, status=self.status,
                hopestatus=ok_statuses)
        if (self.status == fields.PciDeviceStatus.CLAIMED and
                self.instance_uuid != instance['uuid']):
            raise exception.PciDeviceInvalidOwner(
                compute_node_id=self.compute_node_id,
                address=self.address, owner=self.instance_uuid,
                hopeowner=instance['uuid'])
        if self.dev_type == fields.PciDeviceType.SRIOV_PF:
            vfs_list = self.child_devices
            if not all([vf.status in dependants_ok_statuses for
                        vf in vfs_list]):
                raise exception.PciDeviceVFInvalidStatus(
                    compute_node_id=self.compute_node_id,
                    address=self.address)
            self._bulk_update_status(vfs_list,
                                     fields.PciDeviceStatus.UNAVAILABLE)

        elif self.dev_type in (
            fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
        ):
            parent = self.parent_device
            if parent:
                if parent.status not in parent_ok_statuses:
                    raise exception.PciDevicePFInvalidStatus(
                        compute_node_id=self.compute_node_id,
                        address=self.parent_addr, status=self.status,
                        vf_address=self.address,
                        hopestatus=parent_ok_statuses)
                # Set PF status
                parent.status = fields.PciDeviceStatus.UNAVAILABLE
            else:
                LOG.debug('Physical function addr: %(pf_addr)s parent of '
                          'VF addr: %(vf_addr)s was not found',
                           {'pf_addr': self.parent_addr,
                            'vf_addr': self.address})

        self.status = fields.PciDeviceStatus.ALLOCATED
        self.instance_uuid = instance['uuid']

        # Notes(yjiang5): remove this check when instance object for
        # compute manager is finished
        if isinstance(instance, dict):
            if 'pci_devices' not in instance:
                instance['pci_devices'] = []
            instance['pci_devices'].append(copy.copy(self))
        else:
            instance.pci_devices.objects.append(copy.copy(self))
Exemple #5
0
 def claim(self, instance):
     if self.status != fields.PciDeviceStatus.AVAILABLE:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=self.compute_node_id,
             address=self.address, status=self.status,
             hopestatus=[fields.PciDeviceStatus.AVAILABLE])
     self.status = fields.PciDeviceStatus.CLAIMED
     self.instance_uuid = instance['uuid']
Exemple #6
0
 def remove(self):
     if self.status != fields.PciDeviceStatus.AVAILABLE:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=self.compute_node_id,
             address=self.address, status=self.status,
             hopestatus=[fields.PciDeviceStatus.AVAILABLE])
     self.status = fields.PciDeviceStatus.REMOVED
     self.instance_uuid = None
     self.request_id = None
Exemple #7
0
 def free(self, instance=None):
     ok_statuses = (fields.PciDeviceStatus.ALLOCATED,
                    fields.PciDeviceStatus.CLAIMED)
     free_devs = []
     if self.status not in ok_statuses:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=self.compute_node_id,
             address=self.address,
             status=self.status,
             hopestatus=ok_statuses)
     if instance and self.instance_uuid != instance['uuid']:
         raise exception.PciDeviceInvalidOwner(
             compute_node_id=self.compute_node_id,
             address=self.address,
             owner=self.instance_uuid,
             hopeowner=instance['uuid'])
     if self.dev_type == fields.PciDeviceType.SRIOV_PF:
         # Set all PF dependants status to AVAILABLE
         vfs_list = objects.PciDeviceList.get_by_parent_address(
             self._context, self.compute_node_id, self.address)
         self._bulk_update_status(vfs_list,
                                  fields.PciDeviceStatus.AVAILABLE)
         free_devs.extend(vfs_list)
     if self.dev_type == fields.PciDeviceType.SRIOV_VF:
         # Set PF status to AVAILABLE if all of it's VFs are free
         vfs_list = objects.PciDeviceList.get_by_parent_address(
             self._context, self.compute_node_id, self.parent_addr)
         if all([vf.is_available() for vf in vfs_list if vf.id != self.id]):
             try:
                 parent = self.get_by_dev_addr(self._context,
                                               self.compute_node_id,
                                               self.parent_addr)
                 parent.status = fields.PciDeviceStatus.AVAILABLE
                 free_devs.append(parent)
             except exception.PciDeviceNotFound:
                 LOG.debug(
                     'Physical function addr: %(pf_addr)s parent of '
                     'VF addr: %(vf_addr)s was not found', {
                         'pf_addr': self.parent_addr,
                         'vf_addr': self.address
                     })
     old_status = self.status
     self.status = fields.PciDeviceStatus.AVAILABLE
     free_devs.append(self)
     self.instance_uuid = None
     self.request_id = None
     if old_status == fields.PciDeviceStatus.ALLOCATED and instance:
         # Notes(yjiang5): remove this check when instance object for
         # compute manager is finished
         existed = next(
             (dev for dev in instance['pci_devices'] if dev.id == self.id))
         if isinstance(instance, dict):
             instance['pci_devices'].remove(existed)
         else:
             instance.pci_devices.objects.remove(existed)
     return free_devs
Exemple #8
0
 def inner(devobj, instance=None):
     if devobj['status'] not in dev_status:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=devobj.compute_node_id,
             address=devobj.address, status=devobj.status,
             hopestatus=dev_status)
     if instance:
         return f(devobj, instance)
     else:
         return f(devobj)
Exemple #9
0
 def inner(self, instance=None):
     if self['status'] not in dev_status:
         raise exception.PciDeviceInvalidStatus(
             compute_node_id=self.compute_node_id,
             address=self.address, status=self.status,
             hopestatus=dev_status)
     if instance:
         return f(self, instance)
     else:
         return f(self)
Exemple #10
0
    def claim(self, instance_uuid):
        if self.status != fields.PciDeviceStatus.AVAILABLE:
            raise exception.PciDeviceInvalidStatus(
                compute_node_id=self.compute_node_id,
                address=self.address,
                status=self.status,
                hopestatus=[fields.PciDeviceStatus.AVAILABLE])

        if self.dev_type == fields.PciDeviceType.SRIOV_PF:
            # Update PF status to CLAIMED if all of it dependants are free
            # and set their status to UNCLAIMABLE
            vfs_list = objects.PciDeviceList.get_by_parent_address(
                self._context, self.compute_node_id, self.address)
            if not all([vf.is_available() for vf in vfs_list]):
                raise exception.PciDeviceVFInvalidStatus(
                    compute_node_id=self.compute_node_id, address=self.address)
            self._bulk_update_status(vfs_list,
                                     fields.PciDeviceStatus.UNCLAIMABLE)

        elif self.dev_type == fields.PciDeviceType.SRIOV_VF:
            # Update VF status to CLAIMED if it's parent has not been
            # previuosly allocated or claimed
            # When claiming/allocating a VF, it's parent PF becomes
            # unclaimable/unavailable. Therefore, it is expected to find the
            # parent PF in an unclaimable/unavailable state for any following
            # claims to a sibling VF

            parent_ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                                  fields.PciDeviceStatus.UNCLAIMABLE,
                                  fields.PciDeviceStatus.UNAVAILABLE)
            try:
                parent = self.get_by_dev_addr(self._context,
                                              self.compute_node_id,
                                              self.parent_addr)
                if parent.status not in parent_ok_statuses:
                    raise exception.PciDevicePFInvalidStatus(
                        compute_node_id=self.compute_node_id,
                        address=self.parent_addr,
                        status=self.status,
                        vf_address=self.address,
                        hopestatus=parent_ok_statuses)
                # Set PF status
                if parent.status == fields.PciDeviceStatus.AVAILABLE:
                    parent.status = fields.PciDeviceStatus.UNCLAIMABLE
            except exception.PciDeviceNotFound:
                LOG.debug(
                    'Physical function addr: %(pf_addr)s parent of '
                    'VF addr: %(vf_addr)s was not found', {
                        'pf_addr': self.parent_addr,
                        'vf_addr': self.address
                    })

        self.status = fields.PciDeviceStatus.CLAIMED
        self.instance_uuid = instance_uuid
Exemple #11
0
    def claim(self, instance_uuid):
        if self.status != fields.PciDeviceStatus.AVAILABLE:
            raise exception.PciDeviceInvalidStatus(
                compute_node_id=self.compute_node_id,
                address=self.address, status=self.status,
                hopestatus=[fields.PciDeviceStatus.AVAILABLE])

        if self.dev_type == fields.PciDeviceType.SRIOV_PF:
            # Update PF status to CLAIMED if all of it dependants are free
            # and set their status to UNCLAIMABLE
            vfs_list = self.child_devices
            non_free_dependants = [
                vf for vf in vfs_list if not vf.is_available()]
            if non_free_dependants:
                # NOTE(gibi): There should not be any dependent devices that
                # are UNCLAIMABLE or UNAVAILABLE as the parent is AVAILABLE,
                # but we got reports in bug 1969496 that this inconsistency
                # can happen. So check if the only non-free devices are in
                # state UNCLAIMABLE or UNAVAILABLE then we log a warning but
                # allow to claim the parent.
                actual_statuses = {
                    child.status for child in non_free_dependants}
                allowed_non_free_statues = {
                    fields.PciDeviceStatus.UNCLAIMABLE,
                    fields.PciDeviceStatus.UNAVAILABLE,
                }
                if actual_statuses - allowed_non_free_statues == set():
                    LOG.warning(
                        "Some child device of parent %s is in an inconsistent "
                        "state. If you can reproduce this warning then please "
                        "report a bug at "
                        "https://bugs.launchpad.net/nova/+filebug with "
                        "reproduction steps. Inconsistent children with "
                        "state: %s",
                        self.address,
                        ",".join(
                            "%s - %s" % (child.address, child.status)
                            for child in non_free_dependants
                        ),
                    )

                else:
                    raise exception.PciDeviceVFInvalidStatus(
                        compute_node_id=self.compute_node_id,
                        address=self.address)
            self._bulk_update_status(vfs_list,
                                           fields.PciDeviceStatus.UNCLAIMABLE)

        elif self.dev_type in (
            fields.PciDeviceType.SRIOV_VF, fields.PciDeviceType.VDPA
        ):
            # Update VF status to CLAIMED if it's parent has not been
            # previously allocated or claimed
            # When claiming/allocating a VF, it's parent PF becomes
            # unclaimable/unavailable. Therefore, it is expected to find the
            # parent PF in an unclaimable/unavailable state for any following
            # claims to a sibling VF

            parent_ok_statuses = (fields.PciDeviceStatus.AVAILABLE,
                                  fields.PciDeviceStatus.UNCLAIMABLE,
                                  fields.PciDeviceStatus.UNAVAILABLE)
            parent = self.parent_device
            if parent:
                if parent.status not in parent_ok_statuses:
                    raise exception.PciDevicePFInvalidStatus(
                        compute_node_id=self.compute_node_id,
                        address=self.parent_addr, status=self.status,
                        vf_address=self.address,
                        hopestatus=parent_ok_statuses)
                # Set PF status
                if parent.status == fields.PciDeviceStatus.AVAILABLE:
                    parent.status = fields.PciDeviceStatus.UNCLAIMABLE
            else:
                LOG.debug('Physical function addr: %(pf_addr)s parent of '
                          'VF addr: %(vf_addr)s was not found',
                          {'pf_addr': self.parent_addr,
                           'vf_addr': self.address})

        self.status = fields.PciDeviceStatus.CLAIMED
        self.instance_uuid = instance_uuid