From 84bbcb6f2a5400112751517e41bb50b5056220e0 Mon Sep 17 00:00:00 2001 From: Kevin Fox Date: Wed, 18 Feb 2015 14:01:49 -0800 Subject: [PATCH] Fixes floating IP regression with multiple routers During the refactor here: Change-Id: I09e8a694cdff7f64a642a39b45cbd12422132806 Too much code was removed and caused floating ips to get miss assigned when multiple routers with external networks in the same tenant are present. The first router in the tenant was always being chosen. This patch adds back some of the original code as well as a unit test. Change-Id: I6f663cb1ce3e4a1340c415d13787a9855c4dcac2 Closes-Bug: 1422476 --- neutron/db/l3_db.py | 13 +++++--- neutron/tests/unit/test_l3_plugin.py | 44 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 5d7d01781..7bc1d2d0e 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -716,10 +716,15 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): models_v2.IPAllocation.subnet_id == internal_subnet_id ) - router_port = routerport_qry.first() - - if router_port and router_port.router.gw_port: - return router_port.router.id + for router_port in routerport_qry: + router_id = router_port.router.id + router_gw_qry = context.session.query(models_v2.Port) + has_gw_port = router_gw_qry.filter_by( + network_id=external_network_id, + device_id=router_id, + device_owner=DEVICE_OWNER_ROUTER_GW).count() + if has_gw_port: + return router_id raise l3.ExternalGatewayForFloatingIPNotFound( subnet_id=internal_subnet_id, diff --git a/neutron/tests/unit/test_l3_plugin.py b/neutron/tests/unit/test_l3_plugin.py index 56cba4177..639b276d7 100644 --- a/neutron/tests/unit/test_l3_plugin.py +++ b/neutron/tests/unit/test_l3_plugin.py @@ -1998,6 +1998,50 @@ class L3NatTestCaseBase(L3NatTestCaseMixin): self._delete('floatingips', fp2['floatingip']['id']) self._delete('floatingips', fp3['floatingip']['id']) + def test_floatingip_multi_external_one_internal(self): + with contextlib.nested(self.subnet(cidr="10.0.0.0/24"), + self.subnet(cidr="11.0.0.0/24"), + self.subnet(cidr="12.0.0.0/24") + ) as (exs1, exs2, ins1): + network_ex_id1 = exs1['subnet']['network_id'] + network_ex_id2 = exs2['subnet']['network_id'] + self._set_net_external(network_ex_id1) + self._set_net_external(network_ex_id2) + + r2i_fixed_ips = [{'ip_address': '12.0.0.2'}] + with contextlib.nested(self.router(no_delete=True), + self.router(no_delete=True), + self.port(subnet=ins1, + fixed_ips=r2i_fixed_ips) + ) as (r1, r2, r2i_port): + self._add_external_gateway_to_router( + r1['router']['id'], + network_ex_id1) + self._router_interface_action('add', r1['router']['id'], + ins1['subnet']['id'], + None) + self._add_external_gateway_to_router( + r2['router']['id'], + network_ex_id2) + self._router_interface_action('add', r2['router']['id'], + None, + r2i_port['port']['id']) + + with self.port(subnet=ins1, + fixed_ips=[{'ip_address': '12.0.0.3'}] + ) as private_port: + + fp1 = self._make_floatingip(self.fmt, network_ex_id1, + private_port['port']['id'], + floating_ip='10.0.0.3') + fp2 = self._make_floatingip(self.fmt, network_ex_id2, + private_port['port']['id'], + floating_ip='11.0.0.3') + self.assertEqual(fp1['floatingip']['router_id'], + r1['router']['id']) + self.assertEqual(fp2['floatingip']['router_id'], + r2['router']['id']) + def test_floatingip_delete_router_intf_with_subnet_id_returns_409(self): found = False with self.floatingip_with_assoc(): -- 2.45.2