From 9fd1f58394efd083cfe9a194601e30b827af56a5 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Wed, 31 Jul 2024 14:58:18 +0200 Subject: [PATCH] [OVN] Set reside-on-chassis-redirect also for FLAT networks This ovn option for the Logical Router Port was added to be set with [1] but FLAT networks are basically working in the same way and should have this option set in the same way. [1] https://review.opendev.org/c/openstack/neutron/+/871252 Change-Id: I3203678c1ca6fb778c993b6084bab171a312ec28 --- .../ovn/mech_driver/ovsdb/maintenance.py | 11 +-- .../ovn/mech_driver/ovsdb/ovn_client.py | 4 +- .../ovn/mech_driver/ovsdb/test_maintenance.py | 67 ++++++++++++++++++- .../ovn/mech_driver/ovsdb/test_ovn_client.py | 49 ++++++++++++++ .../ovn/mech_driver/ovsdb/test_maintenance.py | 12 ++-- 5 files changed, 128 insertions(+), 15 deletions(-) diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py index f17a18b5ab0..2941cfbaef4 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py @@ -753,16 +753,17 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase): periodic_run_limit=ovn_const.MAINTENANCE_TASK_RETRY_LIMIT, spacing=ovn_const.MAINTENANCE_ONE_RUN_TASK_SPACING, run_immediately=True) - def check_vlan_distributed_ports(self): - """Check VLAN distributed ports + def check_provider_distributed_ports(self): + """Check provider (VLAN and FLAT) distributed ports Check for the option "reside-on-redirect-chassis" value for - distributed VLAN ports. + distributed ports which belongs to the FLAT or VLAN networks. """ context = n_context.get_admin_context() cmds = [] - # Get router ports belonging to VLAN networks + # Get router ports belonging to VLAN or FLAT networks vlan_nets = self._ovn_client._plugin.get_networks( - context, {pnet.NETWORK_TYPE: [n_const.TYPE_VLAN]}) + context, {pnet.NETWORK_TYPE: [n_const.TYPE_VLAN, + n_const.TYPE_FLAT]}) vlan_net_ids = [vn['id'] for vn in vlan_nets] router_ports = self._ovn_client._plugin.get_ports( context, {'network_id': vlan_net_ids, 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 c6c3c3a2c36..67554d0076d 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 @@ -1684,12 +1684,12 @@ class OVNClient(object): network_type = ls.external_ids[ovn_const.OVN_NETTYPE_EXT_ID_KEY] network_mtu = int( ls.external_ids[ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY]) - # For VLAN type networks we need to set the + # For provider networks (VLAN, FLAT types) we need to set the # "reside-on-redirect-chassis" option so the routing for this # logical router port is centralized in the chassis hosting the # distributed gateway port. # https://github.com/openvswitch/ovs/commit/85706c34d53d4810f54bec1de662392a3c06a996 - if network_type == const.TYPE_VLAN: + if network_type in [const.TYPE_VLAN, const.TYPE_FLAT]: reside_redir_ch = self._get_reside_redir_for_gateway_port( port['device_id']) options[ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH] = reside_redir_ch diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py index 27088cd65e9..60c592e7de8 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py @@ -16,6 +16,7 @@ from unittest import mock from oslo_config import cfg +from oslo_utils import strutils from futurist import periodics from neutron_lib.api.definitions import external_net as extnet_apidef @@ -68,12 +69,17 @@ class _TestMaintenanceHelper(base.TestOVNFunctionalBase): ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY) == name): return row - def _create_network(self, name, external=False, provider=None): + def _create_network(self, name, external=False, provider=None, + net_type=None): data = {'network': {'name': name, extnet_apidef.EXTERNAL: external}} + if net_type: + data['network'][provnet_apidef.NETWORK_TYPE] = net_type if provider: - data['network'][provnet_apidef.NETWORK_TYPE] = 'flat' + net_type = net_type or 'flat' + data['network'][provnet_apidef.NETWORK_TYPE] = net_type data['network'][provnet_apidef.PHYSICAL_NETWORK] = provider + req = self.new_create_request('networks', data, self.fmt, as_admin=True) res = req.get_response(self.api) @@ -1063,6 +1069,63 @@ class TestMaintenance(_TestMaintenanceHelper): lsp = self.nb_api.lookup('Logical_Switch_Port', p1['id']) self.assertEqual(hcg_uuid, lsp.ha_chassis_group[0].uuid) + def _test_check_provider_distributed_ports( + self, is_distributed_fip, net_type, expected_value=None): + cfg.CONF.set_override( + 'enable_distributed_floating_ip', is_distributed_fip, group='ovn') + net_args = {'net_type': net_type} + if net_type == n_const.TYPE_FLAT: + net_args['provider'] = 'datacentre' + net = self._create_network( + 'net_distributed_ports_test', **net_args) + subnet = self._create_subnet('subnet_distributed_ports_test', + net['id']) + router = self._create_router('router_distributed_ports_test') + self._add_router_interface(router['id'], subnet['id']) + + # Lets make sure that reside-on-chassis-redirect is not set for the LRP + lr = self.nb_api.lookup('Logical_Router', + utils.ovn_name(router['id'])) + lrp = lr.ports[0] + self.nb_api.db_remove( + 'Logical_Router_Port', + lrp.name, + 'options', + ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH + ).execute() + + self.assertRaises(periodics.NeverAgain, + self.maint.check_provider_distributed_ports) + + lrp = self.nb_api.lookup('Logical_Router_Port', lrp.name) + if net_type in [n_const.TYPE_VLAN, n_const.TYPE_FLAT]: + self.assertEqual( + expected_value, + strutils.bool_from_string( + lrp.options[ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH])) + else: + self.assertNotIn( + ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH, + lrp.options) + + def test_check_provider_distributed_ports_dvr_vlan_net(self): + self._test_check_provider_distributed_ports(True, 'vlan', False) + + def test_check_provider_distributed_ports_non_dvr_vlan_net(self): + self._test_check_provider_distributed_ports(False, 'vlan', True) + + def test_check_provider_distributed_ports_dvr_flat_net(self): + self._test_check_provider_distributed_ports(True, 'flat', False) + + def test_check_provider_distributed_ports_non_dvr_flat_net(self): + self._test_check_provider_distributed_ports(False, 'flat', True) + + def test_check_provider_distributed_ports_dvr_geneve_net(self): + self._test_check_provider_distributed_ports(True, 'geneve') + + def test_check_provider_distributed_ports_non_dvr_geneve_net(self): + self._test_check_provider_distributed_ports(False, 'geneve') + def test_configure_nb_global(self): def options_intersect(options1, options2): return bool(set( diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py index f0def1d62c5..80cd5a8d584 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_client.py @@ -15,6 +15,7 @@ from neutron_lib.api.definitions import external_net from neutron_lib.api.definitions import provider_net from neutron_lib import constants +from oslo_config import cfg from oslo_utils import strutils from neutron.common.ovn import constants as ovn_const @@ -131,3 +132,51 @@ class TestOVNClient(base.TestOVNFunctionalBase, ovn_utils.ovn_name(router_id), default=None) self.assertIsNone(hcg) + + def _test_router_reside_chassis_redirect( + self, is_distributed_fip, net_type, expected_value=None): + cfg.CONF.set_override( + 'enable_distributed_floating_ip', is_distributed_fip, group='ovn') + net_arg = { + provider_net.NETWORK_TYPE: net_type} + if net_type == constants.TYPE_FLAT: + net_arg[provider_net.PHYSICAL_NETWORK] = 'datacentre' + with self.network('test-ovn-client', as_admin=True, + arg_list=tuple(net_arg.keys()), **net_arg) as net: + with self.subnet(net) as subnet: + subnet_id = subnet['subnet']['id'] + with self.router() as router: + router_id = router['router']['id'] + self._router_interface_action( + 'add', router_id, subnet_id, None) + lr = self.nb_api.lookup('Logical_Router', + ovn_utils.ovn_name(router_id)) + lrp = lr.ports[0] + if net_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]: + self.assertEqual( + expected_value, + strutils.bool_from_string( + lrp.options[ + ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH])) + else: + self.assertNotIn( + ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH, + lrp.options) + + def test_router_reside_chassis_redirect_dvr_vlan_net(self): + self._test_router_reside_chassis_redirect(True, 'vlan', False) + + def test_router_reside_chassis_redirect_non_dvr_vlan_net(self): + self._test_router_reside_chassis_redirect(False, 'vlan', True) + + def test_router_reside_chassis_redirect_dvr_flat_net(self): + self._test_router_reside_chassis_redirect(True, 'flat', False) + + def test_router_reside_chassis_redirect_non_dvr_flat_net(self): + self._test_router_reside_chassis_redirect(False, 'flat', True) + + def test_router_reside_chassis_redirect_dvr_geneve_net(self): + self._test_router_reside_chassis_redirect(True, 'geneve', False) + + def test_router_reside_chassis_redirect_non_dvr_geneve_net(self): + self._test_router_reside_chassis_redirect(False, 'geneve') diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py index dec9f427788..0664a0cbf28 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py @@ -834,7 +834,7 @@ class TestDBInconsistenciesPeriodics(testlib_api.SqlTestCaseLight, self._test_check_redirect_type_router_gateway_ports( networks, False, flavored_router=True) - def _test_check_vlan_distributed_ports(self, opt_value=None): + def _test_check_provider_distributed_ports(self, opt_value=None): fake_net0 = {'id': 'net0'} fake_net1 = {'id': 'net1'} fake_port0 = {'id': 'port0', 'device_id': 'device0'} @@ -856,18 +856,18 @@ class TestDBInconsistenciesPeriodics(testlib_api.SqlTestCaseLight, # Invoke the periodic method, it meant to run only once at startup # so NeverAgain will be raised at the end self.assertRaises(periodics.NeverAgain, - self.periodic.check_vlan_distributed_ports) + self.periodic.check_provider_distributed_ports) - def test_check_vlan_distributed_ports_expected_value(self): - self._test_check_vlan_distributed_ports(opt_value='true') + def test_check_provider_distributed_ports_expected_value(self): + self._test_check_provider_distributed_ports(opt_value='true') # If the "reside-on-redirect-chassis" option value do match # the expected value, assert we do not update the database self.assertFalse( self.fake_ovn_client._nb_idl.db_set.called) - def test_check_vlan_distributed_ports_non_expected_value(self): - self._test_check_vlan_distributed_ports(opt_value='false') + def test_check_provider_distributed_ports_non_expected_value(self): + self._test_check_provider_distributed_ports(opt_value='false') # If the "reside-on-redirect-chassis" option value does not match # the expected value, assert we update the database