]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Preserve floating ips when initializing l3 gateway interface
authorCarl Baldwin <carl.baldwin@hp.com>
Tue, 15 Oct 2013 22:39:47 +0000 (22:39 +0000)
committerCarl Baldwin <carl.baldwin@hp.com>
Mon, 25 Nov 2013 16:14:26 +0000 (16:14 +0000)
Change-Id: I5a88225d291538cb9db0f8f4afa348192b8b984d
Closes-Bug: #1233271

neutron/agent/l3_agent.py
neutron/agent/linux/interface.py
neutron/tests/unit/test_l3_agent.py
neutron/tests/unit/test_linux_interface.py

index 16c73fa81d7daa950e47a71955fb28f7cfee0616..6c9783fcf349396ce2c563a66669fc55913dceb9 100644 (file)
@@ -50,6 +50,7 @@ NS_PREFIX = 'qrouter-'
 INTERNAL_DEV_PREFIX = 'qr-'
 EXTERNAL_DEV_PREFIX = 'qg-'
 RPC_LOOP_INTERVAL = 1
+FLOATING_IP_CIDR_SUFFIX = '/32'
 
 
 class L3PluginApi(proxy.RpcProxy):
@@ -521,8 +522,17 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, manager.Manager):
                              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)
 
index 42a1f82d15d9fcbe49865d859156bf3902818634..f0d7387125d32d50a56ffa600c9f31430bf195ef 100644 (file)
@@ -70,10 +70,12 @@ class LinuxInterfaceDriver(object):
         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,
@@ -95,7 +97,8 @@ class LinuxInterfaceDriver(object):
 
         # 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):
index f7cfdcff3faa57e65fab50ee2ca21d781cde6d94..d4c55bd8d67edcde624aee48765e696148cd5e4d 100644 (file)
@@ -166,12 +166,20 @@ class TestBasicRouterOperations(base.BaseTestCase):
 
         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
index d5576439e47b3f2710f482bf5f0664c625c9a89a..8b8894ac949ed2ed703e377127273e1a092f23f3 100644 (file)
@@ -93,6 +93,21 @@ class TestABCDriver(TestBase):
              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):