@@ -2107,16 +2107,16 @@ def create_resource_requests(
21072107 port_numa_policy = None
21082108
21092109 if request_net .port_id :
2110+ # InstancePCIRequest.requester_id is semantically linked
2111+ # to a port with a resource_request.
2112+ requester_id = request_net .port_id
21102113 (vnic_type , trusted , network_id , resource_request ,
21112114 port_numa_policy ) = self ._get_port_vnic_info (
21122115 context , neutron , request_net .port_id )
21132116 physnet , tunneled_ = self ._get_physnet_tunneled_info (
21142117 context , neutron , network_id )
21152118
21162119 if resource_request :
2117- # InstancePCIRequest.requester_id is semantically linked
2118- # to a port with a resource_request.
2119- requester_id = request_net .port_id
21202120 # NOTE(gibi): explicitly orphan the RequestGroup by setting
21212121 # context=None as we never intended to save it to the DB.
21222122 resource_requests .append (
@@ -3364,6 +3364,37 @@ def _get_pci_mapping_for_migration(self, instance, migration):
33643364 migration .get ('status' ) == 'reverted' )
33653365 return instance .migration_context .get_pci_mapping_for_migration (revert )
33663366
3367+ def _get_port_pci_slot (self , context , instance , port ):
3368+ """Find the PCI address of the device corresponding to the port.
3369+ Assumes the port is an SRIOV one.
3370+
3371+ :param context: The request context.
3372+ :param instance: The instance to which the port is attached.
3373+ :param port: The Neutron port, as obtained from the Neutron API
3374+ JSON form.
3375+ :return: The PCI address as a string, or None if unable to find.
3376+ """
3377+ # Find the port's PCIRequest, or return None
3378+ for r in instance .pci_requests .requests :
3379+ if r .requester_id == port ['id' ]:
3380+ request = r
3381+ break
3382+ else :
3383+ LOG .debug ('No PCI request found for port %s' , port ['id' ],
3384+ instance = instance )
3385+ return None
3386+ # Find the request's device, or return None
3387+ for d in instance .pci_devices :
3388+ if d .request_id == request .request_id :
3389+ device = d
3390+ break
3391+ else :
3392+ LOG .debug ('No PCI device found for request %s' ,
3393+ request .request_id , instance = instance )
3394+ return None
3395+ # Return the device's PCI address
3396+ return device .address
3397+
33673398 def _update_port_binding_for_instance (
33683399 self , context , instance , host , migration = None ,
33693400 provider_mappings = None ):
@@ -3372,7 +3403,6 @@ def _update_port_binding_for_instance(
33723403 search_opts = {'device_id' : instance .uuid ,
33733404 'tenant_id' : instance .project_id }
33743405 data = neutron .list_ports (** search_opts )
3375- pci_mapping = None
33763406 port_updates = []
33773407 ports = data ['ports' ]
33783408 FAILED_VIF_TYPES = (network_model .VIF_TYPE_UNBOUND ,
@@ -3405,25 +3435,36 @@ def _update_port_binding_for_instance(
34053435 # that this function is called without a migration object, such
34063436 # as in an unshelve operation.
34073437 vnic_type = p .get ('binding:vnic_type' )
3408- if (vnic_type in network_model .VNIC_TYPES_SRIOV and
3409- migration is not None and
3410- not migration .is_live_migration ):
3411- # Note(adrianc): for live migration binding profile was already
3412- # updated in conductor when calling bind_ports_to_host()
3413- if not pci_mapping :
3414- pci_mapping = self ._get_pci_mapping_for_migration (
3415- instance , migration )
3416-
3417- pci_slot = binding_profile .get ('pci_slot' )
3418- new_dev = pci_mapping .get (pci_slot )
3419- if new_dev :
3420- binding_profile .update (
3421- self ._get_pci_device_profile (new_dev ))
3422- updates [constants .BINDING_PROFILE ] = binding_profile
3438+ if vnic_type in network_model .VNIC_TYPES_SRIOV :
3439+ # NOTE(artom) For migrations, update the binding profile from
3440+ # the migration object...
3441+ if migration is not None :
3442+ # NOTE(artom) ... except for live migrations, because the
3443+ # conductor has already done that whe calling
3444+ # bind_ports_to_host().
3445+ if not migration .is_live_migration :
3446+ pci_mapping = self ._get_pci_mapping_for_migration (
3447+ instance , migration )
3448+
3449+ pci_slot = binding_profile .get ('pci_slot' )
3450+ new_dev = pci_mapping .get (pci_slot )
3451+ if new_dev :
3452+ binding_profile .update (
3453+ self ._get_pci_device_profile (new_dev ))
3454+ updates [
3455+ constants .BINDING_PROFILE ] = binding_profile
3456+ else :
3457+ raise exception .PortUpdateFailed (port_id = p ['id' ],
3458+ reason = _ ("Unable to correlate PCI slot %s" ) %
3459+ pci_slot )
3460+ # NOTE(artom) If migration is None, this is an unshevle, and we
3461+ # need to figure out the pci_slot from the InstancePCIRequest
3462+ # and PciDevice objects.
34233463 else :
3424- raise exception .PortUpdateFailed (port_id = p ['id' ],
3425- reason = _ ("Unable to correlate PCI slot %s" ) %
3426- pci_slot )
3464+ pci_slot = self ._get_port_pci_slot (context , instance , p )
3465+ if pci_slot :
3466+ binding_profile .update ({'pci_slot' : pci_slot })
3467+ updates [constants .BINDING_PROFILE ] = binding_profile
34273468
34283469 # NOTE(gibi): during live migration the conductor already sets the
34293470 # allocation key in the port binding. However during resize, cold
0 commit comments