]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Reorganize and improve l3_agent functional tests
authorManjeet Singh Bhatia <manjeet.s.bhatia@intel.com>
Mon, 9 Nov 2015 22:03:15 +0000 (22:03 +0000)
committerManjeet Singh Bhatia <manjeet.s.bhatia@intel.com>
Fri, 20 Nov 2015 16:24:29 +0000 (16:24 +0000)
This will reorganize the l3_agent functional tests

Change-Id: I10008fd7216c8de47162657e280b7245c38f5154
Closes-Bug: #1501150

neutron/tests/functional/agent/l3/framework.py [new file with mode: 0644]
neutron/tests/functional/agent/l3/test_dvr_router.py [new file with mode: 0644]
neutron/tests/functional/agent/l3/test_ha_router.py [new file with mode: 0644]
neutron/tests/functional/agent/l3/test_legacy_router.py [new file with mode: 0644]
neutron/tests/functional/agent/l3/test_metadata_proxy.py [new file with mode: 0644]
neutron/tests/functional/agent/test_l3_agent.py

diff --git a/neutron/tests/functional/agent/l3/framework.py b/neutron/tests/functional/agent/l3/framework.py
new file mode 100644 (file)
index 0000000..465338a
--- /dev/null
@@ -0,0 +1,483 @@
+# Copyright (c) 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import functools
+
+import mock
+import netaddr
+import testtools
+
+from oslo_config import cfg
+from oslo_log import log as logging
+from oslo_utils import uuidutils
+
+from neutron.agent.common import config as agent_config
+from neutron.agent.common import ovs_lib
+from neutron.agent.l3 import agent as neutron_l3_agent
+from neutron.agent import l3_agent as l3_agent_main
+from neutron.agent.linux import external_process
+from neutron.agent.linux import ip_lib
+from neutron.agent.linux import utils
+from neutron.common import config as common_config
+from neutron.common import constants as l3_constants
+from neutron.common import utils as common_utils
+from neutron.tests.common import l3_test_common
+from neutron.tests.common import net_helpers
+from neutron.tests.functional import base
+
+
+LOG = logging.getLogger(__name__)
+_uuid = uuidutils.generate_uuid
+
+
+def get_ovs_bridge(br_name):
+    return ovs_lib.OVSBridge(br_name)
+
+
+class L3AgentTestFramework(base.BaseSudoTestCase):
+    def setUp(self):
+        super(L3AgentTestFramework, self).setUp()
+        self.mock_plugin_api = mock.patch(
+            'neutron.agent.l3.agent.L3PluginApi').start().return_value
+        mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
+        self.conf = self._configure_agent('agent1')
+        self.agent = neutron_l3_agent.L3NATAgentWithStateReport('agent1',
+                                                                self.conf)
+
+    def _get_config_opts(self):
+        config = cfg.ConfigOpts()
+        config.register_opts(common_config.core_opts)
+        config.register_opts(common_config.core_cli_opts)
+        logging.register_options(config)
+        agent_config.register_process_monitor_opts(config)
+        return config
+
+    def _configure_agent(self, host, agent_mode='dvr_snat'):
+        conf = self._get_config_opts()
+        l3_agent_main.register_opts(conf)
+        conf.set_override(
+            'interface_driver',
+            'neutron.agent.linux.interface.OVSInterfaceDriver')
+
+        br_int = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
+        br_ex = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
+        conf.set_override('ovs_integration_bridge', br_int.br_name)
+        conf.set_override('external_network_bridge', br_ex.br_name)
+
+        temp_dir = self.get_new_temp_dir()
+        get_temp_file_path = functools.partial(self.get_temp_file_path,
+                                               root=temp_dir)
+        conf.set_override('state_path', temp_dir.path)
+        # NOTE(cbrandily): log_file or log_dir must be set otherwise
+        # metadata_proxy_watch_log has no effect
+        conf.set_override('log_file',
+                          get_temp_file_path('log_file'))
+        conf.set_override('metadata_proxy_socket',
+                          get_temp_file_path('metadata_proxy'))
+        conf.set_override('ha_confs_path',
+                          get_temp_file_path('ha_confs'))
+        conf.set_override('external_pids',
+                          get_temp_file_path('external/pids'))
+        conf.set_override('host', host)
+        conf.set_override('agent_mode', agent_mode)
+
+        return conf
+
+    def _get_agent_ovs_integration_bridge(self, agent):
+        return get_ovs_bridge(agent.conf.ovs_integration_bridge)
+
+    def generate_router_info(self, enable_ha, ip_version=4, extra_routes=True,
+                             enable_fip=True, enable_snat=True,
+                             dual_stack=False, v6_ext_gw_with_sub=True):
+        if ip_version == 6 and not dual_stack:
+            enable_snat = False
+            enable_fip = False
+            extra_routes = False
+
+        return l3_test_common.prepare_router_data(ip_version=ip_version,
+                                                 enable_snat=enable_snat,
+                                                 enable_floating_ip=enable_fip,
+                                                 enable_ha=enable_ha,
+                                                 extra_routes=extra_routes,
+                                                 dual_stack=dual_stack,
+                                                 v6_ext_gw_with_sub=(
+                                                     v6_ext_gw_with_sub))
+
+    def _test_conntrack_disassociate_fip(self, ha):
+        '''Test that conntrack immediately drops stateful connection
+           that uses floating IP once it's disassociated.
+        '''
+        router_info = self.generate_router_info(enable_ha=ha)
+        router = self.manage_router(self.agent, router_info)
+
+        port = net_helpers.get_free_namespace_port(l3_constants.PROTO_NAME_TCP,
+                                                   router.ns_name)
+        client_address = '19.4.4.3'
+        server_address = '35.4.0.4'
+
+        def clean_fips(router):
+            router.router[l3_constants.FLOATINGIP_KEY] = []
+
+        clean_fips(router)
+        self._add_fip(router, client_address, fixed_address=server_address)
+        router.process(self.agent)
+
+        router_ns = ip_lib.IPWrapper(namespace=router.ns_name)
+        netcat = net_helpers.NetcatTester(
+            router.ns_name, router.ns_name, client_address, port,
+            protocol=net_helpers.NetcatTester.TCP)
+        self.addCleanup(netcat.stop_processes)
+
+        def assert_num_of_conntrack_rules(n):
+            out = router_ns.netns.execute(["conntrack", "-L",
+                                           "--orig-src", client_address])
+            self.assertEqual(
+                n, len([line for line in out.strip().split('\n') if line]))
+
+        if ha:
+            utils.wait_until_true(lambda: router.ha_state == 'master')
+
+        with self.assert_max_execution_time(100):
+            assert_num_of_conntrack_rules(0)
+
+            self.assertTrue(netcat.test_connectivity())
+            assert_num_of_conntrack_rules(1)
+
+            clean_fips(router)
+            router.process(self.agent)
+            assert_num_of_conntrack_rules(0)
+
+            with testtools.ExpectedException(RuntimeError):
+                netcat.test_connectivity()
+
+    def _gateway_check(self, gateway_ip, external_device):
+        expected_gateway = gateway_ip
+        ip_vers = netaddr.IPAddress(expected_gateway).version
+        existing_gateway = (external_device.route.get_gateway(
+            ip_version=ip_vers).get('gateway'))
+        self.assertEqual(expected_gateway, existing_gateway)
+
+    def _assert_ha_device(self, router):
+        def ha_router_dev_name_getter(not_used):
+            return router.get_ha_device_name()
+        self.assertTrue(self.device_exists_with_ips_and_mac(
+            router.router[l3_constants.HA_INTERFACE_KEY],
+            ha_router_dev_name_getter, router.ns_name))
+
+    def _assert_gateway(self, router, v6_ext_gw_with_sub=True):
+        external_port = router.get_ex_gw_port()
+        external_device_name = router.get_external_device_name(
+            external_port['id'])
+        external_device = ip_lib.IPDevice(external_device_name,
+                                          namespace=router.ns_name)
+        for subnet in external_port['subnets']:
+            self._gateway_check(subnet['gateway_ip'], external_device)
+        if not v6_ext_gw_with_sub:
+            self._gateway_check(self.agent.conf.ipv6_gateway,
+                                external_device)
+
+    def _assert_external_device(self, router):
+        external_port = router.get_ex_gw_port()
+        self.assertTrue(self.device_exists_with_ips_and_mac(
+            external_port, router.get_external_device_name,
+            router.ns_name))
+
+    def _router_lifecycle(self, enable_ha, ip_version=4,
+                          dual_stack=False, v6_ext_gw_with_sub=True):
+        router_info = self.generate_router_info(enable_ha, ip_version,
+                                                dual_stack=dual_stack,
+                                                v6_ext_gw_with_sub=(
+                                                    v6_ext_gw_with_sub))
+        router = self.manage_router(self.agent, router_info)
+
+        # Add multiple-IPv6-prefix internal router port
+        slaac = l3_constants.IPV6_SLAAC
+        slaac_mode = {'ra_mode': slaac, 'address_mode': slaac}
+        subnet_modes = [slaac_mode] * 2
+        self._add_internal_interface_by_subnet(router.router,
+                                               count=2,
+                                               ip_version=6,
+                                               ipv6_subnet_modes=subnet_modes)
+        router.process(self.agent)
+
+        if enable_ha:
+            port = router.get_ex_gw_port()
+            interface_name = router.get_external_device_name(port['id'])
+            self._assert_no_ip_addresses_on_interface(router.ns_name,
+                                                      interface_name)
+            utils.wait_until_true(lambda: router.ha_state == 'master')
+
+            # Keepalived notifies of a state transition when it starts,
+            # not when it ends. Thus, we have to wait until keepalived finishes
+            # configuring everything. We verify this by waiting until the last
+            # device has an IP address.
+            device = router.router[l3_constants.INTERFACE_KEY][-1]
+            device_exists = functools.partial(
+                self.device_exists_with_ips_and_mac,
+                device,
+                router.get_internal_device_name,
+                router.ns_name)
+            utils.wait_until_true(device_exists)
+
+        self.assertTrue(self._namespace_exists(router.ns_name))
+        utils.wait_until_true(
+            lambda: self._metadata_proxy_exists(self.agent.conf, router))
+        self._assert_internal_devices(router)
+        self._assert_external_device(router)
+        if not (enable_ha and (ip_version == 6 or dual_stack)):
+            # Note(SridharG): enable the assert_gateway for IPv6 once
+            # keepalived on Ubuntu14.04 (i.e., check-neutron-dsvm-functional
+            # platform) is updated to 1.2.10 (or above).
+            # For more details: https://review.openstack.org/#/c/151284/
+            self._assert_gateway(router, v6_ext_gw_with_sub)
+            self.assertTrue(self.floating_ips_configured(router))
+            self._assert_snat_chains(router)
+            self._assert_floating_ip_chains(router)
+            self._assert_extra_routes(router)
+            ip_versions = [4, 6] if (ip_version == 6 or dual_stack) else [4]
+            self._assert_onlink_subnet_routes(router, ip_versions)
+        self._assert_metadata_chains(router)
+
+        # Verify router gateway interface is configured to receive Router Advts
+        # when IPv6 is enabled and no IPv6 gateway is configured.
+        if router.use_ipv6 and not v6_ext_gw_with_sub:
+            if not self.agent.conf.ipv6_gateway:
+                external_port = router.get_ex_gw_port()
+                external_device_name = router.get_external_device_name(
+                    external_port['id'])
+                ip_wrapper = ip_lib.IPWrapper(namespace=router.ns_name)
+                ra_state = ip_wrapper.netns.execute(['sysctl', '-b',
+                    'net.ipv6.conf.%s.accept_ra' % external_device_name])
+                self.assertEqual('2', ra_state)
+
+        if enable_ha:
+            self._assert_ha_device(router)
+            self.assertTrue(router.keepalived_manager.get_process().active)
+
+        self._delete_router(self.agent, router.router_id)
+
+        self._assert_interfaces_deleted_from_ovs()
+        self._assert_router_does_not_exist(router)
+        if enable_ha:
+            self.assertFalse(router.keepalived_manager.get_process().active)
+
+    def manage_router(self, agent, router):
+        self.addCleanup(agent._safe_router_removed, router['id'])
+        agent._process_added_router(router)
+        return agent.router_info[router['id']]
+
+    def _delete_router(self, agent, router_id):
+        agent._router_removed(router_id)
+
+    def _add_fip(self, router, fip_address, fixed_address='10.0.0.2',
+                 host=None):
+        fip = {'id': _uuid(),
+               'port_id': _uuid(),
+               'floating_ip_address': fip_address,
+               'fixed_ip_address': fixed_address,
+               'host': host}
+        router.router[l3_constants.FLOATINGIP_KEY].append(fip)
+
+    def _add_internal_interface_by_subnet(self, router, count=1,
+                                          ip_version=4,
+                                          ipv6_subnet_modes=None,
+                                          interface_id=None):
+        return l3_test_common.router_append_subnet(router, count,
+                ip_version, ipv6_subnet_modes, interface_id)
+
+    def _namespace_exists(self, namespace):
+        ip = ip_lib.IPWrapper(namespace=namespace)
+        return ip.netns.exists(namespace)
+
+    def _metadata_proxy_exists(self, conf, router):
+        pm = external_process.ProcessManager(
+            conf,
+            router.router_id,
+            router.ns_name)
+        return pm.active
+
+    def device_exists_with_ips_and_mac(self, expected_device, name_getter,
+                                       namespace):
+        ip_cidrs = common_utils.fixed_ip_cidrs(expected_device['fixed_ips'])
+        return ip_lib.device_exists_with_ips_and_mac(
+            name_getter(expected_device['id']), ip_cidrs,
+            expected_device['mac_address'], namespace)
+
+    @staticmethod
+    def _port_first_ip_cidr(port):
+        fixed_ip = port['fixed_ips'][0]
+        return common_utils.ip_to_cidr(fixed_ip['ip_address'],
+                                       fixed_ip['prefixlen'])
+
+    def get_device_mtu(self, target_device, name_getter, namespace):
+        device = ip_lib.IPDevice(name_getter(target_device), namespace)
+        return device.link.mtu
+
+    def get_expected_keepalive_configuration(self, router):
+        ha_device_name = router.get_ha_device_name()
+        external_port = router.get_ex_gw_port()
+        ex_port_ipv6 = ip_lib.get_ipv6_lladdr(external_port['mac_address'])
+        external_device_name = router.get_external_device_name(
+            external_port['id'])
+        external_device_cidr = self._port_first_ip_cidr(external_port)
+        internal_port = router.router[l3_constants.INTERFACE_KEY][0]
+        int_port_ipv6 = ip_lib.get_ipv6_lladdr(internal_port['mac_address'])
+        internal_device_name = router.get_internal_device_name(
+            internal_port['id'])
+        internal_device_cidr = self._port_first_ip_cidr(internal_port)
+        floating_ip_cidr = common_utils.ip_to_cidr(
+            router.get_floating_ips()[0]['floating_ip_address'])
+        default_gateway_ip = external_port['subnets'][0].get('gateway_ip')
+        extra_subnet_cidr = external_port['extra_subnets'][0].get('cidr')
+        return """vrrp_instance VR_1 {
+    state BACKUP
+    interface %(ha_device_name)s
+    virtual_router_id 1
+    priority 50
+    garp_master_repeat 5
+    garp_master_refresh 10
+    nopreempt
+    advert_int 2
+    track_interface {
+        %(ha_device_name)s
+    }
+    virtual_ipaddress {
+        169.254.0.1/24 dev %(ha_device_name)s
+    }
+    virtual_ipaddress_excluded {
+        %(floating_ip_cidr)s dev %(external_device_name)s
+        %(external_device_cidr)s dev %(external_device_name)s
+        %(internal_device_cidr)s dev %(internal_device_name)s
+        %(ex_port_ipv6)s dev %(external_device_name)s scope link
+        %(int_port_ipv6)s dev %(internal_device_name)s scope link
+    }
+    virtual_routes {
+        0.0.0.0/0 via %(default_gateway_ip)s dev %(external_device_name)s
+        8.8.8.0/24 via 19.4.4.4
+        %(extra_subnet_cidr)s dev %(external_device_name)s scope link
+    }
+}""" % {
+            'ha_device_name': ha_device_name,
+            'external_device_name': external_device_name,
+            'external_device_cidr': external_device_cidr,
+            'internal_device_name': internal_device_name,
+            'internal_device_cidr': internal_device_cidr,
+            'floating_ip_cidr': floating_ip_cidr,
+            'default_gateway_ip': default_gateway_ip,
+            'int_port_ipv6': int_port_ipv6,
+            'ex_port_ipv6': ex_port_ipv6,
+            'extra_subnet_cidr': extra_subnet_cidr,
+        }
+
+    def _get_rule(self, iptables_manager, table, chain, predicate):
+        rules = iptables_manager.get_chain(table, chain)
+        result = next(rule for rule in rules if predicate(rule))
+        return result
+
+    def _assert_router_does_not_exist(self, router):
+        # If the namespace assertion succeeds
+        # then the devices and iptable rules have also been deleted,
+        # so there's no need to check that explicitly.
+        self.assertFalse(self._namespace_exists(router.ns_name))
+        utils.wait_until_true(
+            lambda: not self._metadata_proxy_exists(self.agent.conf, router))
+
+    def _assert_snat_chains(self, router):
+        self.assertFalse(router.iptables_manager.is_chain_empty(
+            'nat', 'snat'))
+        self.assertFalse(router.iptables_manager.is_chain_empty(
+            'nat', 'POSTROUTING'))
+
+    def _assert_floating_ip_chains(self, router):
+        self.assertFalse(router.iptables_manager.is_chain_empty(
+            'nat', 'float-snat'))
+
+    def _assert_metadata_chains(self, router):
+        metadata_port_filter = lambda rule: (
+            str(self.agent.conf.metadata_port) in rule.rule)
+        self.assertTrue(self._get_rule(router.iptables_manager,
+                                       'nat',
+                                       'PREROUTING',
+                                       metadata_port_filter))
+        self.assertTrue(self._get_rule(router.iptables_manager,
+                                       'filter',
+                                       'INPUT',
+                                       metadata_port_filter))
+
+    def _assert_internal_devices(self, router):
+        internal_devices = router.router[l3_constants.INTERFACE_KEY]
+        self.assertTrue(len(internal_devices))
+        for device in internal_devices:
+            self.assertTrue(self.device_exists_with_ips_and_mac(
+                device, router.get_internal_device_name, router.ns_name))
+
+    def _assert_extra_routes(self, router):
+        routes = ip_lib.get_routing_table(4, namespace=router.ns_name)
+        routes = [{'nexthop': route['nexthop'],
+                   'destination': route['destination']} for route in routes]
+
+        for extra_route in router.router['routes']:
+            self.assertIn(extra_route, routes)
+
+    def _assert_onlink_subnet_routes(
+            self, router, ip_versions, namespace=None):
+        ns_name = namespace or router.ns_name
+        routes = []
+        for ip_version in ip_versions:
+            _routes = ip_lib.get_routing_table(ip_version,
+                                               namespace=ns_name)
+            routes.extend(_routes)
+        routes = set(route['destination'] for route in routes)
+        extra_subnets = router.get_ex_gw_port()['extra_subnets']
+        for extra_subnet in (route['cidr'] for route in extra_subnets):
+            self.assertIn(extra_subnet, routes)
+
+    def _assert_interfaces_deleted_from_ovs(self):
+
+        def assert_ovs_bridge_empty(bridge_name):
+            bridge = ovs_lib.OVSBridge(bridge_name)
+            self.assertFalse(bridge.get_port_name_list())
+
+        assert_ovs_bridge_empty(self.agent.conf.ovs_integration_bridge)
+        assert_ovs_bridge_empty(self.agent.conf.external_network_bridge)
+
+    def floating_ips_configured(self, router):
+        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
+        external_port = router.get_ex_gw_port()
+        return len(floating_ips) and all(
+            ip_lib.device_exists_with_ips_and_mac(
+                router.get_external_device_name(external_port['id']),
+                ['%s/32' % fip['floating_ip_address']],
+                external_port['mac_address'],
+                namespace=router.ns_name) for fip in floating_ips)
+
+    def fail_ha_router(self, router):
+        device_name = router.get_ha_device_name()
+        ha_device = ip_lib.IPDevice(device_name, router.ha_namespace)
+        ha_device.link.set_down()
+
+    @classmethod
+    def _get_addresses_on_device(cls, namespace, interface):
+        return [address['cidr'] for address in
+                ip_lib.IPDevice(interface, namespace=namespace).addr.list()]
+
+    def _assert_no_ip_addresses_on_interface(self, namespace, interface):
+        self.assertEqual(
+            [], self._get_addresses_on_device(namespace, interface))
+
+    def _assert_ip_address_on_interface(self,
+                                        namespace, interface, ip_address):
+        self.assertIn(
+            ip_address, self._get_addresses_on_device(namespace, interface))
diff --git a/neutron/tests/functional/agent/l3/test_dvr_router.py b/neutron/tests/functional/agent/l3/test_dvr_router.py
new file mode 100644 (file)
index 0000000..1cdb84b
--- /dev/null
@@ -0,0 +1,637 @@
+# Copyright (c) 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import functools
+
+import mock
+import netaddr
+
+from neutron.agent.l3 import agent as neutron_l3_agent
+from neutron.agent.l3 import dvr_snat_ns
+from neutron.agent.l3 import namespaces
+from neutron.agent.linux import ip_lib
+from neutron.agent.linux import utils
+from neutron.common import constants as l3_constants
+from neutron.tests.common import l3_test_common
+from neutron.tests.common import net_helpers
+from neutron.tests.functional.agent.l3 import framework
+
+
+DEVICE_OWNER_COMPUTE = l3_constants.DEVICE_OWNER_COMPUTE_PREFIX + 'fake'
+
+
+class TestDvrRouter(framework.L3AgentTestFramework):
+    def test_dvr_router_lifecycle_without_ha_without_snat_with_fips(self):
+        self._dvr_router_lifecycle(enable_ha=False, enable_snat=False)
+
+    def test_dvr_router_lifecycle_without_ha_with_snat_with_fips(self):
+        self._dvr_router_lifecycle(enable_ha=False, enable_snat=True)
+
+    def test_dvr_router_lifecycle_ha_with_snat_with_fips(self):
+        self._dvr_router_lifecycle(enable_ha=True, enable_snat=True)
+
+    def _helper_create_dvr_router_fips_for_ext_network(
+            self, agent_mode, **dvr_router_kwargs):
+        self.agent.conf.agent_mode = agent_mode
+        router_info = self.generate_dvr_router_info(**dvr_router_kwargs)
+        self.mock_plugin_api.get_external_network_id.return_value = (
+            router_info['_floatingips'][0]['floating_network_id'])
+        router = self.manage_router(self.agent, router_info)
+        fip_ns = router.fip_ns.get_name()
+        return router, fip_ns
+
+    def _validate_fips_for_external_network(self, router, fip_ns):
+        self.assertTrue(self._namespace_exists(router.ns_name))
+        self.assertTrue(self._namespace_exists(fip_ns))
+        self._assert_dvr_floating_ips(router)
+        self._assert_snat_namespace_does_not_exist(router)
+
+    def test_dvr_router_fips_for_multiple_ext_networks(self):
+        agent_mode = 'dvr'
+        # Create the first router fip with external net1
+        dvr_router1_kwargs = {'ip_address': '19.4.4.3',
+                              'subnet_cidr': '19.4.4.0/24',
+                              'gateway_ip': '19.4.4.1',
+                              'gateway_mac': 'ca:fe:de:ab:cd:ef'}
+        router1, fip1_ns = (
+            self._helper_create_dvr_router_fips_for_ext_network(
+                agent_mode, **dvr_router1_kwargs))
+        # Validate the fip with external net1
+        self._validate_fips_for_external_network(router1, fip1_ns)
+
+        # Create the second router fip with external net2
+        dvr_router2_kwargs = {'ip_address': '19.4.5.3',
+                              'subnet_cidr': '19.4.5.0/24',
+                              'gateway_ip': '19.4.5.1',
+                              'gateway_mac': 'ca:fe:de:ab:cd:fe'}
+        router2, fip2_ns = (
+            self._helper_create_dvr_router_fips_for_ext_network(
+                agent_mode, **dvr_router2_kwargs))
+        # Validate the fip with external net2
+        self._validate_fips_for_external_network(router2, fip2_ns)
+
+    def _dvr_router_lifecycle(self, enable_ha=False, enable_snat=False,
+                              custom_mtu=2000,
+                              ip_version=4,
+                              dual_stack=False):
+        '''Test dvr router lifecycle
+
+        :param enable_ha: sets the ha value for the router.
+        :param enable_snat:  the value of enable_snat is used
+        to  set the  agent_mode.
+        '''
+
+        # The value of agent_mode can be dvr, dvr_snat, or legacy.
+        # Since by definition this is a dvr (distributed = true)
+        # only dvr and dvr_snat are applicable
+        self.agent.conf.agent_mode = 'dvr_snat' if enable_snat else 'dvr'
+        self.agent.conf.network_device_mtu = custom_mtu
+
+        # We get the router info particular to a dvr router
+        router_info = self.generate_dvr_router_info(
+            enable_ha, enable_snat)
+
+        # We need to mock the get_agent_gateway_port return value
+        # because the whole L3PluginApi is mocked and we need the port
+        # gateway_port information before the l3_agent will create it.
+        # The port returned needs to have the same information as
+        # router_info['gw_port']
+        self.mock_plugin_api.get_agent_gateway_port.return_value = router_info[
+            'gw_port']
+
+        # We also need to mock the get_external_network_id method to
+        # get the correct fip namespace.
+        self.mock_plugin_api.get_external_network_id.return_value = (
+            router_info['_floatingips'][0]['floating_network_id'])
+
+        # With all that set we can now ask the l3_agent to
+        # manage the router (create it, create namespaces,
+        # attach interfaces, etc...)
+        router = self.manage_router(self.agent, router_info)
+        if enable_ha:
+            port = router.get_ex_gw_port()
+            interface_name = router.get_external_device_name(port['id'])
+            self._assert_no_ip_addresses_on_interface(router.ha_namespace,
+                                                      interface_name)
+            utils.wait_until_true(lambda: router.ha_state == 'master')
+
+            # Keepalived notifies of a state transition when it starts,
+            # not when it ends. Thus, we have to wait until keepalived finishes
+            # configuring everything. We verify this by waiting until the last
+            # device has an IP address.
+            device = router.router[l3_constants.INTERFACE_KEY][-1]
+            device_exists = functools.partial(
+                self.device_exists_with_ips_and_mac,
+                device,
+                router.get_internal_device_name,
+                router.ns_name)
+            utils.wait_until_true(device_exists)
+
+        ext_gateway_port = router_info['gw_port']
+        self.assertTrue(self._namespace_exists(router.ns_name))
+        utils.wait_until_true(
+            lambda: self._metadata_proxy_exists(self.agent.conf, router))
+        self._assert_internal_devices(router)
+        self._assert_dvr_external_device(router)
+        self._assert_dvr_gateway(router)
+        self._assert_dvr_floating_ips(router)
+        self._assert_snat_chains(router)
+        self._assert_floating_ip_chains(router)
+        self._assert_metadata_chains(router)
+        self._assert_extra_routes(router)
+        self._assert_rfp_fpr_mtu(router, custom_mtu)
+        if enable_snat:
+            ip_versions = [4, 6] if (ip_version == 6 or dual_stack) else [4]
+            snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+                router.router_id)
+            self._assert_onlink_subnet_routes(
+                router, ip_versions, snat_ns_name)
+
+        self._delete_router(self.agent, router.router_id)
+        self._assert_fip_namespace_deleted(ext_gateway_port)
+        self._assert_router_does_not_exist(router)
+        self._assert_snat_namespace_does_not_exist(router)
+
+    def generate_dvr_router_info(self,
+                                 enable_ha=False,
+                                 enable_snat=False,
+                                 agent=None,
+                                 **kwargs):
+        if not agent:
+            agent = self.agent
+        router = l3_test_common.prepare_router_data(
+            enable_snat=enable_snat,
+            enable_floating_ip=True,
+            enable_ha=enable_ha,
+            **kwargs)
+        internal_ports = router.get(l3_constants.INTERFACE_KEY, [])
+        router['distributed'] = True
+        router['gw_port_host'] = agent.conf.host
+        router['gw_port']['binding:host_id'] = agent.conf.host
+        floating_ip = router['_floatingips'][0]
+        floating_ip['floating_network_id'] = router['gw_port']['network_id']
+        floating_ip['host'] = agent.conf.host
+        floating_ip['port_id'] = internal_ports[0]['id']
+        floating_ip['status'] = 'ACTIVE'
+
+        self._add_snat_port_info_to_router(router, internal_ports)
+        # FIP has a dependency on external gateway. So we need to create
+        # the snat_port info and fip_agent_gw_port_info irrespective of
+        # the agent type the dvr supports. The namespace creation is
+        # dependent on the agent_type.
+        external_gw_port = router['gw_port']
+        self._add_fip_agent_gw_port_info_to_router(router, external_gw_port)
+        return router
+
+    def _add_fip_agent_gw_port_info_to_router(self, router, external_gw_port):
+        # Add fip agent gateway port information to the router_info
+        fip_gw_port_list = router.get(
+            l3_constants.FLOATINGIP_AGENT_INTF_KEY, [])
+        if not fip_gw_port_list and external_gw_port:
+            # Get values from external gateway port
+            fixed_ip = external_gw_port['fixed_ips'][0]
+            float_subnet = external_gw_port['subnets'][0]
+            port_ip = fixed_ip['ip_address']
+            # Pick an ip address which is not the same as port_ip
+            fip_gw_port_ip = str(netaddr.IPAddress(port_ip) + 5)
+            # Add floatingip agent gateway port info to router
+            prefixlen = netaddr.IPNetwork(float_subnet['cidr']).prefixlen
+            router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = [
+                {'subnets': [
+                    {'cidr': float_subnet['cidr'],
+                     'gateway_ip': float_subnet['gateway_ip'],
+                     'id': fixed_ip['subnet_id']}],
+                 'network_id': external_gw_port['network_id'],
+                 'device_owner': l3_constants.DEVICE_OWNER_AGENT_GW,
+                 'mac_address': 'fa:16:3e:80:8d:89',
+                 'binding:host_id': self.agent.conf.host,
+                 'fixed_ips': [{'subnet_id': fixed_ip['subnet_id'],
+                                'ip_address': fip_gw_port_ip,
+                                'prefixlen': prefixlen}],
+                 'id': framework._uuid(),
+                 'device_id': framework._uuid()}
+            ]
+
+    def _add_snat_port_info_to_router(self, router, internal_ports):
+        # Add snat port information to the router
+        snat_port_list = router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
+        if not snat_port_list and internal_ports:
+            # Get values from internal port
+            port = internal_ports[0]
+            fixed_ip = port['fixed_ips'][0]
+            snat_subnet = port['subnets'][0]
+            port_ip = fixed_ip['ip_address']
+            # Pick an ip address which is not the same as port_ip
+            snat_ip = str(netaddr.IPAddress(port_ip) + 5)
+            # Add the info to router as the first snat port
+            # in the list of snat ports
+            prefixlen = netaddr.IPNetwork(snat_subnet['cidr']).prefixlen
+            router[l3_constants.SNAT_ROUTER_INTF_KEY] = [
+                {'subnets': [
+                    {'cidr': snat_subnet['cidr'],
+                     'gateway_ip': snat_subnet['gateway_ip'],
+                     'id': fixed_ip['subnet_id']}],
+                 'network_id': port['network_id'],
+                 'device_owner': l3_constants.DEVICE_OWNER_ROUTER_SNAT,
+                 'mac_address': 'fa:16:3e:80:8d:89',
+                 'fixed_ips': [{'subnet_id': fixed_ip['subnet_id'],
+                                'ip_address': snat_ip,
+                                'prefixlen': prefixlen}],
+                 'id': framework._uuid(),
+                 'device_id': framework._uuid()}
+            ]
+
+    def _assert_dvr_external_device(self, router):
+        external_port = router.get_ex_gw_port()
+        snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+
+        # if the agent is in dvr_snat mode, then we have to check
+        # that the correct ports and ip addresses exist in the
+        # snat_ns_name namespace
+        if self.agent.conf.agent_mode == 'dvr_snat':
+            device_exists = functools.partial(
+                self.device_exists_with_ips_and_mac,
+                external_port,
+                router.get_external_device_name,
+                snat_ns_name)
+            utils.wait_until_true(device_exists)
+        # if the agent is in dvr mode then the snat_ns_name namespace
+        # should not be present at all:
+        elif self.agent.conf.agent_mode == 'dvr':
+            self.assertFalse(
+                self._namespace_exists(snat_ns_name),
+                "namespace %s was found but agent is in dvr mode not dvr_snat"
+                % (str(snat_ns_name))
+            )
+        # if the agent is anything else the test is misconfigured
+        # we force a test failure with message
+        else:
+            self.assertTrue(False, " agent not configured for dvr or dvr_snat")
+
+    def _assert_dvr_gateway(self, router):
+        gateway_expected_in_snat_namespace = (
+            self.agent.conf.agent_mode == 'dvr_snat'
+        )
+        if gateway_expected_in_snat_namespace:
+            self._assert_dvr_snat_gateway(router)
+            self._assert_removal_of_already_deleted_gateway_device(router)
+
+        snat_namespace_should_not_exist = (
+            self.agent.conf.agent_mode == 'dvr'
+        )
+        if snat_namespace_should_not_exist:
+            self._assert_snat_namespace_does_not_exist(router)
+
+    def _assert_dvr_snat_gateway(self, router):
+        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+        external_port = router.get_ex_gw_port()
+        external_device_name = router.get_external_device_name(
+            external_port['id'])
+        external_device = ip_lib.IPDevice(external_device_name,
+                                          namespace=namespace)
+        existing_gateway = (
+            external_device.route.get_gateway().get('gateway'))
+        expected_gateway = external_port['subnets'][0]['gateway_ip']
+        self.assertEqual(expected_gateway, existing_gateway)
+
+    def _assert_removal_of_already_deleted_gateway_device(self, router):
+        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+        device = ip_lib.IPDevice("fakedevice",
+                                 namespace=namespace)
+
+        # Assert that no exception is thrown for this case
+        self.assertIsNone(router._delete_gateway_device_if_exists(
+                          device, "192.168.0.1", 0))
+
+    def _assert_snat_namespace_does_not_exist(self, router):
+        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+        self.assertFalse(self._namespace_exists(namespace))
+
+    def _assert_dvr_floating_ips(self, router):
+        # in the fip namespace:
+        # Check that the fg-<port-id> (floatingip_agent_gateway)
+        # is created with the ip address of the external gateway port
+        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
+        self.assertTrue(floating_ips)
+        # We need to fetch the floatingip agent gateway port info
+        # from the router_info
+        floating_agent_gw_port = (
+            router.router[l3_constants.FLOATINGIP_AGENT_INTF_KEY])
+        self.assertTrue(floating_agent_gw_port)
+
+        external_gw_port = floating_agent_gw_port[0]
+        fip_ns = self.agent.get_fip_ns(floating_ips[0]['floating_network_id'])
+        fip_ns_name = fip_ns.get_name()
+        fg_port_created_successfully = ip_lib.device_exists_with_ips_and_mac(
+            fip_ns.get_ext_device_name(external_gw_port['id']),
+            [self._port_first_ip_cidr(external_gw_port)],
+            external_gw_port['mac_address'],
+            namespace=fip_ns_name)
+        self.assertTrue(fg_port_created_successfully)
+        # Check fpr-router device has been created
+        device_name = fip_ns.get_int_device_name(router.router_id)
+        fpr_router_device_created_successfully = ip_lib.device_exists(
+            device_name, namespace=fip_ns_name)
+        self.assertTrue(fpr_router_device_created_successfully)
+
+        # In the router namespace
+        # Check rfp-<router-id> is created correctly
+        for fip in floating_ips:
+            device_name = fip_ns.get_rtr_ext_device_name(router.router_id)
+            self.assertTrue(ip_lib.device_exists(
+                device_name, namespace=router.ns_name))
+
+    def test_dvr_router_rem_fips_on_restarted_agent(self):
+        self.agent.conf.agent_mode = 'dvr_snat'
+        router_info = self.generate_dvr_router_info()
+        router1 = self.manage_router(self.agent, router_info)
+        fip_ns = router1.fip_ns.get_name()
+        self.assertTrue(self._namespace_exists(fip_ns))
+        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            self.agent.host, self.agent.conf)
+        router1.router[l3_constants.FLOATINGIP_KEY] = []
+        self.manage_router(restarted_agent, router1.router)
+        self._assert_dvr_snat_gateway(router1)
+        self.assertTrue(self._namespace_exists(fip_ns))
+
+    def test_dvr_router_add_fips_on_restarted_agent(self):
+        self.agent.conf.agent_mode = 'dvr'
+        router_info = self.generate_dvr_router_info()
+        router = self.manage_router(self.agent, router_info)
+        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
+        router_ns = router.ns_name
+        fip_rule_prio_1 = self._get_fixed_ip_rule_priority(
+            router_ns, floating_ips[0]['fixed_ip_address'])
+        restarted_agent = neutron_l3_agent.L3NATAgent(
+            self.agent.host, self.agent.conf)
+        floating_ips[0]['floating_ip_address'] = '21.4.4.2'
+        floating_ips[0]['fixed_ip_address'] = '10.0.0.2'
+        self.manage_router(restarted_agent, router_info)
+        fip_rule_prio_2 = self._get_fixed_ip_rule_priority(
+            router_ns, floating_ips[0]['fixed_ip_address'])
+        self.assertNotEqual(fip_rule_prio_1, fip_rule_prio_2)
+
+    def _get_fixed_ip_rule_priority(self, namespace, fip):
+        iprule = ip_lib.IPRule(namespace)
+        lines = iprule.rule._as_root([4], ['show']).splitlines()
+        for line in lines:
+            if fip in line:
+                info = iprule.rule._parse_line(4, line)
+                return info['priority']
+
+    def test_dvr_router_add_internal_network_set_arp_cache(self):
+        # Check that, when the router is set up and there are
+        # existing ports on the uplinked subnet, the ARP
+        # cache is properly populated.
+        self.agent.conf.agent_mode = 'dvr_snat'
+        router_info = l3_test_common.prepare_router_data()
+        router_info['distributed'] = True
+        expected_neighbor = '35.4.1.10'
+        port_data = {
+            'fixed_ips': [{'ip_address': expected_neighbor}],
+            'mac_address': 'fa:3e:aa:bb:cc:dd',
+            'device_owner': DEVICE_OWNER_COMPUTE
+        }
+        self.agent.plugin_rpc.get_ports_by_subnet.return_value = [port_data]
+        router1 = self.manage_router(self.agent, router_info)
+        internal_device = router1.get_internal_device_name(
+            router_info['_interfaces'][0]['id'])
+        neighbors = ip_lib.IPDevice(internal_device, router1.ns_name).neigh
+        self.assertEqual(expected_neighbor,
+                         neighbors.show(ip_version=4).split()[0])
+
+    def _assert_rfp_fpr_mtu(self, router, expected_mtu=1500):
+        dev_mtu = self.get_device_mtu(
+            router.router_id, router.fip_ns.get_rtr_ext_device_name,
+            router.ns_name)
+        self.assertEqual(expected_mtu, dev_mtu)
+        dev_mtu = self.get_device_mtu(
+            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)
+
+    def _assert_snat_namespace_exists(self, router):
+        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+        self.assertTrue(self._namespace_exists(namespace))
+
+    def _get_dvr_snat_namespace_device_status(
+        self, router, internal_dev_name=None):
+        """Function returns the internal and external device status."""
+        snat_ns = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
+            router.router_id)
+        external_port = router.get_ex_gw_port()
+        external_device_name = router.get_external_device_name(
+            external_port['id'])
+        qg_device_created_successfully = ip_lib.device_exists(
+            external_device_name, namespace=snat_ns)
+        sg_device_created_successfully = ip_lib.device_exists(
+            internal_dev_name, namespace=snat_ns)
+        return qg_device_created_successfully, sg_device_created_successfully
+
+    def test_dvr_router_snat_namespace_with_interface_remove(self):
+        """Test to validate the snat namespace with interface remove.
+
+        This test validates the snat namespace for all the external
+        and internal devices. It also validates if the internal
+        device corresponding to the router interface is removed
+        when the router interface is deleted.
+        """
+        self.agent.conf.agent_mode = 'dvr_snat'
+        router_info = self.generate_dvr_router_info()
+        snat_internal_port = router_info[l3_constants.SNAT_ROUTER_INTF_KEY]
+        router1 = self.manage_router(self.agent, router_info)
+        csnat_internal_port = (
+            router1.router[l3_constants.SNAT_ROUTER_INTF_KEY])
+        # Now save the internal device name to verify later
+        internal_device_name = router1._get_snat_int_device_name(
+            csnat_internal_port[0]['id'])
+        self._assert_snat_namespace_exists(router1)
+        qg_device, sg_device = self._get_dvr_snat_namespace_device_status(
+            router1, internal_dev_name=internal_device_name)
+        self.assertTrue(qg_device)
+        self.assertTrue(sg_device)
+        self.assertEqual(router1.snat_ports, snat_internal_port)
+        # Now let us not pass INTERFACE_KEY, to emulate
+        # the interface has been removed.
+        router1.router[l3_constants.INTERFACE_KEY] = []
+        # Now let us not pass the SNAT_ROUTER_INTF_KEY, to emulate
+        # that the server did not send it, since the interface has been
+        # removed.
+        router1.router[l3_constants.SNAT_ROUTER_INTF_KEY] = []
+        self.agent._process_updated_router(router1.router)
+        router_updated = self.agent.router_info[router_info['id']]
+        self._assert_snat_namespace_exists(router_updated)
+        qg_device, sg_device = self._get_dvr_snat_namespace_device_status(
+            router_updated, internal_dev_name=internal_device_name)
+        self.assertFalse(sg_device)
+        self.assertTrue(qg_device)
+
+    def _mocked_dvr_ha_router(self, agent):
+        r_info = self.generate_dvr_router_info(enable_ha=True,
+                                               enable_snat=True,
+                                               agent=agent)
+
+        r_snat_ns_name = namespaces.build_ns_name(dvr_snat_ns.SNAT_NS_PREFIX,
+                                                  r_info['id'])
+
+        mocked_r_snat_ns_name = r_snat_ns_name + '@' + agent.host
+        r_ns_name = namespaces.build_ns_name(namespaces.NS_PREFIX,
+                                             r_info['id'])
+
+        mocked_r_ns_name = r_ns_name + '@' + agent.host
+
+        return r_info, mocked_r_ns_name, mocked_r_snat_ns_name
+
+    def _setup_dvr_ha_agents(self):
+        self.agent.conf.agent_mode = 'dvr_snat'
+
+        conf = self._configure_agent('agent2')
+        self.failover_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            'agent2', conf)
+        self.failover_agent.conf.agent_mode = 'dvr_snat'
+
+    def _setup_dvr_ha_bridges(self):
+        br_int_1 = self._get_agent_ovs_integration_bridge(self.agent)
+        br_int_2 = self._get_agent_ovs_integration_bridge(self.failover_agent)
+
+        veth1, veth2 = self.useFixture(net_helpers.VethFixture()).ports
+        br_int_1.add_port(veth1.name)
+        br_int_2.add_port(veth2.name)
+
+    def _create_dvr_ha_router(self, agent):
+        get_ns_name = mock.patch.object(namespaces.RouterNamespace,
+                                        '_get_ns_name').start()
+        get_snat_ns_name = mock.patch.object(dvr_snat_ns.SnatNamespace,
+                                             'get_snat_ns_name').start()
+        (r_info,
+         mocked_r_ns_name,
+         mocked_r_snat_ns_name) = self._mocked_dvr_ha_router(agent)
+        get_ns_name.return_value = mocked_r_ns_name
+        get_snat_ns_name.return_value = mocked_r_snat_ns_name
+        router = self.manage_router(agent, r_info)
+        return router
+
+    def _assert_ip_addresses_in_dvr_ha_snat_namespace(self, router):
+        namespace = router.ha_namespace
+        ex_gw_port = router.get_ex_gw_port()
+        snat_port = router.get_snat_interfaces()[0]
+        ex_gw_port_name = router.get_external_device_name(
+            ex_gw_port['id'])
+        snat_port_name = router._get_snat_int_device_name(
+            snat_port['id'])
+
+        ip = ex_gw_port["fixed_ips"][0]['ip_address']
+        prefix_len = ex_gw_port["fixed_ips"][0]['prefixlen']
+        ex_gw_port_cidr = ip + "/" + str(prefix_len)
+        ip = snat_port["fixed_ips"][0]['ip_address']
+        prefix_len = snat_port["fixed_ips"][0]['prefixlen']
+        snat_port_cidr = ip + "/" + str(prefix_len)
+
+        self._assert_ip_address_on_interface(namespace,
+                                             ex_gw_port_name,
+                                             ex_gw_port_cidr)
+        self._assert_ip_address_on_interface(namespace,
+                                             snat_port_name,
+                                             snat_port_cidr)
+
+    def _assert_no_ip_addresses_in_dvr_ha_snat_namespace(self, router):
+        namespace = router.ha_namespace
+        ex_gw_port = router.get_ex_gw_port()
+        snat_port = router.get_snat_interfaces()[0]
+        ex_gw_port_name = router.get_external_device_name(
+            ex_gw_port['id'])
+        snat_port_name = router._get_snat_int_device_name(
+            snat_port['id'])
+
+        self._assert_no_ip_addresses_on_interface(namespace,
+                                                  snat_port_name)
+        self._assert_no_ip_addresses_on_interface(namespace,
+                                                  ex_gw_port_name)
+
+    def test_dvr_ha_router_failover(self):
+        self._setup_dvr_ha_agents()
+        self._setup_dvr_ha_bridges()
+
+        router1 = self._create_dvr_ha_router(self.agent)
+        router2 = self._create_dvr_ha_router(self.failover_agent)
+
+        utils.wait_until_true(lambda: router1.ha_state == 'master')
+        utils.wait_until_true(lambda: router2.ha_state == 'backup')
+
+        self._assert_ip_addresses_in_dvr_ha_snat_namespace(router1)
+        self._assert_no_ip_addresses_in_dvr_ha_snat_namespace(router2)
+
+        self.fail_ha_router(router1)
+
+        utils.wait_until_true(lambda: router2.ha_state == 'master')
+        utils.wait_until_true(lambda: router1.ha_state == 'backup')
+
+        self._assert_ip_addresses_in_dvr_ha_snat_namespace(router2)
+        self._assert_no_ip_addresses_in_dvr_ha_snat_namespace(router1)
+
+    def _assert_fip_namespace_deleted(self, ext_gateway_port):
+        ext_net_id = ext_gateway_port['network_id']
+        self.agent.fipnamespace_delete_on_ext_net(
+            self.agent.context, ext_net_id)
+        self._assert_interfaces_deleted_from_ovs()
diff --git a/neutron/tests/functional/agent/l3/test_ha_router.py b/neutron/tests/functional/agent/l3/test_ha_router.py
new file mode 100644 (file)
index 0000000..1bdffa6
--- /dev/null
@@ -0,0 +1,284 @@
+# Copyright (c) 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import copy
+
+import mock
+import six
+
+from neutron.agent.l3 import agent as neutron_l3_agent
+from neutron.agent.l3 import namespaces
+from neutron.agent.linux import ip_lib
+from neutron.agent.linux import utils
+from neutron.common import constants as l3_constants
+from neutron.common import utils as common_utils
+from neutron.tests.common import l3_test_common
+from neutron.tests.common import net_helpers
+from neutron.tests.functional.agent.l3 import framework
+
+
+class L3HATestCase(framework.L3AgentTestFramework):
+
+    def test_keepalived_state_change_notification(self):
+        enqueue_mock = mock.patch.object(
+            self.agent, 'enqueue_state_change').start()
+        router_info = self.generate_router_info(enable_ha=True)
+        router = self.manage_router(self.agent, router_info)
+        utils.wait_until_true(lambda: router.ha_state == 'master')
+
+        self.fail_ha_router(router)
+        utils.wait_until_true(lambda: router.ha_state == 'backup')
+
+        utils.wait_until_true(lambda: enqueue_mock.call_count == 3)
+        calls = [args[0] for args in enqueue_mock.call_args_list]
+        self.assertEqual((router.router_id, 'backup'), calls[0])
+        self.assertEqual((router.router_id, 'master'), calls[1])
+        self.assertEqual((router.router_id, 'backup'), calls[2])
+
+    def _expected_rpc_report(self, expected):
+        calls = (args[0][1] for args in
+                 self.agent.plugin_rpc.update_ha_routers_states.call_args_list)
+
+        # Get the last state reported for each router
+        actual_router_states = {}
+        for call in calls:
+            for router_id, state in six.iteritems(call):
+                actual_router_states[router_id] = state
+
+        return actual_router_states == expected
+
+    def test_keepalived_state_change_bulk_rpc(self):
+        router_info = self.generate_router_info(enable_ha=True)
+        router1 = self.manage_router(self.agent, router_info)
+        self.fail_ha_router(router1)
+        router_info = self.generate_router_info(enable_ha=True)
+        router2 = self.manage_router(self.agent, router_info)
+
+        utils.wait_until_true(lambda: router1.ha_state == 'backup')
+        utils.wait_until_true(lambda: router2.ha_state == 'master')
+        utils.wait_until_true(
+            lambda: self._expected_rpc_report(
+                {router1.router_id: 'standby', router2.router_id: 'active'}))
+
+    def test_ha_router_lifecycle(self):
+        self._router_lifecycle(enable_ha=True)
+
+    def test_conntrack_disassociate_fip_ha_router(self):
+        self._test_conntrack_disassociate_fip(ha=True)
+
+    def test_ipv6_ha_router_lifecycle(self):
+        self._router_lifecycle(enable_ha=True, ip_version=6)
+
+    def test_ipv6_ha_router_lifecycle_with_no_gw_subnet(self):
+        self.agent.conf.set_override('ipv6_gateway',
+                                     'fe80::f816:3eff:fe2e:1')
+        self._router_lifecycle(enable_ha=True, ip_version=6,
+                               v6_ext_gw_with_sub=False)
+
+    def test_ipv6_ha_router_lifecycle_with_no_gw_subnet_for_router_advts(self):
+        # Verify that router gw interface is configured to receive Router
+        # Advts from upstream router when no external gateway is configured.
+        self._router_lifecycle(enable_ha=True, dual_stack=True,
+                               v6_ext_gw_with_sub=False)
+
+    def test_keepalived_configuration(self):
+        router_info = self.generate_router_info(enable_ha=True)
+        router = self.manage_router(self.agent, router_info)
+        expected = self.get_expected_keepalive_configuration(router)
+
+        self.assertEqual(expected,
+                         router.keepalived_manager.get_conf_on_disk())
+
+        # Add a new FIP and change the GW IP address
+        router.router = copy.deepcopy(router.router)
+        existing_fip = '19.4.4.2'
+        new_fip = '19.4.4.3'
+        self._add_fip(router, new_fip)
+        subnet_id = framework._uuid()
+        fixed_ips = [{'ip_address': '19.4.4.10',
+                      'prefixlen': 24,
+                      'subnet_id': subnet_id}]
+        subnets = [{'id': subnet_id,
+                    'cidr': '19.4.4.0/24',
+                    'gateway_ip': '19.4.4.5'}]
+        router.router['gw_port']['subnets'] = subnets
+        router.router['gw_port']['fixed_ips'] = fixed_ips
+
+        router.process(self.agent)
+
+        # Get the updated configuration and assert that both FIPs are in,
+        # and that the GW IP address was updated.
+        new_config = router.keepalived_manager.config.get_config_str()
+        old_gw = '0.0.0.0/0 via 19.4.4.1'
+        new_gw = '0.0.0.0/0 via 19.4.4.5'
+        old_external_device_ip = '19.4.4.4'
+        new_external_device_ip = '19.4.4.10'
+        self.assertIn(existing_fip, new_config)
+        self.assertIn(new_fip, new_config)
+        self.assertNotIn(old_gw, new_config)
+        self.assertIn(new_gw, new_config)
+        external_port = router.get_ex_gw_port()
+        external_device_name = router.get_external_device_name(
+            external_port['id'])
+        self.assertNotIn('%s/24 dev %s' %
+                         (old_external_device_ip, external_device_name),
+                         new_config)
+        self.assertIn('%s/24 dev %s' %
+                      (new_external_device_ip, external_device_name),
+                      new_config)
+
+    def test_ha_router_conf_on_restarted_agent(self):
+        router_info = self.generate_router_info(enable_ha=True)
+        router1 = self.manage_router(self.agent, router_info)
+        self._add_fip(router1, '192.168.111.12')
+        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            self.agent.host, self.agent.conf)
+        self.manage_router(restarted_agent, router1.router)
+        utils.wait_until_true(lambda: self.floating_ips_configured(router1))
+        self.assertIn(
+            router1._get_primary_vip(),
+            self._get_addresses_on_device(
+                router1.ns_name,
+                router1.get_ha_device_name()))
+
+    def test_ha_router_ipv6_radvd_status(self):
+        router_info = self.generate_router_info(ip_version=6, enable_ha=True)
+        router1 = self.manage_router(self.agent, router_info)
+        utils.wait_until_true(lambda: router1.ha_state == 'master')
+        utils.wait_until_true(lambda: router1.radvd.enabled)
+
+        def _check_lla_status(router, expected):
+            internal_devices = router.router[l3_constants.INTERFACE_KEY]
+            for device in internal_devices:
+                lladdr = ip_lib.get_ipv6_lladdr(device['mac_address'])
+                exists = ip_lib.device_exists_with_ips_and_mac(
+                    router.get_internal_device_name(device['id']), [lladdr],
+                    device['mac_address'], router.ns_name)
+                self.assertEqual(expected, exists)
+
+        _check_lla_status(router1, True)
+
+        device_name = router1.get_ha_device_name()
+        ha_device = ip_lib.IPDevice(device_name, namespace=router1.ns_name)
+        ha_device.link.set_down()
+
+        utils.wait_until_true(lambda: router1.ha_state == 'backup')
+        utils.wait_until_true(lambda: not router1.radvd.enabled, timeout=10)
+        _check_lla_status(router1, False)
+
+    def test_ha_router_process_ipv6_subnets_to_existing_port(self):
+        router_info = self.generate_router_info(enable_ha=True, ip_version=6)
+        router = self.manage_router(self.agent, router_info)
+
+        def verify_ip_in_keepalived_config(router, iface):
+            config = router.keepalived_manager.config.get_config_str()
+            ip_cidrs = common_utils.fixed_ip_cidrs(iface['fixed_ips'])
+            for ip_addr in ip_cidrs:
+                self.assertIn(ip_addr, config)
+
+        interface_id = router.router[l3_constants.INTERFACE_KEY][0]['id']
+        slaac = l3_constants.IPV6_SLAAC
+        slaac_mode = {'ra_mode': slaac, 'address_mode': slaac}
+
+        # Add a second IPv6 subnet to the router internal interface.
+        self._add_internal_interface_by_subnet(router.router, count=1,
+                ip_version=6, ipv6_subnet_modes=[slaac_mode],
+                interface_id=interface_id)
+        router.process(self.agent)
+        utils.wait_until_true(lambda: router.ha_state == 'master')
+
+        # Verify that router internal interface is present and is configured
+        # with IP address from both the subnets.
+        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
+        self.assertEqual(2, len(internal_iface['fixed_ips']))
+        self._assert_internal_devices(router)
+
+        # Verify that keepalived config is properly updated.
+        verify_ip_in_keepalived_config(router, internal_iface)
+
+        # Remove one subnet from the router internal iface
+        interfaces = copy.deepcopy(router.router.get(
+            l3_constants.INTERFACE_KEY, []))
+        fixed_ips, subnets = [], []
+        fixed_ips.append(interfaces[0]['fixed_ips'][0])
+        subnets.append(interfaces[0]['subnets'][0])
+        interfaces[0].update({'fixed_ips': fixed_ips, 'subnets': subnets})
+        router.router[l3_constants.INTERFACE_KEY] = interfaces
+        router.process(self.agent)
+
+        # Verify that router internal interface has a single ipaddress
+        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
+        self.assertEqual(1, len(internal_iface['fixed_ips']))
+        self._assert_internal_devices(router)
+
+        # Verify that keepalived config is properly updated.
+        verify_ip_in_keepalived_config(router, internal_iface)
+
+    def test_delete_external_gateway_on_standby_router(self):
+        router_info = self.generate_router_info(enable_ha=True)
+        router = self.manage_router(self.agent, router_info)
+
+        self.fail_ha_router(router)
+        utils.wait_until_true(lambda: router.ha_state == 'backup')
+
+        # The purpose of the test is to simply make sure no exception is raised
+        port = router.get_ex_gw_port()
+        interface_name = router.get_external_device_name(port['id'])
+        router.external_gateway_removed(port, interface_name)
+
+
+class L3HATestFailover(framework.L3AgentTestFramework):
+
+    NESTED_NAMESPACE_SEPARATOR = '@'
+
+    def setUp(self):
+        super(L3HATestFailover, self).setUp()
+        conf = self._configure_agent('agent2')
+        self.failover_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            'agent2', conf)
+
+        br_int_1 = self._get_agent_ovs_integration_bridge(self.agent)
+        br_int_2 = self._get_agent_ovs_integration_bridge(self.failover_agent)
+
+        veth1, veth2 = self.useFixture(net_helpers.VethFixture()).ports
+        br_int_1.add_port(veth1.name)
+        br_int_2.add_port(veth2.name)
+
+    def test_ha_router_failover(self):
+        router_info = self.generate_router_info(enable_ha=True)
+        get_ns_name = mock.patch.object(
+            namespaces.RouterNamespace, '_get_ns_name').start()
+        get_ns_name.return_value = "%s%s%s" % (
+            'qrouter-' + router_info['id'],
+            self.NESTED_NAMESPACE_SEPARATOR, self.agent.host)
+        router1 = self.manage_router(self.agent, router_info)
+
+        router_info_2 = copy.deepcopy(router_info)
+        router_info_2[l3_constants.HA_INTERFACE_KEY] = (
+            l3_test_common.get_ha_interface(ip='169.254.192.2',
+                                            mac='22:22:22:22:22:22'))
+
+        get_ns_name.return_value = "%s%s%s" % (
+            namespaces.RouterNamespace._get_ns_name(router_info_2['id']),
+            self.NESTED_NAMESPACE_SEPARATOR, self.failover_agent.host)
+        router2 = self.manage_router(self.failover_agent, router_info_2)
+
+        utils.wait_until_true(lambda: router1.ha_state == 'master')
+        utils.wait_until_true(lambda: router2.ha_state == 'backup')
+
+        self.fail_ha_router(router1)
+
+        utils.wait_until_true(lambda: router2.ha_state == 'master')
+        utils.wait_until_true(lambda: router1.ha_state == 'backup')
diff --git a/neutron/tests/functional/agent/l3/test_legacy_router.py b/neutron/tests/functional/agent/l3/test_legacy_router.py
new file mode 100644 (file)
index 0000000..2f07597
--- /dev/null
@@ -0,0 +1,199 @@
+# Copyright (c) 2014 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+
+import mock
+
+from neutron.agent.l3 import namespace_manager
+from neutron.agent.l3 import namespaces
+from neutron.callbacks import events
+from neutron.callbacks import registry
+from neutron.callbacks import resources
+from neutron.common import constants as l3_constants
+from neutron.tests.common import machine_fixtures
+from neutron.tests.common import net_helpers
+from neutron.tests.functional.agent.l3 import framework
+
+
+class L3AgentTestCase(framework.L3AgentTestFramework):
+
+    def test_agent_notifications_for_router_events(self):
+        """Test notifications for router create, update, and delete.
+
+        Make sure that when the agent sends notifications of router events
+        for router create, update, and delete, that the correct handler is
+        called with the right resource, event, and router information.
+        """
+        event_handler = mock.Mock()
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.BEFORE_CREATE)
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.AFTER_CREATE)
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.BEFORE_UPDATE)
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.AFTER_UPDATE)
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.BEFORE_DELETE)
+        registry.subscribe(event_handler,
+                           resources.ROUTER, events.AFTER_DELETE)
+
+        router_info = self.generate_router_info(enable_ha=False)
+        router = self.manage_router(self.agent, router_info)
+        self.agent._process_updated_router(router.router)
+        self._delete_router(self.agent, router.router_id)
+
+        expected_calls = [
+            mock.call('router', 'before_create', self.agent, router=router),
+            mock.call('router', 'after_create', self.agent, router=router),
+            mock.call('router', 'before_update', self.agent, router=router),
+            mock.call('router', 'after_update', self.agent, router=router),
+            mock.call('router', 'before_delete', self.agent, router=router),
+            mock.call('router', 'after_delete', self.agent, router=router)]
+        event_handler.assert_has_calls(expected_calls)
+
+    def test_legacy_router_lifecycle(self):
+        self._router_lifecycle(enable_ha=False, dual_stack=True)
+
+    def test_legacy_router_lifecycle_with_no_gateway_subnet(self):
+        self.agent.conf.set_override('ipv6_gateway',
+                                     'fe80::f816:3eff:fe2e:1')
+        self._router_lifecycle(enable_ha=False, dual_stack=True,
+                               v6_ext_gw_with_sub=False)
+
+    def test_conntrack_disassociate_fip_legacy_router(self):
+        self._test_conntrack_disassociate_fip(ha=False)
+
+    def _test_periodic_sync_routers_task(self,
+                                         routers_to_keep,
+                                         routers_deleted,
+                                         routers_deleted_during_resync):
+        ns_names_to_retrieve = set()
+        deleted_routers_info = []
+        for r in routers_to_keep:
+            ri = self.manage_router(self.agent, r)
+            ns_names_to_retrieve.add(ri.ns_name)
+        for r in routers_deleted + routers_deleted_during_resync:
+            ri = self.manage_router(self.agent, r)
+            deleted_routers_info.append(ri)
+            ns_names_to_retrieve.add(ri.ns_name)
+
+        mocked_get_routers = self.mock_plugin_api.get_routers
+        mocked_get_routers.return_value = (routers_to_keep +
+                                           routers_deleted_during_resync)
+        # clear agent router_info as it will be after restart
+        self.agent.router_info = {}
+
+        # Synchronize the agent with the plug-in
+        with mock.patch.object(namespace_manager.NamespaceManager, 'list_all',
+                               return_value=ns_names_to_retrieve):
+            self.agent.periodic_sync_routers_task(self.agent.context)
+
+        # Mock the plugin RPC API so a known external network id is returned
+        # when the router updates are processed by the agent
+        external_network_id = framework._uuid()
+        self.mock_plugin_api.get_external_network_id.return_value = (
+            external_network_id)
+
+        # Plug external_gateway_info in the routers that are not going to be
+        # deleted by the agent when it processes the updates. Otherwise,
+        # _process_router_if_compatible in the agent fails
+        for r in routers_to_keep:
+            r['external_gateway_info'] = {'network_id': external_network_id}
+
+        # while sync updates are still in the queue, higher priority
+        # router_deleted events may be added there as well
+        for r in routers_deleted_during_resync:
+            self.agent.router_deleted(self.agent.context, r['id'])
+
+        # make sure all events are processed
+        while not self.agent._queue._queue.empty():
+            self.agent._process_router_update()
+
+        for r in routers_to_keep:
+            self.assertIn(r['id'], self.agent.router_info)
+            self.assertTrue(self._namespace_exists(namespaces.NS_PREFIX +
+                                                   r['id']))
+        for ri in deleted_routers_info:
+            self.assertNotIn(ri.router_id,
+                             self.agent.router_info)
+            self._assert_router_does_not_exist(ri)
+
+    def test_periodic_sync_routers_task(self):
+        routers_to_keep = []
+        for i in range(2):
+            routers_to_keep.append(self.generate_router_info(False))
+        self._test_periodic_sync_routers_task(routers_to_keep,
+                                              routers_deleted=[],
+                                              routers_deleted_during_resync=[])
+
+    def test_periodic_sync_routers_task_routers_deleted_while_agent_down(self):
+        routers_to_keep = []
+        routers_deleted = []
+        for i in range(2):
+            routers_to_keep.append(self.generate_router_info(False))
+        for i in range(2):
+            routers_deleted.append(self.generate_router_info(False))
+        self._test_periodic_sync_routers_task(routers_to_keep,
+                                              routers_deleted,
+                                              routers_deleted_during_resync=[])
+
+    def test_periodic_sync_routers_task_routers_deleted_while_agent_sync(self):
+        routers_to_keep = []
+        routers_deleted_during_resync = []
+        for i in range(2):
+            routers_to_keep.append(self.generate_router_info(False))
+        for i in range(2):
+            routers_deleted_during_resync.append(
+                self.generate_router_info(False))
+        self._test_periodic_sync_routers_task(
+            routers_to_keep,
+            routers_deleted=[],
+            routers_deleted_during_resync=routers_deleted_during_resync)
+
+    def test_fip_connection_from_same_subnet(self):
+        '''Test connection to floatingip which is associated with
+           fixed_ip on the same subnet of the source fixed_ip.
+           In other words it confirms that return packets surely
+           go through the router.
+        '''
+        router_info = self.generate_router_info(enable_ha=False)
+        router = self.manage_router(self.agent, router_info)
+        router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
+        router_ip = router_ip_cidr.partition('/')[0]
+
+        br_int = framework.get_ovs_bridge(
+            self.agent.conf.ovs_integration_bridge)
+
+        src_machine, dst_machine = self.useFixture(
+            machine_fixtures.PeerMachines(
+                br_int,
+                net_helpers.increment_ip_cidr(router_ip_cidr),
+                router_ip)).machines
+
+        dst_fip = '19.4.4.10'
+        router.router[l3_constants.FLOATINGIP_KEY] = []
+        self._add_fip(router, dst_fip, fixed_address=dst_machine.ip)
+        router.process(self.agent)
+
+        protocol_port = net_helpers.get_free_namespace_port(
+            l3_constants.PROTO_NAME_TCP, dst_machine.namespace)
+        # client sends to fip
+        netcat = net_helpers.NetcatTester(
+            src_machine.namespace, dst_machine.namespace,
+            dst_fip, protocol_port,
+            protocol=net_helpers.NetcatTester.TCP)
+        self.addCleanup(netcat.stop_processes)
+        self.assertTrue(netcat.test_connectivity())
diff --git a/neutron/tests/functional/agent/l3/test_metadata_proxy.py b/neutron/tests/functional/agent/l3/test_metadata_proxy.py
new file mode 100644 (file)
index 0000000..fb0aa97
--- /dev/null
@@ -0,0 +1,152 @@
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import os.path
+import time
+
+import webob
+import webob.dec
+import webob.exc
+
+from neutron.agent.linux import dhcp
+from neutron.agent.linux import utils
+from neutron.tests.common import machine_fixtures
+from neutron.tests.common import net_helpers
+from neutron.tests.functional.agent.l3 import framework
+from neutron.tests.functional.agent.linux import helpers
+
+
+METADATA_REQUEST_TIMEOUT = 60
+METADATA_REQUEST_SLEEP = 5
+
+
+class MetadataFakeProxyHandler(object):
+
+    def __init__(self, status):
+        self.status = status
+
+    @webob.dec.wsgify()
+    def __call__(self, req):
+        return webob.Response(status=self.status)
+
+
+class MetadataL3AgentTestCase(framework.L3AgentTestFramework):
+
+    SOCKET_MODE = 0o644
+
+    def _create_metadata_fake_server(self, status):
+        server = utils.UnixDomainWSGIServer('metadata-fake-server')
+        self.addCleanup(server.stop)
+
+        # NOTE(cbrandily): TempDir fixture creates a folder with 0o700
+        # permissions but metadata_proxy_socket folder must be readable by all
+        # users
+        self.useFixture(
+            helpers.RecursivePermDirFixture(
+                os.path.dirname(self.agent.conf.metadata_proxy_socket), 0o555))
+        server.start(MetadataFakeProxyHandler(status),
+                     self.agent.conf.metadata_proxy_socket,
+                     workers=0, backlog=4096, mode=self.SOCKET_MODE)
+
+    def _query_metadata_proxy(self, machine):
+        url = 'http://%(host)s:%(port)s' % {'host': dhcp.METADATA_DEFAULT_IP,
+                                            'port': dhcp.METADATA_PORT}
+        cmd = 'curl', '--max-time', METADATA_REQUEST_TIMEOUT, '-D-', url
+        i = 0
+        CONNECTION_REFUSED_TIMEOUT = METADATA_REQUEST_TIMEOUT // 2
+        while i <= CONNECTION_REFUSED_TIMEOUT:
+            try:
+                raw_headers = machine.execute(cmd)
+                break
+            except RuntimeError as e:
+                if 'Connection refused' in str(e):
+                    time.sleep(METADATA_REQUEST_SLEEP)
+                    i += METADATA_REQUEST_SLEEP
+                else:
+                    self.fail('metadata proxy unreachable '
+                              'on %s before timeout' % url)
+
+        if i > CONNECTION_REFUSED_TIMEOUT:
+            self.fail('Timed out waiting metadata proxy to become available')
+        return raw_headers.splitlines()[0]
+
+    def test_access_to_metadata_proxy(self):
+        """Test access to the l3-agent metadata proxy.
+
+        The test creates:
+         * A l3-agent metadata service:
+           * A router (which creates a metadata proxy in the router namespace),
+           * A fake metadata server
+         * A "client" namespace (simulating a vm) with a port on router
+           internal subnet.
+
+        The test queries from the "client" namespace the metadata proxy on
+        http://169.254.169.254 and asserts that the metadata proxy added
+        the X-Forwarded-For and X-Neutron-Router-Id headers to the request
+        and forwarded the http request to the fake metadata server and the
+        response to the "client" namespace.
+        """
+        router_info = self.generate_router_info(enable_ha=False)
+        router = self.manage_router(self.agent, router_info)
+        self._create_metadata_fake_server(webob.exc.HTTPOk.code)
+
+        # Create and configure client namespace
+        router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
+        br_int = framework.get_ovs_bridge(
+            self.agent.conf.ovs_integration_bridge)
+
+        machine = self.useFixture(
+            machine_fixtures.FakeMachine(
+                br_int,
+                net_helpers.increment_ip_cidr(router_ip_cidr),
+                router_ip_cidr.partition('/')[0]))
+
+        # Query metadata proxy
+        firstline = self._query_metadata_proxy(machine)
+
+        # Check status code
+        self.assertIn(str(webob.exc.HTTPOk.code), firstline.split())
+
+
+class UnprivilegedUserMetadataL3AgentTestCase(MetadataL3AgentTestCase):
+    """Test metadata proxy with least privileged user.
+
+    The least privileged user has uid=65534 and is commonly named 'nobody' but
+    not always, that's why we use its uid.
+    """
+
+    SOCKET_MODE = 0o664
+
+    def setUp(self):
+        super(UnprivilegedUserMetadataL3AgentTestCase, self).setUp()
+        self.agent.conf.set_override('metadata_proxy_user', '65534')
+        self.agent.conf.set_override('metadata_proxy_watch_log', False)
+
+
+class UnprivilegedUserGroupMetadataL3AgentTestCase(MetadataL3AgentTestCase):
+    """Test metadata proxy with least privileged user/group.
+
+    The least privileged user has uid=65534 and is commonly named 'nobody' but
+    not always, that's why we use its uid.
+    Its group has gid=65534 and is commonly named 'nobody' or 'nogroup', that's
+    why we use its gid.
+    """
+
+    SOCKET_MODE = 0o666
+
+    def setUp(self):
+        super(UnprivilegedUserGroupMetadataL3AgentTestCase, self).setUp()
+        self.agent.conf.set_override('metadata_proxy_user', '65534')
+        self.agent.conf.set_override('metadata_proxy_group', '65534')
+        self.agent.conf.set_override('metadata_proxy_watch_log', False)
index d2c0d8fbe72e932908e0f1d45508eb9e45c348de..1e550f2c3d09614bf76402f2a17fc57c89b581c1 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
-import functools
-import os.path
-import time
-
 import mock
