]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Include IPv6 SLAAC addresses implicitly for port update
authorDane LeBlanc <leblancd@cisco.com>
Mon, 16 Mar 2015 16:27:34 +0000 (12:27 -0400)
committerDane LeBlanc <leblancd@cisco.com>
Wed, 18 Mar 2015 14:43:13 +0000 (14:43 +0000)
(Patch set #4 for the multiple-ipv6-prefixes blueprint)

This change adds functional code and UT for port-update
handling changes as described in the Neutron blueprint
'multiple-ipv6-prefixes'.

Whenever a port is updated on a network that includes one
or more auto-address subnets (e.g. SLAAC or DHCPv6-stateless),
then any addresses that the port previously had for those
subnets needs to be implicitly retained for the update
operation. This patch set adds this implicit retention
of the auto-addresses for port update operation.

Change-Id: I91687d05a48bc3938e4bf34a7c454823a500730c
Partially-implements: blueprint multiple-ipv6-prefixes

neutron/db/db_base_plugin_v2.py
neutron/tests/unit/test_db_plugin.py

index 0abb7d02584fe5fba558d688e2361e522c42fcfd..1d895710b1e572df7d59111f37e65115baccdfce 100644 (file)
@@ -481,6 +481,16 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
                     original_ips.remove(original_ip)
                     new_ips.remove(new_ip)
                     prev_ips.append(original_ip)
+                    break
+            else:
+                # For ports that are not router ports, retain any automatic
+                # (non-optional, e.g. IPv6 SLAAC) addresses.
+                if device_owner not in constants.ROUTER_INTERFACE_OWNERS:
+                    subnet = self._get_subnet(context,
+                                              original_ip['subnet_id'])
+                    if (ipv6_utils.is_auto_address_subnet(subnet)):
+                        original_ips.remove(original_ip)
+                        prev_ips.append(original_ip)
 
         # Check if the IP's to add are OK
         to_add = self._test_fixed_ips_for_port(context, network_id, new_ips,
index a352bcc6809619d308b2c763c8ded209057e6b1d..cf2ca09681adf2293053b46b15af9baebadd5ad6 100644 (file)
@@ -1728,6 +1728,57 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
         self._show('ports', port['port']['id'],
                    expected_code=webob.exc.HTTPNotFound.code)
 
+    def test_update_port_with_ipv6_slaac_subnet_in_fixed_ips(self):
+        """Test port update with an IPv6 SLAAC subnet in fixed IPs."""
+        res = self._create_network(fmt=self.fmt, name='net',
+                                   admin_state_up=True)
+        network = self.deserialize(self.fmt, res)
+        # Create a port using an IPv4 subnet and an IPv6 SLAAC subnet
+        self._make_subnet(self.fmt, network, gateway='10.0.0.1',
+                          cidr='10.0.0.0/24', ip_version=4)
+        subnet_v6 = self._make_v6_subnet(network, constants.IPV6_SLAAC)
+        res = self._create_port(self.fmt, net_id=network['network']['id'])
+        port = self.deserialize(self.fmt, res)
+        self.assertEqual(2, len(port['port']['fixed_ips']))
+        # Update port including only the IPv6 SLAAC subnet
+        data = {'port': {'fixed_ips': [{'subnet_id':
+                                        subnet_v6['subnet']['id']}]}}
+        req = self.new_update_request('ports', data,
+                                      port['port']['id'])
+        res = self.deserialize(self.fmt, req.get_response(self.api))
+        # Port should only have an address corresponding to IPv6 SLAAC subnet
+        ips = res['port']['fixed_ips']
+        self.assertEqual(1, len(ips))
+        self.assertEqual(self._calc_ipv6_addr_by_EUI64(port, subnet_v6),
+                         ips[0]['ip_address'])
+
+    def test_update_port_excluding_ipv6_slaac_subnet_from_fixed_ips(self):
+        """Test port update excluding IPv6 SLAAC subnet from fixed ips."""
+        res = self._create_network(fmt=self.fmt, name='net',
+                                   admin_state_up=True)
+        network = self.deserialize(self.fmt, res)
+        # Create a port using an IPv4 subnet and an IPv6 SLAAC subnet
+        subnet_v4 = self._make_subnet(self.fmt, network, gateway='10.0.0.1',
+                                      cidr='10.0.0.0/24', ip_version=4)
+        subnet_v6 = self._make_v6_subnet(network, constants.IPV6_SLAAC)
+        res = self._create_port(self.fmt, net_id=network['network']['id'])
+        port = self.deserialize(self.fmt, res)
+        self.assertEqual(2, len(port['port']['fixed_ips']))
+        # Update port including only the IPv4 subnet
+        data = {'port': {'fixed_ips': [{'subnet_id':
+                                        subnet_v4['subnet']['id'],
+                                        'ip_address': "10.0.0.10"}]}}
+        req = self.new_update_request('ports', data,
+                                      port['port']['id'])
+        res = self.deserialize(self.fmt, req.get_response(self.api))
+        # Port should still have an addr corresponding to IPv6 SLAAC subnet
+        ips = res['port']['fixed_ips']
+        self.assertEqual(2, len(ips))
+        eui_addr = self._calc_ipv6_addr_by_EUI64(port, subnet_v6)
+        expected_v6_ip = {'subnet_id': subnet_v6['subnet']['id'],
+                          'ip_address': eui_addr}
+        self.assertIn(expected_v6_ip, ips)
+
     def test_ip_allocation_for_ipv6_2_subnet_slaac_mode(self):
         res = self._create_network(fmt=self.fmt, name='net',
                                    admin_state_up=True)