Move get_pci_mapping_for_migration to MigrationContext
In order to fix Bug #1809095, it is required to update PCI related VIFs with the original PCI address on the source host to allow virt driver to properly unplug the VIF from hypervisor, e.g allow the proper VF representor to be unplugged from the integration bridge in case of a hardware offloaded OVS. To do so, some preliminary work is needed to allow code-sharing between nova.network.neutronv2 and nova.compute.manager This change: - Moves common logic to retrieve the PCI mapping between the source and destination node from nova.network.neutronv2 to objects.migration_context. - Makes code adjustments to methods in nova.network.neutronv2 to accomodate the former. Change-Id: I9a5118373548c525b2b1c2271e7d210cc92e4f4c Partial-Bug: #1809095
This commit is contained in:
parent
387d5a9835
commit
5a1c385b99
|
@ -3174,45 +3174,14 @@ class API(base_api.NetworkAPI):
|
|||
# device_id field on the port which is not what we'd want for shelve.
|
||||
pass
|
||||
|
||||
def _get_pci_devices_from_migration_context(self, migration_context,
|
||||
migration):
|
||||
if migration and migration.get('status') == 'reverted':
|
||||
# In case of revert, swap old and new devices to
|
||||
# update the ports back to the original devices.
|
||||
return (migration_context.new_pci_devices,
|
||||
migration_context.old_pci_devices)
|
||||
return (migration_context.old_pci_devices,
|
||||
migration_context.new_pci_devices)
|
||||
|
||||
def _get_pci_mapping_for_migration(self, context, instance, migration):
|
||||
"""Get the mapping between the old PCI devices and the new PCI
|
||||
devices that have been allocated during this migration. The
|
||||
correlation is based on PCI request ID which is unique per PCI
|
||||
devices for SR-IOV ports.
|
||||
|
||||
:param context: The request context.
|
||||
:param instance: Get PCI mapping for this instance.
|
||||
:param migration: The migration for this instance.
|
||||
:Returns: dictionary of mapping {'<old pci address>': <New PciDevice>}
|
||||
"""
|
||||
migration_context = instance.migration_context
|
||||
if not migration_context:
|
||||
def _get_pci_mapping_for_migration(self, instance, migration):
|
||||
if not instance.migration_context:
|
||||
return {}
|
||||
|
||||
old_pci_devices, new_pci_devices = \
|
||||
self._get_pci_devices_from_migration_context(migration_context,
|
||||
migration)
|
||||
if old_pci_devices and new_pci_devices:
|
||||
LOG.debug("Determining PCI devices mapping using migration "
|
||||
"context: old_pci_devices: %(old)s, "
|
||||
"new_pci_devices: %(new)s",
|
||||
{'old': [dev for dev in old_pci_devices],
|
||||
'new': [dev for dev in new_pci_devices]})
|
||||
return {old.address: new
|
||||
for old in old_pci_devices
|
||||
for new in new_pci_devices
|
||||
if old.request_id == new.request_id}
|
||||
return {}
|
||||
# In case of revert, swap old and new devices to
|
||||
# update the ports back to the original devices.
|
||||
revert = (migration and
|
||||
migration.get('status') == 'reverted')
|
||||
return instance.migration_context.get_pci_mapping_for_migration(revert)
|
||||
|
||||
def _update_port_binding_for_instance(self, context, instance, host,
|
||||
migration=None):
|
||||
|
@ -3262,7 +3231,7 @@ class API(base_api.NetworkAPI):
|
|||
# Note(adrianc): for live migration binding profile was already
|
||||
# updated in conductor when calling bind_ports_to_host()
|
||||
if not pci_mapping:
|
||||
pci_mapping = self._get_pci_mapping_for_migration(context,
|
||||
pci_mapping = self._get_pci_mapping_for_migration(
|
||||
instance, migration)
|
||||
|
||||
pci_slot = binding_profile.get('pci_slot')
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import versionutils
|
||||
|
||||
|
@ -20,6 +21,8 @@ from nova import exception
|
|||
from nova.objects import base
|
||||
from nova.objects import fields
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@base.NovaObjectRegistry.register
|
||||
class MigrationContext(base.NovaPersistentObject, base.NovaObject):
|
||||
|
@ -80,3 +83,32 @@ class MigrationContext(base.NovaPersistentObject, base.NovaObject):
|
|||
return None
|
||||
|
||||
return cls.obj_from_db_obj(db_extra['migration_context'])
|
||||
|
||||
def get_pci_mapping_for_migration(self, revert):
|
||||
"""Get the mapping between the old PCI devices and the new PCI
|
||||
devices that have been allocated during this migration. The
|
||||
correlation is based on PCI request ID which is unique per PCI
|
||||
devices for SR-IOV ports.
|
||||
|
||||
:param revert: If True, return a reverse mapping i.e
|
||||
mapping between new PCI devices and old PCI devices.
|
||||
:returns: dictionary of PCI mapping.
|
||||
if revert==False:
|
||||
{'<old pci address>': <New PciDevice>}
|
||||
if revert==True:
|
||||
{'<new pci address>': <Old PciDevice>}
|
||||
"""
|
||||
step = -1 if revert else 1
|
||||
current_pci_devs, updated_pci_devs = (self.old_pci_devices,
|
||||
self.new_pci_devices)[::step]
|
||||
if current_pci_devs and updated_pci_devs:
|
||||
LOG.debug("Determining PCI devices mapping using migration "
|
||||
"context: current_pci_devs: %(cur)s, "
|
||||
"updated_pci_devs: %(upd)s",
|
||||
{'cur': [dev for dev in current_pci_devs],
|
||||
'upd': [dev for dev in updated_pci_devs]})
|
||||
return {curr_dev.address: upd_dev
|
||||
for curr_dev in current_pci_devs
|
||||
for upd_dev in updated_pci_devs
|
||||
if curr_dev.request_id == upd_dev.request_id}
|
||||
return {}
|
||||
|
|
|
@ -4384,56 +4384,29 @@ class TestNeutronv2WithMock(TestNeutronv2Base):
|
|||
def test_get_pci_mapping_for_migration(self):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
instance.migration_context = objects.MigrationContext()
|
||||
old_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0a:00.1',
|
||||
compute_node_id=1,
|
||||
request_id='1234567890')])
|
||||
|
||||
new_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0b:00.1',
|
||||
compute_node_id=2,
|
||||
request_id='1234567890')])
|
||||
|
||||
instance.migration_context.old_pci_devices = old_pci_devices
|
||||
instance.migration_context.new_pci_devices = new_pci_devices
|
||||
instance.pci_devices = instance.migration_context.old_pci_devices
|
||||
migration = {'status': 'confirmed'}
|
||||
|
||||
pci_mapping = self.api._get_pci_mapping_for_migration(
|
||||
self.context, instance, migration)
|
||||
self.assertEqual(
|
||||
{old_pci_devices[0].address: new_pci_devices[0]}, pci_mapping)
|
||||
with mock.patch.object(instance.migration_context,
|
||||
'get_pci_mapping_for_migration') as map_func:
|
||||
self.api._get_pci_mapping_for_migration(instance, migration)
|
||||
map_func.assert_called_with(False)
|
||||
|
||||
def test_get_pci_mapping_for_migration_reverted(self):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
instance.migration_context = objects.MigrationContext()
|
||||
old_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0a:00.1',
|
||||
compute_node_id=1,
|
||||
request_id='1234567890')])
|
||||
|
||||
new_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0b:00.1',
|
||||
compute_node_id=2,
|
||||
request_id='1234567890')])
|
||||
|
||||
instance.migration_context.old_pci_devices = old_pci_devices
|
||||
instance.migration_context.new_pci_devices = new_pci_devices
|
||||
instance.pci_devices = instance.migration_context.old_pci_devices
|
||||
migration = {'status': 'reverted'}
|
||||
|
||||
with mock.patch.object(instance.migration_context,
|
||||
'get_pci_mapping_for_migration') as map_func:
|
||||
self.api._get_pci_mapping_for_migration(instance, migration)
|
||||
map_func.assert_called_with(True)
|
||||
|
||||
def test_get_pci_mapping_for_migration_no_migration_context(self):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
instance.migration_context = None
|
||||
pci_mapping = self.api._get_pci_mapping_for_migration(
|
||||
self.context, instance, migration)
|
||||
self.assertEqual(
|
||||
{new_pci_devices[0].address: old_pci_devices[0]}, pci_mapping)
|
||||
instance, None)
|
||||
self.assertDictEqual({}, pci_mapping)
|
||||
|
||||
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
|
||||
def test_update_port_profile_for_migration_teardown_false(
|
||||
|
|
|
@ -52,6 +52,23 @@ def get_fake_migration_context_obj(ctxt):
|
|||
return obj
|
||||
|
||||
|
||||
def get_fake_migration_context_with_pci_devs(ctxt=None):
|
||||
obj = get_fake_migration_context_obj(ctxt)
|
||||
obj.old_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0a:00.1',
|
||||
compute_node_id=1,
|
||||
request_id=uuids.pcidev)])
|
||||
obj.new_pci_devices = objects.PciDeviceList(
|
||||
objects=[objects.PciDevice(vendor_id='1377',
|
||||
product_id='0047',
|
||||
address='0000:0b:00.1',
|
||||
compute_node_id=2,
|
||||
request_id=uuids.pcidev)])
|
||||
return obj
|
||||
|
||||
|
||||
class _TestMigrationContext(object):
|
||||
|
||||
def _test_get_by_instance_uuid(self, db_data):
|
||||
|
@ -104,7 +121,20 @@ class _TestMigrationContext(object):
|
|||
|
||||
|
||||
class TestMigrationContext(test_objects._LocalTest, _TestMigrationContext):
|
||||
pass
|
||||
|
||||
def test_pci_mapping_for_migration(self):
|
||||
mig_ctx = get_fake_migration_context_with_pci_devs()
|
||||
pci_mapping = mig_ctx.get_pci_mapping_for_migration(False)
|
||||
self.assertDictEqual(
|
||||
{mig_ctx.old_pci_devices[0].address: mig_ctx.new_pci_devices[0]},
|
||||
pci_mapping)
|
||||
|
||||
def test_pci_mapping_for_migration_revert(self):
|
||||
mig_ctx = get_fake_migration_context_with_pci_devs()
|
||||
pci_mapping = mig_ctx.get_pci_mapping_for_migration(True)
|
||||
self.assertDictEqual(
|
||||
{mig_ctx.new_pci_devices[0].address: mig_ctx.old_pci_devices[0]},
|
||||
pci_mapping)
|
||||
|
||||
|
||||
class TestMigrationContextRemote(test_objects._RemoteTest,
|
||||
|
|
Loading…
Reference in New Issue