From f178c3a4079e2a3dc7f73dc5acd73639040dd56e Mon Sep 17 00:00:00 2001 From: Hong Hui Xiao Date: Fri, 13 May 2016 07:12:57 +0000 Subject: [PATCH] DVR: Fix check multiprefix when delete ipv4 router interface Current code will prevent from deleting router centralized snat port, when there is a ipv6 subnet attatched to DVR. This is correct when deleting a v6 router centralized snat port, because multiple v6 subnets share one router port. But it is not correct when deleteing a v4 router centralized snat port, because v4 subnet doesn't share router port with v6 subnet. Deleteing a v4 router centralized snat port should be allowed no matter if there is v6 subnet attached to DVR. Change-Id: I2d06c8c79f9ff9a9300a94bcbbae13569e4d963e Closes-bug: #1581348 (cherry picked from commit 084173338e5e21ff37f042f69718237b94843665) --- neutron/db/l3_dvr_db.py | 6 +++ neutron/tests/unit/db/test_l3_dvr_db.py | 54 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index cb5aefad121..5cc38af5881 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -357,6 +357,12 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, [fixedip for fixedip in cs_port['port']['fixed_ips'] if fixedip['subnet_id'] != subnet_id]) + + if len(fixed_ips) == len(cs_port['port']['fixed_ips']): + # The subnet being detached from router is not part of + # ipv6 router port. No need to update the multiprefix. + return False + if fixed_ips: # multiple prefix port - delete prefix from port self._core_plugin.update_port( diff --git a/neutron/tests/unit/db/test_l3_dvr_db.py b/neutron/tests/unit/db/test_l3_dvr_db.py index 38ffb4d9a4d..42d42e7618e 100644 --- a/neutron/tests/unit/db/test_l3_dvr_db.py +++ b/neutron/tests/unit/db/test_l3_dvr_db.py @@ -525,6 +525,60 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): self.ctx, filters=dvr_filters) self.assertEqual(1, len(dvr_ports)) + def test_remove_router_interface_csnat_ports_removal_with_ipv6(self): + router_dict = {'name': 'test_router', 'admin_state_up': True, + 'distributed': True} + router = self._create_router(router_dict) + plugin = mock.MagicMock() + with self.network() as net_ext, self.network() as net_int: + ext_net_id = net_ext['network']['id'] + self.core_plugin.update_network( + self.ctx, ext_net_id, + {'network': {'router:external': True}}) + self.mixin.update_router( + self.ctx, router['id'], + {'router': {'external_gateway_info': + {'network_id': ext_net_id}}}) + with self.subnet( + network=net_int, cidr='20.0.0.0/24') as subnet_v4,\ + self.subnet( + network=net_int, cidr='fe80::/64', + gateway_ip='fe80::1', ip_version=6) as subnet_v6: + self.mixin.add_router_interface(self.ctx, router['id'], + {'subnet_id': subnet_v4['subnet']['id']}) + self.mixin.add_router_interface(self.ctx, router['id'], + {'subnet_id': subnet_v6['subnet']['id']}) + csnat_filters = {'device_owner': + [l3_const.DEVICE_OWNER_ROUTER_SNAT]} + csnat_ports = self.core_plugin.get_ports( + self.ctx, filters=csnat_filters) + self.assertEqual(2, len(csnat_ports)) + dvr_filters = {'device_owner': + [l3_const.DEVICE_OWNER_DVR_INTERFACE]} + dvr_ports = self.core_plugin.get_ports( + self.ctx, filters=dvr_filters) + self.assertEqual(2, len(dvr_ports)) + with mock.patch.object( + manager.NeutronManager, + 'get_service_plugins') as get_svc_plugin: + get_svc_plugin.return_value = { + plugin_const.L3_ROUTER_NAT: plugin} + self.mixin.manager = manager + self.mixin.remove_router_interface( + self.ctx, router['id'], + {'subnet_id': subnet_v4['subnet']['id']}) + + csnat_ports = self.core_plugin.get_ports( + self.ctx, filters=csnat_filters) + self.assertEqual(1, len(csnat_ports)) + self.assertEqual( + subnet_v6['subnet']['id'], + csnat_ports[0]['fixed_ips'][0]['subnet_id']) + + dvr_ports = self.core_plugin.get_ports( + self.ctx, filters=dvr_filters) + self.assertEqual(1, len(dvr_ports)) + def test__validate_router_migration_notify_advanced_services(self): router = {'name': 'foo_router', 'admin_state_up': False} router_db = self._create_router(router)