-import netaddr
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import uuidutils
-import six
-import testtools
-import webob
-import webob.dec
-import webob.exc
 
-from neutron.agent.common import config as agent_config
-from neutron.agent.common import ovs_lib
-from neutron.agent.l3 import agent as neutron_l3_agent
-from neutron.agent.l3 import dvr_snat_ns
-from neutron.agent.l3 import namespace_manager
-from neutron.agent.l3 import namespaces
-from neutron.agent import l3_agent as l3_agent_main
-from neutron.agent.linux import dhcp
-from neutron.agent.linux import external_process
-from neutron.agent.linux import ip_lib
-from neutron.agent.linux import utils
-from neutron.callbacks import events
-from neutron.callbacks import registry
-from neutron.callbacks import resources
-from neutron.common import config as common_config
-from neutron.common import constants as l3_constants
 from neutron.common import topics
-from neutron.common import utils as common_utils
-from neutron.tests.common import l3_test_common
-from neutron.tests.common import machine_fixtures
-from neutron.tests.common import net_helpers
-from neutron.tests.functional.agent.linux import helpers
-from neutron.tests.functional import base
+from neutron.tests.functional.agent.l3 import framework
 from neutron.tests.functional import test_service
 
 
-LOG = logging.getLogger(__name__)
-_uuid = uuidutils.generate_uuid
-
-METADATA_REQUEST_TIMEOUT = 60
-METADATA_REQUEST_SLEEP = 5
-
-DEVICE_OWNER_COMPUTE = l3_constants.DEVICE_OWNER_COMPUTE_PREFIX + 'fake'
-
-
-def get_ovs_bridge(br_name):
-    return ovs_lib.OVSBridge(br_name)
-
-
-class L3AgentTestFramework(base.BaseSudoTestCase):
-    def setUp(self):
-        super(L3AgentTestFramework, self).setUp()
-        self.mock_plugin_api = mock.patch(
-            'neutron.agent.l3.agent.L3PluginApi').start().return_value
-        mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
-        self.conf = self._configure_agent('agent1')
-        self.agent = neutron_l3_agent.L3NATAgentWithStateReport('agent1',
-                                                                self.conf)
-
-    def _get_config_opts(self):
-        config = cfg.ConfigOpts()
-        config.register_opts(common_config.core_opts)
-        config.register_opts(common_config.core_cli_opts)
-        logging.register_options(config)
-        agent_config.register_process_monitor_opts(config)
-        return config
-
-    def _configure_agent(self, host, agent_mode='dvr_snat'):
-        conf = self._get_config_opts()
-        l3_agent_main.register_opts(conf)
-        conf.set_override(
-            'interface_driver',
-            'neutron.agent.linux.interface.OVSInterfaceDriver')
-
-        br_int = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
-        br_ex = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
-        conf.set_override('ovs_integration_bridge', br_int.br_name)
-        conf.set_override('external_network_bridge', br_ex.br_name)
-
-        temp_dir = self.get_new_temp_dir()
-        get_temp_file_path = functools.partial(self.get_temp_file_path,
-                                               root=temp_dir)
-        conf.set_override('state_path', temp_dir.path)
-        # NOTE(cbrandily): log_file or log_dir must be set otherwise
-        # metadata_proxy_watch_log has no effect
-        conf.set_override('log_file',
-                          get_temp_file_path('log_file'))
-        conf.set_override('metadata_proxy_socket',
-                          get_temp_file_path('metadata_proxy'))
-        conf.set_override('ha_confs_path',
-                          get_temp_file_path('ha_confs'))
-        conf.set_override('external_pids',
-                          get_temp_file_path('external/pids'))
-        conf.set_override('host', host)
-        conf.set_override('agent_mode', agent_mode)
-
-        return conf
-
-    def _get_agent_ovs_integration_bridge(self, agent):
-        return get_ovs_bridge(agent.conf.ovs_integration_bridge)
-
-    def generate_router_info(self, enable_ha, ip_version=4, extra_routes=True,
-                             enable_fip=True, enable_snat=True,
-                             dual_stack=False, v6_ext_gw_with_sub=True):
-        if ip_version == 6 and not dual_stack:
-            enable_snat = False
-            enable_fip = False
-            extra_routes = False
-
-        return l3_test_common.prepare_router_data(ip_version=ip_version,
-                                                 enable_snat=enable_snat,
-                                                 enable_floating_ip=enable_fip,
-                                                 enable_ha=enable_ha,
-                                                 extra_routes=extra_routes,
-                                                 dual_stack=dual_stack,
-                                                 v6_ext_gw_with_sub=(
-                                                     v6_ext_gw_with_sub))
-
-    def manage_router(self, agent, router):
-        self.addCleanup(agent._safe_router_removed, router['id'])
-        agent._process_added_router(router)
-        return agent.router_info[router['id']]
-
-    def _delete_router(self, agent, router_id):
-        agent._router_removed(router_id)
-
-    def _add_fip(self, router, fip_address, fixed_address='10.0.0.2',
-                 host=None):
-        fip = {'id': _uuid(),
-               'port_id': _uuid(),
-               'floating_ip_address': fip_address,
-               'fixed_ip_address': fixed_address,
-               'host': host}
-        router.router[l3_constants.FLOATINGIP_KEY].append(fip)
-
-    def _add_internal_interface_by_subnet(self, router, count=1,
-                                          ip_version=4,
-                                          ipv6_subnet_modes=None,
-                                          interface_id=None):
-        return l3_test_common.router_append_subnet(router, count,
-                ip_version, ipv6_subnet_modes, interface_id)
-
-    def _namespace_exists(self, namespace):
-        ip = ip_lib.IPWrapper(namespace=namespace)
-        return ip.netns.exists(namespace)
-
-    def _metadata_proxy_exists(self, conf, router):
-        pm = external_process.ProcessManager(
-            conf,
-            router.router_id,
-            router.ns_name)
-        return pm.active
-
-    def device_exists_with_ips_and_mac(self, expected_device, name_getter,
-                                       namespace):
-        ip_cidrs = common_utils.fixed_ip_cidrs(expected_device['fixed_ips'])
-        return ip_lib.device_exists_with_ips_and_mac(
-            name_getter(expected_device['id']), ip_cidrs,
-            expected_device['mac_address'], namespace)
-
-    @staticmethod
-    def _port_first_ip_cidr(port):
-        fixed_ip = port['fixed_ips'][0]
-        return common_utils.ip_to_cidr(fixed_ip['ip_address'],
-                                       fixed_ip['prefixlen'])
-
-    def get_device_mtu(self, target_device, name_getter, namespace):
-        device = ip_lib.IPDevice(name_getter(target_device), namespace)
-        return device.link.mtu
-
-    def get_expected_keepalive_configuration(self, router):
-        ha_device_name = router.get_ha_device_name()
-        external_port = router.get_ex_gw_port()
-        ex_port_ipv6 = ip_lib.get_ipv6_lladdr(external_port['mac_address'])
-        external_device_name = router.get_external_device_name(
-            external_port['id'])
-        external_device_cidr = self._port_first_ip_cidr(external_port)
-        internal_port = router.router[l3_constants.INTERFACE_KEY][0]
-        int_port_ipv6 = ip_lib.get_ipv6_lladdr(internal_port['mac_address'])
-        internal_device_name = router.get_internal_device_name(
-            internal_port['id'])
-        internal_device_cidr = self._port_first_ip_cidr(internal_port)
-        floating_ip_cidr = common_utils.ip_to_cidr(
-            router.get_floating_ips()[0]['floating_ip_address'])
-        default_gateway_ip = external_port['subnets'][0].get('gateway_ip')
-        extra_subnet_cidr = external_port['extra_subnets'][0].get('cidr')
-        return """vrrp_instance VR_1 {
-    state BACKUP
-    interface %(ha_device_name)s
-    virtual_router_id 1
-    priority 50
-    garp_master_repeat 5
-    garp_master_refresh 10
-    nopreempt
-    advert_int 2
-    track_interface {
-        %(ha_device_name)s
-    }
-    virtual_ipaddress {
-        169.254.0.1/24 dev %(ha_device_name)s
-    }
-    virtual_ipaddress_excluded {
-        %(floating_ip_cidr)s dev %(external_device_name)s
-        %(external_device_cidr)s dev %(external_device_name)s
-        %(internal_device_cidr)s dev %(internal_device_name)s
-        %(ex_port_ipv6)s dev %(external_device_name)s scope link
-        %(int_port_ipv6)s dev %(internal_device_name)s scope link
-    }
-    virtual_routes {
-        0.0.0.0/0 via %(default_gateway_ip)s dev %(external_device_name)s
-        8.8.8.0/24 via 19.4.4.4
-        %(extra_subnet_cidr)s dev %(external_device_name)s scope link
-    }
-}""" % {
-            'ha_device_name': ha_device_name,
-            'external_device_name': external_device_name,
-            'external_device_cidr': external_device_cidr,
-            'internal_device_name': internal_device_name,
-            'internal_device_cidr': internal_device_cidr,
-            'floating_ip_cidr': floating_ip_cidr,
-            'default_gateway_ip': default_gateway_ip,
-            'int_port_ipv6': int_port_ipv6,
-            'ex_port_ipv6': ex_port_ipv6,
-            'extra_subnet_cidr': extra_subnet_cidr,
-        }
-
-    def _get_rule(self, iptables_manager, table, chain, predicate):
-        rules = iptables_manager.get_chain(table, chain)
-        result = next(rule for rule in rules if predicate(rule))
-        return result
-
-    def _assert_router_does_not_exist(self, router):
-        # If the namespace assertion succeeds
-        # then the devices and iptable rules have also been deleted,
-        # so there's no need to check that explicitly.
-        self.assertFalse(self._namespace_exists(router.ns_name))
-        utils.wait_until_true(
-            lambda: not self._metadata_proxy_exists(self.agent.conf, router))
-
-    def _assert_snat_chains(self, router):
-        self.assertFalse(router.iptables_manager.is_chain_empty(
-            'nat', 'snat'))
-        self.assertFalse(router.iptables_manager.is_chain_empty(
-            'nat', 'POSTROUTING'))
-
-    def _assert_floating_ip_chains(self, router):
-        self.assertFalse(router.iptables_manager.is_chain_empty(
-            'nat', 'float-snat'))
-
-    def _assert_metadata_chains(self, router):
-        metadata_port_filter = lambda rule: (
-            str(self.agent.conf.metadata_port) in rule.rule)
-        self.assertTrue(self._get_rule(router.iptables_manager,
-                                       'nat',
-                                       'PREROUTING',
-                                       metadata_port_filter))
-        self.assertTrue(self._get_rule(router.iptables_manager,
-                                       'filter',
-                                       'INPUT',
-                                       metadata_port_filter))
-
-    def _assert_internal_devices(self, router):
-        internal_devices = router.router[l3_constants.INTERFACE_KEY]
-        self.assertTrue(len(internal_devices))
-        for device in internal_devices:
-            self.assertTrue(self.device_exists_with_ips_and_mac(
-                device, router.get_internal_device_name, router.ns_name))
-
-    def _assert_extra_routes(self, router):
-        routes = ip_lib.get_routing_table(4, namespace=router.ns_name)
-        routes = [{'nexthop': route['nexthop'],
-                   'destination': route['destination']} for route in routes]
-
-        for extra_route in router.router['routes']:
-            self.assertIn(extra_route, routes)
-
-    def _assert_onlink_subnet_routes(
-            self, router, ip_versions, namespace=None):
-        ns_name = namespace or router.ns_name
-        routes = []
-        for ip_version in ip_versions:
-            _routes = ip_lib.get_routing_table(ip_version,
-                                               namespace=ns_name)
-            routes.extend(_routes)
-        routes = set(route['destination'] for route in routes)
-        extra_subnets = router.get_ex_gw_port()['extra_subnets']
-        for extra_subnet in (route['cidr'] for route in extra_subnets):
-            self.assertIn(extra_subnet, routes)
-
-    def _assert_interfaces_deleted_from_ovs(self):
-        def assert_ovs_bridge_empty(bridge_name):
-            bridge = ovs_lib.OVSBridge(bridge_name)
-            self.assertFalse(bridge.get_port_name_list())
-
-        assert_ovs_bridge_empty(self.agent.conf.ovs_integration_bridge)
-        assert_ovs_bridge_empty(self.agent.conf.external_network_bridge)
-
-    def floating_ips_configured(self, router):
-        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
-        external_port = router.get_ex_gw_port()
-        return len(floating_ips) and all(
-            ip_lib.device_exists_with_ips_and_mac(
-                router.get_external_device_name(external_port['id']),
-                ['%s/32' % fip['floating_ip_address']],
-                external_port['mac_address'],
-                namespace=router.ns_name) for fip in floating_ips)
-
-    def fail_ha_router(self, router):
-        device_name = router.get_ha_device_name()
-        ha_device = ip_lib.IPDevice(device_name, router.ha_namespace)
-        ha_device.link.set_down()
-
-    @classmethod
-    def _get_addresses_on_device(cls, namespace, interface):
-        return [address['cidr'] for address in
-                ip_lib.IPDevice(interface, namespace=namespace).addr.list()]
-
-    def _assert_no_ip_addresses_on_interface(self, namespace, interface):
-        self.assertEqual(
-            [], self._get_addresses_on_device(namespace, interface))
-
-    def _assert_ip_address_on_interface(self,
-                                        namespace, interface, ip_address):
-        self.assertIn(
-            ip_address, self._get_addresses_on_device(namespace, interface))
-
-
-class L3AgentTestCase(L3AgentTestFramework):
-
-    def test_keepalived_state_change_notification(self):
-        enqueue_mock = mock.patch.object(
-            self.agent, 'enqueue_state_change').start()
-        router_info = self.generate_router_info(enable_ha=True)
-        router = self.manage_router(self.agent, router_info)
-        utils.wait_until_true(lambda: router.ha_state == 'master')
-
-        self.fail_ha_router(router)
-        utils.wait_until_true(lambda: router.ha_state == 'backup')
-
-        utils.wait_until_true(lambda: enqueue_mock.call_count == 3)
-        calls = [args[0] for args in enqueue_mock.call_args_list]
-        self.assertEqual((router.router_id, 'backup'), calls[0])
-        self.assertEqual((router.router_id, 'master'), calls[1])
-        self.assertEqual((router.router_id, 'backup'), calls[2])
-
-    def _expected_rpc_report(self, expected):
-        calls = (args[0][1] for args in
-                 self.agent.plugin_rpc.update_ha_routers_states.call_args_list)
-
-        # Get the last state reported for each router
-        actual_router_states = {}
-        for call in calls:
-            for router_id, state in six.iteritems(call):
-                actual_router_states[router_id] = state
-
-        return actual_router_states == expected
-
-    def test_keepalived_state_change_bulk_rpc(self):
-        router_info = self.generate_router_info(enable_ha=True)
-        router1 = self.manage_router(self.agent, router_info)
-        self.fail_ha_router(router1)
-        router_info = self.generate_router_info(enable_ha=True)
-        router2 = self.manage_router(self.agent, router_info)
-
-        utils.wait_until_true(lambda: router1.ha_state == 'backup')
-        utils.wait_until_true(lambda: router2.ha_state == 'master')
-        utils.wait_until_true(
-            lambda: self._expected_rpc_report(
-                {router1.router_id: 'standby', router2.router_id: 'active'}))
-
-    def test_agent_notifications_for_router_events(self):
-        """Test notifications for router create, update, and delete.
-
-        Make sure that when the agent sends notifications of router events
-        for router create, update, and delete, that the correct handler is
-        called with the right resource, event, and router information.
-        """
-        event_handler = mock.Mock()
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.BEFORE_CREATE)
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.AFTER_CREATE)
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.BEFORE_UPDATE)
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.AFTER_UPDATE)
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.BEFORE_DELETE)
-        registry.subscribe(event_handler,
-                           resources.ROUTER, events.AFTER_DELETE)
-
-        router_info = self.generate_router_info(enable_ha=False)
-        router = self.manage_router(self.agent, router_info)
-        self.agent._process_updated_router(router.router)
-        self._delete_router(self.agent, router.router_id)
-
-        expected_calls = [
-            mock.call('router', 'before_create', self.agent, router=router),
-            mock.call('router', 'after_create', self.agent, router=router),
-            mock.call('router', 'before_update', self.agent, router=router),
-            mock.call('router', 'after_update', self.agent, router=router),
-            mock.call('router', 'before_delete', self.agent, router=router),
-            mock.call('router', 'after_delete', self.agent, router=router)]
-        event_handler.assert_has_calls(expected_calls)
-
-    def test_legacy_router_lifecycle(self):
-        self._router_lifecycle(enable_ha=False, dual_stack=True)
-
-    def test_legacy_router_lifecycle_with_no_gateway_subnet(self):
-        self.agent.conf.set_override('ipv6_gateway',
-                                     'fe80::f816:3eff:fe2e:1')
-        self._router_lifecycle(enable_ha=False, dual_stack=True,
-                               v6_ext_gw_with_sub=False)
-
-    def test_ha_router_lifecycle(self):
-        self._router_lifecycle(enable_ha=True)
-
-    def test_conntrack_disassociate_fip_legacy_router(self):
-        self._test_conntrack_disassociate_fip(ha=False)
-
-    def test_conntrack_disassociate_fip_ha_router(self):
-        self._test_conntrack_disassociate_fip(ha=True)
-
-    def _test_conntrack_disassociate_fip(self, ha):
-        '''Test that conntrack immediately drops stateful connection
-           that uses floating IP once it's disassociated.
-        '''
-        router_info = self.generate_router_info(enable_ha=ha)
-        router = self.manage_router(self.agent, router_info)
-
-        port = net_helpers.get_free_namespace_port(l3_constants.PROTO_NAME_TCP,
-                                                   router.ns_name)
-        client_address = '19.4.4.3'
-        server_address = '35.4.0.4'
-
-        def clean_fips(router):
-            router.router[l3_constants.FLOATINGIP_KEY] = []
-
-        clean_fips(router)
-        self._add_fip(router, client_address, fixed_address=server_address)
-        router.process(self.agent)
-
-        router_ns = ip_lib.IPWrapper(namespace=router.ns_name)
-        netcat = net_helpers.NetcatTester(
-            router.ns_name, router.ns_name, client_address, port,
-            protocol=net_helpers.NetcatTester.TCP)
-        self.addCleanup(netcat.stop_processes)
-
-        def assert_num_of_conntrack_rules(n):
-            out = router_ns.netns.execute(["conntrack", "-L",
-                                           "--orig-src", client_address])
-            self.assertEqual(
-                n, len([line for line in out.strip().split('\n') if line]))
-
-        if ha:
-            utils.wait_until_true(lambda: router.ha_state == 'master')
-
-        with self.assert_max_execution_time(100):
-            assert_num_of_conntrack_rules(0)
-
-            self.assertTrue(netcat.test_connectivity())
-            assert_num_of_conntrack_rules(1)
-
-            clean_fips(router)
-            router.process(self.agent)
-            assert_num_of_conntrack_rules(0)
-
-            with testtools.ExpectedException(RuntimeError):
-                netcat.test_connectivity()
-
-    def test_ipv6_ha_router_lifecycle(self):
-        self._router_lifecycle(enable_ha=True, ip_version=6)
-
-    def test_ipv6_ha_router_lifecycle_with_no_gw_subnet(self):
-        self.agent.conf.set_override('ipv6_gateway',
-                                     'fe80::f816:3eff:fe2e:1')
-        self._router_lifecycle(enable_ha=True, ip_version=6,
-                               v6_ext_gw_with_sub=False)
-
-    def test_ipv6_ha_router_lifecycle_with_no_gw_subnet_for_router_advts(self):
-        # Verify that router gw interface is configured to receive Router
-        # Advts from upstream router when no external gateway is configured.
-        self._router_lifecycle(enable_ha=True, dual_stack=True,
-                               v6_ext_gw_with_sub=False)
-
-    def test_keepalived_configuration(self):
-        router_info = self.generate_router_info(enable_ha=True)
-        router = self.manage_router(self.agent, router_info)
-        expected = self.get_expected_keepalive_configuration(router)
-
-        self.assertEqual(expected,
-                         router.keepalived_manager.get_conf_on_disk())
-
-        # Add a new FIP and change the GW IP address
-        router.router = copy.deepcopy(router.router)
-        existing_fip = '19.4.4.2'
-        new_fip = '19.4.4.3'
-        self._add_fip(router, new_fip)
-        subnet_id = _uuid()
-        fixed_ips = [{'ip_address': '19.4.4.10',
-                      'prefixlen': 24,
-                      'subnet_id': subnet_id}]
-        subnets = [{'id': subnet_id,
-                    'cidr': '19.4.4.0/24',
-                    'gateway_ip': '19.4.4.5'}]
-        router.router['gw_port']['subnets'] = subnets
-        router.router['gw_port']['fixed_ips'] = fixed_ips
-
-        router.process(self.agent)
-
-        # Get the updated configuration and assert that both FIPs are in,
-        # and that the GW IP address was updated.
-        new_config = router.keepalived_manager.config.get_config_str()
-        old_gw = '0.0.0.0/0 via 19.4.4.1'
-        new_gw = '0.0.0.0/0 via 19.4.4.5'
-        old_external_device_ip = '19.4.4.4'
-        new_external_device_ip = '19.4.4.10'
-        self.assertIn(existing_fip, new_config)
-        self.assertIn(new_fip, new_config)
-        self.assertNotIn(old_gw, new_config)
-        self.assertIn(new_gw, new_config)
-        external_port = router.get_ex_gw_port()
-        external_device_name = router.get_external_device_name(
-            external_port['id'])
-        self.assertNotIn('%s/24 dev %s' %
-                         (old_external_device_ip, external_device_name),
-                         new_config)
-        self.assertIn('%s/24 dev %s' %
-                      (new_external_device_ip, external_device_name),
-                      new_config)
-
-    def _test_periodic_sync_routers_task(self,
-                                         routers_to_keep,
-                                         routers_deleted,
-                                         routers_deleted_during_resync):
-        ns_names_to_retrieve = set()
-        deleted_routers_info = []
-        for r in routers_to_keep:
-            ri = self.manage_router(self.agent, r)
-            ns_names_to_retrieve.add(ri.ns_name)
-        for r in routers_deleted + routers_deleted_during_resync:
-            ri = self.manage_router(self.agent, r)
-            deleted_routers_info.append(ri)
-            ns_names_to_retrieve.add(ri.ns_name)
-
-        mocked_get_routers = self.mock_plugin_api.get_routers
-        mocked_get_routers.return_value = (routers_to_keep +
-                                           routers_deleted_during_resync)
-        # clear agent router_info as it will be after restart
-        self.agent.router_info = {}
-
-        # Synchronize the agent with the plug-in
-        with mock.patch.object(namespace_manager.NamespaceManager, 'list_all',
-                               return_value=ns_names_to_retrieve):
-            self.agent.periodic_sync_routers_task(self.agent.context)
-
-        # Mock the plugin RPC API so a known external network id is returned
-        # when the router updates are processed by the agent
-        external_network_id = _uuid()
-        self.mock_plugin_api.get_external_network_id.return_value = (
-            external_network_id)
-
-        # Plug external_gateway_info in the routers that are not going to be
-        # deleted by the agent when it processes the updates. Otherwise,
-        # _process_router_if_compatible in the agent fails
-        for r in routers_to_keep:
-            r['external_gateway_info'] = {'network_id': external_network_id}
-
-        # while sync updates are still in the queue, higher priority
-        # router_deleted events may be added there as well
-        for r in routers_deleted_during_resync:
-            self.agent.router_deleted(self.agent.context, r['id'])
-
-        # make sure all events are processed
-        while not self.agent._queue._queue.empty():
-            self.agent._process_router_update()
-
-        for r in routers_to_keep:
-            self.assertIn(r['id'], self.agent.router_info)
-            self.assertTrue(self._namespace_exists(namespaces.NS_PREFIX +
-                                                   r['id']))
-        for ri in deleted_routers_info:
-            self.assertNotIn(ri.router_id,
-                             self.agent.router_info)
-            self._assert_router_does_not_exist(ri)
-
-    def test_periodic_sync_routers_task(self):
-        routers_to_keep = []
-        for i in range(2):
-            routers_to_keep.append(self.generate_router_info(False))
-        self._test_periodic_sync_routers_task(routers_to_keep,
-                                              routers_deleted=[],
-                                              routers_deleted_during_resync=[])
-
-    def test_periodic_sync_routers_task_routers_deleted_while_agent_down(self):
-        routers_to_keep = []
-        routers_deleted = []
-        for i in range(2):
-            routers_to_keep.append(self.generate_router_info(False))
-        for i in range(2):
-            routers_deleted.append(self.generate_router_info(False))
-        self._test_periodic_sync_routers_task(routers_to_keep,
-                                              routers_deleted,
-                                              routers_deleted_during_resync=[])
-
-    def test_periodic_sync_routers_task_routers_deleted_while_agent_sync(self):
-        routers_to_keep = []
-        routers_deleted_during_resync = []
-        for i in range(2):
-            routers_to_keep.append(self.generate_router_info(False))
-        for i in range(2):
-            routers_deleted_during_resync.append(
-                self.generate_router_info(False))
-        self._test_periodic_sync_routers_task(
-            routers_to_keep,
-            routers_deleted=[],
-            routers_deleted_during_resync=routers_deleted_during_resync)
-
-    def _router_lifecycle(self, enable_ha, ip_version=4,
-                          dual_stack=False, v6_ext_gw_with_sub=True):
-        router_info = self.generate_router_info(enable_ha, ip_version,
-                                                dual_stack=dual_stack,
-                                                v6_ext_gw_with_sub=(
-                                                    v6_ext_gw_with_sub))
-        router = self.manage_router(self.agent, router_info)
-
-        # Add multiple-IPv6-prefix internal router port
-        slaac = l3_constants.IPV6_SLAAC
-        slaac_mode = {'ra_mode': slaac, 'address_mode': slaac}
-        subnet_modes = [slaac_mode] * 2
-        self._add_internal_interface_by_subnet(router.router,
-                                               count=2,
-                                               ip_version=6,
-                                               ipv6_subnet_modes=subnet_modes)
-        router.process(self.agent)
-
-        if enable_ha:
-            port = router.get_ex_gw_port()
-            interface_name = router.get_external_device_name(port['id'])
-            self._assert_no_ip_addresses_on_interface(router.ns_name,
-                                                      interface_name)
-            utils.wait_until_true(lambda: router.ha_state == 'master')
-
-            # Keepalived notifies of a state transition when it starts,
-            # not when it ends. Thus, we have to wait until keepalived finishes
-            # configuring everything. We verify this by waiting until the last
-            # device has an IP address.
-            device = router.router[l3_constants.INTERFACE_KEY][-1]
-            device_exists = functools.partial(
-                self.device_exists_with_ips_and_mac,
-                device,
-                router.get_internal_device_name,
-                router.ns_name)
-            utils.wait_until_true(device_exists)
-
-        self.assertTrue(self._namespace_exists(router.ns_name))
-        utils.wait_until_true(
-            lambda: self._metadata_proxy_exists(self.agent.conf, router))
-        self._assert_internal_devices(router)
-        self._assert_external_device(router)
-        if not (enable_ha and (ip_version == 6 or dual_stack)):
-            # Note(SridharG): enable the assert_gateway for IPv6 once
-            # keepalived on Ubuntu14.04 (i.e., check-neutron-dsvm-functional
-            # platform) is updated to 1.2.10 (or above).
-            # For more details: https://review.openstack.org/#/c/151284/
-            self._assert_gateway(router, v6_ext_gw_with_sub)
-            self.assertTrue(self.floating_ips_configured(router))
-            self._assert_snat_chains(router)
-            self._assert_floating_ip_chains(router)
-            self._assert_extra_routes(router)
-            ip_versions = [4, 6] if (ip_version == 6 or dual_stack) else [4]
-            self._assert_onlink_subnet_routes(router, ip_versions)
-        self._assert_metadata_chains(router)
-
-        # Verify router gateway interface is configured to receive Router Advts
-        # when IPv6 is enabled and no IPv6 gateway is configured.
-        if router.use_ipv6 and not v6_ext_gw_with_sub:
-            if not self.agent.conf.ipv6_gateway:
-                external_port = router.get_ex_gw_port()
-                external_device_name = router.get_external_device_name(
-                    external_port['id'])
-                ip_wrapper = ip_lib.IPWrapper(namespace=router.ns_name)
-                ra_state = ip_wrapper.netns.execute(['sysctl', '-b',
-                    'net.ipv6.conf.%s.accept_ra' % external_device_name])
-                self.assertEqual('2', ra_state)
-
-        if enable_ha:
-            self._assert_ha_device(router)
-            self.assertTrue(router.keepalived_manager.get_process().active)
-
-        self._delete_router(self.agent, router.router_id)
-
-        self._assert_interfaces_deleted_from_ovs()
-        self._assert_router_does_not_exist(router)
-        if enable_ha:
-            self.assertFalse(router.keepalived_manager.get_process().active)
-
-    def _assert_external_device(self, router):
-        external_port = router.get_ex_gw_port()
-        self.assertTrue(self.device_exists_with_ips_and_mac(
-            external_port, router.get_external_device_name,
-            router.ns_name))
-
-    def _assert_gateway(self, router, v6_ext_gw_with_sub=True):
-        external_port = router.get_ex_gw_port()
-        external_device_name = router.get_external_device_name(
-            external_port['id'])
-        external_device = ip_lib.IPDevice(external_device_name,
-                                          namespace=router.ns_name)
-        for subnet in external_port['subnets']:
-            self._gateway_check(subnet['gateway_ip'], external_device)
-        if not v6_ext_gw_with_sub:
-            self._gateway_check(self.agent.conf.ipv6_gateway,
-                                external_device)
-
-    def _gateway_check(self, gateway_ip, external_device):
-        expected_gateway = gateway_ip
-        ip_vers = netaddr.IPAddress(expected_gateway).version
-        existing_gateway = (external_device.route.get_gateway(
-            ip_version=ip_vers).get('gateway'))
-        self.assertEqual(expected_gateway, existing_gateway)
-
-    def _assert_ha_device(self, router):
-        def ha_router_dev_name_getter(not_used):
-            return router.get_ha_device_name()
-        self.assertTrue(self.device_exists_with_ips_and_mac(
-            router.router[l3_constants.HA_INTERFACE_KEY],
-            ha_router_dev_name_getter, router.ns_name))
-
-    def test_ha_router_conf_on_restarted_agent(self):
-        router_info = self.generate_router_info(enable_ha=True)
-        router1 = self.manage_router(self.agent, router_info)
-        self._add_fip(router1, '192.168.111.12')
-        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
-            self.agent.host, self.agent.conf)
-        self.manage_router(restarted_agent, router1.router)
-        utils.wait_until_true(lambda: self.floating_ips_configured(router1))
-        self.assertIn(
-            router1._get_primary_vip(),
-            self._get_addresses_on_device(
-                router1.ns_name,
-                router1.get_ha_device_name()))
-
-    def test_fip_connection_from_same_subnet(self):
-        '''Test connection to floatingip which is associated with
-           fixed_ip on the same subnet of the source fixed_ip.
-           In other words it confirms that return packets surely
-           go through the router.
-        '''
-        router_info = self.generate_router_info(enable_ha=False)
-        router = self.manage_router(self.agent, router_info)
-        router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
-        router_ip = router_ip_cidr.partition('/')[0]
-
-        br_int = get_ovs_bridge(self.agent.conf.ovs_integration_bridge)
-        src_machine, dst_machine = self.useFixture(
-            machine_fixtures.PeerMachines(
-                br_int,
-                net_helpers.increment_ip_cidr(router_ip_cidr),
-                router_ip)).machines
-
-        dst_fip = '19.4.4.10'
-        router.router[l3_constants.FLOATINGIP_KEY] = []
-        self._add_fip(router, dst_fip, fixed_address=dst_machine.ip)
-        router.process(self.agent)
-
-        protocol_port = net_helpers.get_free_namespace_port(
-            l3_constants.PROTO_NAME_TCP, dst_machine.namespace)
-        # client sends to fip
-        netcat = net_helpers.NetcatTester(
-            src_machine.namespace, dst_machine.namespace,
-            dst_fip, protocol_port,
-            protocol=net_helpers.NetcatTester.TCP)
-        self.addCleanup(netcat.stop_processes)
-        self.assertTrue(netcat.test_connectivity())
-
-    def test_delete_external_gateway_on_standby_router(self):
-        router_info = self.generate_router_info(enable_ha=True)
-        router = self.manage_router(self.agent, router_info)
-
-        self.fail_ha_router(router)
-        utils.wait_until_true(lambda: router.ha_state == 'backup')
-
-        # The purpose of the test is to simply make sure no exception is raised
-        port = router.get_ex_gw_port()
-        interface_name = router.get_external_device_name(port['id'])
-        router.external_gateway_removed(port, interface_name)
-
-
-class L3HATestFramework(L3AgentTestFramework):
-
-    NESTED_NAMESPACE_SEPARATOR = '@'
-
-    def setUp(self):
-        super(L3HATestFramework, self).setUp()
-        self.conf = self._configure_agent('agent2')
-        self.failover_agent = neutron_l3_agent.L3NATAgentWithStateReport(
-            'agent2', self.conf)
-
-        br_int_1 = self._get_agent_ovs_integration_bridge(self.agent)
-        br_int_2 = self._get_agent_ovs_integration_bridge(self.failover_agent)
-
-        veth1, veth2 = self.useFixture(net_helpers.VethFixture()).ports
-        br_int_1.add_port(veth1.name)
-        br_int_2.add_port(veth2.name)
-
-    def test_ha_router_failover(self):
-        router_info = self.generate_router_info(enable_ha=True)
-        get_ns_name = mock.patch.object(
-            namespaces.RouterNamespace, '_get_ns_name').start()
-        get_ns_name.return_value = "%s%s%s" % (
-            'qrouter-' + router_info['id'],
-            self.NESTED_NAMESPACE_SEPARATOR, self.agent.host)
-        router1 = self.manage_router(self.agent, router_info)
-
-        router_info_2 = copy.deepcopy(router_info)
-        router_info_2[l3_constants.HA_INTERFACE_KEY] = (
-            l3_test_common.get_ha_interface(ip='169.254.192.2',
-                                            mac='22:22:22:22:22:22'))
-
-        get_ns_name.return_value = "%s%s%s" % (
-            namespaces.RouterNamespace._get_ns_name(router_info_2['id']),
-            self.NESTED_NAMESPACE_SEPARATOR, self.failover_agent.host)
-        router2 = self.manage_router(self.failover_agent, router_info_2)
-
-        utils.wait_until_true(lambda: router1.ha_state == 'master')
-        utils.wait_until_true(lambda: router2.ha_state == 'backup')
-
-        self.fail_ha_router(router1)
-
-        utils.wait_until_true(lambda: router2.ha_state == 'master')
-        utils.wait_until_true(lambda: router1.ha_state == 'backup')
-
-    def test_ha_router_ipv6_radvd_status(self):
-        router_info = self.generate_router_info(ip_version=6, enable_ha=True)
-        router1 = self.manage_router(self.agent, router_info)
-        utils.wait_until_true(lambda: router1.ha_state == 'master')
-        utils.wait_until_true(lambda: router1.radvd.enabled)
-
-        def _check_lla_status(router, expected):
-            internal_devices = router.router[l3_constants.INTERFACE_KEY]
-            for device in internal_devices:
-                lladdr = ip_lib.get_ipv6_lladdr(device['mac_address'])
-                exists = ip_lib.device_exists_with_ips_and_mac(
-                    router.get_internal_device_name(device['id']), [lladdr],
-                    device['mac_address'], router.ns_name)
-                self.assertEqual(expected, exists)
-
-        _check_lla_status(router1, True)
-
-        device_name = router1.get_ha_device_name()
-        ha_device = ip_lib.IPDevice(device_name, namespace=router1.ns_name)
-        ha_device.link.set_down()
-
-        utils.wait_until_true(lambda: router1.ha_state == 'backup')
-        utils.wait_until_true(lambda: not router1.radvd.enabled, timeout=10)
-        _check_lla_status(router1, False)
-
-    def test_ha_router_process_ipv6_subnets_to_existing_port(self):
-        router_info = self.generate_router_info(enable_ha=True, ip_version=6)
-        router = self.manage_router(self.agent, router_info)
-
-        def verify_ip_in_keepalived_config(router, iface):
-            config = router.keepalived_manager.config.get_config_str()
-            ip_cidrs = common_utils.fixed_ip_cidrs(iface['fixed_ips'])
-            for ip_addr in ip_cidrs:
-                self.assertIn(ip_addr, config)
-
-        interface_id = router.router[l3_constants.INTERFACE_KEY][0]['id']
-        slaac = l3_constants.IPV6_SLAAC
-        slaac_mode = {'ra_mode': slaac, 'address_mode': slaac}
-
-        # Add a second IPv6 subnet to the router internal interface.
-        self._add_internal_interface_by_subnet(router.router, count=1,
-                ip_version=6, ipv6_subnet_modes=[slaac_mode],
-                interface_id=interface_id)
-        router.process(self.agent)
-        utils.wait_until_true(lambda: router.ha_state == 'master')
-
-        # Verify that router internal interface is present and is configured
-        # with IP address from both the subnets.
-        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
-        self.assertEqual(2, len(internal_iface['fixed_ips']))
-        self._assert_internal_devices(router)
-
-        # Verify that keepalived config is properly updated.
-        verify_ip_in_keepalived_config(router, internal_iface)
-
-        # Remove one subnet from the router internal iface
-        interfaces = copy.deepcopy(router.router.get(
-            l3_constants.INTERFACE_KEY, []))
-        fixed_ips, subnets = [], []
-        fixed_ips.append(interfaces[0]['fixed_ips'][0])
-        subnets.append(interfaces[0]['subnets'][0])
-        interfaces[0].update({'fixed_ips': fixed_ips, 'subnets': subnets})
-        router.router[l3_constants.INTERFACE_KEY] = interfaces
-        router.process(self.agent)
-
-        # Verify that router internal interface has a single ipaddress
-        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
-        self.assertEqual(1, len(internal_iface['fixed_ips']))
-        self._assert_internal_devices(router)
-
-        # Verify that keepalived config is properly updated.
-        verify_ip_in_keepalived_config(router, internal_iface)
-
-
 class TestL3AgentRestart(test_service.TestServiceRestart,
-                         L3AgentTestFramework):
+                         framework.L3AgentTestFramework):
 
     def _start_l3_agent(self, workers=1):
         with mock.patch("neutron.service.Service.start") as start_method:
