summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-04-22 10:19:47 +0000
committerGerrit Code Review <review@openstack.org>2015-04-22 10:19:47 +0000
commit5061c0291001b92f4d9ab1d77e6b74e6e1476481 (patch)
tree34b7c1a48657e02b2e3b2e9021d0ac4c8e39b146
parente2f6902315de76a1020aa87ea161c8fdc6697ed7 (diff)
parent1dc98e414f200a78a6b1dc78f222c588646e6935 (diff)
downloadneutron-5061c0291001b92f4d9ab1d77e6b74e6e1476481.tar.gz
Merge "IPv6 SLAAC subnet create should update ports on net" into stable/kilo
-rw-r--r--neutron/db/db_base_plugin_v2.py68
-rw-r--r--neutron/tests/unit/db/test_db_base_plugin_v2.py69
2 files changed, 125 insertions, 12 deletions
diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py
index f7bcf8db53..dcf7adc6f6 100644
--- a/neutron/db/db_base_plugin_v2.py
+++ b/neutron/db/db_base_plugin_v2.py
@@ -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)
diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py
index 0dc18001dd..e8ef97e8fd 100644
--- a/neutron/tests/unit/db/test_db_base_plugin_v2.py
+++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py
@@ -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'}]