Subnet delete for IPv6 SLAAC should not require prior port disassoc

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
This commit is contained in:
Dane LeBlanc 2014-11-17 10:40:04 -05:00
parent 8edf980078
commit fcf69f63ec
3 changed files with 39 additions and 3 deletions

View 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:

View File

@ -31,6 +31,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
@ -729,7 +730,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"))

View 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'