diff --git a/neutron/conf/plugins/ml2/drivers/ovn/ovn_conf.py b/neutron/conf/plugins/ml2/drivers/ovn/ovn_conf.py index 77f16d99d7b..cffc3f33768 100644 --- a/neutron/conf/plugins/ml2/drivers/ovn/ovn_conf.py +++ b/neutron/conf/plugins/ml2/drivers/ovn/ovn_conf.py @@ -230,6 +230,15 @@ ovn_opts = [ 'connected to the router through any other routers, ' 'similar to the default ML2/OVS behavior. Defaults to ' '"False".')), + cfg.StrOpt('live_migration_activation_strategy', + default="rarp", + choices=["rarp", ""], + help=_('Activation strategy to use for live migration. ' + 'The default `rarp` strategy expects the hypervisor to ' + 'send a Reverse ARP request through the migrated port ' + 'after migration is complete. ' + 'An empty value means a migrated port is immediately ' + 'activated on the destination host.')), ] nb_global_opts = [ @@ -334,6 +343,10 @@ def is_ovn_distributed_floating_ip(): return cfg.CONF.ovn.enable_distributed_floating_ip +def get_ovn_lm_activation_strategy(): + return cfg.CONF.ovn.live_migration_activation_strategy + + def get_ovn_vhost_sock_dir(): return cfg.CONF.ovn.vhost_sock_dir diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py index 312340cadac..a7e49d39037 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py @@ -485,34 +485,13 @@ class OVNClient: ovn_const.VIF_DETAILS_PF_MAC_ADDRESS)), ovn_const.LSP_OPTIONS_VIF_PLUG_REPRESENTOR_VF_NUM_KEY: str( bp_info.bp_param.get(ovn_const.VIF_DETAILS_VF_NUM))}) - chassis = utils.determine_bind_host(self._sb_idl, 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 utils.is_additional_chassis_supported(self._sb_idl): - 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 - # TODO(ihrachys) Remove this once OVN properly supports - # activation of DPDK ports (bug 2092407) - if (port[portbindings.VIF_TYPE] != - portbindings.VIF_TYPE_VHOST_USER): - options['activation-strategy'] = 'rarp' + if port_type != ovn_const.LSP_TYPE_VIRTUAL: # Virtual ports can not be bound by using the requested-chassis # mechanism, ovn-controller will create the Port_Binding entry # when it sees an ARP coming from the VIP - if port_type != ovn_const.LSP_TYPE_VIRTUAL: - options[ovn_const.LSP_OPTIONS_REQUESTED_CHASSIS_KEY] = \ - chassis + options = self._configure_requested_chassis_options( + options, port) if self.is_mcast_flood_broken and port_type not in ( 'vtep', ovn_const.LSP_TYPE_LOCALPORT, 'router'): @@ -526,6 +505,33 @@ class OVNClient: bp_info.vnic_type, bp_info.capabilities, mtu ) + def _configure_requested_chassis_options(self, options, port): + options = copy.deepcopy(options) + chassis = utils.determine_bind_host(self._sb_idl, 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 utils.is_additional_chassis_supported(self._sb_idl): + 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 + # TODO(ihrachys) Remove this once OVN properly supports + # activation of DPDK ports (bug 2092407) + if (port[portbindings.VIF_TYPE] != + portbindings.VIF_TYPE_VHOST_USER): + strategy = ovn_conf.get_ovn_lm_activation_strategy() + if strategy: + options['activation-strategy'] = strategy + options[ovn_const.LSP_OPTIONS_REQUESTED_CHASSIS_KEY] = chassis + return options + def update_port_dhcp_options(self, port_info, txn): dhcpv4_options = [] dhcpv6_options = [] diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py index 74d6dbae5c2..ed7ab5c54aa 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py @@ -2102,6 +2102,30 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): self.assertEqual('fake-src,fake-dest', options.options['requested-chassis']) + def test__get_port_options_no_activation_strategy(self): + cfg.CONF.set_override('live_migration_activation_strategy', + '', group='ovn') + 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', + }, + portbindings.VIF_TYPE: portbindings.VIF_TYPE_VHOST_USER, + } + + 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,fake-dest', + options.options['requested-chassis']) + def test__get_port_options_not_migrating_additional_chassis_present(self): port = { 'id': 'virt-port', diff --git a/releasenotes/notes/add-ovn-live-migration-activation-strategy-option-8ef113349aa97ff1.yaml b/releasenotes/notes/add-ovn-live-migration-activation-strategy-option-8ef113349aa97ff1.yaml new file mode 100644 index 00000000000..213e1c65142 --- /dev/null +++ b/releasenotes/notes/add-ovn-live-migration-activation-strategy-option-8ef113349aa97ff1.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + For OVN, you can now select which port binding activation strategy to use + for migrated ports, by setting the new configuration option + ``[ovn]ovn_live_migration_activation_strategy``. If set to an empty string, + no activation strategy will be used, and the destination port binding will + be immediately activated after creation without waiting for migration to + complete.