Fix IP allocation for multiple slaac subnets
Currently when one network contains multiple IPv6 slaac
subnets, the IP allocation for the port on this network
is not correct. Only the first fixed ip is based on EUI64.
This is caused by a wrong usage of removing element in list.
Change-Id: I1b0a478997371afeae34c0536d5fed7a18223f63
Closes-Bug:1358709
(cherry picked from commit 1dac7c4347
)
This commit is contained in:
parent
e27f00d949
commit
755f2ad747
|
@ -552,32 +552,30 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||
subnets = self.get_subnets(context, filters=filter)
|
||||
# Split into v4 and v6 subnets
|
||||
v4 = []
|
||||
v6 = []
|
||||
v6_stateful = []
|
||||
v6_stateless = []
|
||||
for subnet in subnets:
|
||||
if subnet['ip_version'] == 4:
|
||||
v4.append(subnet)
|
||||
else:
|
||||
v6.append(subnet)
|
||||
for subnet in v6:
|
||||
if ipv6_utils.is_auto_address_subnet(subnet):
|
||||
#(dzyu) If true, calculate an IPv6 address
|
||||
# by mac address and prefix, then remove this
|
||||
# subnet from the array of subnets that will be passed
|
||||
# to the _generate_ip() function call, since we just
|
||||
# generated an IP.
|
||||
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())
|
||||
ips.append({'ip_address': ip_address.format(),
|
||||
'subnet_id': subnet['id']})
|
||||
v6.remove(subnet)
|
||||
version_subnets = [v4, v6]
|
||||
if ipv6_utils.is_auto_address_subnet(subnet):
|
||||
v6_stateless.append(subnet)
|
||||
else:
|
||||
v6_stateful.append(subnet)
|
||||
|
||||
for subnet in v6_stateless:
|
||||
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())
|
||||
ips.append({'ip_address': ip_address.format(),
|
||||
'subnet_id': subnet['id']})
|
||||
version_subnets = [v4, v6_stateful]
|
||||
for subnets in version_subnets:
|
||||
if subnets:
|
||||
result = NeutronDbPluginV2._generate_ip(context, subnets)
|
||||
|
|
|
@ -1492,6 +1492,34 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||
port_mac))
|
||||
self.assertEqual(port['port']['fixed_ips'][0]['ip_address'], eui_addr)
|
||||
|
||||
def test_ip_allocation_for_ipv6_2_subnet_slaac_mode(self):
|
||||
res = self._create_network(fmt=self.fmt, name='net',
|
||||
admin_state_up=True)
|
||||
network = self.deserialize(self.fmt, res)
|
||||
v6_subnet_1 = self._make_subnet(self.fmt, network,
|
||||
gateway='2001:100::1',
|
||||
cidr='2001:100::0/64',
|
||||
ip_version=6,
|
||||
ipv6_ra_mode=constants.IPV6_SLAAC)
|
||||
v6_subnet_2 = self._make_subnet(self.fmt, network,
|
||||
gateway='2001:200::1',
|
||||
cidr='2001:200::0/64',
|
||||
ip_version=6,
|
||||
ipv6_ra_mode=constants.IPV6_SLAAC)
|
||||
port = self._make_port(self.fmt, network['network']['id'])
|
||||
self.assertEqual(len(port['port']['fixed_ips']), 2)
|
||||
port_mac = port['port']['mac_address']
|
||||
cidr_1 = v6_subnet_1['subnet']['cidr']
|
||||
cidr_2 = v6_subnet_2['subnet']['cidr']
|
||||
eui_addr_1 = str(ipv6_utils.get_ipv6_addr_by_EUI64(cidr_1,
|
||||
port_mac))
|
||||
eui_addr_2 = str(ipv6_utils.get_ipv6_addr_by_EUI64(cidr_2,
|
||||
port_mac))
|
||||
self.assertEqual(port['port']['fixed_ips'][0]['ip_address'],
|
||||
eui_addr_1)
|
||||
self.assertEqual(port['port']['fixed_ips'][1]['ip_address'],
|
||||
eui_addr_2)
|
||||
|
||||
def test_range_allocation(self):
|
||||
with self.subnet(gateway_ip='10.0.0.3',
|
||||
cidr='10.0.0.0/29') as subnet:
|
||||
|
@ -4143,6 +4171,48 @@ class TestNeutronDbPluginV2(base.BaseTestCase):
|
|||
self._validate_rebuild_availability_ranges(pools, allocations,
|
||||
expected)
|
||||
|
||||
def _test__allocate_ips_for_port(self, subnets, port, expected):
|
||||
plugin = db_base_plugin_v2.NeutronDbPluginV2()
|
||||
with mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
'get_subnets') as get_subnets:
|
||||
with mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
'_check_unique_ip') as check_unique:
|
||||
context = mock.Mock()
|
||||
get_subnets.return_value = subnets
|
||||
check_unique.return_value = True
|
||||
actual = plugin._allocate_ips_for_port(context, port)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test__allocate_ips_for_port_2_slaac_subnets(self):
|
||||
subnets = [
|
||||
{
|
||||
'cidr': u'2001:100::/64',
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': u'2001:100::1',
|
||||
'id': u'd1a28edd-bd83-480a-bd40-93d036c89f13',
|
||||
'ip_version': 6,
|
||||
'ipv6_address_mode': None,
|
||||
'ipv6_ra_mode': u'slaac'},
|
||||
{
|
||||
'cidr': u'2001:200::/64',
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': u'2001:200::1',
|
||||
'id': u'dc813d3d-ed66-4184-8570-7325c8195e28',
|
||||
'ip_version': 6,
|
||||
'ipv6_address_mode': None,
|
||||
'ipv6_ra_mode': u'slaac'}]
|
||||
port = {'port': {
|
||||
'network_id': 'fbb9b578-95eb-4b79-a116-78e5c4927176',
|
||||
'fixed_ips': attributes.ATTR_NOT_SPECIFIED,
|
||||
'mac_address': '12:34:56:78:44:ab'}}
|
||||
expected = []
|
||||
for subnet in subnets:
|
||||
addr = str(ipv6_utils.get_ipv6_addr_by_EUI64(
|
||||
subnet['cidr'], port['port']['mac_address']))
|
||||
expected.append({'ip_address': addr, 'subnet_id': subnet['id']})
|
||||
|
||||
self._test__allocate_ips_for_port(subnets, port, expected)
|
||||
|
||||
|
||||
class NeutronDbPluginV2AsMixinTestCase(testlib_api.SqlTestCase):
|
||||
"""Tests for NeutronDbPluginV2 as Mixin.
|
||||
|
|
Loading…
Reference in New Issue