Delete duplicate external devices in router namespace

When a router's gateway is removed during L3-agent restart, the agent
will fail to delete the old external device.  This device should be
identified and removed as soon as possible.

Change-Id: Ifd3e6ca009242138bea4a098e3fde258aeaa391e
Closes-Bug: #1298658
This commit is contained in:
Carl Baldwin 2014-03-27 22:21:53 +00:00
parent f1c7054309
commit 80eb1faf1b
2 changed files with 44 additions and 6 deletions

View File

@ -414,12 +414,11 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
prefixlen = netaddr.IPNetwork(port['subnet']['cidr']).prefixlen
port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen)
def _get_existing_internal_devices(self, ri):
def _get_existing_devices(self, ri):
ip_wrapper = ip_lib.IPWrapper(root_helper=self.root_helper,
namespace=ri.ns_name())
ip_devs = ip_wrapper.get_devices(exclude_loopback=True)
return [ip_dev.name for ip_dev in ip_devs if
ip_dev.name.startswith(INTERNAL_DEV_PREFIX)]
return [ip_dev.name for ip_dev in ip_devs]
def process_router(self, ri):
ri.iptables_manager.defer_apply_on()
@ -443,7 +442,9 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
self.internal_network_removed(ri, p['id'], p['ip_cidr'])
ri.internal_ports.remove(p)
current_internal_devs = set(self._get_existing_internal_devices(ri))
existing_devices = self._get_existing_devices(ri)
current_internal_devs = set([n for n in existing_devices
if n.startswith(INTERNAL_DEV_PREFIX)])
current_port_devs = set([self.get_internal_device_name(id) for
id in current_port_ids])
stale_devs = current_internal_devs - current_port_devs
@ -471,6 +472,17 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
self.external_gateway_removed(ri, ri.ex_gw_port,
interface_name, internal_cidrs)
stale_devs = [dev for dev in existing_devices
if dev.startswith(EXTERNAL_DEV_PREFIX)
and dev != interface_name]
for stale_dev in stale_devs:
LOG.debug(_('Deleting stale external router device: %s'),
stale_dev)
self.driver.unplug(stale_dev,
bridge=self.conf.external_network_bridge,
namespace=ri.ns_name(),
prefix=EXTERNAL_DEV_PREFIX)
# Process static routes for router
self.routes_updated(ri)
# Process SNAT rules for external gateway

View File

@ -796,8 +796,7 @@ class TestBasicRouterOperations(base.BaseTestCase):
FakeDev('qr-b2c3d4e5-f6')]
stale_devnames = [dev.name for dev in stale_devlist]
get_devices_return = [FakeDev('qg-a1b2c3d4-e5'),
FakeDev('qg-b2c3d4e5-f6')]
get_devices_return = []
get_devices_return.extend(stale_devlist)
self.mock_ip.get_devices.return_value = get_devices_return
@ -844,6 +843,33 @@ class TestBasicRouterOperations(base.BaseTestCase):
for stale_devname in stale_devnames]
self.mock_driver.unplug.assert_has_calls(calls, any_order=True)
def test_process_router_delete_stale_external_devices(self):
class FakeDev(object):
def __init__(self, name):
self.name = name
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
stale_devlist = [FakeDev('qg-a1b2c3d4-e5')]
stale_devnames = [dev.name for dev in stale_devlist]
router = self._prepare_router_data(enable_snat=True,
num_internal_ports=1)
del router['gw_port']
ri = l3_agent.RouterInfo(router['id'],
self.conf.root_helper,
self.conf.use_namespaces,
router=router)
self.mock_ip.get_devices.return_value = stale_devlist
agent.process_router(ri)
self.mock_driver.unplug.assert_called_with(
stale_devnames[0],
bridge="br-ex",
namespace=ri.ns_name(),
prefix=l3_agent.EXTERNAL_DEV_PREFIX)
def test_routers_with_admin_state_down(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.plugin_api.get_external_network_id.return_value = None