Skip to content

Commit

Permalink
Preserve floating ips when initializing l3 gateway interface
Browse files Browse the repository at this point in the history
Change-Id: I5a88225d291538cb9db0f8f4afa348192b8b984d
Closes-Bug: #1233271
  • Loading branch information
Carl Baldwin committed Nov 25, 2013
1 parent b1d56ed commit 5652e20
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 3 deletions.
12 changes: 11 additions & 1 deletion neutron/agent/l3_agent.py
Expand Up @@ -50,6 +50,7 @@
INTERNAL_DEV_PREFIX = 'qr-'
EXTERNAL_DEV_PREFIX = 'qg-'
RPC_LOOP_INTERVAL = 1
FLOATING_IP_CIDR_SUFFIX = '/32'


class L3PluginApi(proxy.RpcProxy):
Expand Down Expand Up @@ -521,8 +522,17 @@ def external_gateway_added(self, ri, ex_gw_port,
bridge=self.conf.external_network_bridge,
namespace=ri.ns_name(),
prefix=EXTERNAL_DEV_PREFIX)

# Compute a list of addresses this router is supposed to have.
# This avoids unnecessarily removing those addresses and
# causing a momentarily network outage.
floating_ips = ri.router.get(l3_constants.FLOATINGIP_KEY, [])
preserve_ips = [ip['floating_ip_address'] + FLOATING_IP_CIDR_SUFFIX
for ip in floating_ips]

self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']],
namespace=ri.ns_name())
namespace=ri.ns_name(),
preserve_ips=preserve_ips)
ip_address = ex_gw_port['ip_cidr'].split('/')[0]
self._send_gratuitous_arp_packet(ri, interface_name, ip_address)

Expand Down
7 changes: 5 additions & 2 deletions neutron/agent/linux/interface.py
Expand Up @@ -70,10 +70,12 @@ def __init__(self, conf):
self.conf = conf
self.root_helper = config.get_root_helper(conf)

def init_l3(self, device_name, ip_cidrs, namespace=None):
def init_l3(self, device_name, ip_cidrs, namespace=None,
preserve_ips=[]):
"""Set the L3 settings for the interface using data from the port.
ip_cidrs: list of 'X.X.X.X/YY' strings
preserve_ips: list of ip cidrs that should not be removed from device
"""
device = ip_lib.IPDevice(device_name,
self.root_helper,
Expand All @@ -95,7 +97,8 @@ def init_l3(self, device_name, ip_cidrs, namespace=None):

# clean up any old addresses
for ip_cidr, ip_version in previous.items():
device.addr.delete(ip_version, ip_cidr)
if ip_cidr not in preserve_ips:
device.addr.delete(ip_version, ip_cidr)

def check_bridge_exists(self, bridge):
if not ip_lib.device_exists(bridge):
Expand Down
8 changes: 8 additions & 0 deletions neutron/tests/unit/test_l3_agent.py
Expand Up @@ -166,12 +166,20 @@ def _test_external_gateway_action(self, action):

if action == 'add':
self.device_exists.return_value = False
ri.router = mock.Mock()
ri.router.get.return_value = [{'floating_ip_address':
'192.168.1.34'}]
agent.external_gateway_added(ri, ex_gw_port,
interface_name, internal_cidrs)
self.assertEqual(self.mock_driver.plug.call_count, 1)
self.assertEqual(self.mock_driver.init_l3.call_count, 1)
self.send_arp.assert_called_once_with(ri, interface_name,
'20.0.0.30')
kwargs = {'preserve_ips': ['192.168.1.34/32'],
'namespace': 'qrouter-' + router_id}
self.mock_driver.init_l3.assert_called_with(interface_name,
['20.0.0.30/24'],
**kwargs)

elif action == 'remove':
self.device_exists.return_value = True
Expand Down
15 changes: 15 additions & 0 deletions neutron/tests/unit/test_linux_interface.py
Expand Up @@ -93,6 +93,21 @@ def test_l3_init(self):
mock.call().addr.add(4, '192.168.1.2/24', '192.168.1.255'),
mock.call().addr.delete(4, '172.16.77.240/24')])

def test_l3_init_with_preserve(self):
addresses = [dict(ip_version=4, scope='global',
dynamic=False, cidr='192.168.1.3/32')]
self.ip_dev().addr.list = mock.Mock(return_value=addresses)

bc = BaseChild(self.conf)
ns = '12345678-1234-5678-90ab-ba0987654321'
bc.init_l3('tap0', ['192.168.1.2/24'], namespace=ns,
preserve_ips=['192.168.1.3/32'])
self.ip_dev.assert_has_calls(
[mock.call('tap0', 'sudo', namespace=ns),
mock.call().addr.list(scope='global', filters=['permanent']),
mock.call().addr.add(4, '192.168.1.2/24', '192.168.1.255')])
self.assertFalse(self.ip_dev().addr.delete.called)


class TestOVSInterfaceDriver(TestBase):

Expand Down

0 comments on commit 5652e20

Please sign in to comment.