diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index f223eb34ac7..9ed99c55b94 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2257,8 +2257,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } - if (ipv6 && !NetUtils.isValidIp6Cidr(ip6Cidr)) { - throw new InvalidParameterValueException("Invalid IPv6 cidr specified"); + if (ipv6 && NetUtils.getIp6CidrSize(ip6Cidr) != 64) { + throw new InvalidParameterValueException("IPv6 subnet should be exactly 64-bits in size"); } //TODO(VXLAN): Support VNI specified diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index cb7210d33ac..f840d0d7af4 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -57,7 +57,6 @@ import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; import com.cloud.dc.PodVlanMapVO; -import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; @@ -2014,7 +2013,6 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage if (network.getGateway() != null) { if (nic.getIPv4Address() == null) { - ipv4 = true; PublicIp ip = null; //Get ip address from the placeholder and don't allocate a new one @@ -2050,30 +2048,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage nic.setIPv4Dns2(dc.getDns2()); } - //FIXME - get ipv6 address from the placeholder if it's stored there - if (network.getIp6Gateway() != null) { - if (nic.getIPv6Address() == null) { - UserIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); - Vlan vlan = _vlanDao.findById(ip.getVlanId()); - nic.setIPv6Address(ip.getAddress().toString()); - nic.setIPv6Gateway(vlan.getIp6Gateway()); - nic.setIPv6Cidr(vlan.getIp6Cidr()); - if (ipv4) { - nic.setFormat(AddressFormat.DualStack); - } else { - nic.setIsolationUri(IsolationType.Vlan.toUri(vlan.getVlanTag())); - nic.setBroadcastType(BroadcastDomainType.Vlan); - nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlan.getVlanTag())); - nic.setFormat(AddressFormat.Ip6); - nic.setReservationId(String.valueOf(vlan.getVlanTag())); - if(nic.getMacAddress() == null) { - nic.setMacAddress(ip.getMacAddress()); - } - } - } - nic.setIPv6Dns1(dc.getIp6Dns1()); - nic.setIPv6Dns2(dc.getIp6Dns2()); - } + _ipv6Mgr.setNicIp6Address(nic, dc, network); } }); } @@ -2123,29 +2098,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage nic.setIPv4Dns2(dc.getDns2()); } - // TODO: the IPv6 logic is not changed. - //FIXME - get ipv6 address from the placeholder if it's stored there - if (network.getIp6Gateway() != null) { - if (nic.getIPv6Address() == null) { - UserIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); - Vlan vlan = _vlanDao.findById(ip.getVlanId()); - nic.setIPv6Address(ip.getAddress().toString()); - nic.setIPv6Gateway(vlan.getIp6Gateway()); - nic.setIPv6Cidr(vlan.getIp6Cidr()); - if (ipv4) { - nic.setFormat(AddressFormat.DualStack); - } else { - nic.setIsolationUri(IsolationType.Vlan.toUri(vlan.getVlanTag())); - nic.setBroadcastType(BroadcastDomainType.Vlan); - nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlan.getVlanTag())); - nic.setFormat(AddressFormat.Ip6); - nic.setReservationId(String.valueOf(vlan.getVlanTag())); - nic.setMacAddress(ip.getMacAddress()); - } - } - nic.setIPv6Dns1(dc.getIp6Dns1()); - nic.setIPv6Dns2(dc.getIp6Dns2()); - } + _ipv6Mgr.setNicIp6Address(nic, dc, network); } }); } diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManager.java b/server/src/main/java/com/cloud/network/Ipv6AddressManager.java index 4db3ec1c4c8..7dcba11a00a 100644 --- a/server/src/main/java/com/cloud/network/Ipv6AddressManager.java +++ b/server/src/main/java/com/cloud/network/Ipv6AddressManager.java @@ -17,20 +17,20 @@ package com.cloud.network; +import com.cloud.dc.DataCenter; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.user.Account; import com.cloud.utils.component.Manager; +import com.cloud.vm.NicProfile; public interface Ipv6AddressManager extends Manager { - public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException; - - public void revokeDirectIpv6Address(long networkId, String ip6Address); - public String allocateGuestIpv6(Network network, String requestedIpv6) throws InsufficientAddressCapacityException; public String allocatePublicIp6ForGuestNic(Network network, Long podId, Account ipOwner, String requestedIp) throws InsufficientAddressCapacityException; public String acquireGuestIpv6Address(Network network, String requestedIpv6) throws InsufficientAddressCapacityException; + public void setNicIp6Address(final NicProfile nic, final DataCenter dc, final Network network); + } diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java index 1cb432efdc0..0371833f869 100644 --- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java @@ -17,20 +17,18 @@ package com.cloud.network; -import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.vm.NicProfile; +import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; import com.cloud.configuration.Config; import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.Vlan; -import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.exception.InsufficientAddressCapacityException; @@ -39,13 +37,11 @@ import com.cloud.network.IpAddress.State; import com.cloud.network.Network.IpAddresses; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.user.Account; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; @@ -65,8 +61,6 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa @Inject UserIpv6AddressDao _ipv6Dao; @Inject - NetworkDao _networkDao; - @Inject ConfigurationDao _configDao; @Inject IpAddressManager ipAddressManager; @@ -83,87 +77,6 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa return true; } - @Override - public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException { - Network network = _networkDao.findById(networkId); - if (network == null) { - return null; - } - List vlans = _vlanDao.listVlansByNetworkId(networkId); - if (vlans == null) { - s_logger.debug("Cannot find related vlan attached to network " + networkId); - return null; - } - String ip = null; - Vlan ipVlan = null; - if (requestedIp6 == null) { - if (!_networkModel.areThereIPv6AddressAvailableInNetwork(networkId)) { - throw new InsufficientAddressCapacityException("There is no more address available in the network " + network.getName(), DataCenter.class, - network.getDataCenterId()); - } - for (Vlan vlan : vlans) { - if (!_networkModel.isIP6AddressAvailableInVlan(vlan.getId())) { - continue; - } - ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); - int count = 0; - while (_ipv6Dao.findByNetworkIdAndIp(networkId, ip) != null) { - ip = NetUtils.getNextIp6InRange(ip, vlan.getIp6Range()); - count++; - // It's an arbitrate number to prevent the infinite loop - if (count > _ipv6RetryMax) { - ip = null; - break; - } - } - if (ip != null) { - ipVlan = vlan; - } - } - if (ip == null) { - throw new InsufficientAddressCapacityException("Cannot find a usable IP in the network " + network.getName() + " after " + _ipv6RetryMax + - "(network.ipv6.search.retry.max) times retry!", DataCenter.class, network.getDataCenterId()); - } - } else { - for (Vlan vlan : vlans) { - if (NetUtils.isIp6InRange(requestedIp6, vlan.getIp6Range())) { - ipVlan = vlan; - break; - } - } - if (ipVlan == null) { - throw new CloudRuntimeException("Requested IPv6 is not in the predefined range!"); - } - ip = requestedIp6; - if (_ipv6Dao.findByNetworkIdAndIp(networkId, ip) != null) { - throw new CloudRuntimeException("The requested IP is already taken!"); - } - } - DataCenterVO dc = _dcDao.findById(dcId); - Long mac = dc.getMacAddress(); - Long nextMac = mac + 1; - dc.setMacAddress(nextMac); - _dcDao.update(dc.getId(), dc); - - String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac, NetworkModel.MACIdentifier.value())); - UserIpv6AddressVO ipVO = new UserIpv6AddressVO(ip, dcId, macAddress, ipVlan.getId()); - ipVO.setPhysicalNetworkId(network.getPhysicalNetworkId()); - ipVO.setSourceNetworkId(networkId); - ipVO.setState(UserIpv6Address.State.Allocated); - ipVO.setDomainId(owner.getDomainId()); - ipVO.setAccountId(owner.getAccountId()); - _ipv6Dao.persist(ipVO); - return ipVO; - } - - @Override - public void revokeDirectIpv6Address(long networkId, String ip6Address) { - UserIpv6AddressVO ip = _ipv6Dao.findByNetworkIdAndIp(networkId, ip6Address); - if (ip != null) { - _ipv6Dao.remove(ip.getId()); - } - } - /** * Executes method {@link #acquireGuestIpv6Address(Network, String)} and returns the requested IPv6 (String) in case of successfully allocating the guest IPv6 address. */ @@ -260,4 +173,43 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa return ip6Vo != null || nicSecondaryIpVO != null; } + /** + * Calculate the IPv6 Address the Instance will obtain using SLAAC and IPv6 EUI-64 + * + * Linux, FreeBSD and Windows all calculate the same IPv6 address when configured properly. (SLAAC) + * + * Using Router Advertisements the routers in the network should announce the IPv6 CIDR which is configured + * for the network. + * + * It is up to the network administrator to make sure the IPv6 Routers in the network are sending out Router Advertisements + * with the correct IPv6 (Prefix, DNS, Lifetime) information. + * + * This way the NIC will be populated with a IPv6 address on which the Instance is reachable. + * + * This method calculates the IPv6 address the Instance will obtain and updates the Nic object with the correct + * address information. + */ + @Override + public void setNicIp6Address(final NicProfile nic, final DataCenter dc, final Network network) { + if (network.getIp6Gateway() != null) { + if (nic.getIPv6Address() == null) { + s_logger.debug("Found IPv6 CIDR " + network.getIp6Cidr() + " for Network " + network); + nic.setIPv6Cidr(network.getIp6Cidr()); + nic.setIPv6Gateway(network.getIp6Gateway()); + + IPv6Address ipv6addr = NetUtils.EUI64Address(network.getIp6Cidr(), nic.getMacAddress()); + s_logger.info("Calculated IPv6 address " + ipv6addr + " using EUI-64 for NIC " + nic.getUuid()); + nic.setIPv6Address(ipv6addr.toString()); + + if (nic.getIPv4Address() != null) { + nic.setFormat(Networks.AddressFormat.DualStack); + } else { + nic.setFormat(Networks.AddressFormat.Ip6); + } + } + nic.setIPv6Dns1(dc.getIp6Dns1()); + nic.setIPv6Dns2(dc.getIp6Dns2()); + } + } + } diff --git a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java index 1d8355ab584..f6279bfc636 100644 --- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java @@ -39,7 +39,6 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.IpAddressManager; -import com.cloud.network.Ipv6AddressManager; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Service; @@ -55,9 +54,7 @@ import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.db.DB; @@ -94,12 +91,6 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { @Inject IPAddressDao _ipAddressDao; @Inject - NetworkOfferingDao _networkOfferingDao; - @Inject - UserIpv6AddressDao _ipv6Dao; - @Inject - Ipv6AddressManager _ipv6Mgr; - @Inject NicSecondaryIpDao _nicSecondaryIpDao; @Inject NicDao _nicDao; @@ -367,9 +358,6 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { } } - if (nic.getIPv6Address() != null) { - _ipv6Mgr.revokeDirectIpv6Address(nic.getNetworkId(), nic.getIPv6Address()); - } nic.deallocate(); } diff --git a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java index 26ca8f450ab..827f5331740 100644 --- a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java +++ b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java @@ -19,6 +19,8 @@ package com.cloud.network; import static org.mockito.Mockito.mock; +import com.cloud.dc.DataCenter; +import com.cloud.vm.NicProfile; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -226,4 +228,24 @@ public class Ipv6AddressManagerTest { Mockito.when(ipVo.getState()).thenReturn(state); } + @Test + public void setNICIPv6AddressTest() { + NicProfile nic = new NicProfile(); + Network network = mock(Network.class); + DataCenter dc = mock(DataCenter.class); + + nic.setMacAddress("1e:00:b1:00:0a:f6"); + + Mockito.when(network.getIp6Cidr()).thenReturn("2001:db8:100::/64"); + Mockito.when(network.getIp6Gateway()).thenReturn("2001:db8:100::1"); + + Mockito.when(dc.getIp6Dns1()).thenReturn("2001:db8::53:1"); + Mockito.when(dc.getIp6Dns1()).thenReturn("2001:db8::53:2"); + + String expected = "2001:db8:100:0:1c00:b1ff:fe00:af6"; + + ip6Manager.setNicIp6Address(nic, dc, network); + + Assert.assertEquals(expected, nic.getIPv6Address()); + } }