]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix FloatingIP Namespace creation in DVR for Late Binding
authorSwaminathan Vasudevan <swaminathan.vasudevan@hp.com>
Fri, 24 Apr 2015 23:58:48 +0000 (16:58 -0700)
committerSwaminathan Vasudevan <swaminathan.vasudevan@hp.com>
Tue, 23 Jun 2015 18:24:44 +0000 (11:24 -0700)
DVR has dependency on the portbinding host to determine
where to start the FloatingIP Namespace when floatingip
is configured. But when we assign a floatingip to a port
that is not bound, even though the API will succeed, the
FloatingIP Namespace will not be created by the Agent and
so the FloatingIP will not be functional.

This patch addresses the issue by creating the Namespace
and configuring the rules when the late binding happens.

The agent will be requesting the FIP agent gateway port,
if required and then proceed to configure the FloatingIP
Namespace.

Change-Id: I9b9158bddb626c2bb535acd709452560546fd184
Closes-Bug: #1447034
Closes-Bug: #1460408

neutron/agent/l3/dvr_local_router.py
neutron/tests/functional/agent/test_l3_agent.py
neutron/tests/unit/agent/l3/test_agent.py

index 01f03487263c00835b4a2ea85a23383faabfc379..ead84e4e7bba955562b7d729481a047fcab0da56 100755 (executable)
@@ -417,6 +417,17 @@ class DvrLocalRouter(router.RouterInfo):
         is_first = False
         if floating_ips:
             is_first = self.fip_ns.subscribe(self.router_id)
+            if is_first and not fip_agent_port:
+                LOG.debug("No FloatingIP agent gateway port possibly due to "
+                          "late binding of the private port to the host, "
+                          "requesting agent gateway port for 'network-id' :"
+                          "%s", ex_gw_port['network_id'])
+                fip_agent_port = self.agent.plugin_rpc.get_agent_gateway_port(
+                    self.agent.context, ex_gw_port['network_id'])
+                if not fip_agent_port:
+                    LOG.error(_LE("No FloatingIP agent gateway port "
+                                  "returned from server for 'network-id': "
+                                  "%s"), ex_gw_port['network_id'])
             if is_first and fip_agent_port:
                 if 'subnets' not in fip_agent_port:
                     LOG.error(_LE('Missing subnet/agent_gateway_port'))
index f2674d82aaac2b82ca74ce09fa135d429b655444..6c28f7da47e25c239a27fa08a4f5ba169682b318 100644 (file)
@@ -1265,3 +1265,47 @@ class TestDvrRouter(L3AgentTestFramework):
             router.router_id, router.fip_ns.get_int_device_name,
             router.fip_ns.get_name())
         self.assertEqual(expected_mtu, dev_mtu)
+
+    def test_dvr_router_fip_agent_mismatch(self):
+        """Test to validate the floatingip agent mismatch.
+
+        This test validates the condition where floatingip agent
+        gateway port host mismatches with the agent and so the
+        binding will not be there.
+
+        """
+        self.agent.conf.agent_mode = 'dvr'
+        router_info = self.generate_dvr_router_info()
+        floating_ip = router_info['_floatingips'][0]
+        floating_ip['host'] = 'my_new_host'
+        # In this case the floatingip binding is different and so it
+        # should not create the floatingip namespace on the given agent.
+        # This is also like there is no current binding.
+        router1 = self.manage_router(self.agent, router_info)
+        fip_ns = router1.fip_ns.get_name()
+        self.assertTrue(self._namespace_exists(router1.ns_name))
+        self.assertFalse(self._namespace_exists(fip_ns))
+        self._assert_snat_namespace_does_not_exist(router1)
+
+    def test_dvr_router_fip_late_binding(self):
+        """Test to validate the floatingip migration or latebinding.
+
+        This test validates the condition where floatingip private
+        port changes while migration or when the private port host
+        binding is done later after floatingip association.
+
+        """
+        self.agent.conf.agent_mode = 'dvr'
+        router_info = self.generate_dvr_router_info()
+        fip_agent_gw_port = router_info[l3_constants.FLOATINGIP_AGENT_INTF_KEY]
+        # Now let us not pass the FLOATINGIP_AGENT_INTF_KEY, to emulate
+        # that the server did not create the port, since there was no valid
+        # host binding.
+        router_info[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = []
+        self.mock_plugin_api.get_agent_gateway_port.return_value = (
+            fip_agent_gw_port[0])
+        router1 = self.manage_router(self.agent, router_info)
+        fip_ns = router1.fip_ns.get_name()
+        self.assertTrue(self._namespace_exists(router1.ns_name))
+        self.assertTrue(self._namespace_exists(fip_ns))
+        self._assert_snat_namespace_does_not_exist(router1)
index 5042ce2874284ba519609cbe162b9302b7e099de..f6f67fac93cadf7a2126974ddb0f347e01245ab7 100644 (file)
@@ -847,6 +847,50 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
         ri.add_floating_ip.assert_called_once_with(
             floating_ips[0], mock.sentinel.interface_name, device)
 
+    @mock.patch.object(lla.LinkLocalAllocator, '_write')
+    def test_create_dvr_fip_interfaces_for_late_binding(self, lla_write):
+        fake_network_id = _uuid()
+        fake_subnet_id = _uuid()
+        fake_floatingips = {'floatingips': [
+            {'id': _uuid(),
+             'floating_ip_address': '20.0.0.3',
+             'fixed_ip_address': '192.168.0.1',
+             'floating_network_id': _uuid(),
+             'port_id': _uuid(),
+             'host': HOSTNAME}]}
+        agent_gateway_port = (
+            {'fixed_ips': [
+                {'ip_address': '20.0.0.30',
+                 'prefixlen': 24,
+                 'subnet_id': fake_subnet_id}],
+             'subnets': [
+                 {'id': fake_subnet_id,
+                  'gateway_ip': '20.0.0.1'}],
+             'id': _uuid(),
+             'network_id': fake_network_id,
+             'mac_address': 'ca:fe:de:ad:be:ef'}
+        )
+
+        router = l3_test_common.prepare_router_data(enable_snat=True)
+        router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
+        router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = []
+        router['distributed'] = True
+        agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
+        ri = dvr_router.DvrEdgeRouter(
+            agent, HOSTNAME, router['id'], router, **self.ri_kwargs)
+
+        ext_gw_port = ri.router.get('gw_port')
+        ri.fip_ns = agent.get_fip_ns(ext_gw_port['network_id'])
+        ri.dist_fip_count = 0
+        ri.fip_ns.subscribe = mock.Mock()
+        with mock.patch.object(agent.plugin_rpc,
+                               'get_agent_gateway_port') as fip_gw_port:
+            fip_gw_port.return_value = agent_gateway_port
+            ri.create_dvr_fip_interfaces(ext_gw_port)
+            self.assertTrue(fip_gw_port.called)
+            self.assertEqual(agent_gateway_port,
+                             ri.fip_ns.agent_gateway_port)
+
     @mock.patch.object(lla.LinkLocalAllocator, '_write')
     def test_create_dvr_fip_interfaces(self, lla_write):
         fake_network_id = _uuid()