@@ -941,728 +35,3 @@ class TestL3AgentRestart(test_service.TestServiceRestart,
     def test_restart_l3_agent_on_sighup(self):
         self._test_restart_service_on_sighup(service=self._start_l3_agent,
                                              workers=1)
-
-
-class MetadataFakeProxyHandler(object):
-
-    def __init__(self, status):
-        self.status = status
-
-    @webob.dec.wsgify()
-    def __call__(self, req):
-        return webob.Response(status=self.status)
-
-
-class MetadataL3AgentTestCase(L3AgentTestFramework):
-
-    SOCKET_MODE = 0o644
-
-    def _create_metadata_fake_server(self, status):
-        server = utils.UnixDomainWSGIServer('metadata-fake-server')
-        self.addCleanup(server.stop)
-
-        # NOTE(cbrandily): TempDir fixture creates a folder with 0o700
-        # permissions but metadata_proxy_socket folder must be readable by all
-        # users
-        self.useFixture(
-            helpers.RecursivePermDirFixture(
-                os.path.dirname(self.agent.conf.metadata_proxy_socket), 0o555))
-        server.start(MetadataFakeProxyHandler(status),
-                     self.agent.conf.metadata_proxy_socket,
-                     workers=0, backlog=4096, mode=self.SOCKET_MODE)
-
-    def _query_metadata_proxy(self, machine):
-        url = 'http://%(host)s:%(port)s' % {'host': dhcp.METADATA_DEFAULT_IP,
-                                            'port': dhcp.METADATA_PORT}
-        cmd = 'curl', '--max-time', METADATA_REQUEST_TIMEOUT, '-D-', url
-        i = 0
-        CONNECTION_REFUSED_TIMEOUT = METADATA_REQUEST_TIMEOUT // 2
-        while i <= CONNECTION_REFUSED_TIMEOUT:
-            try:
-                raw_headers = machine.execute(cmd)
-                break
-            except RuntimeError as e:
-                if 'Connection refused' in str(e):
-                    time.sleep(METADATA_REQUEST_SLEEP)
-                    i += METADATA_REQUEST_SLEEP
-                else:
-                    self.fail('metadata proxy unreachable '
-                              'on %s before timeout' % url)
-
-        if i > CONNECTION_REFUSED_TIMEOUT:
-            self.fail('Timed out waiting metadata proxy to become available')
-        return raw_headers.splitlines()[0]
-
-    def test_access_to_metadata_proxy(self):
-        """Test access to the l3-agent metadata proxy.
-
-        The test creates:
-         * A l3-agent metadata service:
-           * A router (which creates a metadata proxy in the router namespace),
-           * A fake metadata server
-         * A "client" namespace (simulating a vm) with a port on router
-           internal subnet.
-
-        The test queries from the "client" namespace the metadata proxy on
-        http://169.254.169.254 and asserts that the metadata proxy added
-        the X-Forwarded-For and X-Neutron-Router-Id headers to the request
-        and forwarded the http request to the fake metadata server and the
-        response to the "client" namespace.
-        """
-        router_info = self.generate_router_info(enable_ha=False)
-        router = self.manage_router(self.agent, router_info)
-        self._create_metadata_fake_server(webob.exc.HTTPOk.code)
-
-        # Create and configure client namespace
-        router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
-        br_int = get_ovs_bridge(self.agent.conf.ovs_integration_bridge)
-
-        machine = self.useFixture(
-            machine_fixtures.FakeMachine(
-                br_int,
-                net_helpers.increment_ip_cidr(router_ip_cidr),
-                router_ip_cidr.partition('/')[0]))
-
-        # Query metadata proxy
-        firstline = self._query_metadata_proxy(machine)
-
-        # Check status code
-        self.assertIn(str(webob.exc.HTTPOk.code), firstline.split())
-
-
-class UnprivilegedUserMetadataL3AgentTestCase(MetadataL3AgentTestCase):
-    """Test metadata proxy with least privileged user.
-
-    The least privileged user has uid=65534 and is commonly named 'nobody' but
-    not always, that's why we use its uid.
-    """
-
-    SOCKET_MODE = 0o664
-
-    def setUp(self):
-        super(UnprivilegedUserMetadataL3AgentTestCase, self).setUp()
-        self.agent.conf.set_override('metadata_proxy_user', '65534')
-        self.agent.conf.set_override('metadata_proxy_watch_log', False)
-
-
-class UnprivilegedUserGroupMetadataL3AgentTestCase(MetadataL3AgentTestCase):
-    """Test metadata proxy with least privileged user/group.
-
-    The least privileged user has uid=65534 and is commonly named 'nobody' but
-    not always, that's why we use its uid.
-    Its group has gid=65534 and is commonly named 'nobody' or 'nogroup', that's
-    why we use its gid.
-    """
-
-    SOCKET_MODE = 0o666
-
-    def setUp(self):
-        super(UnprivilegedUserGroupMetadataL3AgentTestCase, self).setUp()
-        self.agent.conf.set_override('metadata_proxy_user', '65534')
-        self.agent.conf.set_override('metadata_proxy_group', '65534')
-        self.agent.conf.set_override('metadata_proxy_watch_log', False)
-
-
-class TestDvrRouter(L3AgentTestFramework):
-    def test_dvr_router_lifecycle_without_ha_without_snat_with_fips(self):
-        self._dvr_router_lifecycle(enable_ha=False, enable_snat=False)
-
-    def test_dvr_router_lifecycle_without_ha_with_snat_with_fips(self):
-        self._dvr_router_lifecycle(enable_ha=False, enable_snat=True)
-
-    def test_dvr_router_lifecycle_ha_with_snat_with_fips(self):
-        self._dvr_router_lifecycle(enable_ha=True, enable_snat=True)
-
-    def _helper_create_dvr_router_fips_for_ext_network(
-            self, agent_mode, **dvr_router_kwargs):
-        self.agent.conf.agent_mode = agent_mode
-        router_info = self.generate_dvr_router_info(**dvr_router_kwargs)
-        self.mock_plugin_api.get_external_network_id.return_value = (
-            router_info['_floatingips'][0]['floating_network_id'])
-        router = self.manage_router(self.agent, router_info)
-        fip_ns = router.fip_ns.get_name()
-        return router, fip_ns
-
-    def _validate_fips_for_external_network(self, router, fip_ns):
-        self.assertTrue(self._namespace_exists(router.ns_name))
-        self.assertTrue(self._namespace_exists(fip_ns))
-        self._assert_dvr_floating_ips(router)
-        self._assert_snat_namespace_does_not_exist(router)
-
-    def test_dvr_router_fips_for_multiple_ext_networks(self):
-        agent_mode = 'dvr'
-        # Create the first router fip with external net1
-        dvr_router1_kwargs = {'ip_address': '19.4.4.3',
-                              'subnet_cidr': '19.4.4.0/24',
-                              'gateway_ip': '19.4.4.1',
-                              'gateway_mac': 'ca:fe:de:ab:cd:ef'}
-        router1, fip1_ns = (
-            self._helper_create_dvr_router_fips_for_ext_network(
-                agent_mode, **dvr_router1_kwargs))
-        # Validate the fip with external net1
-        self._validate_fips_for_external_network(router1, fip1_ns)
-
-        # Create the second router fip with external net2
-        dvr_router2_kwargs = {'ip_address': '19.4.5.3',
-                              'subnet_cidr': '19.4.5.0/24',
-                              'gateway_ip': '19.4.5.1',
-                              'gateway_mac': 'ca:fe:de:ab:cd:fe'}
-        router2, fip2_ns = (
-            self._helper_create_dvr_router_fips_for_ext_network(
-                agent_mode, **dvr_router2_kwargs))
-        # Validate the fip with external net2
-        self._validate_fips_for_external_network(router2, fip2_ns)
-
-    def _dvr_router_lifecycle(self, enable_ha=False, enable_snat=False,
-                              custom_mtu=2000,
-                              ip_version=4,
-                              dual_stack=False):
-        '''Test dvr router lifecycle
-
-        :param enable_ha: sets the ha value for the router.
-        :param enable_snat:  the value of enable_snat is used
-        to  set the  agent_mode.
-        '''
-
-        # The value of agent_mode can be dvr, dvr_snat, or legacy.
-        # Since by definition this is a dvr (distributed = true)
-        # only dvr and dvr_snat are applicable
-        self.agent.conf.agent_mode = 'dvr_snat' if enable_snat else 'dvr'
-        self.agent.conf.network_device_mtu = custom_mtu
-
-        # We get the router info particular to a dvr router
-        router_info = self.generate_dvr_router_info(
-            enable_ha, enable_snat)
-
-        # We need to mock the get_agent_gateway_port return value
-        # because the whole L3PluginApi is mocked and we need the port
-        # gateway_port information before the l3_agent will create it.
-        # The port returned needs to have the same information as
-        # router_info['gw_port']
-        self.mock_plugin_api.get_agent_gateway_port.return_value = router_info[
-            'gw_port']
-
-        # We also need to mock the get_external_network_id method to
-        # get the correct fip namespace.
-        self.mock_plugin_api.get_external_network_id.return_value = (
-            router_info['_floatingips'][0]['floating_network_id'])
-
-        # With all that set we can now ask the l3_agent to
-        # manage the router (create it, create namespaces,
-        # attach interfaces, etc...)
-        router = self.manage_router(self.agent, router_info)
-        if enable_ha:
-            port = router.get_ex_gw_port()
-            interface_name = router.get_external_device_name(port['id'])
-            self._assert_no_ip_addresses_on_interface(router.ha_namespace,
-                                                      interface_name)
-            utils.wait_until_true(lambda: router.ha_state == 'master')
-
-            # Keepalived notifies of a state transition when it starts,
-            # not when it ends. Thus, we have to wait until keepalived finishes
-            # configuring everything. We verify this by waiting until the last
-            # device has an IP address.
-            device = router.router[l3_constants.INTERFACE_KEY][-1]
-            device_exists = functools.partial(
-                self.device_exists_with_ips_and_mac,
-                device,
-                router.get_internal_device_name,
-                router.ns_name)
-            utils.wait_until_true(device_exists)
-
-        ext_gateway_port = router_info['gw_port']
-        self.assertTrue(self._namespace_exists(router.ns_name))
-        utils.wait_until_true(
-            lambda: self._metadata_proxy_exists(self.agent.conf, router))
-        self._assert_internal_devices(router)
-        self._assert_dvr_external_device(router)
-        self._assert_dvr_gateway(router)
-        self._assert_dvr_floating_ips(router)
-        self._assert_snat_chains(router)
-        self._assert_floating_ip_chains(router)
-        self._assert_metadata_chains(router)
-        self._assert_extra_routes(router)
-        self._assert_rfp_fpr_mtu(router, custom_mtu)
-        if enable_snat:
-            ip_versions = [4, 6] if (ip_version == 6 or dual_stack) else [4]
-            snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-                router.router_id)
-            self._assert_onlink_subnet_routes(
-                router, ip_versions, snat_ns_name)
-
-        self._delete_router(self.agent, router.router_id)
-        self._assert_fip_namespace_deleted(ext_gateway_port)
-        self._assert_router_does_not_exist(router)
-        self._assert_snat_namespace_does_not_exist(router)
-
-    def generate_dvr_router_info(self,
-                                 enable_ha=False,
-                                 enable_snat=False,
-                                 agent=None,
-                                 **kwargs):
-        if not agent:
-            agent = self.agent
-        router = l3_test_common.prepare_router_data(
-            enable_snat=enable_snat,
-            enable_floating_ip=True,
-            enable_ha=enable_ha,
-            **kwargs)
-        internal_ports = router.get(l3_constants.INTERFACE_KEY, [])
-        router['distributed'] = True
-        router['gw_port_host'] = agent.conf.host
-        router['gw_port']['binding:host_id'] = agent.conf.host
-        floating_ip = router['_floatingips'][0]
-        floating_ip['floating_network_id'] = router['gw_port']['network_id']
-        floating_ip['host'] = agent.conf.host
-        floating_ip['port_id'] = internal_ports[0]['id']
-        floating_ip['status'] = 'ACTIVE'
-
-        self._add_snat_port_info_to_router(router, internal_ports)
-        # FIP has a dependency on external gateway. So we need to create
-        # the snat_port info and fip_agent_gw_port_info irrespective of
-        # the agent type the dvr supports. The namespace creation is
-        # dependent on the agent_type.
-        external_gw_port = router['gw_port']
-        self._add_fip_agent_gw_port_info_to_router(router, external_gw_port)
-        return router
-
-    def _add_fip_agent_gw_port_info_to_router(self, router, external_gw_port):
-        # Add fip agent gateway port information to the router_info
-        fip_gw_port_list = router.get(
-            l3_constants.FLOATINGIP_AGENT_INTF_KEY, [])
-        if not fip_gw_port_list and external_gw_port:
-            # Get values from external gateway port
-            fixed_ip = external_gw_port['fixed_ips'][0]
-            float_subnet = external_gw_port['subnets'][0]
-            port_ip = fixed_ip['ip_address']
-            # Pick an ip address which is not the same as port_ip
-            fip_gw_port_ip = str(netaddr.IPAddress(port_ip) + 5)
-            # Add floatingip agent gateway port info to router
-            prefixlen = netaddr.IPNetwork(float_subnet['cidr']).prefixlen
-            router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = [
-                {'subnets': [
-                    {'cidr': float_subnet['cidr'],
-                     'gateway_ip': float_subnet['gateway_ip'],
-                     'id': fixed_ip['subnet_id']}],
-                 'network_id': external_gw_port['network_id'],
-                 'device_owner': l3_constants.DEVICE_OWNER_AGENT_GW,
-                 'mac_address': 'fa:16:3e:80:8d:89',
-                 'binding:host_id': self.agent.conf.host,
-                 'fixed_ips': [{'subnet_id': fixed_ip['subnet_id'],
-                                'ip_address': fip_gw_port_ip,
-                                'prefixlen': prefixlen}],
-                 'id': _uuid(),
-                 'device_id': _uuid()}
-            ]
-
-    def _add_snat_port_info_to_router(self, router, internal_ports):
-        # Add snat port information to the router
-        snat_port_list = router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
-        if not snat_port_list and internal_ports:
-            # Get values from internal port
-            port = internal_ports[0]
-            fixed_ip = port['fixed_ips'][0]
-            snat_subnet = port['subnets'][0]
-            port_ip = fixed_ip['ip_address']
-            # Pick an ip address which is not the same as port_ip
-            snat_ip = str(netaddr.IPAddress(port_ip) + 5)
-            # Add the info to router as the first snat port
-            # in the list of snat ports
-            prefixlen = netaddr.IPNetwork(snat_subnet['cidr']).prefixlen
-            router[l3_constants.SNAT_ROUTER_INTF_KEY] = [
-                {'subnets': [
-                    {'cidr': snat_subnet['cidr'],
-                     'gateway_ip': snat_subnet['gateway_ip'],
-                     'id': fixed_ip['subnet_id']}],
-                 'network_id': port['network_id'],
-                 'device_owner': l3_constants.DEVICE_OWNER_ROUTER_SNAT,
-                 'mac_address': 'fa:16:3e:80:8d:89',
-                 'fixed_ips': [{'subnet_id': fixed_ip['subnet_id'],
-                                'ip_address': snat_ip,
-                                'prefixlen': prefixlen}],
-                 'id': _uuid(),
-                 'device_id': _uuid()}
-            ]
-
-    def _assert_dvr_external_device(self, router):
-        external_port = router.get_ex_gw_port()
-        snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-
-        # if the agent is in dvr_snat mode, then we have to check
-        # that the correct ports and ip addresses exist in the
-        # snat_ns_name namespace
-        if self.agent.conf.agent_mode == 'dvr_snat':
-            device_exists = functools.partial(
-                self.device_exists_with_ips_and_mac,
-                external_port,
-                router.get_external_device_name,
-                snat_ns_name)
-            utils.wait_until_true(device_exists)
-        # if the agent is in dvr mode then the snat_ns_name namespace
-        # should not be present at all:
-        elif self.agent.conf.agent_mode == 'dvr':
-            self.assertFalse(
-                self._namespace_exists(snat_ns_name),
-                "namespace %s was found but agent is in dvr mode not dvr_snat"
-                % (str(snat_ns_name))
-            )
-        # if the agent is anything else the test is misconfigured
-        # we force a test failure with message
-        else:
-            self.assertTrue(False, " agent not configured for dvr or dvr_snat")
-
-    def _assert_dvr_gateway(self, router):
-        gateway_expected_in_snat_namespace = (
-            self.agent.conf.agent_mode == 'dvr_snat'
-        )
-        if gateway_expected_in_snat_namespace:
-            self._assert_dvr_snat_gateway(router)
-            self._assert_removal_of_already_deleted_gateway_device(router)
-
-        snat_namespace_should_not_exist = (
-            self.agent.conf.agent_mode == 'dvr'
-        )
-        if snat_namespace_should_not_exist:
-            self._assert_snat_namespace_does_not_exist(router)
-
-    def _assert_dvr_snat_gateway(self, router):
-        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-        external_port = router.get_ex_gw_port()
-        external_device_name = router.get_external_device_name(
-            external_port['id'])
-        external_device = ip_lib.IPDevice(external_device_name,
-                                          namespace=namespace)
-        existing_gateway = (
-            external_device.route.get_gateway().get('gateway'))
-        expected_gateway = external_port['subnets'][0]['gateway_ip']
-        self.assertEqual(expected_gateway, existing_gateway)
-
-    def _assert_removal_of_already_deleted_gateway_device(self, router):
-        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-        device = ip_lib.IPDevice("fakedevice",
-                                 namespace=namespace)
-
-        # Assert that no exception is thrown for this case
-        self.assertIsNone(router._delete_gateway_device_if_exists(
-                          device, "192.168.0.1", 0))
-
-    def _assert_snat_namespace_does_not_exist(self, router):
-        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-        self.assertFalse(self._namespace_exists(namespace))
-
-    def _assert_dvr_floating_ips(self, router):
-        # in the fip namespace:
-        # Check that the fg-<port-id> (floatingip_agent_gateway)
-        # is created with the ip address of the external gateway port
-        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
-        self.assertTrue(floating_ips)
-        # We need to fetch the floatingip agent gateway port info
-        # from the router_info
-        floating_agent_gw_port = (
-            router.router[l3_constants.FLOATINGIP_AGENT_INTF_KEY])
-        self.assertTrue(floating_agent_gw_port)
-
-        external_gw_port = floating_agent_gw_port[0]
-        fip_ns = self.agent.get_fip_ns(floating_ips[0]['floating_network_id'])
-        fip_ns_name = fip_ns.get_name()
-        fg_port_created_successfully = ip_lib.device_exists_with_ips_and_mac(
-            fip_ns.get_ext_device_name(external_gw_port['id']),
-            [self._port_first_ip_cidr(external_gw_port)],
-            external_gw_port['mac_address'],
-            namespace=fip_ns_name)
-        self.assertTrue(fg_port_created_successfully)
-        # Check fpr-router device has been created
-        device_name = fip_ns.get_int_device_name(router.router_id)
-        fpr_router_device_created_successfully = ip_lib.device_exists(
-            device_name, namespace=fip_ns_name)
-        self.assertTrue(fpr_router_device_created_successfully)
-
-        # In the router namespace
-        # Check rfp-<router-id> is created correctly
-        for fip in floating_ips:
-            device_name = fip_ns.get_rtr_ext_device_name(router.router_id)
-            self.assertTrue(ip_lib.device_exists(
-                device_name, namespace=router.ns_name))
-
-    def test_dvr_router_rem_fips_on_restarted_agent(self):
-        self.agent.conf.agent_mode = 'dvr_snat'
-        router_info = self.generate_dvr_router_info()
-        router1 = self.manage_router(self.agent, router_info)
-        fip_ns = router1.fip_ns.get_name()
-        self.assertTrue(self._namespace_exists(fip_ns))
-        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
-            self.agent.host, self.agent.conf)
-        router1.router[l3_constants.FLOATINGIP_KEY] = []
-        self.manage_router(restarted_agent, router1.router)
-        self._assert_dvr_snat_gateway(router1)
-        self.assertTrue(self._namespace_exists(fip_ns))
-
-    def test_dvr_router_add_fips_on_restarted_agent(self):
-        self.agent.conf.agent_mode = 'dvr'
-        router_info = self.generate_dvr_router_info()
-        router = self.manage_router(self.agent, router_info)
-        floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
-        router_ns = router.ns_name
-        fip_rule_prio_1 = self._get_fixed_ip_rule_priority(
-            router_ns, floating_ips[0]['fixed_ip_address'])
-        restarted_agent = neutron_l3_agent.L3NATAgent(
-            self.agent.host, self.agent.conf)
-        floating_ips[0]['floating_ip_address'] = '21.4.4.2'
-        floating_ips[0]['fixed_ip_address'] = '10.0.0.2'
-        self.manage_router(restarted_agent, router_info)
-        fip_rule_prio_2 = self._get_fixed_ip_rule_priority(
-            router_ns, floating_ips[0]['fixed_ip_address'])
-        self.assertNotEqual(fip_rule_prio_1, fip_rule_prio_2)
-
-    def _get_fixed_ip_rule_priority(self, namespace, fip):
-        iprule = ip_lib.IPRule(namespace)
-        lines = iprule.rule._as_root([4], ['show']).splitlines()
-        for line in lines:
-            if fip in line:
-                info = iprule.rule._parse_line(4, line)
-                return info['priority']
-
-    def test_dvr_router_add_internal_network_set_arp_cache(self):
-        # Check that, when the router is set up and there are
-        # existing ports on the uplinked subnet, the ARP
-        # cache is properly populated.
-        self.agent.conf.agent_mode = 'dvr_snat'
-        router_info = l3_test_common.prepare_router_data()
-        router_info['distributed'] = True
-        expected_neighbor = '35.4.1.10'
-        port_data = {
-            'fixed_ips': [{'ip_address': expected_neighbor}],
-            'mac_address': 'fa:3e:aa:bb:cc:dd',
-            'device_owner': DEVICE_OWNER_COMPUTE
-        }
-        self.agent.plugin_rpc.get_ports_by_subnet.return_value = [port_data]
-        router1 = self.manage_router(self.agent, router_info)
-        internal_device = router1.get_internal_device_name(
-            router_info['_interfaces'][0]['id'])
-        neighbors = ip_lib.IPDevice(internal_device, router1.ns_name).neigh
-        self.assertEqual(expected_neighbor,
-                         neighbors.show(ip_version=4).split()[0])
-
-    def _assert_rfp_fpr_mtu(self, router, expected_mtu=1500):
-        dev_mtu = self.get_device_mtu(
-            router.router_id, router.fip_ns.get_rtr_ext_device_name,
-            router.ns_name)
-        self.assertEqual(expected_mtu, dev_mtu)
-        dev_mtu = self.get_device_mtu(
-            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)
-
-    def _assert_snat_namespace_exists(self, router):
-        namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-        self.assertTrue(self._namespace_exists(namespace))
-
-    def _get_dvr_snat_namespace_device_status(
-        self, router, internal_dev_name=None):
-        """Function returns the internal and external device status."""
-        snat_ns = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
-            router.router_id)
-        external_port = router.get_ex_gw_port()
-        external_device_name = router.get_external_device_name(
-            external_port['id'])
-        qg_device_created_successfully = ip_lib.device_exists(
-            external_device_name, namespace=snat_ns)
-        sg_device_created_successfully = ip_lib.device_exists(
-            internal_dev_name, namespace=snat_ns)
-        return qg_device_created_successfully, sg_device_created_successfully
-
-    def test_dvr_router_snat_namespace_with_interface_remove(self):
-        """Test to validate the snat namespace with interface remove.
-
-        This test validates the snat namespace for all the external
-        and internal devices. It also validates if the internal
-        device corresponding to the router interface is removed
-        when the router interface is deleted.
-        """
-        self.agent.conf.agent_mode = 'dvr_snat'
-        router_info = self.generate_dvr_router_info()
-        snat_internal_port = router_info[l3_constants.SNAT_ROUTER_INTF_KEY]
-        router1 = self.manage_router(self.agent, router_info)
-        csnat_internal_port = (
-            router1.router[l3_constants.SNAT_ROUTER_INTF_KEY])
-        # Now save the internal device name to verify later
-        internal_device_name = router1._get_snat_int_device_name(
-            csnat_internal_port[0]['id'])
-        self._assert_snat_namespace_exists(router1)
-        qg_device, sg_device = self._get_dvr_snat_namespace_device_status(
-            router1, internal_dev_name=internal_device_name)
-        self.assertTrue(qg_device)
-        self.assertTrue(sg_device)
-        self.assertEqual(router1.snat_ports, snat_internal_port)
-        # Now let us not pass INTERFACE_KEY, to emulate
-        # the interface has been removed.
-        router1.router[l3_constants.INTERFACE_KEY] = []
-        # Now let us not pass the SNAT_ROUTER_INTF_KEY, to emulate
-        # that the server did not send it, since the interface has been
-        # removed.
-        router1.router[l3_constants.SNAT_ROUTER_INTF_KEY] = []
-        self.agent._process_updated_router(router1.router)
-        router_updated = self.agent.router_info[router_info['id']]
-        self._assert_snat_namespace_exists(router_updated)
-        qg_device, sg_device = self._get_dvr_snat_namespace_device_status(
-            router_updated, internal_dev_name=internal_device_name)
-        self.assertFalse(sg_device)
-        self.assertTrue(qg_device)
-
-    def _mocked_dvr_ha_router(self, agent):
-        r_info = self.generate_dvr_router_info(enable_ha=True,
-                                               enable_snat=True,
-                                               agent=agent)
-
-        r_snat_ns_name = namespaces.build_ns_name(dvr_snat_ns.SNAT_NS_PREFIX,
-                                                  r_info['id'])
-
-        mocked_r_snat_ns_name = r_snat_ns_name + '@' + agent.host
-        r_ns_name = namespaces.build_ns_name(namespaces.NS_PREFIX,
-                                             r_info['id'])
-
-        mocked_r_ns_name = r_ns_name + '@' + agent.host
-
-        return r_info, mocked_r_ns_name, mocked_r_snat_ns_name
-
-    def _setup_dvr_ha_agents(self):
-        self.agent.conf.agent_mode = 'dvr_snat'
-
-        self.conf = self._configure_agent('agent2')
-        self.failover_agent = neutron_l3_agent.L3NATAgentWithStateReport(
-            'agent2', self.conf)
-        self.failover_agent.conf.agent_mode = 'dvr_snat'
-
-    def _setup_dvr_ha_bridges(self):
-        br_int_1 = self._get_agent_ovs_integration_bridge(self.agent)
-        br_int_2 = self._get_agent_ovs_integration_bridge(self.failover_agent)
-
-        veth1, veth2 = self.useFixture(net_helpers.VethFixture()).ports
-        br_int_1.add_port(veth1.name)
-        br_int_2.add_port(veth2.name)
-
-    def _create_dvr_ha_router(self, agent):
-        get_ns_name = mock.patch.object(namespaces.RouterNamespace,
-                                        '_get_ns_name').start()
-        get_snat_ns_name = mock.patch.object(dvr_snat_ns.SnatNamespace,
-                                             'get_snat_ns_name').start()
-        (r_info,
-         mocked_r_ns_name,
-         mocked_r_snat_ns_name) = self._mocked_dvr_ha_router(agent)
-        get_ns_name.return_value = mocked_r_ns_name
-        get_snat_ns_name.return_value = mocked_r_snat_ns_name
-        router = self.manage_router(agent, r_info)
-        return router
-
-    def _assert_ip_addresses_in_dvr_ha_snat_namespace(self, router):
-        namespace = router.ha_namespace
-        ex_gw_port = router.get_ex_gw_port()
-        snat_port = router.get_snat_interfaces()[0]
-        ex_gw_port_name = router.get_external_device_name(
-            ex_gw_port['id'])
-        snat_port_name = router._get_snat_int_device_name(
-            snat_port['id'])
-
-        ip = ex_gw_port["fixed_ips"][0]['ip_address']
-        prefix_len = ex_gw_port["fixed_ips"][0]['prefixlen']
-        ex_gw_port_cidr = ip + "/" + str(prefix_len)
-        ip = snat_port["fixed_ips"][0]['ip_address']
-        prefix_len = snat_port["fixed_ips"][0]['prefixlen']
-        snat_port_cidr = ip + "/" + str(prefix_len)
-
-        self._assert_ip_address_on_interface(namespace,
-                                             ex_gw_port_name,
-                                             ex_gw_port_cidr)
-        self._assert_ip_address_on_interface(namespace,
-                                             snat_port_name,
-                                             snat_port_cidr)
-
-    def _assert_no_ip_addresses_in_dvr_ha_snat_namespace(self, router):
-        namespace = router.ha_namespace
-        ex_gw_port = router.get_ex_gw_port()
-        snat_port = router.get_snat_interfaces()[0]
-        ex_gw_port_name = router.get_external_device_name(
-            ex_gw_port['id'])
-        snat_port_name = router._get_snat_int_device_name(
-            snat_port['id'])
-
-        self._assert_no_ip_addresses_on_interface(namespace,
-                                                  snat_port_name)
-        self._assert_no_ip_addresses_on_interface(namespace,
-                                                  ex_gw_port_name)
-
-    def test_dvr_ha_router_failover(self):
-        self._setup_dvr_ha_agents()
-        self._setup_dvr_ha_bridges()
-
-        router1 = self._create_dvr_ha_router(self.agent)
-        router2 = self._create_dvr_ha_router(self.failover_agent)
-
-        utils.wait_until_true(lambda: router1.ha_state == 'master')
-        utils.wait_until_true(lambda: router2.ha_state == 'backup')
-
-        self._assert_ip_addresses_in_dvr_ha_snat_namespace(router1)
-        self._assert_no_ip_addresses_in_dvr_ha_snat_namespace(router2)
-
-        self.fail_ha_router(router1)
-
-        utils.wait_until_true(lambda: router2.ha_state == 'master')
-        utils.wait_until_true(lambda: router1.ha_state == 'backup')
-
-        self._assert_ip_addresses_in_dvr_ha_snat_namespace(router2)
-        self._assert_no_ip_addresses_in_dvr_ha_snat_namespace(router1)
-
-    def _assert_fip_namespace_deleted(self, ext_gateway_port):
-        ext_net_id = ext_gateway_port['network_id']
-        self.agent.fipnamespace_delete_on_ext_net(
-            self.agent.context, ext_net_id)
-        self._assert_interfaces_deleted_from_ovs()