From e1377425b7586b2071340f39796669d2e593f145 Mon Sep 17 00:00:00 2001 From: Dane LeBlanc Date: Mon, 16 Mar 2015 12:27:34 -0400 Subject: [PATCH] Include IPv6 SLAAC addresses implicitly for port update (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 | 10 ++++++ neutron/tests/unit/test_db_plugin.py | 51 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 0abb7d025..1d895710b 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -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, diff --git a/neutron/tests/unit/test_db_plugin.py b/neutron/tests/unit/test_db_plugin.py index a352bcc68..cf2ca0968 100644 --- a/neutron/tests/unit/test_db_plugin.py +++ b/neutron/tests/unit/test_db_plugin.py @@ -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) -- 2.45.2