ovn: use requested-chassis list format for live migration

This makes OVN asynchronously set up destination port while VMs
are being migrated, reducing network downtime.

Also configure 'rarp' activation strategy to wait until libvirt
notifies the network about new VM location with a RARP issued from
the vif.

Change-Id: I55811ea72b2bf0d0b244f422861dca4a7bf8f257
This commit is contained in:
Ihar Hrachyshka 2022-01-28 19:48:28 +00:00
parent f8673c0516
commit 35fade3b5f
2 changed files with 72 additions and 3 deletions

View File

@ -372,9 +372,25 @@ class OVNClient(object):
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS)),
ovn_const.LSP_OPTIONS_VIF_PLUG_REPRESENTOR_VF_NUM_KEY: str(
binding_prof.get(ovn_const.VIF_DETAILS_VF_NUM))})
options.update({
ovn_const.LSP_OPTIONS_REQUESTED_CHASSIS_KEY: (
self.determine_bind_host(port))})
chassis = self.determine_bind_host(port)
if chassis:
# If OVN supports multi-chassis port bindings, use it for live
# migration to asynchronously configure destination port while
# VM is migrating
if self._sb_idl.is_col_present('Port_Binding',
'additional_chassis'):
mdst = port.get(
portbindings.PROFILE, {}).get(
ovn_const.MIGRATING_ATTR)
if mdst:
# Let OVN know that the port should be configured on
# destination too
chassis += ',%s' % mdst
# Block traffic on destination host until libvirt sends
# a RARP packet from it to inform network about the new
# location of the port
options['activation-strategy'] = 'rarp'
options[ovn_const.LSP_OPTIONS_REQUESTED_CHASSIS_KEY] = chassis
# TODO(lucasagomes): Enable the mcast_flood_reports by default,
# according to core OVN developers it shouldn't cause any harm

View File

@ -1843,6 +1843,59 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
mock.ANY,
filters={'id': subnet_ids})
def test__get_port_options_migrating_additional_chassis_missing(self):
port = {
'id': 'virt-port',
'mac_address': '00:00:00:00:00:00',
'device_owner': 'device_owner',
'network_id': 'foo',
'fixed_ips': [],
portbindings.HOST_ID: 'fake-src',
portbindings.PROFILE: {
ovn_const.MIGRATING_ATTR: 'fake-dest',
}
}
options = self.mech_driver._ovn_client._get_port_options(port)
self.assertNotIn('activation-strategy', options.options)
self.assertEqual('fake-src', options.options['requested-chassis'])
def test__get_port_options_migrating_additional_chassis_present(self):
port = {
'id': 'virt-port',
'mac_address': '00:00:00:00:00:00',
'device_owner': 'device_owner',
'network_id': 'foo',
'fixed_ips': [],
portbindings.HOST_ID: 'fake-src',
portbindings.PROFILE: {
ovn_const.MIGRATING_ATTR: 'fake-dest',
}
}
with mock.patch.object(
self.mech_driver._ovn_client._sb_idl, 'is_col_present',
return_value=True):
options = self.mech_driver._ovn_client._get_port_options(port)
self.assertEqual('rarp', options.options['activation-strategy'])
self.assertEqual('fake-src,fake-dest',
options.options['requested-chassis'])
def test__get_port_options_not_migrating_additional_chassis_present(self):
port = {
'id': 'virt-port',
'mac_address': '00:00:00:00:00:00',
'device_owner': 'device_owner',
'network_id': 'foo',
'fixed_ips': [],
portbindings.HOST_ID: 'fake-src',
}
with mock.patch.object(
self.mech_driver._ovn_client._sb_idl, 'is_col_present',
return_value=True):
options = self.mech_driver._ovn_client._get_port_options(port)
self.assertNotIn('activation-strategy', options.options)
self.assertEqual('fake-src',
options.options['requested-chassis'])
def test_update_port(self):
with mock.patch.object(
self.mech_driver._ovn_client, 'is_metadata_port') as \