from neutron.api.v2 import attributes
from neutron.common import constants
from neutron.common import exceptions as n_exc
+from neutron.common import ipv6_utils
from neutron import context as ctx
from neutron.db import api as db
from neutron.db import models_v2
ip_address=ip_address,
subnet_id=subnet_id).delete()
+ @staticmethod
+ def _check_if_subnet_uses_eui64(subnet):
+ """Check if ipv6 address will be calculated via EUI64."""
+ return (subnet['ipv6_address_mode'] == constants.IPV6_SLAAC
+ or subnet['ipv6_address_mode'] == constants.DHCPV6_STATELESS)
+
@staticmethod
def _generate_ip(context, subnets):
try:
v4.append(subnet)
else:
v6.append(subnet)
+ for subnet in v6:
+ if self._check_if_subnet_uses_eui64(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.
+ mac = p['mac_address']
+ prefix = subnet['cidr']
+ ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(
+ prefix, mac)
+ ips.append({'ip_address': ip_address.format(),
+ 'subnet_id': subnet['id']})
+ v6.remove(subnet)
version_subnets = [v4, v6]
for subnets in version_subnets:
if subnets:
p = port['port']
port_id = p.get('id') or uuidutils.generate_uuid()
network_id = p['network_id']
- mac_address = p['mac_address']
# NOTE(jkoelker) Get the tenant_id outside of the session to avoid
# unneeded db action if the operation raises
tenant_id = self._get_tenant_id_for_create(context, p)
# Ensure that a MAC address is defined and it is unique on the
# network
- if mac_address is attributes.ATTR_NOT_SPECIFIED:
- mac_address = NeutronDbPluginV2._generate_mac(context,
- network_id)
+ if p['mac_address'] is attributes.ATTR_NOT_SPECIFIED:
+ #Note(scollins) Add the generated mac_address to the port,
+ #since _allocate_ips_for_port will need the mac when
+ #calculating an EUI-64 address for a v6 subnet
+ p['mac_address'] = NeutronDbPluginV2._generate_mac(context,
+ network_id)
else:
# Ensure that the mac on the network is unique
if not NeutronDbPluginV2._check_unique_mac(context,
network_id,
- mac_address):
+ p['mac_address']):
raise n_exc.MacAddressInUse(net_id=network_id,
- mac=mac_address)
+ mac=p['mac_address'])
# Returns the IP's for the port
ips = self._allocate_ips_for_port(context, network, port)
name=p['name'],
id=port_id,
network_id=network_id,
- mac_address=mac_address,
+ mac_address=p['mac_address'],
admin_state_up=p['admin_state_up'],
status=status,
device_id=p['device_id'],
from neutron.api.v2 import router
from neutron.common import constants
from neutron.common import exceptions as n_exc
+from neutron.common import ipv6_utils
from neutron.common import test_lib
from neutron.common import utils
from neutron import context
self._delete('ports', port3['port']['id'])
self._delete('ports', port4['port']['id'])
+ def test_ip_allocation_for_ipv6_subnet_slaac_adddress_mode(self):
+ res = self._create_network(fmt=self.fmt, name='net',
+ admin_state_up=True)
+ network = self.deserialize(self.fmt, res)
+ v6_subnet = self._make_subnet(self.fmt, network,
+ gateway='fe80::1',
+ cidr='fe80::/80',
+ ip_version=6,
+ ipv6_ra_mode=None,
+ ipv6_address_mode=constants.IPV6_SLAAC)
+ port = self._make_port(self.fmt, network['network']['id'])
+ self.assertEqual(len(port['port']['fixed_ips']), 1)
+ port_mac = port['port']['mac_address']
+ subnet_cidr = v6_subnet['subnet']['cidr']
+ eui_addr = str(ipv6_utils.get_ipv6_addr_by_EUI64(subnet_cidr,
+ port_mac))
+ self.assertEqual(port['port']['fixed_ips'][0]['ip_address'], eui_addr)
+
def test_range_allocation(self):
with self.subnet(gateway_ip='10.0.0.3',
cidr='10.0.0.0/29') as subnet: