diff --git a/neutron/agent/l3/dvr_fip_ns.py b/neutron/agent/l3/dvr_fip_ns.py index 8b45915bcaf..63f81701664 100644 --- a/neutron/agent/l3/dvr_fip_ns.py +++ b/neutron/agent/l3/dvr_fip_ns.py @@ -109,6 +109,18 @@ class FipNamespace(namespaces.Namespace): prefix=FIP_EXT_DEV_PREFIX, mtu=ex_gw_port.get('mtu')) + # Remove stale fg devices + ip_wrapper = ip_lib.IPWrapper(namespace=ns_name) + devices = ip_wrapper.get_devices() + for device in devices: + name = device.name + if name.startswith(FIP_EXT_DEV_PREFIX) and name != interface_name: + ext_net_bridge = self.agent_conf.external_network_bridge + self.driver.unplug(name, + bridge=ext_net_bridge, + namespace=ns_name, + prefix=FIP_EXT_DEV_PREFIX) + ip_cidrs = common_utils.fixed_ip_cidrs(ex_gw_port['fixed_ips']) self.driver.init_l3(interface_name, ip_cidrs, namespace=ns_name, clean_connections=True) @@ -116,8 +128,6 @@ class FipNamespace(namespaces.Namespace): self.update_gateway_port(ex_gw_port) cmd = ['sysctl', '-w', 'net.ipv4.conf.%s.proxy_arp=1' % interface_name] - # TODO(Carl) mlavelle's work has self.ip_wrapper - ip_wrapper = ip_lib.IPWrapper(namespace=ns_name) ip_wrapper.netns.execute(cmd, check_exit_code=False) def create(self): diff --git a/neutron/tests/functional/agent/l3/test_dvr_router.py b/neutron/tests/functional/agent/l3/test_dvr_router.py index 0d2ac27f9ef..96d530237d7 100644 --- a/neutron/tests/functional/agent/l3/test_dvr_router.py +++ b/neutron/tests/functional/agent/l3/test_dvr_router.py @@ -20,6 +20,7 @@ import netaddr import testtools from neutron.agent.l3 import agent as neutron_l3_agent +from neutron.agent.l3 import dvr_fip_ns from neutron.agent.l3 import dvr_snat_ns from neutron.agent.l3 import namespaces from neutron.agent.linux import ip_lib @@ -82,6 +83,69 @@ class TestDvrRouter(framework.L3AgentTestFramework): self._assert_dvr_floating_ips(router) self._assert_snat_namespace_does_not_exist(router) + def test_dvr_router_fips_stale_gw_port(self): + self.agent.conf.agent_mode = 'dvr' + + # Create the router with external net + dvr_router_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'} + router_info = self.generate_dvr_router_info(**dvr_router_kwargs) + external_gw_port = router_info['gw_port'] + ext_net_id = router_info['_floatingips'][0]['floating_network_id'] + self.mock_plugin_api.get_external_network_id.return_value(ext_net_id) + + # Create the fip namespace up front + stale_fip_ns = dvr_fip_ns.FipNamespace(ext_net_id, + self.agent.conf, + self.agent.driver, + self.agent.use_ipv6) + stale_fip_ns.create() + + # Add a stale fg port to the namespace + fixed_ip = external_gw_port['fixed_ips'][0] + float_subnet = external_gw_port['subnets'][0] + fip_gw_port_ip = str(netaddr.IPAddress(fixed_ip['ip_address']) + 10) + prefixlen = netaddr.IPNetwork(float_subnet['cidr']).prefixlen + stale_agent_gw_port = { + '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:8f:89', + portbindings.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()} + stale_fip_ns.create_gateway_port(stale_agent_gw_port) + + stale_dev_exists = self.device_exists_with_ips_and_mac( + stale_agent_gw_port, + stale_fip_ns.get_ext_device_name, + stale_fip_ns.get_name()) + self.assertTrue(stale_dev_exists) + + # Create the router, this shouldn't allow the duplicate port to stay + router = self.manage_router(self.agent, router_info) + + # Assert the device no longer exists + stale_dev_exists = self.device_exists_with_ips_and_mac( + stale_agent_gw_port, + stale_fip_ns.get_ext_device_name, + stale_fip_ns.get_name()) + self.assertFalse(stale_dev_exists) + + # Validate things are looking good and clean up + self._validate_fips_for_external_network( + router, router.fip_ns.get_name()) + ext_gateway_port = router_info['gw_port'] + self._delete_router(self.agent, router.router_id) + self._assert_fip_namespace_deleted(ext_gateway_port) + def test_dvr_router_fips_for_multiple_ext_networks(self): agent_mode = 'dvr' # Create the first router fip with external net1