]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Subnet delete for IPv6 SLAAC should not require prior port disassoc
authorDane LeBlanc <leblancd@cisco.com>
Mon, 17 Nov 2014 15:40:04 +0000 (10:40 -0500)
committerafazekas <afazekas@redhat.com>
Tue, 25 Nov 2014 12:01:08 +0000 (12:01 +0000)
With the current Neutron implementation, a subnet cannot be deleted
until all associated IP addresses have been remove from ports (via
port update) or the associated ports/VMs have been deleted.

In the case of SLAAC-enabled subnets, however, it's not feasible to
require removal of SLAAC-generated addresses individually from each
associated port before deleting a subnet because of the multicast
nature of RA messages. For SLAAC-enabled subnets, the processing of
subnet delete requests needs to be changed so that these subnets will
be allowed to be deleted, and all ports get disassociated from their
corresponding SLAAC IP address, when there are ports existing on
the SLAAC subnet.

Change-Id: I281f5a1553248e09174dc49d0a42aef4b5c44bee
Closes-Bug: 1393435
(cherry picked from commit ce5e95723925b0d7750bb3daa5be54765985cc30)

neutron/db/db_base_plugin_v2.py
neutron/plugins/ml2/plugin.py
neutron/tests/unit/test_db_plugin.py

index 70827c58afdf73c5b95422696503b7b4ac4a7579..903332de0aabcafd14a3081a985e94dabf68ea9a 100644 (file)
@@ -1276,9 +1276,13 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
                          filter_by(network_id=subnet['network_id']).
                          with_lockmode('update'))
 
-            # remove network owned ports
+            # Remove network owned ports, and delete IP allocations
+            # for IPv6 addresses which were automatically generated
+            # via SLAAC
+            is_ipv6_slaac_subnet = ipv6_utils.is_slaac_subnet(subnet)
             for a in allocated:
-                if a.ports.device_owner in AUTO_DELETE_PORT_OWNERS:
+                if (is_ipv6_slaac_subnet or
+                    a.ports.device_owner in AUTO_DELETE_PORT_OWNERS):
                     NeutronDbPluginV2._delete_ip_allocation(
                         context, subnet.network_id, id, a.ip_address)
                 else:
index d29deda6cef8eef6bb502a06d9e24ebeed6ee1a2..fe3a6face8ac7e3bace9499f134b711c22655d5c 100644 (file)
@@ -29,6 +29,7 @@ from neutron.api.rpc.handlers import securitygroups_rpc
 from neutron.api.v2 import attributes
 from neutron.common import constants as const
 from neutron.common import exceptions as exc
+from neutron.common import ipv6_utils
 from neutron.common import rpc as n_rpc
 from neutron.common import topics
 from neutron.common import utils
@@ -726,7 +727,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
                 LOG.debug(_("Ports to auto-deallocate: %s"), allocated)
                 only_auto_del = all(not a.port_id or
                                     a.ports.device_owner in db_base_plugin_v2.
-                                    AUTO_DELETE_PORT_OWNERS
+                                    AUTO_DELETE_PORT_OWNERS or
+                                    ipv6_utils.is_slaac_subnet(subnet)
                                     for a in allocated)
                 if not only_auto_del:
                     LOG.debug(_("Tenant-owned ports exist"))
index 24eab084400cf1b0badaa1289e59474f6eaf3cb9..ec624c59fbdb456165a42394558bbd1c40485763 100644 (file)
@@ -2641,6 +2641,36 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
                     self.assertEqual(res.status_int,
                                      webob.exc.HTTPNoContent.code)
 
+    def test_delete_subnet_ipv6_slaac_port_exists(self):
+        """Test IPv6 SLAAC subnet delete when a port is still using subnet."""
+        res = self._create_network(fmt=self.fmt, name='net',
+                                   admin_state_up=True)
+        network = self.deserialize(self.fmt, res)
+        # Create an IPv6 SLAAC subnet and a port using that subnet
+        subnet = self._make_subnet(self.fmt, network, gateway='fe80::1',
+                                   cidr='fe80::/64', ip_version=6,
+                                   ipv6_ra_mode=constants.IPV6_SLAAC,
+                                   ipv6_address_mode=constants.IPV6_SLAAC)
+        res = self._create_port(self.fmt, net_id=network['network']['id'])
+        port = self.deserialize(self.fmt, res)
+        self.assertEqual(1, len(port['port']['fixed_ips']))
+
+        # The port should have an address from the subnet
+        req = self.new_show_request('ports', port['port']['id'], self.fmt)
+        res = req.get_response(self.api)
+        sport = self.deserialize(self.fmt, req.get_response(self.api))
+        self.assertEqual(1, len(sport['port']['fixed_ips']))
+
+        # Delete the subnet
+        req = self.new_delete_request('subnets', subnet['subnet']['id'])
+        res = req.get_response(self.api)
+        self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
+        # The port should no longer have an address from the deleted subnet
+        req = self.new_show_request('ports', port['port']['id'], self.fmt)
+        res = req.get_response(self.api)
+        sport = self.deserialize(self.fmt, req.get_response(self.api))
+        self.assertEqual(0, len(sport['port']['fixed_ips']))
+
     def test_delete_network(self):
         gateway_ip = '10.0.0.1'
         cidr = '10.0.0.0/24'