Merge "IPv6 SLAAC subnet create should update ports on net"

This commit is contained in:
Jenkins 2015-04-16 03:44:58 +00:00 committed by Gerrit Code Review
commit 6c84362187
2 changed files with 125 additions and 12 deletions

View File

@ -472,9 +472,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
# from subnet
else:
if is_auto_addr:
prefix = subnet['cidr']
ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(
prefix, mac_address)
ip_address = self._calculate_ipv6_eui64_addr(context,
subnet,
mac_address)
ips.append({'ip_address': ip_address.format(),
'subnet_id': subnet['id']})
else:
@ -531,6 +531,17 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
ips = self._allocate_fixed_ips(context, to_add, mac_address)
return ips, prev_ips
def _calculate_ipv6_eui64_addr(self, context, subnet, mac_addr):
prefix = subnet['cidr']
network_id = subnet['network_id']
ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(
prefix, mac_addr).format()
if not self._check_unique_ip(context, network_id,
subnet['id'], ip_address):
raise n_exc.IpAddressInUse(net_id=network_id,
ip_address=ip_address)
return ip_address
def _allocate_ips_for_port(self, context, port):
"""Allocate IP addresses for the port.
@ -585,13 +596,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
for subnet in v6_stateless:
# IP addresses for IPv6 SLAAC and DHCPv6-stateless subnets
# are implicitly included.
prefix = subnet['cidr']
ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(prefix,
p['mac_address'])
if not self._check_unique_ip(context, p['network_id'],
subnet['id'], ip_address.format()):
raise n_exc.IpAddressInUse(net_id=p['network_id'],
ip_address=ip_address.format())
ip_address = self._calculate_ipv6_eui64_addr(context, subnet,
p['mac_address'])
ips.append({'ip_address': ip_address.format(),
'subnet_id': subnet['id']})
@ -1343,8 +1349,46 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
'subnet pool')
raise n_exc.BadRequest(resource='subnets', msg=msg)
# Create subnet from the implicit(AKA null) pool
return self._create_subnet_from_implicit_pool(context, subnet)
return self._create_subnet_from_pool(context, subnet, subnetpool_id)
created_subnet = self._create_subnet_from_implicit_pool(context,
subnet)
else:
created_subnet = self._create_subnet_from_pool(context, subnet,
subnetpool_id)
# If this subnet supports auto-addressing, then update any
# internal ports on the network with addresses for this subnet.
if ipv6_utils.is_auto_address_subnet(created_subnet):
self._add_auto_addrs_on_network_ports(context, created_subnet)
return created_subnet
def _add_auto_addrs_on_network_ports(self, context, subnet):
"""For an auto-address subnet, add addrs for ports on the net."""
with context.session.begin(subtransactions=True):
network_id = subnet['network_id']
port_qry = context.session.query(models_v2.Port)
for port in port_qry.filter(
and_(models_v2.Port.network_id == network_id,
models_v2.Port.device_owner !=
constants.DEVICE_OWNER_ROUTER_SNAT,
~models_v2.Port.device_owner.in_(
constants.ROUTER_INTERFACE_OWNERS))):
ip_address = self._calculate_ipv6_eui64_addr(
context, subnet, port['mac_address'])
allocated = models_v2.IPAllocation(network_id=network_id,
port_id=port['id'],
ip_address=ip_address,
subnet_id=subnet['id'])
try:
# Do the insertion of each IP allocation entry within
# the context of a nested transaction, so that the entry
# is rolled back independently of other entries whenever
# the corresponding port has been deleted.
with context.session.begin_nested():
context.session.add(allocated)
except db_exc.DBReferenceError:
LOG.debug("Port %s was deleted while updating it with an "
"IPv6 auto-address. Ignoring.", port['id'])
def _update_subnet_dns_nameservers(self, context, id, s):
old_dns_list = self._get_dns_by_subnet(context, id)

View File

@ -20,7 +20,9 @@ import itertools
import mock
import netaddr
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_utils import importutils
from sqlalchemy import orm
from testtools import matchers
import webob.exc
@ -3811,6 +3813,71 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
self.assertEqual(ctx_manager.exception.code,
webob.exc.HTTPClientError.code)
def _test_create_subnet_ipv6_auto_addr_with_port_on_network(
self, addr_mode, device_owner=DEVICE_OWNER_COMPUTE,
insert_db_reference_error=False):
# Create a network with one IPv4 subnet and one port
with self.network() as network,\
self.subnet(network=network) as v4_subnet,\
self.port(subnet=v4_subnet, device_owner=device_owner) as port:
if insert_db_reference_error:
def db_ref_err_for_ipalloc(instance):
if instance.__class__.__name__ == 'IPAllocation':
raise db_exc.DBReferenceError(
'dummy_table', 'dummy_constraint',
'dummy_key', 'dummy_key_table')
mock.patch.object(orm.Session, 'add',
side_effect=db_ref_err_for_ipalloc).start()
# Add an IPv6 auto-address subnet to the network
v6_subnet = self._make_subnet(self.fmt, network, 'fe80::1',
'fe80::/64', ip_version=6,
ipv6_ra_mode=addr_mode,
ipv6_address_mode=addr_mode)
if (insert_db_reference_error
or device_owner == constants.DEVICE_OWNER_ROUTER_SNAT
or device_owner in constants.ROUTER_INTERFACE_OWNERS):
# DVR SNAT and router interfaces should not have been
# updated with addresses from the new auto-address subnet
self.assertEqual(1, len(port['port']['fixed_ips']))
else:
# Confirm that the port has been updated with an address
# from the new auto-address subnet
req = self.new_show_request('ports', port['port']['id'],
self.fmt)
sport = self.deserialize(self.fmt, req.get_response(self.api))
fixed_ips = sport['port']['fixed_ips']
self.assertEqual(2, len(fixed_ips))
self.assertIn(v6_subnet['subnet']['id'],
[fixed_ip['subnet_id'] for fixed_ip
in fixed_ips])
def test_create_subnet_ipv6_slaac_with_port_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC)
def test_create_subnet_dhcpv6_stateless_with_port_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.DHCPV6_STATELESS)
def test_create_subnet_ipv6_slaac_with_dhcp_port_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC,
device_owner=constants.DEVICE_OWNER_DHCP)
def test_create_subnet_ipv6_slaac_with_router_intf_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC,
device_owner=constants.DEVICE_OWNER_ROUTER_INTF)
def test_create_subnet_ipv6_slaac_with_snat_intf_on_network(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC,
device_owner=constants.DEVICE_OWNER_ROUTER_SNAT)
def test_create_subnet_ipv6_slaac_with_db_reference_error(self):
self._test_create_subnet_ipv6_auto_addr_with_port_on_network(
constants.IPV6_SLAAC, insert_db_reference_error=True)
def test_update_subnet_no_gateway(self):
with self.subnet() as subnet:
data = {'subnet': {'gateway_ip': '10.0.0.1'}}
@ -5330,6 +5397,7 @@ class TestNeutronDbPluginV2(base.BaseTestCase):
'enable_dhcp': True,
'gateway_ip': u'2001:100::1',
'id': u'd1a28edd-bd83-480a-bd40-93d036c89f13',
'network_id': 'fbb9b578-95eb-4b79-a116-78e5c4927176',
'ip_version': 6,
'ipv6_address_mode': None,
'ipv6_ra_mode': u'slaac'},
@ -5338,6 +5406,7 @@ class TestNeutronDbPluginV2(base.BaseTestCase):
'enable_dhcp': True,
'gateway_ip': u'2001:200::1',
'id': u'dc813d3d-ed66-4184-8570-7325c8195e28',
'network_id': 'fbb9b578-95eb-4b79-a116-78e5c4927176',
'ip_version': 6,
'ipv6_address_mode': None,
'ipv6_ra_mode': u'slaac'}]