From bd4bc025d126c32389478b4df7048bdd2e16376e Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 24 Jan 2013 20:09:37 -0800 Subject: [PATCH 01/26] IPv6: Accept IPv6 parameter for createNetworkCmd Also ass public_ipv6_address for ipv6 address management. Extend nics and vlans for ipv6 address. Add dependency to com.googlecode.ipv6(java-ipv6). Modify dhcpcommand for ipv6. --- .../agent/api/routing/DhcpEntryCommand.java | 35 ++- api/src/com/cloud/dc/Vlan.java | 5 + api/src/com/cloud/network/Network.java | 6 +- api/src/com/cloud/network/NetworkModel.java | 1 + api/src/com/cloud/network/NetworkProfile.java | 14 ++ api/src/com/cloud/vm/Nic.java | 6 + api/src/com/cloud/vm/NicProfile.java | 42 +++- .../apache/cloudstack/api/ApiConstants.java | 5 + .../user/network/CreateNetworkCmd.java | 60 ++++- client/tomcatconf/components.xml.in | 1 + pom.xml | 1 + .../baremetal/ExternalDhcpManagerImpl.java | 2 +- .../configuration/ConfigurationManager.java | 2 +- .../ConfigurationManagerImpl.java | 208 +++++++++++------- .../DefaultComponentLibrary.java | 2 + server/src/com/cloud/dc/VlanVO.java | 43 +++- .../src/com/cloud/network/NetworkManager.java | 8 +- .../com/cloud/network/NetworkManagerImpl.java | 141 ++++++++++-- .../com/cloud/network/NetworkModelImpl.java | 37 +++- .../com/cloud/network/NetworkServiceImpl.java | 136 +++++++++--- server/src/com/cloud/network/NetworkVO.java | 24 ++ .../com/cloud/network/PublicIpv6Address.java | 52 +++++ .../cloud/network/PublicIpv6AddressVO.java | 189 ++++++++++++++++ .../src/com/cloud/network/addr/PublicIp.java | 15 ++ .../network/dao/PublicIpv6AddressDao.java | 23 ++ .../network/dao/PublicIpv6AddressDaoImpl.java | 96 ++++++++ .../cloud/network/guru/DirectNetworkGuru.java | 49 ++++- .../guru/DirectPodBasedNetworkGuru.java | 2 +- .../guru/ExternalGuestNetworkGuru.java | 2 +- .../cloud/network/guru/GuestNetworkGuru.java | 4 +- .../network/guru/PodBasedNetworkGuru.java | 2 +- .../cloud/network/guru/PublicNetworkGuru.java | 2 +- .../VirtualNetworkApplianceManagerImpl.java | 8 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 2 +- server/src/com/cloud/vm/NicVO.java | 25 +++ .../src/com/cloud/vm/UserVmManagerImpl.java | 8 +- .../cloud/network/MockNetworkManagerImpl.java | 12 +- .../cloud/network/MockNetworkModelImpl.java | 6 + .../vpc/MockConfigurationManagerImpl.java | 2 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 18 +- setup/db/create-schema.sql | 32 +++ utils/pom.xml | 5 + utils/src/com/cloud/utils/net/NetUtils.java | 72 ++++++ .../com/cloud/utils/net/NetUtilsTest.java | 14 ++ 44 files changed, 1220 insertions(+), 199 deletions(-) create mode 100644 server/src/com/cloud/network/PublicIpv6Address.java create mode 100644 server/src/com/cloud/network/PublicIpv6AddressVO.java create mode 100644 server/src/com/cloud/network/dao/PublicIpv6AddressDao.java create mode 100644 server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java diff --git a/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java b/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java index 5c2cd582d4c..f0ce70e9a80 100644 --- a/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java +++ b/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java @@ -28,7 +28,9 @@ public class DhcpEntryCommand extends NetworkElementCommand { String defaultRouter; String staticRoutes; String defaultDns; - + String vmIp6Address; + String ip6Gateway; + String duid; protected DhcpEntryCommand() { @@ -39,14 +41,15 @@ public class DhcpEntryCommand extends NetworkElementCommand { return true; } - public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName) { + public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String vmIp6Address) { this.vmMac = vmMac; this.vmIpAddress = vmIpAddress; this.vmName = vmName; + this.vmIp6Address = vmIp6Address; } - public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String dns, String gateway) { - this(vmMac, vmIpAddress, vmName); + public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String vmIp6Address, String dns, String gateway, String ip6Gateway) { + this(vmMac, vmIpAddress, vmName, vmIp6Address); this.dns = dns; this.gateway = gateway; } @@ -102,4 +105,28 @@ public class DhcpEntryCommand extends NetworkElementCommand { public void setDefaultDns(String defaultDns) { this.defaultDns = defaultDns; } + + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public String getDuid() { + return duid; + } + + public void setDuid(String duid) { + this.duid = duid; + } + + public String getVmIp6Address() { + return vmIp6Address; + } + + public void setVmIp6Address(String ip6Address) { + this.vmIp6Address = ip6Address; + } } diff --git a/api/src/com/cloud/dc/Vlan.java b/api/src/com/cloud/dc/Vlan.java index 0f629ef3cbf..790195f9f3c 100644 --- a/api/src/com/cloud/dc/Vlan.java +++ b/api/src/com/cloud/dc/Vlan.java @@ -44,4 +44,9 @@ public interface Vlan extends InfrastructureEntity, InternalIdentity, Identity { public Long getPhysicalNetworkId(); + public String getIp6Gateway(); + + public String getIp6Cidr(); + + public String getIp6Range(); } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index c91f6a9b80d..29ba9f33c44 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -264,7 +264,11 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { String getGateway(); String getCidr(); - + + String getIp6Gateway(); + + String getIp6Cidr(); + long getDataCenterId(); long getNetworkOfferingId(); diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 9baa0ec435c..7e17405f434 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -249,4 +249,5 @@ public interface NetworkModel { boolean isNetworkInlineMode(Network network); + Vlan getVlanForNetwork(long networkId); } \ No newline at end of file diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index b5c463de375..cce4897999e 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -39,6 +39,8 @@ public class NetworkProfile implements Network { private TrafficType trafficType; private String gateway; private String cidr; + private String ip6Gateway; + private String ip6Cidr; private long networkOfferingId; private long related; private String displayText; @@ -64,6 +66,8 @@ public class NetworkProfile implements Network { this.trafficType = network.getTrafficType(); this.gateway = network.getGateway(); this.cidr = network.getCidr(); + this.ip6Gateway = network.getIp6Gateway(); + this.ip6Cidr = network.getIp6Cidr(); this.networkOfferingId = network.getNetworkOfferingId(); this.related = network.getRelated(); this.displayText = network.getDisplayText(); @@ -226,4 +230,14 @@ public class NetworkProfile implements Network { return vpcId; } + @Override + public String getIp6Gateway() { + return ip6Gateway; + } + + @Override + public String getIp6Cidr() { + return ip6Cidr; + } + } diff --git a/api/src/com/cloud/vm/Nic.java b/api/src/com/cloud/vm/Nic.java index 84c0034b430..aeae2aed14c 100644 --- a/api/src/com/cloud/vm/Nic.java +++ b/api/src/com/cloud/vm/Nic.java @@ -144,4 +144,10 @@ public interface Nic extends Identity, InternalIdentity { VirtualMachine.Type getVmType(); AddressFormat getAddressFormat(); + + String getIp6Gateway(); + + String getIp6Cidr(); + + String getIp6Address(); } diff --git a/api/src/com/cloud/vm/NicProfile.java b/api/src/com/cloud/vm/NicProfile.java index 32e3f212e99..9a5e781ff6b 100644 --- a/api/src/com/cloud/vm/NicProfile.java +++ b/api/src/com/cloud/vm/NicProfile.java @@ -37,6 +37,8 @@ public class NicProfile implements InternalIdentity { TrafficType trafficType; String ip4Address; String ip6Address; + String ip6Gateway; + String ip6Cidr; String macAddress; URI isolationUri; String netmask; @@ -50,7 +52,8 @@ public class NicProfile implements InternalIdentity { Integer networkRate; boolean isSecurityGroupEnabled; String name; - String requestedIp; + String requestedIpv4; + String requestedIpv6; public String getDns1() { return dns1; @@ -218,7 +221,7 @@ public class NicProfile implements InternalIdentity { this.trafficType = network.getTrafficType(); this.ip4Address = nic.getIp4Address(); this.format = nic.getAddressFormat(); - this.ip6Address = null; + this.ip6Address = nic.getIp6Address(); this.macAddress = nic.getMacAddress(); this.reservationId = nic.getReservationId(); this.strategy = nic.getReservationStrategy(); @@ -230,6 +233,8 @@ public class NicProfile implements InternalIdentity { this.isSecurityGroupEnabled = isSecurityGroupEnabled; this.vmId = nic.getInstanceId(); this.name = name; + this.ip6Cidr = nic.getIp6Cidr(); + this.ip6Gateway = nic.getIp6Gateway(); if (networkRate != null) { this.networkRate = networkRate; @@ -245,8 +250,9 @@ public class NicProfile implements InternalIdentity { this.strategy = strategy; } - public NicProfile(String requestedIp) { - this.requestedIp = requestedIp; + public NicProfile(String requestedIpv4, String requestedIpv6) { + this.requestedIpv4 = requestedIpv4; + this.requestedIpv6 = requestedIpv6; } public NicProfile() { @@ -272,8 +278,8 @@ public class NicProfile implements InternalIdentity { this.isSecurityGroupEnabled = enabled; } - public String getRequestedIp() { - return requestedIp; + public String getRequestedIpv4() { + return requestedIpv4; } public void deallocate() { @@ -301,4 +307,28 @@ public class NicProfile implements InternalIdentity { append(reservationId).append("-").append(ip4Address).append("-").append(broadcastUri).toString(); } + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public String getRequestedIpv6() { + return requestedIpv6; + } + + public void setRequestedIpv6(String requestedIpv6) { + this.requestedIpv6 = requestedIpv6; + } + } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 58a78318fae..1787f210d4f 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -38,6 +38,7 @@ public class ApiConstants { public static final String DOMAIN_SUFFIX = "domainsuffix"; public static final String DNS_SEARCH_ORDER = "dnssearchorder"; public static final String CIDR = "cidr"; + public static final String IP6CIDR = "ip6cidr"; public static final String CIDR_LIST = "cidrlist"; public static final String CLEANUP = "cleanup"; public static final String CLUSTER_ID = "clusterid"; @@ -64,6 +65,7 @@ public class ApiConstants { public static final String EMAIL = "email"; public static final String END_DATE = "enddate"; public static final String END_IP = "endip"; + public static final String END_IPV6 = "endipv6"; public static final String END_PORT = "endport"; public static final String ENTRY_TIME = "entrytime"; public static final String FETCH_LATEST = "fetchlatest"; @@ -73,6 +75,7 @@ public class ApiConstants { public static final String FORMAT = "format"; public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork"; public static final String GATEWAY = "gateway"; + public static final String IP6GATEWAY = "ip6gateway"; public static final String GROUP = "group"; public static final String GROUP_ID = "groupid"; public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; @@ -181,6 +184,7 @@ public class ApiConstants { public static final String SOURCE_ZONE_ID = "sourcezoneid"; public static final String START_DATE = "startdate"; public static final String START_IP = "startip"; + public static final String START_IPV6 = "startipv6"; public static final String START_PORT = "startport"; public static final String STATE = "state"; public static final String STATUS = "status"; @@ -427,6 +431,7 @@ public class ApiConstants { public static final String CONDITION_IDS = "conditionids"; public static final String COUNTERPARAM_LIST = "counterparam"; public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; + public static final String DUAL_STACK = "dualstack"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 870a591bb36..89aa464d363 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -113,7 +113,22 @@ public class CreateNetworkCmd extends BaseCmd { description="the VPC network belongs to") private Long vpcId; + @Parameter(name=ApiConstants.START_IPV6, type=CommandType.STRING, description="the beginning IPv6 address in the IPv6 network range") + private String startIpv6; + @Parameter(name=ApiConstants.END_IPV6, type=CommandType.STRING, description="the ending IPv6 address in the IPv6 network range") + private String endIpv6; + + @Parameter(name=ApiConstants.IP6GATEWAY, type=CommandType.STRING, description="the gateway of the IPv6 network. Required " + + "for Shared networks and Isolated networks when it belongs to VPC") + private String ip6Gateway; + + @Parameter(name=ApiConstants.IP6CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") + private String ip6Cidr; + + @Parameter(name=ApiConstants.DUAL_STACK, type=CommandType.BOOLEAN, description="The network is dual-stack(IPv6 and IPv4) or not") + private Boolean dualStack; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -207,7 +222,50 @@ public class CreateNetworkCmd extends BaseCmd { } } - ///////////////////////////////////////////////////// + public String getStartIpv6() { + return startIpv6; + } + + public void setStartIpv6(String startIpv6) { + this.startIpv6 = startIpv6; + } + + public String getEndIpv6() { + return endIpv6; + } + + public void setEndIpv6(String endIpv6) { + this.endIpv6 = endIpv6; + } + + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public Boolean isDualStack() { + if (dualStack == null) { + return false; + } + return dualStack; + } + + public void setDualStack(Boolean dualStack) { + this.dualStack = dualStack; + } + + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @Override diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index c41d4f4f18f..b274b862225 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -271,6 +271,7 @@ under the License. + diff --git a/pom.xml b/pom.xml index 35d6520ce6b..34e22c3a952 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,7 @@ 2.6 1.4 0.9.8 + 0.8 diff --git a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java b/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java index c1f0fff6d3c..7bb14c98d7e 100755 --- a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java +++ b/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java @@ -208,7 +208,7 @@ public class ExternalDhcpManagerImpl implements ExternalDhcpManager, ResourceSta if (dns == null) { dns = nic.getDns2(); } - DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), profile.getVirtualMachine().getHostName(), dns, nic.getGateway()); + DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), profile.getVirtualMachine().getHostName(), null, dns, nic.getGateway(), null); String errMsg = String.format("Set dhcp entry on external DHCP %1$s failed(ip=%2$s, mac=%3$s, vmname=%4$s)", h.getPrivateIpAddress(), nic.getIp4Address(), nic.getMacAddress(), profile.getVirtualMachine().getHostName()); //prepareBareMetalDhcpEntry(nic, dhcpCommand); diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 19e74bfd4b4..58fdeeda2e2 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -198,7 +198,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges); - Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; + Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index df6642af9ca..7154dc8cb88 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -44,7 +44,6 @@ import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.*; import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; @@ -2253,7 +2252,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura txn.start(); Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, - endIP, vlanGateway, vlanNetmask, vlanId, vlanOwner); + endIP, vlanGateway, vlanNetmask, vlanId, vlanOwner, null, null, null, null); if (associateIpRangeToAccount) { _networkMgr.associateIpAddressListToAccount(userId, vlanOwner.getId(), zoneId, vlan.getId(), null); @@ -2279,11 +2278,23 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @DB public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, - String vlanId, Account vlanOwner) { - - + String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) { Network network = _networkModel.getNetwork(networkId); + boolean ipv4 = false, ipv6 = false; + + if (startIP != null) { + ipv4 = true; + } + + if (startIPv6 != null) { + ipv6 = true; + } + + if (!ipv4 && !ipv6) { + throw new InvalidParameterValueException("Please specify IPv4 or IPv6 address."); + } + //Validate the zone DataCenterVO zone = _zoneDao.findById(zoneId); if (zone == null) { @@ -2348,90 +2359,108 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura throw new InvalidParameterValueException("Vlan owner can be defined only in the zone of type " + NetworkType.Advanced); } - // Make sure the gateway is valid - if (!NetUtils.isValidIp(vlanGateway)) { - throw new InvalidParameterValueException("Please specify a valid gateway"); + if (ipv4) { + // Make sure the gateway is valid + if (!NetUtils.isValidIp(vlanGateway)) { + throw new InvalidParameterValueException("Please specify a valid gateway"); + } + + // Make sure the netmask is valid + if (!NetUtils.isValidIp(vlanNetmask)) { + throw new InvalidParameterValueException("Please specify a valid netmask"); + } + } + + if (ipv6) { + if (!NetUtils.isValidIPv6(vlanGatewayv6)) { + throw new InvalidParameterValueException("Please specify a valid IPv6 gateway"); + } + if (!NetUtils.isValidIp6Cidr(vlanCidrv6)) { + throw new InvalidParameterValueException("Please specify a valid IPv6 CIDR"); + } } - // Make sure the netmask is valid - if (!NetUtils.isValidIp(vlanNetmask)) { - throw new InvalidParameterValueException("Please specify a valid netmask"); - } + // TODO skip all vlan check for ipv6 now + if (ipv4) { + String newVlanSubnet = NetUtils.getSubNet(vlanGateway, vlanNetmask); - String newVlanSubnet = NetUtils.getSubNet(vlanGateway, vlanNetmask); + // Check if the new VLAN's subnet conflicts with the guest network in + // the specified zone (guestCidr is null for basic zone) + String guestNetworkCidr = zone.getGuestNetworkCidr(); + if (guestNetworkCidr != null) { + String[] cidrPair = guestNetworkCidr.split("\\/"); + String guestIpNetwork = NetUtils.getIpRangeStartIpFromCidr(cidrPair[0], Long.parseLong(cidrPair[1])); + long guestCidrSize = Long.parseLong(cidrPair[1]); + long vlanCidrSize = NetUtils.getCidrSize(vlanNetmask); - // Check if the new VLAN's subnet conflicts with the guest network in - // the specified zone (guestCidr is null for basic zone) - String guestNetworkCidr = zone.getGuestNetworkCidr(); - if (guestNetworkCidr != null) { - String[] cidrPair = guestNetworkCidr.split("\\/"); - String guestIpNetwork = NetUtils.getIpRangeStartIpFromCidr(cidrPair[0], Long.parseLong(cidrPair[1])); - long guestCidrSize = Long.parseLong(cidrPair[1]); - long vlanCidrSize = NetUtils.getCidrSize(vlanNetmask); + long cidrSizeToUse = -1; + if (vlanCidrSize < guestCidrSize) { + cidrSizeToUse = vlanCidrSize; + } else { + cidrSizeToUse = guestCidrSize; + } - long cidrSizeToUse = -1; - if (vlanCidrSize < guestCidrSize) { - cidrSizeToUse = vlanCidrSize; - } else { - cidrSizeToUse = guestCidrSize; - } + String guestSubnet = NetUtils.getCidrSubNet(guestIpNetwork, cidrSizeToUse); - String guestSubnet = NetUtils.getCidrSubNet(guestIpNetwork, cidrSizeToUse); + if (newVlanSubnet.equals(guestSubnet)) { + throw new InvalidParameterValueException("The new IP range you have specified has the same subnet as the guest network in zone: " + zone.getName() + + ". Please specify a different gateway/netmask."); + } + } - if (newVlanSubnet.equals(guestSubnet)) { - throw new InvalidParameterValueException("The new IP range you have specified has the same subnet as the guest network in zone: " + zone.getName() - + ". Please specify a different gateway/netmask."); - } - } + // Check if there are any errors with the IP range + checkPublicIpRangeErrors(zoneId, vlanId, vlanGateway, vlanNetmask, startIP, endIP); - // Check if there are any errors with the IP range - checkPublicIpRangeErrors(zoneId, vlanId, vlanGateway, vlanNetmask, startIP, endIP); + // Throw an exception if any of the following is true: + // 1. Another VLAN in the same zone has a different tag but the same + // subnet as the new VLAN. Make an exception for the + // case when both vlans are Direct. + // 2. Another VLAN in the same zone that has the same tag and subnet as + // the new VLAN has IPs that overlap with the IPs + // being added + // 3. Another VLAN in the same zone that has the same tag and subnet as + // the new VLAN has a different gateway than the + // new VLAN + // 4. If VLAN is untagged and Virtual, and there is existing UNTAGGED + // vlan with different subnet + List vlans = _vlanDao.listByZone(zone.getId()); + for (VlanVO vlan : vlans) { + String otherVlanGateway = vlan.getVlanGateway(); + // Continue if it's IPv6 + if (otherVlanGateway == null) { + continue; + } + String otherVlanSubnet = NetUtils.getSubNet(vlan.getVlanGateway(), vlan.getVlanNetmask()); + String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); + String otherVlanStartIP = otherVlanIpRange[0]; + String otherVlanEndIP = null; + if (otherVlanIpRange.length > 1) { + otherVlanEndIP = otherVlanIpRange[1]; + } - // Throw an exception if any of the following is true: - // 1. Another VLAN in the same zone has a different tag but the same - // subnet as the new VLAN. Make an exception for the - // case when both vlans are Direct. - // 2. Another VLAN in the same zone that has the same tag and subnet as - // the new VLAN has IPs that overlap with the IPs - // being added - // 3. Another VLAN in the same zone that has the same tag and subnet as - // the new VLAN has a different gateway than the - // new VLAN - // 4. If VLAN is untagged and Virtual, and there is existing UNTAGGED - // vlan with different subnet - List vlans = _vlanDao.listByZone(zone.getId()); - for (VlanVO vlan : vlans) { - String otherVlanGateway = vlan.getVlanGateway(); - String otherVlanSubnet = NetUtils.getSubNet(vlan.getVlanGateway(), vlan.getVlanNetmask()); - String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); - String otherVlanStartIP = otherVlanIpRange[0]; - String otherVlanEndIP = null; - if (otherVlanIpRange.length > 1) { - otherVlanEndIP = otherVlanIpRange[1]; - } + if (forVirtualNetwork && !vlanId.equals(vlan.getVlanTag()) && newVlanSubnet.equals(otherVlanSubnet) && !allowIpRangeOverlap(vlan, forVirtualNetwork, networkId)) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " in zone " + zone.getName() + + " has the same subnet. Please specify a different gateway/netmask."); + } - if (forVirtualNetwork && !vlanId.equals(vlan.getVlanTag()) && newVlanSubnet.equals(otherVlanSubnet) && !allowIpRangeOverlap(vlan, forVirtualNetwork, networkId)) { - throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " in zone " + zone.getName() - + " has the same subnet. Please specify a different gateway/netmask."); - } + boolean vlansUntaggedAndVirtual = (vlanId.equals(Vlan.UNTAGGED) && vlanId.equals(vlan.getVlanTag()) && forVirtualNetwork && vlan.getVlanType() == VlanType.VirtualNetwork); - boolean vlansUntaggedAndVirtual = (vlanId.equals(Vlan.UNTAGGED) && vlanId.equals(vlan.getVlanTag()) && forVirtualNetwork && vlan.getVlanType() == VlanType.VirtualNetwork); + if (vlansUntaggedAndVirtual && !newVlanSubnet.equals(otherVlanSubnet)) { + throw new InvalidParameterValueException("The Untagged ip range with different subnet already exists in zone " + zone.getId()); + } - if (vlansUntaggedAndVirtual && !newVlanSubnet.equals(otherVlanSubnet)) { - throw new InvalidParameterValueException("The Untagged ip range with different subnet already exists in zone " + zone.getId()); - } + if (vlanId.equals(vlan.getVlanTag()) && newVlanSubnet.equals(otherVlanSubnet)) { + if (NetUtils.ipRangesOverlap(startIP, endIP, otherVlanStartIP, otherVlanEndIP)) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + + " already has IPs that overlap with the new range. Please specify a different start IP/end IP."); + } - if (vlanId.equals(vlan.getVlanTag()) && newVlanSubnet.equals(otherVlanSubnet)) { - if (NetUtils.ipRangesOverlap(startIP, endIP, otherVlanStartIP, otherVlanEndIP)) { - throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() - + " already has IPs that overlap with the new range. Please specify a different start IP/end IP."); - } - - if (!vlanGateway.equals(otherVlanGateway)) { - throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " has already been added with gateway " + otherVlanGateway - + ". Please specify a different tag."); - } - } + if (!vlanGateway.equals(otherVlanGateway)) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " has already been added with gateway " + otherVlanGateway + + ". Please specify a different tag."); + } + } + } } // Check if a guest VLAN is using the same tag @@ -2453,21 +2482,36 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } } - String ipRange = startIP; - if (endIP != null) { - ipRange += "-" + endIP; + String ipRange = null; + + if (ipv4) { + ipRange = startIP; + if (endIP != null) { + ipRange += "-" + endIP; + } + } + + String ipv6Range = null; + if (ipv6) { + ipv6Range = startIPv6; + if (endIPv6 != null) { + ipv6Range += "-" + endIPv6; + } } // Everything was fine, so persist the VLAN Transaction txn = Transaction.currentTxn(); txn.start(); - VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId); + VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId, vlanGatewayv6, vlanCidrv6, ipv6Range); s_logger.debug("Saving vlan range " + vlan); vlan = _vlanDao.persist(vlan); - if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId)) { - throw new CloudRuntimeException("Failed to save IP range. Please contact Cloud Support."); + // IPv6 use a used ip map, is different from ipv4, no need to save public ip range + if (ipv4) { + if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId)) { + throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support."); + } } if (vlanOwner != null) { diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 98da7adfa39..e2e800b2257 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -122,6 +122,7 @@ import com.cloud.network.dao.PhysicalNetworkDaoImpl; import com.cloud.network.dao.PhysicalNetworkServiceProviderDaoImpl; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl; import com.cloud.network.dao.PortProfileDaoImpl; +import com.cloud.network.dao.PublicIpv6AddressDaoImpl; import com.cloud.network.dao.RemoteAccessVpnDaoImpl; import com.cloud.network.dao.Site2SiteCustomerGatewayDaoImpl; import com.cloud.network.dao.Site2SiteVpnConnectionDaoImpl; @@ -380,6 +381,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addDao("Site2SiteVpnGatewayDao", Site2SiteVpnGatewayDaoImpl.class); addDao("Site2SiteCustomerGatewayDao", Site2SiteCustomerGatewayDaoImpl.class); addDao("Site2SiteVpnConnnectionDao", Site2SiteVpnConnectionDaoImpl.class); + addDao("PublicIpv6AddressDao", PublicIpv6AddressDaoImpl.class); addDao("UserVmJoinDao", UserVmJoinDaoImpl.class); addDao("DomainRouterJoinDao", DomainRouterJoinDaoImpl.class); diff --git a/server/src/com/cloud/dc/VlanVO.java b/server/src/com/cloud/dc/VlanVO.java index fcb46c4971e..af6b5fc8089 100644 --- a/server/src/com/cloud/dc/VlanVO.java +++ b/server/src/com/cloud/dc/VlanVO.java @@ -48,12 +48,21 @@ public class VlanVO implements Vlan { @Column(name="vlan_netmask") String vlanNetmask; + @Column(name="ip6_gateway") + String ip6Gateway; + + @Column(name="ip6_cidr") + String ip6Cidr; + @Column(name="data_center_id") long dataCenterId; @Column(name="description") String ipRange; + @Column(name="ip6_range") + String ip6Range; + @Column(name="network_id") Long networkId; @@ -67,13 +76,16 @@ public class VlanVO implements Vlan { @Column(name="uuid") String uuid; - public VlanVO(VlanType vlanType, String vlanTag, String vlanGateway, String vlanNetmask, long dataCenterId, String ipRange, Long networkId, Long physicalNetworkId) { + public VlanVO(VlanType vlanType, String vlanTag, String vlanGateway, String vlanNetmask, long dataCenterId, String ipRange, Long networkId, Long physicalNetworkId, String ip6Gateway, String ip6Cidr, String ip6Range) { this.vlanType = vlanType; this.vlanTag = vlanTag; this.vlanGateway = vlanGateway; this.vlanNetmask = vlanNetmask; + this.ip6Gateway = ip6Gateway; + this.ip6Cidr = ip6Cidr; this.dataCenterId = dataCenterId; this.ipRange = ipRange; + this.ip6Range = ip6Range; this.networkId = networkId; this.uuid = UUID.randomUUID().toString(); this.physicalNetworkId = physicalNetworkId; @@ -149,9 +161,36 @@ public class VlanVO implements Vlan { public String toString() { if (toString == null) { toString = new StringBuilder("Vlan[").append(vlanTag).append("|").append(vlanGateway).append("|").append(vlanNetmask). - append("|").append(ipRange).append("|").append(networkId).append("]").toString(); + append("|").append(ip6Gateway).append("|").append(ip6Cidr).append("|").append(ipRange).append("|"). + append("|").append(ip6Range).append(networkId).append("]").toString(); } return toString; } + + @Override + public String getIp6Gateway() { + return ip6Gateway; + } + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + @Override + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + @Override + public String getIp6Range() { + return ip6Range; + } + + public void setIp6Range(String ip6Range) { + this.ip6Range = ip6Range; + } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 546f1bf613c..7228a8322e9 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -123,7 +123,7 @@ public interface NetworkManager { Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, - long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId) + long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; /** @@ -167,7 +167,7 @@ public interface NetworkManager { void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, - Network network, String requestedIp) + Network network, String requestedIpv4, String requestedIpv6) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException; @@ -327,4 +327,8 @@ public interface NetworkManager { int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); + + PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, + VlanType type, Long networkId, String requestedIp, boolean isSystem) + throws InsufficientAddressCapacityException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index bb60dcfcdc8..705e5f2d6a6 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -112,6 +112,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; +import com.cloud.network.dao.PublicIpv6AddressDao; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.IpDeployer; import com.cloud.network.element.LoadBalancingServiceProvider; @@ -273,6 +274,8 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { NetworkACLManager _networkACLMgr; @Inject NetworkModel _networkModel; + @Inject + PublicIpv6AddressDao _ipv6Dao; ScheduledExecutorService _executor; @@ -294,6 +297,36 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null); } + @Override + public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) throws InsufficientAddressCapacityException { + Vlan vlan = _networkModel.getVlanForNetwork(networkId); + if (vlan == null) { + s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); + return null; + } + String ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); + //Check for duplicate IP + if (_ipv6Dao.findByDcIdAndIp(dcId, ip) != null) { + //TODO regenerate ip + throw new CloudRuntimeException("Fail to get unique ipv6 address"); + } + 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)); + PublicIpv6AddressVO ipVO = new PublicIpv6AddressVO(ip, dcId, macAddress, vlan.getId()); + ipVO.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); + ipVO.setSourceNetworkId(vlan.getNetworkId()); + ipVO.setState(PublicIpv6Address.State.Allocated); + ipVO.setDomainId(owner.getDomainId()); + ipVO.setAccountId(owner.getAccountId()); + _ipv6Dao.persist(ipVO); + return ipVO; + } + @DB public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long guestNetworkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem, Long vpcId) @@ -1334,6 +1367,11 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { } vo.setState(Nic.State.Allocated); + + vo.setIp6Address(profile.getIp6Address()); + vo.setIp6Gateway(profile.getIp6Gateway()); + vo.setIp6Cidr(profile.getIp6Cidr()); + return deviceId; } @@ -1792,7 +1830,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { @DB public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId) + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1825,9 +1863,18 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { throw ex; } + boolean ipv6 = false; + + if (ip6Gateway != null && ip6Cidr != null) { + ipv6 = true; + } // Validate zone DataCenterVO zone = _dcDao.findById(zoneId); if (zone.getNetworkType() == NetworkType.Basic) { + if (ipv6) { + throw new InvalidParameterValueException("IPv6 is not supported in Basic zone"); + } + // In Basic zone the network should have aclType=Domain, domainId=1, subdomainAccess=true if (aclType == null || aclType != ACLType.Domain) { throw new InvalidParameterValueException("Only AclType=Domain can be specified for network creation in Basic zone"); @@ -1870,6 +1917,9 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { } else if (zone.getNetworkType() == NetworkType.Advanced) { if (zone.isSecurityGroupEnabled()) { + if (ipv6) { + throw new InvalidParameterValueException("IPv6 is not supported with security group!"); + } // Only Account specific Isolated network with sourceNat service disabled are allowed in security group // enabled zone boolean allowCreation = (ntwkOff.getGuestType() == GuestType.Isolated @@ -1948,14 +1998,14 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { } } } - + // In Advance zone Cidr for Shared networks and Isolated networks w/o source nat service can't be NULL - 2.2.x // limitation, remove after we introduce support for multiple ip ranges // with different Cidrs for the same Shared network boolean cidrRequired = zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getTrafficType() == TrafficType.Guest && (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))); - if (cidr == null && cidrRequired) { + if (cidr == null && ip6Cidr == null && cidrRequired) { throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared + " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled"); @@ -1966,11 +2016,11 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask can't be specified for zone of type " + NetworkType.Basic); } - // Check if cidr is RFC1918 compliant if the network is Guest Isolated + // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4 if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) { - if (!NetUtils.validateGuestCidr(cidr)) { - throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC1918 compliant"); - } + if (!NetUtils.validateGuestCidr(cidr)) { + throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC1918 compliant"); + } } Transaction txn = Transaction.currentTxn(); @@ -1997,7 +2047,21 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { } } } - + + if (ip6Cidr != null && ip6Gateway != null) { + userNetwork.setIp6Cidr(ip6Cidr); + userNetwork.setIp6Gateway(ip6Gateway); + if (vlanId != null) { + userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); + userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); + if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); + } else { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); + } + } + } + List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccess, vpcId); @@ -2559,7 +2623,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { guestNetwork = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network" , owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork, zoneId, ACLType.Account, - null, null); + null, null, null, null); if (guestNetwork == null) { s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " + @@ -3303,27 +3367,56 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { return success; } - public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIp) throws InsufficientVirtualNetworkCapcityException, + public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, + String requestedIpv4, String requestedIpv6) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { - if (nic.getIp4Address() == null) { - PublicIp ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIp, false); - nic.setIp4Address(ip.getAddress().toString()); - nic.setGateway(ip.getGateway()); - nic.setNetmask(ip.getNetmask()); - nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); - nic.setBroadcastType(BroadcastDomainType.Vlan); - nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); - nic.setFormat(AddressFormat.Ip4); - nic.setReservationId(String.valueOf(ip.getVlanTag())); - nic.setMacAddress(ip.getMacAddress()); - } + boolean ipv4 = false, ipv6 = false; + if (network.getGateway() != null) { + if (nic.getIp4Address() == null) { + ipv4 = true; + PublicIp ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false); + nic.setIp4Address(ip.getAddress().toString()); + nic.setGateway(ip.getGateway()); + nic.setNetmask(ip.getNetmask()); + nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); + nic.setBroadcastType(BroadcastDomainType.Vlan); + nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + nic.setFormat(AddressFormat.Ip4); + nic.setReservationId(String.valueOf(ip.getVlanTag())); + nic.setMacAddress(ip.getMacAddress()); + } + } + + if (network.getIp6Gateway() != null) { + if (nic.getIp6Address() == null) { + ipv6 = true; + PublicIpv6Address ip = assignPublicIp6Address(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv6, false); + Vlan vlan = _networkModel.getVlanForNetwork(network.getId()); + if (vlan == null) { + s_logger.debug("Cannot find related vlan or too many vlan attached to network " + network.getId()); + return; + } + nic.setIp6Address(ip.getAddress().toString()); + nic.setIp6Gateway(vlan.getIp6Gateway()); + nic.setIp6Cidr(vlan.getIp6Cidr()); + if (ipv4) { + nic.setFormat(AddressFormat.Mixed); + } 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.setDns1(dc.getDns1()); nic.setDns2(dc.getDns2()); } - - @Override + @Override public boolean setupDns(Network network, Provider provider) { boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, provider ); boolean dhcpProvided =_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index a99e9c50cbe..cd0187a2a28 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -36,6 +36,7 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; 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.DataCenterDao; @@ -65,6 +66,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; +import com.cloud.network.dao.PublicIpv6AddressDao; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.rules.FirewallRule.Purpose; @@ -157,7 +159,8 @@ public class NetworkModelImpl implements NetworkModel, Manager{ NetworkServiceMapDao _ntwkSrvcDao; @Inject PrivateIpDao _privateIpDao; - + @Inject + PublicIpv6AddressDao _ipv6Dao; private final HashMap _systemNetworks = new HashMap(5); @@ -510,7 +513,15 @@ public class NetworkModelImpl implements NetworkModel, Manager{ } boolean hasFreeIps = true; if (network.getGuestType() == GuestType.Shared) { - hasFreeIps = _ipAddressDao.countFreeIPsInNetwork(network.getId()) > 0; + if (network.getGateway() != null) { + hasFreeIps = _ipAddressDao.countFreeIPsInNetwork(network.getId()) > 0; + } + if (!hasFreeIps) { + return false; + } + if (network.getIp6Gateway() != null) { + hasFreeIps = isIP6AddressAvailable(network); + } } else { hasFreeIps = (getAvailableIps(network, null)).size() > 0; } @@ -518,9 +529,27 @@ public class NetworkModelImpl implements NetworkModel, Manager{ return hasFreeIps; } - - @Override + public Vlan getVlanForNetwork(long networkId) { + List vlans = _vlanDao.listVlansByNetworkId(networkId); + if (vlans == null || vlans.size() > 1) { + s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); + return null; + } + return vlans.get(0); + } + + private boolean isIP6AddressAvailable(Network network) { + if (network.getIp6Gateway() == null) { + return false; + } + Vlan vlan = getVlanForNetwork(network.getId()); + long existedCount = _ipv6Dao.countExistedIpsInNetwork(network.getId()); + long rangeCount = NetUtils.countIp6InRange(vlan.getIp6Range()); + return (existedCount < rangeCount); + } + + @Override public Map> getNetworkCapabilities(long networkId) { Map> networkCapabilities = new HashMap>(); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 7530e943116..20319ffe7d4 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -615,6 +615,11 @@ public class NetworkServiceImpl implements NetworkService, Manager { boolean isDomainSpecific = false; Boolean subdomainAccess = cmd.getSubdomainAccess(); Long vpcId = cmd.getVpcId(); + String startIPv6 = cmd.getStartIpv6(); + String endIPv6 = cmd.getEndIpv6(); + String ip6Gateway = cmd.getIp6Gateway(); + String ip6Cidr = cmd.getIp6Cidr(); + Boolean dualStack = cmd.isDualStack(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -732,36 +737,85 @@ public class NetworkServiceImpl implements NetworkService, Manager { UserContext.current().setAccountId(owner.getAccountId()); // VALIDATE IP INFO - // if end ip is not specified, default it to startIp + if (startIPv6 != null && startIP != null && (dualStack == null || dualStack == false)) { + throw new InvalidParameterValueException("Cannot specify both IPv4 and IPv6 address without set dualStack = true!"); + } + + boolean ipv4 = false, ipv6 = false; if (startIP != null) { - if (!NetUtils.isValidIp(startIP)) { - throw new InvalidParameterValueException("Invalid format for the startIp parameter"); - } - if (endIP == null) { - endIP = startIP; - } else if (!NetUtils.isValidIp(endIP)) { - throw new InvalidParameterValueException("Invalid format for the endIp parameter"); - } + ipv4 = true; } - - if (startIP != null && endIP != null) { - if (!(gateway != null && netmask != null)) { - throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in"); - } + if (startIPv6 != null) { + ipv6 = true; } - + String cidr = null; - if (gateway != null && netmask != null) { - if (!NetUtils.isValidIp(gateway)) { - throw new InvalidParameterValueException("Invalid gateway"); - } - if (!NetUtils.isValidNetmask(netmask)) { - throw new InvalidParameterValueException("Invalid netmask"); - } + if (ipv4) { + // if end ip is not specified, default it to startIp + if (startIP != null) { + if (!NetUtils.isValidIp(startIP)) { + throw new InvalidParameterValueException("Invalid format for the startIp parameter"); + } + if (endIP == null) { + endIP = startIP; + } else if (!NetUtils.isValidIp(endIP)) { + throw new InvalidParameterValueException("Invalid format for the endIp parameter"); + } + } - cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); + if (startIP != null && endIP != null) { + if (!(gateway != null && netmask != null)) { + throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in"); + } + } + + if (gateway != null && netmask != null) { + if (!NetUtils.isValidIp(gateway)) { + throw new InvalidParameterValueException("Invalid gateway"); + } + if (!NetUtils.isValidNetmask(netmask)) { + throw new InvalidParameterValueException("Invalid netmask"); + } + + cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); + } + + } + + if (ipv6) { + if (!NetUtils.isValidIPv6(startIPv6)) { + throw new InvalidParameterValueException("Invalid format for the startIPv6 parameter"); + } + if (endIPv6 == null) { + endIPv6 = startIPv6; + } else if (!NetUtils.isValidIPv6(endIPv6)) { + throw new InvalidParameterValueException("Invalid format for the endIPv6 parameter"); + } + + if (!(ip6Gateway != null && ip6Cidr != null)) { + throw new InvalidParameterValueException("ip6Gateway and ip6Cidr should be defined when startIPv6/endIPv6 are passed in"); + } + + if (!NetUtils.isValidIPv6(ip6Gateway)) { + throw new InvalidParameterValueException("Invalid ip6Gateway"); + } + if (!NetUtils.isValidIp6Cidr(ip6Cidr)) { + throw new InvalidParameterValueException("Invalid ip6cidr"); + } + + int cidrSize = NetUtils.getIp6CidrSize(ip6Cidr); + // Ipv6 cidr limit should be at least /64 + if (cidrSize < 64) { + throw new InvalidParameterValueException("The cidr size of IPv6 must be bigger than 64 bits!"); + } } + if (ipv6) { + if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared) { + throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!"); + } + } + // Regular user can create Guest Isolated Source Nat enabled network only if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated @@ -775,19 +829,25 @@ public class NetworkServiceImpl implements NetworkService, Manager { if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getSpecifyVlan() || vlanId != null)) { throw new InvalidParameterValueException("Regular user is not allowed to specify vlanId"); } + + if (ipv4) { + // For non-root admins check cidr limit - if it's allowed by global config value + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && cidr != null) { - // For non-root admins check cidr limit - if it's allowed by global config value - if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && cidr != null) { + String[] cidrPair = cidr.split("\\/"); + int cidrSize = Integer.valueOf(cidrPair[1]); - String[] cidrPair = cidr.split("\\/"); - int cidrSize = Integer.valueOf(cidrPair[1]); - - if (cidrSize < _cidrLimit) { - throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit); - } + if (cidrSize < _cidrLimit) { + throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit); + } + } } Collection ntwkProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(ntwkOff, physicalNetworkId).values(); + if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) { + throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!"); + } + if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && isSharedNetworkOfferingWithServices(networkOfferingId)) { @@ -798,7 +858,6 @@ public class NetworkServiceImpl implements NetworkService, Manager { } } - // Vlan is created in 2 cases - works in Advance zone only: // 1) GuestType is Shared // 2) GuestType is Isolated, but SourceNat service is disabled @@ -806,6 +865,13 @@ public class NetworkServiceImpl implements NetworkService, Manager { && ((ntwkOff.getGuestType() == Network.GuestType.Shared) || (ntwkOff.getGuestType() == GuestType.Isolated && !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)))); + + if (!createVlan) { + // Only support advance shared network in IPv6, which means createVlan is a must + if (ipv6) { + createVlan = true; + } + } // Can add vlan range only to the network which allows it if (createVlan && !ntwkOff.getSpecifyIpRanges()) { @@ -851,13 +917,13 @@ public class NetworkServiceImpl implements NetworkService, Manager { throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); } network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId); + networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr); } if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) { // Create vlan ip range _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, - false, null, startIP, endIP, gateway, netmask, vlanId, null); + false, null, startIP, endIP, gateway, netmask, vlanId, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr); } txn.commit(); @@ -2813,7 +2879,7 @@ public class NetworkServiceImpl implements NetworkService, Manager { if (privateNetwork == null) { //create Guest network privateNetwork = _networkMgr.createGuestNetwork(ntwkOff.getId(), networkName, displayText, gateway, cidr, vlan, - null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null); + null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null, null, null); s_logger.debug("Created private network " + privateNetwork); } else { s_logger.debug("Private network already exists: " + privateNetwork); diff --git a/server/src/com/cloud/network/NetworkVO.java b/server/src/com/cloud/network/NetworkVO.java index 14b643b29b7..e4c597698d1 100644 --- a/server/src/com/cloud/network/NetworkVO.java +++ b/server/src/com/cloud/network/NetworkVO.java @@ -148,6 +148,12 @@ public class NetworkVO implements Network { @Column(name="specify_ip_ranges") boolean specifyIpRanges = false; + + @Column(name="ip6_gateway") + String ip6Gateway; + + @Column(name="ip6_cidr") + String ip6Cidr; public NetworkVO() { this.uuid = UUID.randomUUID().toString(); @@ -195,6 +201,8 @@ public class NetworkVO implements Network { state = State.Allocated; } this.uuid = UUID.randomUUID().toString(); + this.ip6Gateway = that.getIp6Gateway(); + this.ip6Cidr = that.getIp6Cidr(); } /** @@ -491,4 +499,20 @@ public class NetworkVO implements Network { public Long getVpcId() { return vpcId; } + + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } } diff --git a/server/src/com/cloud/network/PublicIpv6Address.java b/server/src/com/cloud/network/PublicIpv6Address.java new file mode 100644 index 00000000000..5c51506811f --- /dev/null +++ b/server/src/com/cloud/network/PublicIpv6Address.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +/** + * @author Sheng Yang + * + */ +public interface PublicIpv6Address extends ControlledEntity, Identity, InternalIdentity { + enum State { + Allocating, // The IP Address is being propagated to other network elements and is not ready for use yet. + Allocated, // The IP address is in used. + Releasing, // The IP address is being released for other network elements and is not ready for allocation. + Free // The IP address is ready to be allocated. + } + + long getDataCenterId(); + + String getAddress(); + + long getVlanId(); + + State getState(); + + Long getNetworkId(); + + Long getSourceNetworkId(); + + Long getPhysicalNetworkId(); + + void setState(PublicIpv6Address.State state); + + String getMacAddress(); +} diff --git a/server/src/com/cloud/network/PublicIpv6AddressVO.java b/server/src/com/cloud/network/PublicIpv6AddressVO.java new file mode 100644 index 00000000000..7594fc16d2e --- /dev/null +++ b/server/src/com/cloud/network/PublicIpv6AddressVO.java @@ -0,0 +1,189 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name=("public_ipv6_address")) +public class PublicIpv6AddressVO implements PublicIpv6Address { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + long id; + + @Id + @Column(name="ip_address") + @Enumerated(value=EnumType.STRING) + private String address = null; + + @Column(name="data_center_id", updatable=false) + private long dataCenterId; + + @Column(name="vlan_id") + private long vlanId; + + @Column(name="state") + private State state; + + @Column(name="mac_address") + private String macAddress; + + @Column(name="source_network_id") + private Long sourceNetworkId; + + @Column(name="network_id") + private Long networkId; + + @Column(name="uuid") + private String uuid; + + @Column(name="physical_network_id") + private Long physicalNetworkId; + + @Column(name="account_id") + private Long accountId = null; + + @Column(name="domain_id") + private Long domainId = null; + + @Column(name = GenericDao.CREATED_COLUMN) + Date created; + + protected PublicIpv6AddressVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public PublicIpv6AddressVO(String address, long dataCenterId, String macAddress, long vlanDbId) { + this.address = address; + this.dataCenterId = dataCenterId; + this.vlanId = vlanDbId; + this.state = State.Free; + this.setMacAddress(macAddress); + this.uuid = UUID.randomUUID().toString(); + } + + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getId() { + return id; + } + + @Override + public long getDataCenterId() { + return dataCenterId; + } + + @Override + public String getAddress() { + return address; + } + + @Override + public long getVlanId() { + return vlanId; + } + + @Override + public State getState() { + return state; + } + + @Override + public Long getNetworkId() { + return networkId; + } + + @Override + public Long getSourceNetworkId() { + return sourceNetworkId; + } + + @Override + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + @Override + public void setState(State state) { + this.state = state; + } + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + public void setSourceNetworkId(Long sourceNetworkId) { + this.sourceNetworkId = sourceNetworkId; + } + + public void setNetworkId(Long networkId) { + this.networkId = networkId; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + public void setDomainId(Long domainId) { + this.domainId = domainId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } +} diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java index 8ad716fd631..246aa60a9ec 100644 --- a/server/src/com/cloud/network/addr/PublicIp.java +++ b/server/src/com/cloud/network/addr/PublicIp.java @@ -206,4 +206,19 @@ public class PublicIp implements PublicIpAddress { public void setVpcId(Long vpcId) { _addr.setVpcId(vpcId); } + + @Override + public String getIp6Gateway() { + return _vlan.getIp6Gateway(); + } + + @Override + public String getIp6Cidr() { + return _vlan.getIp6Cidr(); + } + + @Override + public String getIp6Range() { + return _vlan.getIp6Range(); + } } diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java b/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java new file mode 100644 index 00000000000..b8de08a9926 --- /dev/null +++ b/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java @@ -0,0 +1,23 @@ +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.Network; +import com.cloud.network.PublicIpv6AddressVO; +import com.cloud.utils.db.GenericDao; + +public interface PublicIpv6AddressDao extends GenericDao { + List listByAccount(long accountId); + + List listByVlanId(long vlanId); + + List listByDcId(long dcId); + + List listByNetwork(long networkId); + + public PublicIpv6AddressVO findByDcIdAndIp(long dcId, String ipAddress); + + List listByPhysicalNetworkId(long physicalNetworkId); + + long countExistedIpsInNetwork(long networkId); +} diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java b/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java new file mode 100644 index 00000000000..6883d4ec662 --- /dev/null +++ b/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java @@ -0,0 +1,96 @@ +package com.cloud.network.dao; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.network.Network; +import com.cloud.network.PublicIpv6AddressVO; +import com.cloud.utils.Pair; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.SearchCriteria2; + +@Local(value=PublicIpv6AddressDao.class) +public class PublicIpv6AddressDaoImpl extends GenericDaoBase implements PublicIpv6AddressDao { + private static final Logger s_logger = Logger.getLogger(IPAddressDaoImpl.class); + + protected final SearchBuilder AllFieldsSearch; + protected GenericSearchBuilder CountFreePublicIps; + + public PublicIpv6AddressDaoImpl() { + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); + AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ); + AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getAddress(), Op.EQ); + AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ); + AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); + AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ); + AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ); + AllFieldsSearch.done(); + + CountFreePublicIps = createSearchBuilder(Long.class); + CountFreePublicIps.select(null, Func.COUNT, null); + CountFreePublicIps.and("networkId", CountFreePublicIps.entity().getSourceNetworkId(), SearchCriteria.Op.EQ); + CountFreePublicIps.done(); + } + + @Override + public List listByAccount(long accountId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } + + @Override + public List listByVlanId(long vlanId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vlan", vlanId); + return listBy(sc); + } + + @Override + public List listByDcId(long dcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("dataCenterId", dcId); + return listBy(sc); + } + + @Override + public List listByNetwork(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + return listBy(sc); + } + + @Override + public PublicIpv6AddressVO findByDcIdAndIp(long dcId, String ipAddress) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("dataCenterId", dcId); + sc.setParameters("ipAddress", ipAddress); + return findOneBy(sc); + } + + @Override + public List listByPhysicalNetworkId(long physicalNetworkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return listBy(sc); + } + + @Override + public long countExistedIpsInNetwork(long networkId) { + SearchCriteria sc = CountFreePublicIps.create(); + sc.setParameters("networkId", networkId); + return customSearch(sc, null).get(0); + } +} diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index b290c1da3ef..d6a8812da08 100755 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -42,7 +42,9 @@ import com.cloud.network.NetworkVO; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PublicIpv6AddressVO; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.PublicIpv6AddressDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; @@ -72,6 +74,8 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { IPAddressDao _ipAddressDao; @Inject NetworkOfferingDao _networkOfferingDao; + @Inject + PublicIpv6AddressDao _ipv6Dao; private static final TrafficType[] _trafficTypes = {TrafficType.Guest}; @@ -120,11 +124,20 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { throw new InvalidParameterValueException("cidr and gateway must be specified together."); } + if ((userSpecified.getIp6Cidr() == null && userSpecified.getIp6Gateway() != null) || (userSpecified.getIp6Cidr() != null && userSpecified.getIp6Gateway() == null)) { + throw new InvalidParameterValueException("cidrv6 and gatewayv6 must be specified together."); + } + if (userSpecified.getCidr() != null) { config.setCidr(userSpecified.getCidr()); config.setGateway(userSpecified.getGateway()); } + if (userSpecified.getIp6Cidr() != null) { + config.setIp6Cidr(userSpecified.getIp6Cidr()); + config.setIp6Gateway(userSpecified.getIp6Gateway()); + } + if (userSpecified.getBroadcastUri() != null) { config.setBroadcastUri(userSpecified.getBroadcastUri()); config.setState(State.Setup); @@ -137,6 +150,9 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { boolean isSecurityGroupEnabled = _networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Service.SecurityGroup); if (isSecurityGroupEnabled) { + if (userSpecified.getIp6Cidr() != null) { + throw new InvalidParameterValueException("Didn't support security group with IPv6"); + } config.setName("SecurityGroupEnabledNetwork"); config.setDisplayText("SecurityGroupEnabledNetwork"); } @@ -165,13 +181,13 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { if (nic == null) { nic = new NicProfile(ReservationStrategy.Create, null, null, null, null); - } else if (nic.getIp4Address() == null) { + } else if (nic.getIp4Address() == null && nic.getIp6Address() == null) { nic.setStrategy(ReservationStrategy.Start); } else { nic.setStrategy(ReservationStrategy.Create); } - _networkMgr.allocateDirectIp(nic, dc, vm, network, nic.getRequestedIp()); + _networkMgr.allocateDirectIp(nic, dc, vm, network, nic.getRequestedIpv4(), nic.getRequestedIpv6()); nic.setStrategy(ReservationStrategy.Create); return nic; @@ -180,8 +196,8 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { @Override public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { - if (nic.getIp4Address() == null) { - _networkMgr.allocateDirectIp(nic, dest.getDataCenter(), vm, network, null); + if (nic.getIp4Address() == null && nic.getIp6Address() == null) { + _networkMgr.allocateDirectIp(nic, dest.getDataCenter(), vm, network, null, null); nic.setStrategy(ReservationStrategy.Create); } } @@ -202,14 +218,23 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { s_logger.debug("Deallocate network: networkId: " + nic.getNetworkId() + ", ip: " + nic.getIp4Address()); } - IPAddressVO ip = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), nic.getIp4Address()); - if (ip != null) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - _networkMgr.markIpAsUnavailable(ip.getId()); - _ipAddressDao.unassignIpAddress(ip.getId()); - txn.commit(); - } + if (nic.getIp4Address() != null) { + IPAddressVO ip = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), nic.getIp4Address()); + if (ip != null) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + _networkMgr.markIpAsUnavailable(ip.getId()); + _ipAddressDao.unassignIpAddress(ip.getId()); + txn.commit(); + } + } + + if (nic.getIp6Address() != null) { + PublicIpv6AddressVO ip = _ipv6Dao.findByDcIdAndIp(network.getDataCenterId(), nic.getIp6Address()); + if (ip != null) { + _ipv6Dao.remove(ip.getId()); + } + } nic.deallocate(); } diff --git a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java index 8ca4547d686..709d2806533 100755 --- a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java @@ -96,7 +96,7 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru { rsStrategy = ReservationStrategy.Create; } - if (nic != null && nic.getRequestedIp() != null) { + if (nic != null && nic.getRequestedIpv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); } diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index f8a8a95ec05..7a09d94d390 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -195,7 +195,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { - if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) && nic != null && nic.getRequestedIp() != null) { + if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) && nic != null && nic.getRequestedIpv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); } diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index 95878859598..79ab87bb43e 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -352,7 +352,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur String guestIp = null; if (network.getSpecifyIpRanges()) { - _networkMgr.allocateDirectIp(nic, dc, vm, network, nic.getRequestedIp()); + _networkMgr.allocateDirectIp(nic, dc, vm, network, nic.getRequestedIpv4(), null); } else { //if Vm is router vm and source nat is enabled in the network, set ip4 to the network gateway boolean isGateway = false; @@ -371,7 +371,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur if (isGateway) { guestIp = network.getGateway(); } else { - guestIp = _networkMgr.acquireGuestIpAddress(network, nic.getRequestedIp()); + guestIp = _networkMgr.acquireGuestIpAddress(network, nic.getRequestedIpv4()); if (guestIp == null) { throw new InsufficientVirtualNetworkCapcityException("Unable to acquire Guest IP" + " address for network " + network, DataCenter.class, dc.getId()); diff --git a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java index b513325d5ee..bbe568d989f 100755 --- a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java @@ -100,7 +100,7 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { assert trafficType == TrafficType.Management || trafficType == TrafficType.Storage: "Well, I can't take care of this config now can I? " + config; if (nic != null) { - if (nic.getRequestedIp() != null) { + if (nic.getRequestedIpv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); } nic.setStrategy(nic.getIp4Address() != null ? ReservationStrategy.Create : ReservationStrategy.Start); diff --git a/server/src/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/com/cloud/network/guru/PublicNetworkGuru.java index ddee5a588b2..8e912d68460 100755 --- a/server/src/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PublicNetworkGuru.java @@ -142,7 +142,7 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { DataCenter dc = _dcDao.findById(network.getDataCenterId()); - if (nic != null && nic.getRequestedIp() != null) { + if (nic != null && nic.getRequestedIpv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index e1c78e1a4e7..c0e7888094a 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1656,7 +1656,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } } - NicProfile gatewayNic = new NicProfile(defaultNetworkStartIp); + NicProfile gatewayNic = new NicProfile(defaultNetworkStartIp, null); if (setupPublicNetwork) { if (isRedundant) { gatewayNic.setIp4Address(_networkMgr.acquireGuestIpAddress(guestNetwork, null)); @@ -3018,11 +3018,11 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } private void createDhcpEntryCommand(VirtualRouter router, UserVm vm, NicVO nic, Commands cmds) { - DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), vm.getHostName()); + DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), vm.getHostName(), nic.getIp6Address()); DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); String gatewayIp = findGatewayIp(vm.getId()); boolean needGateway = true; - if (!gatewayIp.equals(nic.getGateway())) { + if (gatewayIp != null && !gatewayIp.equals(nic.getGateway())) { needGateway = false; GuestOSVO guestOS = _guestOSDao.findById(vm.getGuestOSId()); // Do set dhcp:router option for non-default nic on certain OS(including Windows), and leave other OS unset. @@ -3038,7 +3038,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian gatewayIp = "0.0.0.0"; } dhcpCommand.setDefaultRouter(gatewayIp); + dhcpCommand.setIp6Gateway(nic.getIp6Gateway()); dhcpCommand.setDefaultDns(findDefaultDnsIp(vm.getId())); + dhcpCommand.setDuid(NetUtils.getDuidLL(nic.getMacAddress())); dhcpCommand.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); dhcpCommand.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index fa6bd30f980..26e882e1864 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1884,7 +1884,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ //2) Create network Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId); + networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null); return guestNetwork; } diff --git a/server/src/com/cloud/vm/NicVO.java b/server/src/com/cloud/vm/NicVO.java index 64b9153a347..8e2edda40aa 100644 --- a/server/src/com/cloud/vm/NicVO.java +++ b/server/src/com/cloud/vm/NicVO.java @@ -99,6 +99,12 @@ public class NicVO implements Nic { @Column(name = "default_nic") boolean defaultNic; + @Column(name = "ip6_gateway") + String ip6Gateway; + + @Column(name = "ip6_cidr") + String ip6Cidr; + @Column(name = "strategy") @Enumerated(value = EnumType.STRING) ReservationStrategy reservationStrategy; @@ -156,6 +162,7 @@ public class NicVO implements Nic { this.defaultNic = defaultNic; } + @Override public String getIp6Address() { return ip6Address; } @@ -324,4 +331,22 @@ public class NicVO implements Nic { public void setUuid(String uuid) { this.uuid = uuid; } + + @Override + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + @Override + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 58910562beb..870eeccd3ca 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2184,7 +2184,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.debug("Creating network for account " + owner + " from the network offering id=" +requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null, - null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null); + null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException("More than 1 default Isolated networks are found for account " + owner + "; please specify networkIds"); @@ -2372,13 +2372,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager requestedIp = requestedIps.get(network.getId()); } - NicProfile profile = new NicProfile(requestedIp); + NicProfile profile = new NicProfile(requestedIp, null); if (defaultNetworkNumber == 0) { defaultNetworkNumber++; // if user requested specific ip for default network, add it if (defaultNetworkIp != null) { - profile = new NicProfile(defaultNetworkIp); + profile = new NicProfile(defaultNetworkIp, null); } profile.setDefaultNic(true); @@ -3543,7 +3543,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, - null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null); + null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException("More than 1 default Isolated networks are found " + diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index ef5b9c9f9b7..df409a83ebc 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -247,7 +247,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; } @@ -660,7 +660,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS */ @Override public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, - Network network, String requestedIp) throws InsufficientVirtualNetworkCapcityException, + Network network, String requestedIpv4, String requestedIpv6) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { // TODO Auto-generated method stub @@ -818,4 +818,12 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS // TODO Auto-generated method stub return null; } + + @Override + public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, + Account owner, VlanType type, Long networkId, String requestedIpv6, + boolean isSystem) throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index 1771660f86c..07c6247a70e 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -806,4 +806,10 @@ public class MockNetworkModelImpl implements NetworkModel, Manager { return false; } + @Override + public Vlan getVlanForNetwork(long networkId) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 3989ecfd0e3..d0f0c62a9fe 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -493,7 +493,7 @@ public class MockConfigurationManagerImpl implements ConfigurationManager, Confi */ @Override public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, - Account vlanOwner) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { + Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index b4e17948a43..13426e601a9 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -56,6 +56,7 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; import com.cloud.network.PublicIpAddress; +import com.cloud.network.PublicIpv6Address; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.element.LoadBalancingServiceProvider; @@ -846,7 +847,7 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId) + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -1011,10 +1012,9 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M */ @Override public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, - Network network, String requestedIp) throws InsufficientVirtualNetworkCapcityException, + Network network, String requestedIpv4, String requestedIpv6) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { // TODO Auto-generated method stub - } @@ -1313,10 +1313,6 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M return null; } - - - - /* (non-Javadoc) * @see com.cloud.network.NetworkService#getNetwork(java.lang.String) */ @@ -1325,4 +1321,12 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M // TODO Auto-generated method stub return null; } + + @Override + public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, + Account owner, VlanType type, Long networkId, String requestedIpv6, + boolean isSystem) throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 174f53cd7ba..db3a8a53950 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -207,6 +207,8 @@ CREATE TABLE `cloud`.`networks` ( `broadcast_uri` varchar(255) COMMENT 'broadcast domain specifier', `gateway` varchar(15) COMMENT 'gateway for this network configuration', `cidr` varchar(18) COMMENT 'network cidr', + `ip6_gateway` varchar(50) COMMENT 'IPv6 gateway for this network', + `ip6_cidr` varchar(50) COMMENT 'IPv6 cidr for this network', `mode` varchar(32) COMMENT 'How to retrieve ip address in this network', `network_offering_id` bigint unsigned NOT NULL COMMENT 'network offering id that this configuration is created from', `physical_network_id` bigint unsigned COMMENT 'physical network id that this configuration is based on', @@ -270,6 +272,8 @@ CREATE TABLE `cloud`.`nics` ( `update_time` timestamp NOT NULL COMMENT 'time the state was changed', `isolation_uri` varchar(255) COMMENT 'id for isolation', `ip6_address` char(40) COMMENT 'ip6 address', + `ip6_gateway` varchar(50) COMMENT 'gateway for ip6 address', + `ip6_cidr` varchar(50) COMMENT 'cidr for ip6 address', `default_nic` tinyint NOT NULL COMMENT "None", `vm_type` varchar(32) COMMENT 'type of vm: System or User vm', `created` datetime NOT NULL COMMENT 'date created', @@ -500,7 +504,10 @@ CREATE TABLE `cloud`.`vlan` ( `vlan_id` varchar(255), `vlan_gateway` varchar(255), `vlan_netmask` varchar(255), + `ip6_gateway` varchar(255), + `ip6_cidr` varchar(255), `description` varchar(255), + `ip6_range` varchar(255), `vlan_type` varchar(255), `data_center_id` bigint unsigned NOT NULL, `network_id` bigint unsigned NOT NULL COMMENT 'id of corresponding network offering', @@ -2543,5 +2550,30 @@ INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (2, INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (3, UUID(), 'snmp','Linux CPU Idle - percentage', '1.3.6.1.4.1.2021.11.11.0', now()); INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (100, UUID(), 'netscaler','Response Time - microseconds', 'RESPTIME', now()); +CREATE TABLE `cloud`.`public_ipv6_address` ( + `id` bigint unsigned NOT NULL UNIQUE auto_increment, + `uuid` varchar(40), + `account_id` bigint unsigned NULL, + `domain_id` bigint unsigned NULL, + `ip_address` char(50) NOT NULL, + `data_center_id` bigint unsigned NOT NULL COMMENT 'zone that it belongs to', + `vlan_id` bigint unsigned NOT NULL, + `state` char(32) NOT NULL default 'Free' COMMENT 'state of the ip address', + `mac_address` varchar(40) NOT NULL COMMENT 'mac address of this ip', + `source_network_id` bigint unsigned NOT NULL COMMENT 'network id ip belongs to', + `network_id` bigint unsigned COMMENT 'network this public ip address is associated with', + `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id that this configuration is based on', + `created` datetime NULL COMMENT 'Date this ip was allocated to someone', + PRIMARY KEY (`id`), + UNIQUE (`ip_address`, `source_network_id`), + CONSTRAINT `fk_public_ipv6_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_public_ipv6_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_public_ipv6_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_public_ipv6_address__vlan_id` FOREIGN KEY (`vlan_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_public_ipv6_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_public_ipv6_address__uuid` UNIQUE (`uuid`), + CONSTRAINT `fk_public_ipv6_address__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + SET foreign_key_checks = 1; diff --git a/utils/pom.xml b/utils/pom.xml index 87c078a7a61..6f45044a6f9 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -128,6 +128,11 @@ ejb-api ${cs.ejb.version} + + com.googlecode.java-ipv6 + java-ipv6 + ${cs.java-ipv6.version} + commons-configuration commons-configuration diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index c456cdcca8e..8bfd3769029 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -41,6 +41,9 @@ import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; +import com.googlecode.ipv6.IPv6Address; +import com.googlecode.ipv6.IPv6Network; + import com.cloud.utils.IteratorUtil; import com.cloud.utils.Pair; import com.cloud.utils.script.Script; @@ -1142,4 +1145,73 @@ public class NetUtils { return true; } + + public static boolean isValidIPv6(String ip) { + try { + IPv6Address address = IPv6Address.fromString(ip); + } catch (IllegalArgumentException ex) { + return false; + } + return true; + } + + public static boolean isValidIp6Cidr(String ip6Cidr) { + try { + IPv6Network network = IPv6Network.fromString(ip6Cidr); + } catch (IllegalArgumentException ex) { + return false; + } + return true; + } + + public static int getIp6CidrSize(String ip6Cidr) { + IPv6Network network = null; + try { + network = IPv6Network.fromString(ip6Cidr); + } catch (IllegalArgumentException ex) { + return 0; + } + return network.getNetmask().asPrefixLength(); + } + + //FIXME: only able to cover lower 32 bits + public static String getIp6FromRange(String ip6Range) { + String[] ips = ip6Range.split("-"); + String startIp = ips[0]; + long gap = countIp6InRange(ip6Range); + IPv6Address start = IPv6Address.fromString(startIp); + // Find a random number based on lower 32 bits + int d = _rand.nextInt((int)(gap % Integer.MAX_VALUE)); + // And a number based on the difference of lower 32 bits + IPv6Address ip = start.add(d); + return ip.toString(); + } + + //RFC3315, section 9.4 + public static String getDuidLL(String macAddress) { + String duid = "00:03:00:06:" + macAddress; + return duid; + } + + //FIXME: only able to cover lower 64 bits + public static long countIp6InRange(String ip6Range) { + String[] ips = ip6Range.split("-"); + String startIp = ips[0]; + String endIp = null; + if (ips.length > 1) { + endIp = ips[1]; + } + IPv6Address start, end; + try { + start = IPv6Address.fromString(startIp); + end = IPv6Address.fromString(endIp); + } catch (IllegalArgumentException ex) { + return 0; + } + long startLow = start.getLowBits(), endLow = end.getLowBits(); + if (startLow > endLow) { + return 0; + } + return endLow - startLow + 1; + } } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 1eccba30df2..6290cd6390d 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -69,4 +69,18 @@ public class NetUtilsTest extends TestCase { assertFalse(NetUtils.isValidS2SVpnPolicy(";modp1536")); assertFalse(NetUtils.isValidS2SVpnPolicy(",aes;modp1536,,,")); } + + public void testIpv6() { + assertTrue(NetUtils.isValidIPv6("fc00::1")); + assertFalse(NetUtils.isValidIPv6("")); + assertFalse(NetUtils.isValidIPv6(null)); + assertFalse(NetUtils.isValidIPv6("1234:5678::1/64")); + assertTrue(NetUtils.isValidIp6Cidr("1234:5678::1/64")); + assertFalse(NetUtils.isValidIp6Cidr("1234:5678::1")); + assertEquals(NetUtils.getIp6CidrSize("1234:5678::1/32"), 32); + assertEquals(NetUtils.getIp6CidrSize("1234:5678::1"), 0); + assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), 2); + assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), 0); + assertEquals(NetUtils.getIp6FromRange("1234:5678::1-1234:5678::1"), "1234:5678::1"); + } } From 6169c1d724b5e0d94dfa7dbe68555cdc3ea043ff Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 24 Jan 2013 20:09:37 -0800 Subject: [PATCH 02/26] IPv6: Enable IPv6 address for router --- .../config/etc/init.d/cloud-early-config | 35 ++++++++++++++++++- .../systemvm/debian/config/etc/sysctl.conf | 6 ++-- .../VirtualNetworkApplianceManagerImpl.java | 20 +++++++++-- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index 285a92fa0a6..74b963b182c 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -229,6 +229,23 @@ setup_interface() { fi } +setup_interface_ipv6() { + sysctl net.ipv6.conf.all.disable_ipv6=0 + sysctl net.ipv6.conf.all.accept_ra=1 + + local intfnum=$1 + local ipv6="$2" + local prelen="$3" + local intf=eth${intfnum} + + echo "iface $intf inet6 static" >> /etc/network/interfaces + echo " address $ipv6 " >> /etc/network/interfaces + echo " netmask $prelen" >> /etc/network/interfaces + echo " accept_ra 1" >> /etc/network/interfaces + ifdown $intf + ifup $intf +} + enable_fwding() { local enabled=$1 log_it "cloud: enable_fwding = $1" @@ -303,7 +320,14 @@ disable_hvc() { setup_common() { init_interfaces $1 $2 $3 - setup_interface "0" $ETH0_IP $ETH0_MASK $GW + if [ -n "$ETH0_IP" ] + then + setup_interface "0" $ETH0_IP $ETH0_MASK $GW + fi + if [ -n "$ETH0_IP6" ] + then + setup_interface_ipv6 "0" $ETH0_IP6 $ETH0_IP6_PRELEN + fi setup_interface "1" $ETH1_IP $ETH1_MASK $GW if [ -n "$ETH2_IP" ] then @@ -903,6 +927,9 @@ for i in $CMDLINE gateway) GW=$VALUE ;; + ip6gateway) + IP6GW=$VALUE + ;; eth0mask) ETH0_MASK=$VALUE ;; @@ -912,6 +939,12 @@ for i in $CMDLINE eth2mask) ETH2_MASK=$VALUE ;; + eth0ip6) + ETH0_IP6=$VALUE + ;; + eth0ip6prelen) + ETH0_IP6_PRELEN=$VALUE + ;; internaldns1) internalNS1=$VALUE ;; diff --git a/patches/systemvm/debian/config/etc/sysctl.conf b/patches/systemvm/debian/config/etc/sysctl.conf index 961d471dfa9..586d5bdb7c6 100644 --- a/patches/systemvm/debian/config/etc/sysctl.conf +++ b/patches/systemvm/debian/config/etc/sysctl.conf @@ -42,8 +42,8 @@ net.ipv4.tcp_max_tw_buckets=1000000 net.core.somaxconn=1000000 # Disable IPv6 -net.ipv6.conf.all.disable_ipv6 = 1 -net.ipv6.conf.all.forwarding = 0 -net.ipv6.conf.all.accept_ra = 0 +net.ipv6.conf.all.disable_ipv6 = 0 +net.ipv6.conf.all.forwarding = 1 +net.ipv6.conf.all.accept_ra = 1 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.all.autoconf = 0 diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index c0e7888094a..679ca241686 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1886,11 +1886,25 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian String defaultDns2 = null; for (NicProfile nic : profile.getNics()) { int deviceId = nic.getDeviceId(); - buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address()); - buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask()); + boolean ipv4 = false, ipv6 = false; + if (nic.getIp4Address() != null) { + ipv4 = true; + buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address()); + buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask()); + } + if (nic.getIp6Address() != null) { + ipv6 = true; + buf.append(" eth").append(deviceId).append("ip6=").append(nic.getIp6Address()); + buf.append(" eth").append(deviceId).append("ip6prelen=").append(NetUtils.getIp6CidrSize(nic.getIp6Cidr())); + } if (nic.isDefaultNic()) { - buf.append(" gateway=").append(nic.getGateway()); + if (ipv4) { + buf.append(" gateway=").append(nic.getGateway()); + } + if (ipv6) { + buf.append(" ip6gateway=").append(nic.getIp6Gateway()); + } defaultDns1 = nic.getDns1(); defaultDns2 = nic.getDns2(); } From 9300a02ba4ec8f926f4f579bc1d4b2d4e4475062 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 24 Jan 2013 20:09:37 -0800 Subject: [PATCH 03/26] IPv6: Update edithosts.sh accept parameters --- .../systemvm/debian/config/root/edithosts.sh | 61 +++++++++++++------ .../vmware/resource/VmwareResource.java | 12 ++-- scripts/network/domr/dhcp_entry.sh | 58 ++++++++---------- 3 files changed, 76 insertions(+), 55 deletions(-) diff --git a/patches/systemvm/debian/config/root/edithosts.sh b/patches/systemvm/debian/config/root/edithosts.sh index 37c75a53022..acc421b8a67 100755 --- a/patches/systemvm/debian/config/root/edithosts.sh +++ b/patches/systemvm/debian/config/root/edithosts.sh @@ -26,12 +26,37 @@ # $5 : nameserver on default nic # $6 : comma separated static routes -mac=$1 -ip=$2 -host=$3 -dflt=$4 -dns=$5 -routes=$6 +usage() { + printf "Usage: %s: -m -4 -h -d -n -s \n" $(basename $0) >&2 +} + +mac= +ipv4= +host= +dflt= +dns= +routes= + +while getopts 'm:4:h:d:n:s:' OPTION +do + case $OPTION in + m) mac="$OPTARG" + ;; + 4) ipv4="$OPTARG" + ;; + h) host="$OPTARG" + ;; + d) dflt="$OPTARG" + ;; + n) dns="$OPTARG" + ;; + s) routes="$OPTARG" + ;; + ?) usage + exit 2 + ;; + esac +done DHCP_HOSTS=/etc/dhcphosts.txt DHCP_OPTS=/etc/dhcpopts.txt @@ -71,25 +96,25 @@ logger -t cloud "edithosts: update $1 $2 $3 to hosts" #delete any previous entries from the dhcp hosts file sed -i /$mac/d $DHCP_HOSTS -sed -i /$ip,/d $DHCP_HOSTS +sed -i /$ipv4,/d $DHCP_HOSTS sed -i /$host,/d $DHCP_HOSTS #put in the new entry -echo "$mac,$ip,$host,infinite" >>$DHCP_HOSTS +echo "$mac,$ipv4,$host,infinite" >>$DHCP_HOSTS #delete leases to supplied mac and ip addresses sed -i /$mac/d $DHCP_LEASES -sed -i /"$ip "/d $DHCP_LEASES +sed -i /"$ipv4 "/d $DHCP_LEASES sed -i /"$host "/d $DHCP_LEASES #put in the new entry -echo "0 $mac $ip $host *" >> $DHCP_LEASES +echo "0 $mac $ipv4 $host *" >> $DHCP_LEASES #edit hosts file as well -sed -i /"$ip "/d $HOSTS +sed -i /"$ipv4 "/d $HOSTS sed -i /" $host$"/d $HOSTS -echo "$ip $host" >> $HOSTS +echo "$ipv4 $host" >> $HOSTS if [ "$dflt" != "" ] then @@ -97,26 +122,26 @@ then sed -i /dhcp-optsfile/d /etc/dnsmasq.conf echo "dhcp-optsfile=$DHCP_OPTS" >> /etc/dnsmasq.conf - tag=$(echo $ip | tr '.' '_') + tag=$(echo $ipv4 | tr '.' '_') sed -i /$tag/d $DHCP_OPTS if [ "$dflt" != "0.0.0.0" ] then - logger -t cloud "$0: setting default router for $ip to $dflt" + logger -t cloud "$0: setting default router for $ipv4 to $dflt" echo "$tag,3,$dflt" >> $DHCP_OPTS else - logger -t cloud "$0: unset default router for $ip" + logger -t cloud "$0: unset default router for $ipv4" echo "$tag,3," >> $DHCP_OPTS fi if [ "$dns" != "" ] then - logger -t cloud "$0: setting dns server for $ip to $dns" + logger -t cloud "$0: setting dns server for $ipv4 to $dns" echo "$tag,6,$dns" >> $DHCP_OPTS fi [ "$routes" != "" ] && echo "$tag,121,$routes" >> $DHCP_OPTS #delete entry we just put in because we need a tag - sed -i /$mac/d $DHCP_HOSTS + sed -i /$ipv4/d $DHCP_HOSTS #put it back with a tag - echo "$mac,set:$tag,$ip,$host,infinite" >>$DHCP_HOSTS + echo "$mac,set:$tag,$ipv4,$host,infinite" >>$DHCP_HOSTS fi # make dnsmasq re-read files diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index dd917f75a6e..0ca25a888af 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1629,20 +1629,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } // ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domr "/root/edithosts.sh $mac $ip $vm $dfltrt $ns $staticrt" >/dev/null - String args = " " + cmd.getVmMac(); - args += " " + cmd.getVmIpAddress(); - args += " " + cmd.getVmName(); + String args = " -m " + cmd.getVmMac(); + args += " -4 " + cmd.getVmIpAddress(); + args += " -h " + cmd.getVmName(); if (cmd.getDefaultRouter() != null) { - args += " " + cmd.getDefaultRouter(); + args += " -d " + cmd.getDefaultRouter(); } if (cmd.getDefaultDns() != null) { - args += " " + cmd.getDefaultDns(); + args += " -n " + cmd.getDefaultDns(); } if (cmd.getStaticRoutes() != null) { - args += " " + cmd.getStaticRoutes(); + args += " -s " + cmd.getStaticRoutes(); } if (s_logger.isDebugEnabled()) { diff --git a/scripts/network/domr/dhcp_entry.sh b/scripts/network/domr/dhcp_entry.sh index c1bf3543dfb..b964eb4c292 100755 --- a/scripts/network/domr/dhcp_entry.sh +++ b/scripts/network/domr/dhcp_entry.sh @@ -22,24 +22,12 @@ # @VERSION@ usage() { - printf "Usage: %s: -r -m -v -n \n" $(basename $0) >&2 + printf "Usage: %s: -r -m -v -n -s -d -N \n" $(basename $0) >&2 exit 2 } cert="/root/.ssh/id_rsa.cloud" -add_dhcp_entry() { - local domr=$1 - local mac=$2 - local ip=$3 - local vm=$4 - local dfltrt=$5 - local ns=$6 - local staticrt=$7 - ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domr "/root/edithosts.sh $mac $ip $vm $dfltrt $ns $staticrt" >/dev/null - return $? -} - domrIp= vmMac= vmIp= @@ -48,29 +36,37 @@ staticrt= dfltrt= dns= +opts= + while getopts 'r:m:v:n:d:s:N:' OPTION do case $OPTION in - r) domrIp="$OPTARG" - ;; - v) vmIp="$OPTARG" - ;; - m) vmMac="$OPTARG" - ;; - n) vmName="$OPTARG" - ;; - s) staticrt="$OPTARG" - ;; - d) dfltrt="$OPTARG" - ;; - N) dns="$OPTARG" - ;; - ?) usage - exit 1 - ;; + r) domrIp="$OPTARG" + ;; + v) vmIp="$OPTARG" + opts="$opts -4 $vmIp" + ;; + m) vmMac="$OPTARG" + opts="$opts -m $vmMac" + ;; + n) vmName="$OPTARG" + opts="$opts -h $vmName" + ;; + s) staticrt="$OPTARG" + opts="$opts -s $staticrt" + ;; + d) dfltrt="$OPTARG" + opts="$opts -d $dfltrt" + ;; + N) dns="$OPTARG" + opts="$opts -n $dns" + ;; + ?) usage + exit 1 + ;; esac done -add_dhcp_entry $domrIp $vmMac $vmIp $vmName $dfltrt $dns $staticrt +ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domrIp "/root/edithosts.sh $opts " >/dev/null exit $? From f89c66070bcbf3f02eec886c50a21a056a9dd032 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 25 Jan 2013 11:26:24 -0800 Subject: [PATCH 04/26] IPv6: Update dnsmasq.conf to new version --- .../systemvm/debian/config/etc/dnsmasq.conf | 273 ++++++++++++++---- 1 file changed, 220 insertions(+), 53 deletions(-) diff --git a/patches/systemvm/debian/config/etc/dnsmasq.conf b/patches/systemvm/debian/config/etc/dnsmasq.conf index 8f999a75cb1..c01e7549d63 100644 --- a/patches/systemvm/debian/config/etc/dnsmasq.conf +++ b/patches/systemvm/debian/config/etc/dnsmasq.conf @@ -4,11 +4,16 @@ # as the long options legal on the command line. See # "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details. +# Listen on this specific port instead of the standard DNS port +# (53). Setting this to zero completely disables DNS function, +# leaving only DHCP and/or TFTP. +#port=5353 + # The following two options make you a better netizen, since they # tell dnsmasq to filter out queries which the public DNS cannot # answer, and which load the servers (especially the root servers) -# uneccessarily. If you have a dial-on-demand link they also stop -# these requests from bringing up the link uneccessarily. +# unnecessarily. If you have a dial-on-demand link they also stop +# these requests from bringing up the link unnecessarily. # Never forward plain names (without a dot or domain part) domain-needed @@ -19,10 +24,10 @@ bogus-priv # Uncomment this to filter useless windows-originated DNS requests # which can trigger dial-on-demand links needlessly. # Note that (amongst other things) this blocks all SRV requests, -# so don't use it if you use eg Kerberos. +# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk. # This option only affects forwarding, SRV records originating for # dnsmasq (via srv-host= lines) are not suppressed by it. -#filterwin2k +filterwin2k # Change this line if you want dns to get its upstream servers from # somewhere other that /etc/resolv.conf @@ -48,7 +53,7 @@ resolv-file=/etc/dnsmasq-resolv.conf # non-public domains. #server=/localnet/192.168.0.1 -# Example of routing PTR queries to nameservers: this will send all +# Example of routing PTR queries to nameservers: this will send all # address->name queries for 192.168.3/24 to nameserver 10.1.2.3 #server=/3.168.192.in-addr.arpa/10.1.2.3 @@ -57,9 +62,21 @@ resolv-file=/etc/dnsmasq-resolv.conf local=/2.vmops-test.vmops.com/ # Add domains which you want to force to an IP address here. -# The example below send any host in doubleclick.net to a local -# webserver. -#address=/doubleclick.net/127.0.0.1 +# The example below send any host in double-click.net to a local +# web-server. +#address=/double-click.net/127.0.0.1 + +# --address (and --server) work with IPv6 addresses too. +#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83 + +# You can control how dnsmasq talks to a server: this forces +# queries to 10.1.2.3 to be routed via eth1 +# server=10.1.2.3@eth1 + +# and this sets the source (ie local) address used to talk to +# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that +# IP on the machine, obviously). +# server=10.1.2.3@192.168.1.1#55 # If you want dnsmasq to change uid and gid to something other # than the default, edit the following lines. @@ -80,7 +97,7 @@ except-interface=lo #listen-address= # If you want dnsmasq to provide only DNS service on an interface, # configure it as shown above, and then use the following line to -# disable DHCP on it. +# disable DHCP and TFTP on it. no-dhcp-interface=eth1 no-dhcp-interface=eth2 @@ -113,13 +130,18 @@ expand-hosts # 3) Provides the domain part for "expand-hosts" domain=2.vmops-test.vmops.com +# Set a different domain for a particular subnet +#domain=wireless.thekelleys.org.uk,192.168.2.0/24 + +# Same idea, but range rather then subnet +#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200 + # Uncomment this to enable the integrated DHCP server, you need # to supply the range of addresses available for lease and optionally # a lease time. If you have more than one network, you will need to # repeat this for each network on which you want to supply DHCP # service. dhcp-range=10.1.1.1,static -#dhcp-range=10.0.0.1,10.255.255.255 dhcp-hostsfile=/etc/dhcphosts.txt # This is an example of a DHCP range where the netmask is given. This @@ -128,17 +150,68 @@ dhcp-hostsfile=/etc/dhcphosts.txt # don't need to worry about this. #dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h -# This is an example of a DHCP range with a network-id, so that +# This is an example of a DHCP range which sets a tag, so that # some DHCP options may be set only for this network. -#dhcp-range=red,192.168.0.50,192.168.0.150 +#dhcp-range=set:red,192.168.0.50,192.168.0.150 + +# Use this DHCP range only when the tag "green" is set. +#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h + +# Specify a subnet which can't be used for dynamic address allocation, +# is available for hosts with matching --dhcp-host lines. Note that +# dhcp-host declarations will be ignored unless there is a dhcp-range +# of some type for the subnet in question. +# In this case the netmask is implied (it comes from the network +# configuration on the machine running dnsmasq) it is possible to give +# an explicit netmask instead. +#dhcp-range=192.168.0.0,static + +# Enable DHCPv6. Note that the prefix-length does not need to be specified +# and defaults to 64 if missing/ +#dhcp-range=1234::2, 1234::500, 64, 12h + +# Do Router Advertisements, BUT NOT DHCP for this subnet. +#dhcp-range=1234::, ra-only + +# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and +# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack +# hosts. Use the DHCPv4 lease to derive the name, network segment and +# MAC address and assume that the host will also have an +# IPv6 address calculated using the SLAAC alogrithm. +#dhcp-range=1234::, ra-names + +# Do Router Advertisements, BUT NOT DHCP for this subnet. +# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.) +#dhcp-range=1234::, ra-only, 48h + +# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA +# so that clients can use SLAAC addresses as well as DHCP ones. +#dhcp-range=1234::2, 1234::500, slaac + +# Do Router Advertisements and stateless DHCP for this subnet. Clients will +# not get addresses from DHCP, but they will get other configuration information. +# They will use SLAAC for addresses. +#dhcp-range=1234::, ra-stateless + +# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses +# from DHCPv4 leases. +#dhcp-range=1234::, ra-stateless, ra-names + +# Do router advertisements for all subnets where we're doing DHCPv6 +# Unless overriden by ra-stateless, ra-names, et al, the router +# advertisements will have the M and O bits set, so that the clients +# get addresses and configuration from DHCPv6, and the A bit reset, so the +# clients don't use SLAAC addresses. +#enable-ra # Supply parameters for specified hosts using DHCP. There are lots # of valid alternatives, so we will give examples of each. Note that # IP addresses DO NOT have to be in the range given above, they just # need to be on the same network. The order of the parameters in these -# do not matter, it's permissble to give name,adddress and MAC in any order +# do not matter, it's permissible to give name, address and MAC in any +# order. -# Always allocate the host with ethernet address 11:22:33:44:55:66 +# Always allocate the host with Ethernet address 11:22:33:44:55:66 # The IP address 192.168.0.60 #dhcp-host=11:22:33:44:55:66,192.168.0.60 @@ -146,11 +219,19 @@ dhcp-hostsfile=/etc/dhcphosts.txt # 11:22:33:44:55:66 to be "fred" #dhcp-host=11:22:33:44:55:66,fred -# Always give the host with ethernet address 11:22:33:44:55:66 +# Always give the host with Ethernet address 11:22:33:44:55:66 # the name fred and IP address 192.168.0.60 and lease time 45 minutes #dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m -# Give the machine which says it's name is "bert" IP address +# Give a host with Ethernet address 11:22:33:44:55:66 or +# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume +# that these two Ethernet interfaces will never be in use at the same +# time, and give the IP address to the second, even if it is already +# in use by the first. Useful for laptops with wired and wireless +# addresses. +#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60 + +# Give the machine which says its name is "bert" IP address # 192.168.0.70 and an infinite lease #dhcp-host=bert,192.168.0.70,infinite @@ -167,41 +248,47 @@ dhcp-hostsfile=/etc/dhcphosts.txt # it asks for a DHCP lease. #dhcp-host=judge -# Never offer DHCP service to a machine whose ethernet +# Never offer DHCP service to a machine whose Ethernet # address is 11:22:33:44:55:66 #dhcp-host=11:22:33:44:55:66,ignore -# Ignore any client-id presented by the machine with ethernet +# Ignore any client-id presented by the machine with Ethernet # address 11:22:33:44:55:66. This is useful to prevent a machine # being treated differently when running under different OS's or # between PXE boot and OS boot. #dhcp-host=11:22:33:44:55:66,id:* # Send extra options which are tagged as "red" to -# the machine with ethernet address 11:22:33:44:55:66 -#dhcp-host=11:22:33:44:55:66,net:red +# the machine with Ethernet address 11:22:33:44:55:66 +#dhcp-host=11:22:33:44:55:66,set:red # Send extra options which are tagged as "red" to -# any machine with ethernet address starting 11:22:33: -#dhcp-host=11:22:33:*:*:*,net:red +# any machine with Ethernet address starting 11:22:33: +#dhcp-host=11:22:33:*:*:*,set:red -# Ignore any clients which are specified in dhcp-host lines -# or /etc/ethers. Equivalent to ISC "deny unkown-clients". -# This relies on the special "known" tag which is set when +# Give a fixed IPv6 address and name to client with +# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2 +# Note the MAC addresses CANNOT be used to identify DHCPv6 clients. +# Note also the they [] around the IPv6 address are obilgatory. +#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5] + +# Ignore any clients which are not specified in dhcp-host lines +# or /etc/ethers. Equivalent to ISC "deny unknown-clients". +# This relies on the special "known" tag which is set when # a host is matched. -#dhcp-ignore=#known +#dhcp-ignore=tag:!known # Send extra options which are tagged as "red" to any machine whose # DHCP vendorclass string includes the substring "Linux" -#dhcp-vendorclass=red,Linux +#dhcp-vendorclass=set:red,Linux # Send extra options which are tagged as "red" to any machine one # of whose DHCP userclass strings includes the substring "accounts" -#dhcp-userclass=red,accounts +#dhcp-userclass=set:red,accounts # Send extra options which are tagged as "red" to any machine whose # MAC address matches the pattern. -#dhcp-mac=red,00:60:8C:*:*:* +#dhcp-mac=set:red,00:60:8C:*:*:* # If this line is uncommented, dnsmasq will read /etc/ethers and act # on the ethernet-address/IP pairs found there just as if they had @@ -211,11 +298,11 @@ dhcp-hostsfile=/etc/dhcphosts.txt # Send options to hosts which ask for a DHCP lease. # See RFC 2132 for details of available options. -# Common options can be given to dnsmasq by name: +# Common options can be given to dnsmasq by name: # run "dnsmasq --help dhcp" to get a list. # Note that all the common settings, such as netmask and # broadcast address, DNS server and default route, are given -# sane defaults by dnsmasq. You very likely will not need +# sane defaults by dnsmasq. You very likely will not need # any dhcp-options. If you use Windows clients and Samba, there # are some options which are recommended, they are detailed at the # end of this section. @@ -229,13 +316,20 @@ dhcp-hostsfile=/etc/dhcphosts.txt # Override the default route supplied by dnsmasq and send no default # route at all. Note that this only works for the options sent by -# default (1, 3, 6, 12, 28) the same line will send a zero-length option +# default (1, 3, 6, 12, 28) the same line will send a zero-length option # for all other option numbers. #dhcp-option=3 # Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5 #dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5 +# Send DHCPv6 option. Note [] around IPv6 addresses. +#dhcp-option=option6:dns-server,[1234::77],[1234::88] + +# Send DHCPv6 option for namservers as the machine running +# dnsmasq and another. +#dhcp-option=option6:dns-server,[::],[1234::88] + # Set the NTP time server address to be the same machine as # is running dnsmasq #dhcp-option=42,0.0.0.0 @@ -258,20 +352,23 @@ dhcp-option=15,"2.vmops-test.vmops.com" # Specify an option which will only be sent to the "red" network # (see dhcp-range for the declaration of the "red" network) -# Note that the net: part must precede the option: part. -#dhcp-option = net:red, option:ntp-server, 192.168.1.1 +# Note that the tag: part must precede the option: part. +#dhcp-option = tag:red, option:ntp-server, 192.168.1.1 # The following DHCP options set up dnsmasq in the same way as is specified # for the ISC dhcpcd in # http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt # adapted for a typical dnsmasq installation where the host running # dnsmasq is also the host running samba. -# you may want to uncomment them if you use Windows clients and Samba. +# you may want to uncomment some or all of them if you use +# Windows clients and Samba. #dhcp-option=19,0 # option ip-forwarding off #dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s) #dhcp-option=45,0.0.0.0 # netbios datagram distribution server #dhcp-option=46,8 # netbios node type -#dhcp-option=47 # empty netbios scope. + +# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave. +#dhcp-option=252,"\n" # Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client # probably doesn't support this...... @@ -280,10 +377,10 @@ dhcp-option=15,"2.vmops-test.vmops.com" # Send RFC-3442 classless static routes (note the netmask encoding) #dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8 -# Send vendor-class specific options encapsulated in DHCP option 43. +# Send vendor-class specific options encapsulated in DHCP option 43. # The meaning of the options is defined by the vendor-class so # options are sent only when the client supplied vendor class -# matches the class given here. (A substring match is OK, so "MSFT" +# matches the class given here. (A substring match is OK, so "MSFT" # matches "MSFT" and "MSFT 5.0"). This example sets the # mtftp address to 0.0.0.0 for PXEClients. #dhcp-option=vendor:PXEClient,1,0.0.0.0 @@ -300,7 +397,7 @@ dhcp-option=vendor:MSFT,2,1i # Send options to PXELinux. Note that we need to send the options even # though they don't appear in the parameter request list, so we need -# to use dhcp-option-force here. +# to use dhcp-option-force here. # See http://syslinux.zytor.com/pxe.php#special for details. # Magic number - needed before anything else is recognised #dhcp-option-force=208,f1:00:74:7e @@ -311,29 +408,97 @@ dhcp-option=vendor:MSFT,2,1i # Reboot time. (Note 'i' to send 32-bit value) #dhcp-option-force=211,30i -# Set the boot filename for BOOTP. You will only need +# Set the boot filename for netboot/PXE. You will only need # this is you want to boot machines over the network and you will need # a TFTP server; either dnsmasq's built in TFTP server or an # external one. (See below for how to enable the TFTP server.) #dhcp-boot=pxelinux.0 +# The same as above, but use custom tftp-server instead machine running dnsmasq +#dhcp-boot=pxelinux,server.name,192.168.1.100 + +# Boot for Etherboot gPXE. The idea is to send two different +# filenames, the first loads gPXE, and the second tells gPXE what to +# load. The dhcp-match sets the gpxe tag for requests from gPXE. +#dhcp-match=set:gpxe,175 # gPXE sends a 175 option. +#dhcp-boot=tag:!gpxe,undionly.kpxe +#dhcp-boot=mybootimage + +# Encapsulated options for Etherboot gPXE. All the options are +# encapsulated within option 175 +#dhcp-option=encap:175, 1, 5b # priority code +#dhcp-option=encap:175, 176, 1b # no-proxydhcp +#dhcp-option=encap:175, 177, string # bus-id +#dhcp-option=encap:175, 189, 1b # BIOS drive code +#dhcp-option=encap:175, 190, user # iSCSI username +#dhcp-option=encap:175, 191, pass # iSCSI password + +# Test for the architecture of a netboot client. PXE clients are +# supposed to send their architecture as option 93. (See RFC 4578) +#dhcp-match=peecees, option:client-arch, 0 #x86-32 +#dhcp-match=itanics, option:client-arch, 2 #IA64 +#dhcp-match=hammers, option:client-arch, 6 #x86-64 +#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64 + +# Do real PXE, rather than just booting a single file, this is an +# alternative to dhcp-boot. +#pxe-prompt="What system shall I netboot?" +# or with timeout before first available action is taken: +#pxe-prompt="Press F8 for menu.", 60 + +# Available boot services. for PXE. +#pxe-service=x86PC, "Boot from local disk" + +# Loads /pxelinux.0 from dnsmasq TFTP server. +#pxe-service=x86PC, "Install Linux", pxelinux + +# Loads /pxelinux.0 from TFTP server at 1.2.3.4. +# Beware this fails on old PXE ROMS. +#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4 + +# Use bootserver on network, found my multicast or broadcast. +#pxe-service=x86PC, "Install windows from RIS server", 1 + +# Use bootserver at a known IP address. +#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4 + +# If you have multicast-FTP available, +# information for that can be passed in a similar way using options 1 +# to 5. See page 19 of +# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf + + # Enable dnsmasq's built-in TFTP server #enable-tftp -# Set the root directory for files availble via FTP. +# Set the root directory for files available via FTP. #tftp-root=/var/ftpd # Make the TFTP server more secure: with this set, only files owned by # the user dnsmasq is running as will be send over the net. #tftp-secure +# This option stops dnsmasq from negotiating a larger blocksize for TFTP +# transfers. It will slow things down, but may rescue some broken TFTP +# clients. +#tftp-no-blocksize + # Set the boot file name only when the "red" tag is set. #dhcp-boot=net:red,pxelinux.red-net -# An example of dhcp-boot with an external server: the name and IP +# An example of dhcp-boot with an external TFTP server: the name and IP # address of the server are given after the filename. +# Can fail with old PXE ROMS. Overridden by --pxe-service. #dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3 +# If there are multiple external tftp servers having a same name +# (using /etc/hosts) then that name can be specified as the +# tftp_servername (the third option to dhcp-boot) and in that +# case dnsmasq resolves this name and returns the resultant IP +# addresses in round robin fasion. This facility can be used to +# load balance the tftp load among a set of servers. +#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name + # Set the limit on DHCP leases, the default is 150 #dhcp-lease-max=150 @@ -347,16 +512,16 @@ leasefile-ro # and take over the lease for any client which broadcasts on the network, # whether it has a record of the lease or not. This avoids long timeouts # when a machine wakes up on a new network. DO NOT enable this if there's -# the slighest chance that you might end up accidentally configuring a DHCP +# the slightest chance that you might end up accidentally configuring a DHCP # server for your campus/company accidentally. The ISC server uses # the same option, and this URL provides more information: -# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php +# http://www.isc.org/files/auth.html #dhcp-authoritative # Run an executable when a DHCP lease is created or destroyed. -# The arguments sent to the script are "add" or "del", +# The arguments sent to the script are "add" or "del", # then the MAC address, the IP address and finally the hostname -# if there is one. +# if there is one. #dhcp-script=/bin/echo # Set the cachesize here. @@ -385,7 +550,8 @@ leasefile-ro #alias=1.2.3.4,5.6.7.8 # and this maps 1.2.3.x to 5.6.7.x #alias=1.2.3.0,5.6.7.0,255.255.255.0 - +# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40 +#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0 # Change these lines if you want dnsmasq to serve MX records. @@ -415,12 +581,12 @@ leasefile-ro # set for this to work.) # A SRV record sending LDAP for the example.com domain to -# ldapserver.example.com port 289 +# ldapserver.example.com port 389 #srv-host=_ldap._tcp.example.com,ldapserver.example.com,389 # A SRV record sending LDAP for the example.com domain to -# ldapserver.example.com port 289 (using domain=) -###domain=example.com +# ldapserver.example.com port 389 (using domain=) +#domain=example.com #srv-host=_ldap._tcp,ldapserver.example.com,389 # Two SRV records for LDAP, each with different priorities @@ -448,6 +614,10 @@ leasefile-ro #Example zeroconf #txt-record=_http._tcp.example.com,name=value,paper=A4 +# Provide an alias for a "local" DNS name. Note that this _only_ works +# for targets which are names from DHCP or /etc/hosts. Give host +# "bert" another name, bertrand +#cname=bertand,bert # For debugging purposes, log each DNS query as it passes through # dnsmasq. @@ -461,6 +631,3 @@ log-facility=/var/log/dnsmasq.log # Include a another lot of configuration options. #conf-file=/etc/dnsmasq.more.conf conf-dir=/etc/dnsmasq.d - -# Don't reply Windows's periodical DNS request -filterwin2k From 8f66d266b3c7ec5aae4afa18cb619684a06fa925 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 24 Jan 2013 20:09:37 -0800 Subject: [PATCH 05/26] IPv6: Enable VR's ability to provide DHCPv6 service --- .../VirtualRoutingResource.java | 9 ++- .../systemvm/debian/config/etc/dnsmasq.conf | 3 +- .../config/etc/init.d/cloud-early-config | 29 ++++++-- .../systemvm/debian/config/root/edithosts.sh | 71 ++++++++++++++++--- .../vmware/resource/VmwareResource.java | 11 ++- .../xen/resource/CitrixResourceBase.java | 9 ++- scripts/network/domr/dhcp_entry.sh | 12 +++- 7 files changed, 120 insertions(+), 24 deletions(-) diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index 18a0426e2fa..b30fcbf2004 100755 --- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -569,7 +569,9 @@ public class VirtualRoutingResource implements Manager { protected synchronized Answer execute (final DhcpEntryCommand cmd) { final Script command = new Script(_dhcpEntryPath, _timeout, s_logger); command.add("-r", cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP)); - command.add("-v", cmd.getVmIpAddress()); + if (cmd.getVmIpAddress() != null) { + command.add("-v", cmd.getVmIpAddress()); + } command.add("-m", cmd.getVmMac()); command.add("-n", cmd.getVmName()); @@ -583,6 +585,11 @@ public class VirtualRoutingResource implements Manager { if (cmd.getDefaultDns() != null) { command.add("-N", cmd.getDefaultDns()); } + + if (cmd.getVmIp6Address() != null) { + command.add("-6", cmd.getVmIp6Address()); + command.add("-u", cmd.getDuid()); + } final String result = command.execute(); return new Answer(cmd, result==null, result); diff --git a/patches/systemvm/debian/config/etc/dnsmasq.conf b/patches/systemvm/debian/config/etc/dnsmasq.conf index c01e7549d63..7d656cb2b77 100644 --- a/patches/systemvm/debian/config/etc/dnsmasq.conf +++ b/patches/systemvm/debian/config/etc/dnsmasq.conf @@ -141,7 +141,8 @@ domain=2.vmops-test.vmops.com # a lease time. If you have more than one network, you will need to # repeat this for each network on which you want to supply DHCP # service. -dhcp-range=10.1.1.1,static +dhcp-range_ip4=10.1.1.1,static +dhcp-range_ip6=::1,static dhcp-hostsfile=/etc/dhcphosts.txt # This is an example of a DHCP range where the netmask is given. This diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index 74b963b182c..ebe2fa4ab5b 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -398,7 +398,8 @@ setup_common() { setup_dnsmasq() { log_it "Setting up dnsmasq" - [ -z $DHCP_RANGE ] && DHCP_RANGE=$ETH0_IP + [ -z $DHCP_RANGE ] && [ $ETH0_IP ] && DHCP_RANGE=$ETH0_IP + [ $ETH0_IP6 ] && DHCP_RANGE_IP6=$ETH0_IP6 [ -z $DOMAIN ] && DOMAIN="cloudnine.internal" if [ -n "$DOMAIN" ] @@ -422,8 +423,20 @@ setup_dnsmasq() { sed -i s/[#]*dhcp-option=15.*$/dhcp-option=15,\""$DNS_SEARCH_ORDER"\"/ /etc/dnsmasq.conf fi - sed -i -e "s/^dhcp-range=.*$/dhcp-range=$DHCP_RANGE,static/" /etc/dnsmasq.conf - sed -i -e "s/^[#]*listen-address=.*$/listen-address=$ETH0_IP/" /etc/dnsmasq.conf + if [ $DHCP_RANGE ] + then + sed -i -e "s/^dhcp-range_ip4=.*$/dhcp-range=$DHCP_RANGE,static/" /etc/dnsmasq.conf + else + sed -i -e "s/^dhcp-range_ip4=.*$//" /etc/dnsmasq.conf + fi + if [ $DHCP_RANGE_IP6 ] + then + sed -i -e "s/^dhcp-range_ip6=.*$/dhcp-range=$DHCP_RANGE_IP6,static/" /etc/dnsmasq.conf + else + sed -i -e "s/^dhcp-range_ip6=.*$//" /etc/dnsmasq.conf + fi + + sed -i -e "s/^[#]*listen-address=.*$/listen-address=$LOCAL_ADDRS/" /etc/dnsmasq.conf if [ "$RROUTER" == "1" ] then @@ -707,14 +720,15 @@ setup_dhcpsrvr() { if [ "$DEFAULTROUTE" != "false" ] then sed -i -e "/^[#]*dhcp-option=option:router.*$/d" /etc/dnsmasq.conf - echo "dhcp-option=option:router,$GW" >> /etc/dnsmasq.conf + [ $GW ] && echo "dhcp-option=option:router,$GW" >> /etc/dnsmasq.conf #for now set up ourself as the dns server as well sed -i -e "/^[#]*dhcp-option=6.*$/d" /etc/dnsmasq.conf if [ "$USE_EXTERNAL_DNS" == "true" ] then echo "dhcp-option=6,$NS" >> /etc/dnsmasq.conf else - echo "dhcp-option=6,$ETH0_IP,$NS" >> /etc/dnsmasq.conf + [ $ETH0_IP ] && echo "dhcp-option=6,$ETH0_IP,$NS" >> /etc/dnsmasq.conf + [ $ETH0_IP6 ] && echo "dhcp-option=option6:dns-server,[::]" >> /etc/dnsmasq.conf fi else sed -i -e "/^[#]*dhcp-option=option:router.*$/d" /etc/dnsmasq.conf @@ -1034,8 +1048,11 @@ for i in $CMDLINE ;; esac done -} +[ $ETH0_IP ] && LOCAL_ADDRS=$ETH0_IP +[ $ETH0_IP6 ] && LOCAL_ADDRS=$ETH0_IP6 +[ $ETH0_IP ] && [ $ETH0_IP6 ] && LOCAL_ADDRS="$ETH0_IP,$ETH0_IP6" +} case "$1" in start) diff --git a/patches/systemvm/debian/config/root/edithosts.sh b/patches/systemvm/debian/config/root/edithosts.sh index acc421b8a67..3cf27427653 100755 --- a/patches/systemvm/debian/config/root/edithosts.sh +++ b/patches/systemvm/debian/config/root/edithosts.sh @@ -27,23 +27,29 @@ # $6 : comma separated static routes usage() { - printf "Usage: %s: -m -4 -h -d -n -s \n" $(basename $0) >&2 + printf "Usage: %s: -m -4 -6 -h -d -n -s -u \n" $(basename $0) >&2 } mac= ipv4= +ipv6= host= dflt= dns= routes= +duid= -while getopts 'm:4:h:d:n:s:' OPTION +while getopts 'm:4:h:d:n:s:6:u:' OPTION do case $OPTION in m) mac="$OPTARG" ;; 4) ipv4="$OPTARG" ;; + 6) ipv6="$OPTARG" + ;; + u) duid="$OPTARG" + ;; h) host="$OPTARG" ;; d) dflt="$OPTARG" @@ -95,26 +101,69 @@ logger -t cloud "edithosts: update $1 $2 $3 to hosts" [ ! -f $DHCP_LEASES ] && touch $DHCP_LEASES #delete any previous entries from the dhcp hosts file -sed -i /$mac/d $DHCP_HOSTS -sed -i /$ipv4,/d $DHCP_HOSTS -sed -i /$host,/d $DHCP_HOSTS +sed -i /$mac/d $DHCP_HOSTS +if [ $ipv4 ] +then + sed -i /$ipv4,/d $DHCP_HOSTS +fi +if [ $ipv6 ] +then + sed -i /$ipv6,/d $DHCP_HOSTS +fi +sed -i /$host,/d $DHCP_HOSTS #put in the new entry -echo "$mac,$ipv4,$host,infinite" >>$DHCP_HOSTS +if [ $ipv4 ] +then + echo "$mac,$ipv4,$host,infinite" >>$DHCP_HOSTS +fi +if [ $ipv6 ] +then + echo "id:$duid,[$ipv6],$host,infinite" >>$DHCP_HOSTS +fi #delete leases to supplied mac and ip addresses -sed -i /$mac/d $DHCP_LEASES -sed -i /"$ipv4 "/d $DHCP_LEASES +if [ $ipv4 ] +then + sed -i /$mac/d $DHCP_LEASES + sed -i /"$ipv4 "/d $DHCP_LEASES +fi +if [ $ipv6 ] +then + sed -i /$duid/d $DHCP_LEASES + sed -i /"$ipv6 "/d $DHCP_LEASES +fi sed -i /"$host "/d $DHCP_LEASES #put in the new entry -echo "0 $mac $ipv4 $host *" >> $DHCP_LEASES +if [ $ipv4 ] +then + echo "0 $mac $ipv4 $host *" >> $DHCP_LEASES +fi +if [ $ipv6 ] +then + echo "0 $duid $ipv6 $host *" >> $DHCP_LEASES +fi #edit hosts file as well -sed -i /"$ipv4 "/d $HOSTS +if [ $ipv4 ] +then + sed -i /"$ipv4 "/d $HOSTS +fi +if [ $ipv6 ] +then + sed -i /"$ipv6 "/d $HOSTS +fi sed -i /" $host$"/d $HOSTS -echo "$ipv4 $host" >> $HOSTS +if [ $ipv4 ] +then + echo "$ipv4 $host" >> $HOSTS +fi +if [ $ipv6 ] +then + echo "$ipv6 $host" >> $HOSTS +fi if [ "$dflt" != "" ] then diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 0ca25a888af..37bff2a4b71 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1630,7 +1630,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domr "/root/edithosts.sh $mac $ip $vm $dfltrt $ns $staticrt" >/dev/null String args = " -m " + cmd.getVmMac(); - args += " -4 " + cmd.getVmIpAddress(); + if (cmd.getVmIpAddress() != null) { + args += " -4 " + cmd.getVmIpAddress(); + } args += " -h " + cmd.getVmName(); if (cmd.getDefaultRouter() != null) { @@ -1642,7 +1644,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } if (cmd.getStaticRoutes() != null) { - args += " -s " + cmd.getStaticRoutes(); + args += " -s " + cmd.getStaticRoutes(); + } + + if (cmd.getVmIp6Address() != null) { + args += " -6 " + cmd.getVmIp6Address(); + args += " -u " + cmd.getDuid(); } if (s_logger.isDebugEnabled()) { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 065d3be0bdd..34703528a71 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1750,7 +1750,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe protected synchronized Answer execute(final DhcpEntryCommand cmd) { Connection conn = getConnection(); String args = "-r " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); - args += " -v " + cmd.getVmIpAddress(); + if (cmd.getVmIpAddress() != null) { + args += " -v " + cmd.getVmIpAddress(); + } args += " -m " + cmd.getVmMac(); args += " -n " + cmd.getVmName(); if (cmd.getDefaultRouter() != null) { @@ -1764,6 +1766,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe args += " -N " + cmd.getDefaultDns(); } + if (cmd.getVmIp6Address() != null) { + args += " -6 " + cmd.getVmIp6Address(); + args += " -u " + cmd.getDuid(); + } + String result = callHostPlugin(conn, "vmops", "saveDhcpEntry", "args", args); if (result == null || result.isEmpty()) { return new Answer(cmd, false, "DhcpEntry failed"); diff --git a/scripts/network/domr/dhcp_entry.sh b/scripts/network/domr/dhcp_entry.sh index b964eb4c292..e417f7273a2 100755 --- a/scripts/network/domr/dhcp_entry.sh +++ b/scripts/network/domr/dhcp_entry.sh @@ -22,7 +22,7 @@ # @VERSION@ usage() { - printf "Usage: %s: -r -m -v -n -s -d -N \n" $(basename $0) >&2 + printf "Usage: %s: -r -m -v -n -s -d -N -6 -u \n" $(basename $0) >&2 exit 2 } @@ -35,10 +35,12 @@ vmName= staticrt= dfltrt= dns= +ipv6= +duid= opts= -while getopts 'r:m:v:n:d:s:N:' OPTION +while getopts 'r:m:v:n:d:s:N:6:u:' OPTION do case $OPTION in r) domrIp="$OPTARG" @@ -61,6 +63,12 @@ do N) dns="$OPTARG" opts="$opts -n $dns" ;; + 6) ipv6="$OPTARG" + opts="$opts -6 $ipv6" + ;; + u) duid="$OPTARG" + opts="$opts -u $duid" + ;; ?) usage exit 1 ;; From 74811fa8b4f2f422a74c291ad2f3a63df52ee992 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 25 Jan 2013 15:41:58 -0800 Subject: [PATCH 06/26] IPv6: Disable password and userdata service for ipv6 for now Would add support later. --- .../src/com/cloud/network/element/VirtualRouterElement.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 2b54ae0fe36..49e726a8183 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -821,6 +821,11 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl if (vm.getType() != VirtualMachine.Type.User) { return false; } + + if (network.getIp6Gateway() != null) { + s_logger.info("Skip password and userdata service setup for IPv6 VM"); + return true; + } @SuppressWarnings("unchecked") VirtualMachineProfile uservm = (VirtualMachineProfile) vm; From fa00ddf07ed7ddffb1a14c2623616a959dc2ad4e Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Sun, 27 Jan 2013 13:53:51 -0800 Subject: [PATCH 07/26] IPv6: Fix getIp6FromRange() --- .../com/cloud/network/NetworkServiceImpl.java | 2 +- utils/src/com/cloud/utils/net/NetUtils.java | 9 ++++++--- utils/test/com/cloud/utils/net/NetUtilsTest.java | 16 +++++++++++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 20319ffe7d4..df44ce0ea27 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -806,7 +806,7 @@ public class NetworkServiceImpl implements NetworkService, Manager { int cidrSize = NetUtils.getIp6CidrSize(ip6Cidr); // Ipv6 cidr limit should be at least /64 if (cidrSize < 64) { - throw new InvalidParameterValueException("The cidr size of IPv6 must be bigger than 64 bits!"); + throw new InvalidParameterValueException("The cidr size of IPv6 network must be no less than 64 bits!"); } } diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 8bfd3769029..b81aff681d8 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -1178,12 +1178,15 @@ public class NetUtils { public static String getIp6FromRange(String ip6Range) { String[] ips = ip6Range.split("-"); String startIp = ips[0]; - long gap = countIp6InRange(ip6Range); IPv6Address start = IPv6Address.fromString(startIp); // Find a random number based on lower 32 bits - int d = _rand.nextInt((int)(gap % Integer.MAX_VALUE)); + long gap = countIp6InRange(ip6Range); + if (gap > Integer.MAX_VALUE) { + gap = Integer.MAX_VALUE; + } + int next = _rand.nextInt((int)(gap)); // And a number based on the difference of lower 32 bits - IPv6Address ip = start.add(d); + IPv6Address ip = start.add(next); return ip.toString(); } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 6290cd6390d..9beb6ca8bf1 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -16,16 +16,20 @@ // under the License. package com.cloud.utils.net; -import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import junit.framework.TestCase; +import org.apache.log4j.Logger; import org.junit.Test; +import com.googlecode.ipv6.IPv6Address; + public class NetUtilsTest extends TestCase { + private static final Logger s_logger = Logger.getLogger(NetUtilsTest.class); + @Test public void testGetRandomIpFromCidr() { String cidr = "192.168.124.1"; @@ -82,5 +86,15 @@ public class NetUtilsTest extends TestCase { assertEquals(NetUtils.countIp6InRange("1234:5678::1-1234:5678::2"), 2); assertEquals(NetUtils.countIp6InRange("1234:5678::2-1234:5678::0"), 0); assertEquals(NetUtils.getIp6FromRange("1234:5678::1-1234:5678::1"), "1234:5678::1"); + String ipString = null; + IPv6Address ipStart = IPv6Address.fromString("1234:5678::1"); + IPv6Address ipEnd = IPv6Address.fromString("1234:5678::8000:0000"); + for (int i = 0; i < 10; i ++) { + ipString = NetUtils.getIp6FromRange(ipStart.toString() + "-" + ipEnd.toString()); + s_logger.info("IP is " + ipString); + IPv6Address ip = IPv6Address.fromString(ipString); + assertTrue(ip.compareTo(ipStart) >= 0); + assertTrue(ip.compareTo(ipEnd) <= 0); + } } } From 9a95495f87044714c795feaa9d1d744e759ba873 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 28 Jan 2013 15:43:37 -0800 Subject: [PATCH 08/26] DeployVMCmd: Remove entityType for ipToNetworkList, MAP is string->string Remove entityType as it can confuse people, right now we process map to string data type maps This map should be handled in cmd class level by an api writer to getObject by uuid or by long int id as in getIpToNetworkMap() of DeployVMCmd Signed-off-by: Rohit Yadav --- .../org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 9d39f692eaf..a019511537f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -147,7 +147,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { private List securityGroupNameList; @ACL(checkKeyAccess=true) - @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, entityType={Network.class, IpAddress.class}, + @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter." + " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") private Map ipToNetworkList; From 5b92c57b2c3a7852fdc5e3c6e2a7e4b4bc701372 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 28 Jan 2013 16:10:12 -0800 Subject: [PATCH 09/26] DeployVMCmd: Remove @ACL on ipToNetwork map to avoid NPE Signed-off-by: Rohit Yadav --- .../org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index a019511537f..5300e3cefc8 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -146,7 +146,6 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { "Mutually exclusive with securitygroupids parameter") private List securityGroupNameList; - @ACL(checkKeyAccess=true) @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter." + " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") From 2cbca372bf3f9231fc8f82b88a896a71caea0ef3 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Sun, 27 Jan 2013 20:10:39 -0800 Subject: [PATCH 10/26] IPv6: Add support for IPv6 on DeployVMCmd --- api/src/com/cloud/network/Network.java | 26 ++++++++++++++ api/src/com/cloud/vm/UserVmService.java | 14 ++++---- .../apache/cloudstack/api/ApiConstants.java | 1 + .../api/command/user/vm/DeployVMCmd.java | 27 +++++++++------ .../src/com/cloud/network/NetworkManager.java | 2 +- .../com/cloud/network/NetworkManagerImpl.java | 33 ++++++++++++++---- .../cloud/network/PublicIpv6AddressVO.java | 1 - .../src/com/cloud/vm/UserVmManagerImpl.java | 34 +++++++++++-------- .../com/cloud/vm/MockUserVmManagerImpl.java | 9 ++--- utils/src/com/cloud/utils/net/NetUtils.java | 16 +++++++++ 10 files changed, 120 insertions(+), 43 deletions(-) diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 29ba9f33c44..50197953098 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -252,7 +252,33 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Implemented); } } + + public class IpAddresses { + private String ip4Address; + private String ip6Address; + + public IpAddresses(String ip4Address, String ip6Address) { + this.setIp4Address(ip4Address); + this.setIp6Address(ip6Address); + } + public String getIp4Address() { + return ip4Address; + } + + public void setIp4Address(String ip4Address) { + this.ip4Address = ip4Address; + } + + public String getIp6Address() { + return ip6Address; + } + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + } + String getName(); Mode getMode(); diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index b1ebe10596d..e1a4143ce2f 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -46,6 +46,7 @@ import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.VirtualMachineMigrationException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network.IpAddresses; import com.cloud.offering.ServiceOffering; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -197,7 +198,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -244,7 +245,7 @@ public interface UserVmService { * - name of the ssh key pair used to login to the virtual machine * @param requestedIps * TODO - * @param defaultIp + * @param defaultIps * TODO * @param accountName * - an optional account for the virtual machine. Must be used with domainId @@ -262,8 +263,8 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, - Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, - String defaultIp, String keyboard) + Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, + IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -308,8 +309,7 @@ public interface UserVmService { * - name of the ssh key pair used to login to the virtual machine * @param requestedIps * TODO - * @param defaultIp - * TODO + * @param defaultIps TODO * @param accountName * - an optional account for the virtual machine. Must be used with domainId * @param domainId @@ -326,7 +326,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1787f210d4f..80e382cc366 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -93,6 +93,7 @@ public class ApiConstants { public static final String INTERNAL_DNS2 = "internaldns2"; public static final String INTERVAL_TYPE = "intervaltype"; public static final String IP_ADDRESS = "ipaddress"; + public static final String IP6_ADDRESS = "ip6address"; public static final String IP_ADDRESS_ID = "ipaddressid"; public static final String IS_ASYNC = "isasync"; public static final String IP_AVAILABLE = "ipavailable"; diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 5300e3cefc8..b3eaed8fddb 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -51,6 +51,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.Network.IpAddresses; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; import com.cloud.template.VirtualMachineTemplate; @@ -148,12 +149,15 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter." + - " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") + " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") private Map ipToNetworkList; @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="the ip address for default vm's network") private String ipAddress; + @Parameter(name=ApiConstants.IP6_ADDRESS, type=CommandType.STRING, description="the ipv6 address for default vm's network") + private String ip6Address; + @Parameter(name=ApiConstants.KEYBOARD, type=CommandType.STRING, description="an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us") private String keyboard; @@ -244,7 +248,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { public List getNetworkIds() { if (ipToNetworkList != null) { - if (networkIds != null || ipAddress != null) { + if (networkIds != null || ipAddress != null || ip6Address != null) { throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress"); } else { List networks = new ArrayList(); @@ -271,13 +275,13 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { return startVm == null ? true : startVm; } - private Map getIpToNetworkMap() { - if ((networkIds != null || ipAddress != null) && ipToNetworkList != null) { + private Map getIpToNetworkMap() { + if ((networkIds != null || ipAddress != null || ip6Address != null) && ipToNetworkList != null) { throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"); } - LinkedHashMap ipToNetworkMap = null; + LinkedHashMap ipToNetworkMap = null; if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) { - ipToNetworkMap = new LinkedHashMap(); + ipToNetworkMap = new LinkedHashMap(); Collection ipsCollection = ipToNetworkList.values(); Iterator iter = ipsCollection.iterator(); while (iter.hasNext()) { @@ -294,7 +298,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } } String requestedIp = (String) ips.get("ip"); - ipToNetworkMap.put(networkId, requestedIp); + String requestedIpv6 = (String) ips.get("ipv6"); + IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6); + ipToNetworkMap.put(networkId, addrs); } } @@ -428,23 +434,24 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { if (getHypervisor() == HypervisorType.BareMetal) { vm = _bareMetalVmService.createVirtualMachine(this); } else { + IpAddresses addrs = new IpAddresses(ipAddress, ip6Address); if (zone.getNetworkType() == NetworkType.Basic) { if (getNetworkIds() != null) { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); } else { vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } else { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); } vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, - diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 7228a8322e9..71ad72abd6a 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -329,6 +329,6 @@ public interface NetworkManager { LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, - VlanType type, Long networkId, String requestedIp, boolean isSystem) + VlanType type, Long networkId, String requestedIp6, boolean isSystem) throws InsufficientAddressCapacityException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 705e5f2d6a6..cea935e8633 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -298,17 +298,38 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { } @Override - public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) throws InsufficientAddressCapacityException { + public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp6, boolean isSystem) throws InsufficientAddressCapacityException { Vlan vlan = _networkModel.getVlanForNetwork(networkId); if (vlan == null) { s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); return null; } - String ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); - //Check for duplicate IP - if (_ipv6Dao.findByDcIdAndIp(dcId, ip) != null) { - //TODO regenerate ip - throw new CloudRuntimeException("Fail to get unique ipv6 address"); + //TODO should check before this point + if (!NetUtils.isIp6InRange(requestedIp6, vlan.getIp6Range())) { + throw new CloudRuntimeException("Requested IPv6 is not in the predefined range!"); + } + String ip = null; + if (requestedIp6 == null) { + int count = 0; + while (ip == null || count >= 10) { + ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); + //Check for duplicate IP + if (_ipv6Dao.findByDcIdAndIp(dcId, ip) == null) { + break; + } else { + ip = null; + } + count ++; + } + if (ip == null) { + throw new CloudRuntimeException("Fail to get unique ipv6 address after 10 times trying!"); + } + } else { + ip = requestedIp6; + //TODO should check before this point + if (_ipv6Dao.findByDcIdAndIp(dcId, ip) != null) { + throw new CloudRuntimeException("The requested IP is already taken!"); + } } DataCenterVO dc = _dcDao.findById(dcId); Long mac = dc.getMacAddress(); diff --git a/server/src/com/cloud/network/PublicIpv6AddressVO.java b/server/src/com/cloud/network/PublicIpv6AddressVO.java index 7594fc16d2e..e5d00a1b1d7 100644 --- a/server/src/com/cloud/network/PublicIpv6AddressVO.java +++ b/server/src/com/cloud/network/PublicIpv6AddressVO.java @@ -39,7 +39,6 @@ public class PublicIpv6AddressVO implements PublicIpv6Address { @Column(name="id") long id; - @Id @Column(name="ip_address") @Enumerated(value=EnumType.STRING) private String address = null; diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 870eeccd3ca..491f8a2c691 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -59,6 +59,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.network.*; +import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; @@ -1994,7 +1995,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, - String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2037,13 +2038,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); } @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, - String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2142,12 +2143,12 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); } @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2228,12 +2229,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } } - return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIp, keyboard); + return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); } @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, - Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, String defaultNetworkIp, String keyboard) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { + Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, String keyboard) + throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -2243,7 +2245,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager long accountId = owner.getId(); - assert !(requestedIps != null && defaultNetworkIp != null) : "requestedIp list and defaultNetworkIp should never be specified together"; + assert !(requestedIps != null && (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null)) : "requestedIp list and defaultNetworkIp should never be specified together"; if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getId()); @@ -2367,18 +2369,22 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new InvalidParameterValueException("Network id=" + network.getId() + " doesn't belong to zone " + zone.getId()); } - String requestedIp = null; + IpAddresses requestedIpPair = null; if (requestedIps != null && !requestedIps.isEmpty()) { - requestedIp = requestedIps.get(network.getId()); + requestedIpPair = requestedIps.get(network.getId()); } - - NicProfile profile = new NicProfile(requestedIp, null); + + if (requestedIpPair == null) { + requestedIpPair = new IpAddresses(null, null); + } + + NicProfile profile = new NicProfile(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); if (defaultNetworkNumber == 0) { defaultNetworkNumber++; // if user requested specific ip for default network, add it - if (defaultNetworkIp != null) { - profile = new NicProfile(defaultNetworkIp, null); + if (defaultIps.getIp4Address() != null || defaultIps.getIp4Address() != null) { + profile = new NicProfile(defaultIps.getIp4Address(), defaultIps.getIp6Address()); } profile.setDefaultNic(true); diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 27508b14c5b..83fd1f0c8fe 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.exception.VirtualMachineMigrationException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network; +import com.cloud.network.Network.IpAddresses; import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.server.Criteria; @@ -351,8 +352,8 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, - String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, - String defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, + IpAddresses defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -361,7 +362,7 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, - String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, + String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -369,7 +370,7 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index b81aff681d8..e3bf7075daf 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -1217,4 +1217,20 @@ public class NetUtils { } return endLow - startLow + 1; } + + public static boolean isIp6InRange(String ip6, String ip6Range) { + String[] ips = ip6Range.split("-"); + String startIp = ips[0]; + String endIp = null; + if (ips.length > 1) { + endIp = ips[1]; + } + IPv6Address start = IPv6Address.fromString(startIp); + IPv6Address end = IPv6Address.fromString(endIp); + IPv6Address ip = IPv6Address.fromString(ip6); + if (start.compareTo(ip) <= 0 && end.compareTo(ip) >= 0) { + return true; + } + return false; + } } From 1f2147d3ec4760c7aafb13f1107ece8d0f448f8b Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Mon, 28 Jan 2013 21:21:30 -0700 Subject: [PATCH 11/26] Summary: Account for embedded nics (e.g. 'em0') when looking for physical nic Signed-off-by: Marcus Sorensen --- .../cloud/hypervisor/kvm/resource/LibvirtComputingResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 8a9f71bf7d5..2ed8478a67d 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -903,7 +903,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements String fname = interfaces[i].getName(); s_logger.debug("matchPifFileInDirectory: file name '"+fname+"'"); if (fname.startsWith("eth") || fname.startsWith("bond") - || fname.startsWith("vlan")) { + || fname.startsWith("vlan") || fname.startsWith("em")) { return fname; } } From cb9f2d018d3abb5a17a244a1071706592f75cdfc Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 18:02:32 -0800 Subject: [PATCH 12/26] IPv6: move assignPublicIp6Address() from NetworkManager to new Ipv6AddressManager Don't want to involve IP address management code in NetworkManager. --- .../DefaultComponentLibrary.java | 2 + .../com/cloud/network/Ipv6AddressManager.java | 28 ++++ .../cloud/network/Ipv6AddressManagerImpl.java | 132 ++++++++++++++++++ .../src/com/cloud/network/NetworkManager.java | 4 - .../com/cloud/network/NetworkManagerImpl.java | 55 +------- .../network/dao/PublicIpv6AddressDao.java | 2 +- .../network/dao/PublicIpv6AddressDaoImpl.java | 4 +- .../cloud/network/guru/DirectNetworkGuru.java | 8 +- .../cloud/network/MockNetworkManagerImpl.java | 8 -- .../com/cloud/vpc/MockNetworkManagerImpl.java | 8 -- 10 files changed, 172 insertions(+), 79 deletions(-) create mode 100644 server/src/com/cloud/network/Ipv6AddressManager.java create mode 100644 server/src/com/cloud/network/Ipv6AddressManagerImpl.java diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index e2e800b2257..e8fcabec555 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -91,6 +91,7 @@ import com.cloud.keystore.KeystoreManagerImpl; import com.cloud.maint.UpgradeManagerImpl; import com.cloud.maint.dao.AgentUpgradeDaoImpl; import com.cloud.network.ExternalLoadBalancerUsageManagerImpl; +import com.cloud.network.Ipv6AddressManagerImpl; import com.cloud.network.NetworkManagerImpl; import com.cloud.network.NetworkModelImpl; import com.cloud.network.NetworkServiceImpl; @@ -464,6 +465,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addManager("TaggedResourcesManager", TaggedResourceManagerImpl.class); addManager("Site2SiteVpnManager", Site2SiteVpnManagerImpl.class); addManager("QueryManager", QueryManagerImpl.class); + addManager("Ipv6AddressManager", Ipv6AddressManagerImpl.class); } @Override diff --git a/server/src/com/cloud/network/Ipv6AddressManager.java b/server/src/com/cloud/network/Ipv6AddressManager.java new file mode 100644 index 00000000000..21c65a926df --- /dev/null +++ b/server/src/com/cloud/network/Ipv6AddressManager.java @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.user.Account; +import com.cloud.utils.component.Manager; + +public interface Ipv6AddressManager extends Manager { + public PublicIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException; + + public void revokeDirectIpv6Address(long networkId, String ip6Address); +} diff --git a/server/src/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java new file mode 100644 index 00000000000..d794ff7e57f --- /dev/null +++ b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java @@ -0,0 +1,132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.network.dao.PublicIpv6AddressDao; +import com.cloud.user.Account; +import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; + +@Local(value = { Ipv6AddressManager.class } ) +public class Ipv6AddressManagerImpl implements Ipv6AddressManager { + public static final Logger s_logger = Logger.getLogger(Ipv6AddressManagerImpl.class.getName()); + + String _name = null; + + @Inject + DataCenterDao _dcDao; + @Inject + VlanDao _vlanDao; + @Inject + NetworkModel _networkModel; + @Inject + PublicIpv6AddressDao _ipv6Dao; + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + @Override + public PublicIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) + throws InsufficientAddressCapacityException { + Vlan vlan = _networkModel.getVlanForNetwork(networkId); + if (vlan == null) { + s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); + return null; + } + String ip = null; + if (requestedIp6 == null) { + int count = 0; + while (ip == null || count >= 10) { + ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); + //Check for duplicate IP + if (_ipv6Dao.findByNetworkIdAndIp(networkId, ip) == null) { + break; + } else { + ip = null; + } + count ++; + } + if (ip == null) { + throw new CloudRuntimeException("Fail to get unique ipv6 address after 10 times trying!"); + } + } else { + if (!NetUtils.isIp6InRange(requestedIp6, vlan.getIp6Range())) { + 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)); + PublicIpv6AddressVO ipVO = new PublicIpv6AddressVO(ip, dcId, macAddress, vlan.getId()); + ipVO.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); + ipVO.setSourceNetworkId(vlan.getNetworkId()); + ipVO.setState(PublicIpv6Address.State.Allocated); + ipVO.setDomainId(owner.getDomainId()); + ipVO.setAccountId(owner.getAccountId()); + _ipv6Dao.persist(ipVO); + return ipVO; + } + + @Override + public void revokeDirectIpv6Address(long networkId, String ip6Address) { + PublicIpv6AddressVO ip = _ipv6Dao.findByNetworkIdAndIp(networkId, ip6Address); + if (ip != null) { + _ipv6Dao.remove(ip.getId()); + } + } +} diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 71ad72abd6a..149d13437cf 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -327,8 +327,4 @@ public interface NetworkManager { int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); - - PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, - VlanType type, Long networkId, String requestedIp6, boolean isSystem) - throws InsufficientAddressCapacityException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index cea935e8633..e06a59b95a4 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -276,6 +276,8 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { NetworkModel _networkModel; @Inject PublicIpv6AddressDao _ipv6Dao; + @Inject + Ipv6AddressManager _ipv6Mgr; ScheduledExecutorService _executor; @@ -297,57 +299,6 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null); } - @Override - public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp6, boolean isSystem) throws InsufficientAddressCapacityException { - Vlan vlan = _networkModel.getVlanForNetwork(networkId); - if (vlan == null) { - s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); - return null; - } - //TODO should check before this point - if (!NetUtils.isIp6InRange(requestedIp6, vlan.getIp6Range())) { - throw new CloudRuntimeException("Requested IPv6 is not in the predefined range!"); - } - String ip = null; - if (requestedIp6 == null) { - int count = 0; - while (ip == null || count >= 10) { - ip = NetUtils.getIp6FromRange(vlan.getIp6Range()); - //Check for duplicate IP - if (_ipv6Dao.findByDcIdAndIp(dcId, ip) == null) { - break; - } else { - ip = null; - } - count ++; - } - if (ip == null) { - throw new CloudRuntimeException("Fail to get unique ipv6 address after 10 times trying!"); - } - } else { - ip = requestedIp6; - //TODO should check before this point - if (_ipv6Dao.findByDcIdAndIp(dcId, 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)); - PublicIpv6AddressVO ipVO = new PublicIpv6AddressVO(ip, dcId, macAddress, vlan.getId()); - ipVO.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); - ipVO.setSourceNetworkId(vlan.getNetworkId()); - ipVO.setState(PublicIpv6Address.State.Allocated); - ipVO.setDomainId(owner.getDomainId()); - ipVO.setAccountId(owner.getAccountId()); - _ipv6Dao.persist(ipVO); - return ipVO; - } - @DB public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long guestNetworkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem, Long vpcId) @@ -3411,7 +3362,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { if (network.getIp6Gateway() != null) { if (nic.getIp6Address() == null) { ipv6 = true; - PublicIpv6Address ip = assignPublicIp6Address(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv6, false); + PublicIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); Vlan vlan = _networkModel.getVlanForNetwork(network.getId()); if (vlan == null) { s_logger.debug("Cannot find related vlan or too many vlan attached to network " + network.getId()); diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java b/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java index b8de08a9926..c347052bc82 100644 --- a/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java +++ b/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java @@ -15,7 +15,7 @@ public interface PublicIpv6AddressDao extends GenericDao listByNetwork(long networkId); - public PublicIpv6AddressVO findByDcIdAndIp(long dcId, String ipAddress); + public PublicIpv6AddressVO findByNetworkIdAndIp(long networkId, String ipAddress); List listByPhysicalNetworkId(long physicalNetworkId); diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java b/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java index 6883d4ec662..8a6bfcc5546 100644 --- a/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java @@ -73,9 +73,9 @@ public class PublicIpv6AddressDaoImpl extends GenericDaoBase sc = AllFieldsSearch.create(); - sc.setParameters("dataCenterId", dcId); + sc.setParameters("networkId", networkId); sc.setParameters("ipAddress", ipAddress); return findOneBy(sc); } diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index d6a8812da08..ef286bdadb8 100755 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -31,6 +31,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IPAddressVO; +import com.cloud.network.Ipv6AddressManager; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Service; @@ -76,6 +77,8 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { NetworkOfferingDao _networkOfferingDao; @Inject PublicIpv6AddressDao _ipv6Dao; + @Inject + Ipv6AddressManager _ipv6Mgr; private static final TrafficType[] _trafficTypes = {TrafficType.Guest}; @@ -230,10 +233,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { } if (nic.getIp6Address() != null) { - PublicIpv6AddressVO ip = _ipv6Dao.findByDcIdAndIp(network.getDataCenterId(), nic.getIp6Address()); - if (ip != null) { - _ipv6Dao.remove(ip.getId()); - } + _ipv6Mgr.revokeDirectIpv6Address(nic.getNetworkId(), nic.getIp6Address()); } nic.deallocate(); } diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index df409a83ebc..122d75a63de 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -818,12 +818,4 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS // TODO Auto-generated method stub return null; } - - @Override - public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, - Account owner, VlanType type, Long networkId, String requestedIpv6, - boolean isSystem) throws InsufficientAddressCapacityException { - // TODO Auto-generated method stub - return null; - } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 13426e601a9..970f5ade04c 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -1321,12 +1321,4 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M // TODO Auto-generated method stub return null; } - - @Override - public PublicIpv6Address assignPublicIp6Address(long dcId, Long podId, - Account owner, VlanType type, Long networkId, String requestedIpv6, - boolean isSystem) throws InsufficientAddressCapacityException { - // TODO Auto-generated method stub - return null; - } } From 0b62fc4c1743bb3f1d61d854d3bca368d146865c Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 18:42:04 -0800 Subject: [PATCH 13/26] IPv6: Verify if requested IPv4/IPv6 addresses are valid Also rename NetUtils.isValidIPv6() to NetUtils.isValidIpv6() --- .../ConfigurationManagerImpl.java | 2 +- .../com/cloud/network/NetworkServiceImpl.java | 6 +++--- .../src/com/cloud/vm/UserVmManagerImpl.java | 20 +++++++++++++++++-- utils/src/com/cloud/utils/net/NetUtils.java | 2 +- .../com/cloud/utils/net/NetUtilsTest.java | 8 ++++---- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 7154dc8cb88..aee32340af4 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2372,7 +2372,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } if (ipv6) { - if (!NetUtils.isValidIPv6(vlanGatewayv6)) { + if (!NetUtils.isValidIpv6(vlanGatewayv6)) { throw new InvalidParameterValueException("Please specify a valid IPv6 gateway"); } if (!NetUtils.isValidIp6Cidr(vlanCidrv6)) { diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index df44ce0ea27..98d93429cd8 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -783,12 +783,12 @@ public class NetworkServiceImpl implements NetworkService, Manager { } if (ipv6) { - if (!NetUtils.isValidIPv6(startIPv6)) { + if (!NetUtils.isValidIpv6(startIPv6)) { throw new InvalidParameterValueException("Invalid format for the startIPv6 parameter"); } if (endIPv6 == null) { endIPv6 = startIPv6; - } else if (!NetUtils.isValidIPv6(endIPv6)) { + } else if (!NetUtils.isValidIpv6(endIPv6)) { throw new InvalidParameterValueException("Invalid format for the endIPv6 parameter"); } @@ -796,7 +796,7 @@ public class NetworkServiceImpl implements NetworkService, Manager { throw new InvalidParameterValueException("ip6Gateway and ip6Cidr should be defined when startIPv6/endIPv6 are passed in"); } - if (!NetUtils.isValidIPv6(ip6Gateway)) { + if (!NetUtils.isValidIpv6(ip6Gateway)) { throw new InvalidParameterValueException("Invalid ip6Gateway"); } if (!NetUtils.isValidIp6Cidr(ip6Cidr)) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 491f8a2c691..1bc7edb0f74 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2376,6 +2376,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (requestedIpPair == null) { requestedIpPair = new IpAddresses(null, null); + } else { + checkRequestedIpAddresses(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); } NicProfile profile = new NicProfile(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); @@ -2383,7 +2385,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (defaultNetworkNumber == 0) { defaultNetworkNumber++; // if user requested specific ip for default network, add it - if (defaultIps.getIp4Address() != null || defaultIps.getIp4Address() != null) { + if (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null) { + checkRequestedIpAddresses(defaultIps.getIp4Address(), defaultIps.getIp6Address()); profile = new NicProfile(defaultIps.getIp4Address(), defaultIps.getIp6Address()); } @@ -2521,7 +2524,20 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager return vm; } - private void validateUserData(String userData) { + private void checkRequestedIpAddresses(String ip4, String ip6) throws InvalidParameterValueException { + if (ip4 != null) { + if (!NetUtils.isValidIp(ip4)) { + throw new InvalidParameterValueException("Invalid specified IPv4 address " + ip4); + } + } + if (ip6 != null) { + if (!NetUtils.isValidIpv6(ip6)) { + throw new InvalidParameterValueException("Invalid specified IPv6 address " + ip6); + } + } + } + + private void validateUserData(String userData) { byte[] decodedUserData = null; if (userData != null) { if (!Base64.isBase64(userData)) { diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index e3bf7075daf..d121ff0a7c3 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -1146,7 +1146,7 @@ public class NetUtils { return true; } - public static boolean isValidIPv6(String ip) { + public static boolean isValidIpv6(String ip) { try { IPv6Address address = IPv6Address.fromString(ip); } catch (IllegalArgumentException ex) { diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 9beb6ca8bf1..c256d6dbfc3 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -75,10 +75,10 @@ public class NetUtilsTest extends TestCase { } public void testIpv6() { - assertTrue(NetUtils.isValidIPv6("fc00::1")); - assertFalse(NetUtils.isValidIPv6("")); - assertFalse(NetUtils.isValidIPv6(null)); - assertFalse(NetUtils.isValidIPv6("1234:5678::1/64")); + assertTrue(NetUtils.isValidIpv6("fc00::1")); + assertFalse(NetUtils.isValidIpv6("")); + assertFalse(NetUtils.isValidIpv6(null)); + assertFalse(NetUtils.isValidIpv6("1234:5678::1/64")); assertTrue(NetUtils.isValidIp6Cidr("1234:5678::1/64")); assertFalse(NetUtils.isValidIp6Cidr("1234:5678::1")); assertEquals(NetUtils.getIp6CidrSize("1234:5678::1/32"), 32); From 85d0546fe8e20ef9577d4fded256b3e1e6d0a2f9 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 19:47:08 -0800 Subject: [PATCH 14/26] IPv6: Make the IPv6 input all lowercase To make them consistent. --- .../apache/cloudstack/api/ApiConstants.java | 4 +- .../user/network/CreateNetworkCmd.java | 44 ++++++++----------- .../api/command/user/vm/DeployVMCmd.java | 17 +++++-- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 80e382cc366..000e1e8c0d0 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -38,7 +38,7 @@ public class ApiConstants { public static final String DOMAIN_SUFFIX = "domainsuffix"; public static final String DNS_SEARCH_ORDER = "dnssearchorder"; public static final String CIDR = "cidr"; - public static final String IP6CIDR = "ip6cidr"; + public static final String IP6_CIDR = "ip6cidr"; public static final String CIDR_LIST = "cidrlist"; public static final String CLEANUP = "cleanup"; public static final String CLUSTER_ID = "clusterid"; @@ -75,7 +75,7 @@ public class ApiConstants { public static final String FORMAT = "format"; public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork"; public static final String GATEWAY = "gateway"; - public static final String IP6GATEWAY = "ip6gateway"; + public static final String IP6_GATEWAY = "ip6gateway"; public static final String GROUP = "group"; public static final String GROUP_ID = "groupid"; public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 89aa464d363..f9969ec8081 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -119,11 +119,11 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.END_IPV6, type=CommandType.STRING, description="the ending IPv6 address in the IPv6 network range") private String endIpv6; - @Parameter(name=ApiConstants.IP6GATEWAY, type=CommandType.STRING, description="the gateway of the IPv6 network. Required " + + @Parameter(name=ApiConstants.IP6_GATEWAY, type=CommandType.STRING, description="the gateway of the IPv6 network. Required " + "for Shared networks and Isolated networks when it belongs to VPC") private String ip6Gateway; - @Parameter(name=ApiConstants.IP6CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") + @Parameter(name=ApiConstants.IP6_CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") private String ip6Cidr; @Parameter(name=ApiConstants.DUAL_STACK, type=CommandType.BOOLEAN, description="The network is dual-stack(IPv6 and IPv4) or not") @@ -223,35 +223,31 @@ public class CreateNetworkCmd extends BaseCmd { } public String getStartIpv6() { - return startIpv6; - } - - public void setStartIpv6(String startIpv6) { - this.startIpv6 = startIpv6; + if (startIpv6 == null) { + return null; + } + return startIpv6.toLowerCase(); } public String getEndIpv6() { - return endIpv6; - } - - public void setEndIpv6(String endIpv6) { - this.endIpv6 = endIpv6; + if (endIpv6 == null) { + return null; + } + return endIpv6.toLowerCase(); } public String getIp6Gateway() { - return ip6Gateway; - } - - public void setIp6Gateway(String ip6Gateway) { - this.ip6Gateway = ip6Gateway; + if (ip6Gateway == null) { + return null; + } + return ip6Gateway.toLowerCase(); } public String getIp6Cidr() { - return ip6Cidr; - } - - public void setIp6Cidr(String ip6Cidr) { - this.ip6Cidr = ip6Cidr; + if (ip6Cidr == null) { + return null; + } + return ip6Cidr.toLowerCase(); } public Boolean isDualStack() { @@ -261,10 +257,6 @@ public class CreateNetworkCmd extends BaseCmd { return dualStack; } - public void setDualStack(Boolean dualStack) { - this.dualStack = dualStack; - } - ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index b3eaed8fddb..83025905cbf 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -248,7 +248,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { public List getNetworkIds() { if (ipToNetworkList != null) { - if (networkIds != null || ipAddress != null || ip6Address != null) { + if (networkIds != null || ipAddress != null || getIp6Address() != null) { throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress"); } else { List networks = new ArrayList(); @@ -276,7 +276,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } private Map getIpToNetworkMap() { - if ((networkIds != null || ipAddress != null || ip6Address != null) && ipToNetworkList != null) { + if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) { throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"); } LinkedHashMap ipToNetworkMap = null; @@ -299,6 +299,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } String requestedIp = (String) ips.get("ip"); String requestedIpv6 = (String) ips.get("ipv6"); + if (requestedIpv6 != null) { + requestedIpv6 = requestedIpv6.toLowerCase(); + } IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6); ipToNetworkMap.put(networkId, addrs); } @@ -306,6 +309,13 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { return ipToNetworkMap; } + + public String getIp6Address() { + if (ip6Address == null) { + return null; + } + return ip6Address.toLowerCase(); + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -434,7 +444,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { if (getHypervisor() == HypervisorType.BareMetal) { vm = _bareMetalVmService.createVirtualMachine(this); } else { - IpAddresses addrs = new IpAddresses(ipAddress, ip6Address); + IpAddresses addrs = new IpAddresses(ipAddress, getIp6Address()); if (zone.getNetworkType() == NetworkType.Basic) { if (getNetworkIds() != null) { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); @@ -474,4 +484,5 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } } + } From b1972f6c113b64a137d3080a2fa98f239114e5ba Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 19:54:06 -0800 Subject: [PATCH 15/26] IPv6: Update NetworkResponse and NicResponse --- .../api/response/NetworkResponse.java | 14 ++++++++++++ .../cloudstack/api/response/NicResponse.java | 22 ++++++++++++++++++- .../src/com/cloud/api/ApiResponseHelper.java | 3 +++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index 64cc9531901..ba8ea3277e7 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -144,6 +144,12 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with network", responseObject = ResourceTagResponse.class) private List tags; + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + public void setId(String id) { this.id = id; } @@ -298,4 +304,12 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes public void setTags(List tags) { this.tags = tags; } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java index a6ca5b8232d..467addc5c2a 100644 --- a/api/src/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java @@ -60,6 +60,15 @@ public class NicResponse extends BaseResponse { @SerializedName("macaddress") @Param(description="true if nic is default, false otherwise") private String macAddress; + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + + @SerializedName(ApiConstants.IP6_ADDRESS) @Param(description="the IPv6 address of network") + private String ip6Address; + public String getId() { return id; } @@ -112,6 +121,18 @@ public class NicResponse extends BaseResponse { public void setMacAddress(String macAddress) { this.macAddress = macAddress; } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } @Override public int hashCode() { @@ -139,5 +160,4 @@ public class NicResponse extends BaseResponse { return false; return true; } - } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 1c8849a9e53..b6a9a3733e5 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2151,6 +2151,9 @@ public class ApiResponseHelper implements ResponseGenerator { if (network.getCidr() != null) { response.setNetmask(NetUtils.cidr2Netmask(network.getCidr())); } + + response.setIp6Gateway(network.getIp6Gateway()); + response.setIp6Cidr(network.getIp6Cidr()); //return vlan information only to Root admin if (network.getBroadcastUri() != null && UserContext.current().getCaller().getType() == Account.ACCOUNT_TYPE_ADMIN) { From f9a68e7f157541b9cc3e8944820ab218c4cdbb4b Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 21:43:58 -0800 Subject: [PATCH 16/26] IPv6: Add vlan overlap checking --- .../configuration/ConfigurationManager.java | 2 +- .../ConfigurationManagerImpl.java | 45 +++++++++++++------ utils/src/com/cloud/utils/net/NetUtils.java | 23 ++++++++++ .../com/cloud/utils/net/NetUtilsTest.java | 5 +++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 58fdeeda2e2..09e8ac902b9 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -198,7 +198,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges); - Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; + Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index aee32340af4..c8acf3b1caa 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2278,7 +2278,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @DB public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, - String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) { + String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) { Network network = _networkModel.getNetwork(networkId); boolean ipv4 = false, ipv6 = false; @@ -2372,15 +2372,14 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } if (ipv6) { - if (!NetUtils.isValidIpv6(vlanGatewayv6)) { + if (!NetUtils.isValidIpv6(vlanIp6Gateway)) { throw new InvalidParameterValueException("Please specify a valid IPv6 gateway"); } - if (!NetUtils.isValidIp6Cidr(vlanCidrv6)) { + if (!NetUtils.isValidIp6Cidr(vlanIp6Cidr)) { throw new InvalidParameterValueException("Please specify a valid IPv6 CIDR"); } } - // TODO skip all vlan check for ipv6 now if (ipv4) { String newVlanSubnet = NetUtils.getSubNet(vlanGateway, vlanNetmask); @@ -2426,7 +2425,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura List vlans = _vlanDao.listByZone(zone.getId()); for (VlanVO vlan : vlans) { String otherVlanGateway = vlan.getVlanGateway(); - // Continue if it's IPv6 + // Continue if it's not IPv4 if (otherVlanGateway == null) { continue; } @@ -2462,6 +2461,32 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } } } + + String ipv6Range = null; + if (ipv6) { + ipv6Range = startIPv6; + if (endIPv6 != null) { + ipv6Range += "-" + endIPv6; + } + + List vlans = _vlanDao.listByZone(zone.getId()); + for (VlanVO vlan : vlans) { + if (vlan.getIp6Gateway() == null) { + continue; + } + if (vlanId.equals(vlan.getVlanTag())) { + if (NetUtils.isIp6RangeOverlap(ipv6Range, vlan.getIp6Range())) { + throw new InvalidParameterValueException("The IPv6 range with tag: " + vlan.getVlanTag() + + " already has IPs that overlap with the new range. Please specify a different start IP/end IP."); + } + + if (!vlanIp6Gateway.equals(vlan.getIp6Gateway())) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " has already been added with gateway " + vlan.getIp6Gateway() + + ". Please specify a different tag."); + } + } + } + } // Check if a guest VLAN is using the same tag if (_zoneDao.findVnet(zoneId, physicalNetworkId, vlanId).size() > 0) { @@ -2491,19 +2516,11 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } } - String ipv6Range = null; - if (ipv6) { - ipv6Range = startIPv6; - if (endIPv6 != null) { - ipv6Range += "-" + endIPv6; - } - } - // Everything was fine, so persist the VLAN Transaction txn = Transaction.currentTxn(); txn.start(); - VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId, vlanGatewayv6, vlanCidrv6, ipv6Range); + VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId, vlanIp6Gateway, vlanIp6Cidr, ipv6Range); s_logger.debug("Saving vlan range " + vlan); vlan = _vlanDao.persist(vlan); diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index d121ff0a7c3..26026194ebb 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -42,6 +42,7 @@ import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import com.googlecode.ipv6.IPv6Address; +import com.googlecode.ipv6.IPv6AddressRange; import com.googlecode.ipv6.IPv6Network; import com.cloud.utils.IteratorUtil; @@ -1233,4 +1234,26 @@ public class NetUtils { } return false; } + + public static boolean isIp6RangeOverlap(String ipRange1, String ipRange2) { + String[] ips = ipRange1.split("-"); + String startIp1 = ips[0]; + String endIp1 = null; + if (ips.length > 1) { + endIp1 = ips[1]; + } + IPv6Address start1 = IPv6Address.fromString(startIp1); + IPv6Address end1 = IPv6Address.fromString(endIp1); + IPv6AddressRange range1 = IPv6AddressRange.fromFirstAndLast(start1, end1); + ips = ipRange2.split("-"); + String startIp2 = ips[0]; + String endIp2 = null; + if (ips.length > 1) { + endIp2 = ips[1]; + } + IPv6Address start2 = IPv6Address.fromString(startIp2); + IPv6Address end2 = IPv6Address.fromString(endIp2); + IPv6AddressRange range2 = IPv6AddressRange.fromFirstAndLast(start2, end2); + return range1.overlaps(range2); + } } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index c256d6dbfc3..5336d93127a 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -96,5 +96,10 @@ public class NetUtilsTest extends TestCase { assertTrue(ip.compareTo(ipStart) >= 0); assertTrue(ip.compareTo(ipEnd) <= 0); } + assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::1-1234:5678::ffff", "1234:5678:1::1-1234:5678:1::ffff")); + assertTrue(NetUtils.isIp6RangeOverlap("1234:5678::1-1234:5678::ffff", "1234:5678::2-1234:5678::f")); + assertTrue(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::ffff", "1234:5678::2-1234:5678::f")); + assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::ffff", "1234:5678::2-1234:5678::e")); + assertFalse(NetUtils.isIp6RangeOverlap("1234:5678::f-1234:5678::f", "1234:5678::2-1234:5678::e")); } } From 4640b82719e5eeda5151f518b6a4e9d50ba46b80 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 21:59:51 -0800 Subject: [PATCH 17/26] IPv6: Fix generated DUID-LL Should be: 00:03:00:01 + --- utils/src/com/cloud/utils/net/NetUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 26026194ebb..fdda5b83f77 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -1193,7 +1193,7 @@ public class NetUtils { //RFC3315, section 9.4 public static String getDuidLL(String macAddress) { - String duid = "00:03:00:06:" + macAddress; + String duid = "00:03:00:01:" + macAddress; return duid; } From dfc9dc19f83383b1896fbff1d04e8073106cfed0 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Tue, 29 Jan 2013 22:08:32 -0800 Subject: [PATCH 18/26] IPv6: Add IPv6 address to router in /etc/hosts --- patches/systemvm/debian/config/etc/init.d/cloud-early-config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index ebe2fa4ab5b..db2fcc2046e 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -738,7 +738,8 @@ setup_dhcpsrvr() { fi sed -i /gateway/d /etc/hosts - echo "$ETH0_IP $NAME" >> /etc/hosts + [ $ETH0_IP ] && echo "$ETH0_IP $NAME" >> /etc/hosts + [ $ETH0_IP6 ] && echo "$ETH0_IP6 $NAME" >> /etc/hosts enable_svc dnsmasq 1 enable_svc haproxy 0 From 6b19086874c6354df59373c5b2d1e9310452f211 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Fri, 25 Jan 2013 14:18:25 -0800 Subject: [PATCH 19/26] Fix a bug in listHosts that returns wrong zoneId for host. --- server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java index e8423836004..13b777aa4b1 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -77,7 +77,7 @@ public class HostJoinDaoImpl extends GenericDaoBase implements hostResponse.setCapabilities(host.getCapabilities()); hostResponse.setClusterId(host.getClusterUuid()); hostResponse.setCpuNumber(host.getCpus()); - hostResponse.setZoneId(host.getUuid()); + hostResponse.setZoneId(host.getZoneUuid()); hostResponse.setDisconnectedOn(host.getDisconnectedOn()); hostResponse.setHypervisor(host.getHypervisorType()); hostResponse.setHostType(host.getType()); From 25ae2e4f3f410e32c5c7a52ab51a570e402e7a0a Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 13:28:46 -0800 Subject: [PATCH 20/26] IPv6: Remove dualstack parameter from createNetworkCmd We can tell if it's dual stack by looking into the startIp and startIpv6. --- api/src/org/apache/cloudstack/api/ApiConstants.java | 1 - .../api/command/user/network/CreateNetworkCmd.java | 10 ---------- server/src/com/cloud/network/NetworkServiceImpl.java | 6 ++---- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 000e1e8c0d0..1537478c621 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -432,7 +432,6 @@ public class ApiConstants { public static final String CONDITION_IDS = "conditionids"; public static final String COUNTERPARAM_LIST = "counterparam"; public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; - public static final String DUAL_STACK = "dualstack"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index f9969ec8081..580948ac2b1 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -126,9 +126,6 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.IP6_CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") private String ip6Cidr; - @Parameter(name=ApiConstants.DUAL_STACK, type=CommandType.BOOLEAN, description="The network is dual-stack(IPv6 and IPv4) or not") - private Boolean dualStack; - ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -250,13 +247,6 @@ public class CreateNetworkCmd extends BaseCmd { return ip6Cidr.toLowerCase(); } - public Boolean isDualStack() { - if (dualStack == null) { - return false; - } - return dualStack; - } - ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 98d93429cd8..e1c020b828b 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -619,7 +619,6 @@ public class NetworkServiceImpl implements NetworkService, Manager { String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); - Boolean dualStack = cmd.isDualStack(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -736,9 +735,8 @@ public class NetworkServiceImpl implements NetworkService, Manager { UserContext.current().setAccountId(owner.getAccountId()); - // VALIDATE IP INFO - if (startIPv6 != null && startIP != null && (dualStack == null || dualStack == false)) { - throw new InvalidParameterValueException("Cannot specify both IPv4 and IPv6 address without set dualStack = true!"); + if (startIPv6 != null && startIP != null) { + throw new InvalidParameterValueException("Cannot support dualstack at this moment!"); } boolean ipv4 = false, ipv6 = false; From c5b2a6559888822e22ff9137e293f7e0e4a820a9 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 30 Jan 2013 16:21:36 -0800 Subject: [PATCH 21/26] Removing the merge conflict statements from git. --- client/tomcatconf/server-ssl.xml.in | 1 - 1 file changed, 1 deletion(-) diff --git a/client/tomcatconf/server-ssl.xml.in b/client/tomcatconf/server-ssl.xml.in index 6e8bf525ec6..5d68f1d3d8b 100755 --- a/client/tomcatconf/server-ssl.xml.in +++ b/client/tomcatconf/server-ssl.xml.in @@ -197,7 +197,6 @@ >>>>>> bcfd64a... CS-15373: Awsapi port change to 7080. maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreType="JKS" From ed547d91f7882774794e4076a6073c902d67a3d9 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 16:02:07 -0800 Subject: [PATCH 22/26] IPv6: Rename public_ipv6_address to user_ipv6_address --- client/tomcatconf/components.xml.in | 2 +- .../DefaultComponentLibrary.java | 4 +-- .../com/cloud/network/Ipv6AddressManager.java | 2 +- .../cloud/network/Ipv6AddressManagerImpl.java | 12 +++---- .../com/cloud/network/NetworkManagerImpl.java | 6 ++-- .../com/cloud/network/NetworkModelImpl.java | 4 +-- ...cIpv6Address.java => UserIpv6Address.java} | 4 +-- ...6AddressVO.java => UserIpv6AddressVO.java} | 8 ++--- .../network/dao/PublicIpv6AddressDao.java | 23 ------------ .../cloud/network/dao/UserIpv6AddressDao.java | 23 ++++++++++++ ...oImpl.java => UserIpv6AddressDaoImpl.java} | 36 +++++++++---------- .../cloud/network/guru/DirectNetworkGuru.java | 6 ++-- .../com/cloud/vpc/MockNetworkManagerImpl.java | 2 +- setup/db/create-schema.sql | 16 ++++----- 14 files changed, 74 insertions(+), 74 deletions(-) rename server/src/com/cloud/network/{PublicIpv6Address.java => UserIpv6Address.java} (91%) rename server/src/com/cloud/network/{PublicIpv6AddressVO.java => UserIpv6AddressVO.java} (94%) delete mode 100644 server/src/com/cloud/network/dao/PublicIpv6AddressDao.java create mode 100644 server/src/com/cloud/network/dao/UserIpv6AddressDao.java rename server/src/com/cloud/network/dao/{PublicIpv6AddressDaoImpl.java => UserIpv6AddressDaoImpl.java} (66%) diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index b274b862225..e9bd56a59e3 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -271,7 +271,7 @@ under the License. - + diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index e8fcabec555..8939439ab71 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -123,7 +123,7 @@ import com.cloud.network.dao.PhysicalNetworkDaoImpl; import com.cloud.network.dao.PhysicalNetworkServiceProviderDaoImpl; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl; import com.cloud.network.dao.PortProfileDaoImpl; -import com.cloud.network.dao.PublicIpv6AddressDaoImpl; +import com.cloud.network.dao.UserIpv6AddressDaoImpl; import com.cloud.network.dao.RemoteAccessVpnDaoImpl; import com.cloud.network.dao.Site2SiteCustomerGatewayDaoImpl; import com.cloud.network.dao.Site2SiteVpnConnectionDaoImpl; @@ -382,7 +382,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addDao("Site2SiteVpnGatewayDao", Site2SiteVpnGatewayDaoImpl.class); addDao("Site2SiteCustomerGatewayDao", Site2SiteCustomerGatewayDaoImpl.class); addDao("Site2SiteVpnConnnectionDao", Site2SiteVpnConnectionDaoImpl.class); - addDao("PublicIpv6AddressDao", PublicIpv6AddressDaoImpl.class); + addDao("UserIpv6AddressDao", UserIpv6AddressDaoImpl.class); addDao("UserVmJoinDao", UserVmJoinDaoImpl.class); addDao("DomainRouterJoinDao", DomainRouterJoinDaoImpl.class); diff --git a/server/src/com/cloud/network/Ipv6AddressManager.java b/server/src/com/cloud/network/Ipv6AddressManager.java index 21c65a926df..2ab7e5a1b7e 100644 --- a/server/src/com/cloud/network/Ipv6AddressManager.java +++ b/server/src/com/cloud/network/Ipv6AddressManager.java @@ -22,7 +22,7 @@ import com.cloud.user.Account; import com.cloud.utils.component.Manager; public interface Ipv6AddressManager extends Manager { - public PublicIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException; + public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException; public void revokeDirectIpv6Address(long networkId, String ip6Address); } diff --git a/server/src/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java index d794ff7e57f..6666596827d 100644 --- a/server/src/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java @@ -29,7 +29,7 @@ import com.cloud.dc.Vlan; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.network.dao.PublicIpv6AddressDao; +import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.user.Account; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; @@ -48,7 +48,7 @@ public class Ipv6AddressManagerImpl implements Ipv6AddressManager { @Inject NetworkModel _networkModel; @Inject - PublicIpv6AddressDao _ipv6Dao; + UserIpv6AddressDao _ipv6Dao; @Override public boolean configure(String name, Map params) @@ -73,7 +73,7 @@ public class Ipv6AddressManagerImpl implements Ipv6AddressManager { } @Override - public PublicIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) + public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException { Vlan vlan = _networkModel.getVlanForNetwork(networkId); if (vlan == null) { @@ -112,10 +112,10 @@ public class Ipv6AddressManagerImpl implements Ipv6AddressManager { _dcDao.update(dc.getId(), dc); String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac)); - PublicIpv6AddressVO ipVO = new PublicIpv6AddressVO(ip, dcId, macAddress, vlan.getId()); + UserIpv6AddressVO ipVO = new UserIpv6AddressVO(ip, dcId, macAddress, vlan.getId()); ipVO.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); ipVO.setSourceNetworkId(vlan.getNetworkId()); - ipVO.setState(PublicIpv6Address.State.Allocated); + ipVO.setState(UserIpv6Address.State.Allocated); ipVO.setDomainId(owner.getDomainId()); ipVO.setAccountId(owner.getAccountId()); _ipv6Dao.persist(ipVO); @@ -124,7 +124,7 @@ public class Ipv6AddressManagerImpl implements Ipv6AddressManager { @Override public void revokeDirectIpv6Address(long networkId, String ip6Address) { - PublicIpv6AddressVO ip = _ipv6Dao.findByNetworkIdAndIp(networkId, ip6Address); + UserIpv6AddressVO ip = _ipv6Dao.findByNetworkIdAndIp(networkId, ip6Address); if (ip != null) { _ipv6Dao.remove(ip.getId()); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index e06a59b95a4..863b3c1ae01 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -112,7 +112,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; -import com.cloud.network.dao.PublicIpv6AddressDao; +import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.IpDeployer; import com.cloud.network.element.LoadBalancingServiceProvider; @@ -275,7 +275,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { @Inject NetworkModel _networkModel; @Inject - PublicIpv6AddressDao _ipv6Dao; + UserIpv6AddressDao _ipv6Dao; @Inject Ipv6AddressManager _ipv6Mgr; @@ -3362,7 +3362,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { if (network.getIp6Gateway() != null) { if (nic.getIp6Address() == null) { ipv6 = true; - PublicIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); + UserIpv6Address ip = _ipv6Mgr.assignDirectIp6Address(dc.getId(), vm.getOwner(), network.getId(), requestedIpv6); Vlan vlan = _networkModel.getVlanForNetwork(network.getId()); if (vlan == null) { s_logger.debug("Cannot find related vlan or too many vlan attached to network " + network.getId()); diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index cd0187a2a28..a03acea8d5d 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -66,7 +66,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; -import com.cloud.network.dao.PublicIpv6AddressDao; +import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.rules.FirewallRule.Purpose; @@ -160,7 +160,7 @@ public class NetworkModelImpl implements NetworkModel, Manager{ @Inject PrivateIpDao _privateIpDao; @Inject - PublicIpv6AddressDao _ipv6Dao; + UserIpv6AddressDao _ipv6Dao; private final HashMap _systemNetworks = new HashMap(5); diff --git a/server/src/com/cloud/network/PublicIpv6Address.java b/server/src/com/cloud/network/UserIpv6Address.java similarity index 91% rename from server/src/com/cloud/network/PublicIpv6Address.java rename to server/src/com/cloud/network/UserIpv6Address.java index 5c51506811f..4c33d456d2a 100644 --- a/server/src/com/cloud/network/PublicIpv6Address.java +++ b/server/src/com/cloud/network/UserIpv6Address.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.api.InternalIdentity; * @author Sheng Yang * */ -public interface PublicIpv6Address extends ControlledEntity, Identity, InternalIdentity { +public interface UserIpv6Address extends ControlledEntity, Identity, InternalIdentity { enum State { Allocating, // The IP Address is being propagated to other network elements and is not ready for use yet. Allocated, // The IP address is in used. @@ -46,7 +46,7 @@ public interface PublicIpv6Address extends ControlledEntity, Identity, InternalI Long getPhysicalNetworkId(); - void setState(PublicIpv6Address.State state); + void setState(UserIpv6Address.State state); String getMacAddress(); } diff --git a/server/src/com/cloud/network/PublicIpv6AddressVO.java b/server/src/com/cloud/network/UserIpv6AddressVO.java similarity index 94% rename from server/src/com/cloud/network/PublicIpv6AddressVO.java rename to server/src/com/cloud/network/UserIpv6AddressVO.java index e5d00a1b1d7..70eb12d32b0 100644 --- a/server/src/com/cloud/network/PublicIpv6AddressVO.java +++ b/server/src/com/cloud/network/UserIpv6AddressVO.java @@ -32,8 +32,8 @@ import javax.persistence.Transient; import com.cloud.utils.db.GenericDao; @Entity -@Table(name=("public_ipv6_address")) -public class PublicIpv6AddressVO implements PublicIpv6Address { +@Table(name=("user_ipv6_address")) +public class UserIpv6AddressVO implements UserIpv6Address { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") @@ -76,11 +76,11 @@ public class PublicIpv6AddressVO implements PublicIpv6Address { @Column(name = GenericDao.CREATED_COLUMN) Date created; - protected PublicIpv6AddressVO() { + protected UserIpv6AddressVO() { this.uuid = UUID.randomUUID().toString(); } - public PublicIpv6AddressVO(String address, long dataCenterId, String macAddress, long vlanDbId) { + public UserIpv6AddressVO(String address, long dataCenterId, String macAddress, long vlanDbId) { this.address = address; this.dataCenterId = dataCenterId; this.vlanId = vlanDbId; diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java b/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java deleted file mode 100644 index c347052bc82..00000000000 --- a/server/src/com/cloud/network/dao/PublicIpv6AddressDao.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.cloud.network.dao; - -import java.util.List; - -import com.cloud.network.Network; -import com.cloud.network.PublicIpv6AddressVO; -import com.cloud.utils.db.GenericDao; - -public interface PublicIpv6AddressDao extends GenericDao { - List listByAccount(long accountId); - - List listByVlanId(long vlanId); - - List listByDcId(long dcId); - - List listByNetwork(long networkId); - - public PublicIpv6AddressVO findByNetworkIdAndIp(long networkId, String ipAddress); - - List listByPhysicalNetworkId(long physicalNetworkId); - - long countExistedIpsInNetwork(long networkId); -} diff --git a/server/src/com/cloud/network/dao/UserIpv6AddressDao.java b/server/src/com/cloud/network/dao/UserIpv6AddressDao.java new file mode 100644 index 00000000000..0e245efcde1 --- /dev/null +++ b/server/src/com/cloud/network/dao/UserIpv6AddressDao.java @@ -0,0 +1,23 @@ +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.Network; +import com.cloud.network.UserIpv6AddressVO; +import com.cloud.utils.db.GenericDao; + +public interface UserIpv6AddressDao extends GenericDao { + List listByAccount(long accountId); + + List listByVlanId(long vlanId); + + List listByDcId(long dcId); + + List listByNetwork(long networkId); + + public UserIpv6AddressVO findByNetworkIdAndIp(long networkId, String ipAddress); + + List listByPhysicalNetworkId(long physicalNetworkId); + + long countExistedIpsInNetwork(long networkId); +} diff --git a/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java b/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java similarity index 66% rename from server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java rename to server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java index 8a6bfcc5546..6989c40d289 100644 --- a/server/src/com/cloud/network/dao/PublicIpv6AddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java @@ -9,7 +9,7 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.network.Network; -import com.cloud.network.PublicIpv6AddressVO; +import com.cloud.network.UserIpv6AddressVO; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -20,14 +20,14 @@ import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria2; -@Local(value=PublicIpv6AddressDao.class) -public class PublicIpv6AddressDaoImpl extends GenericDaoBase implements PublicIpv6AddressDao { +@Local(value=UserIpv6AddressDao.class) +public class UserIpv6AddressDaoImpl extends GenericDaoBase implements UserIpv6AddressDao { private static final Logger s_logger = Logger.getLogger(IPAddressDaoImpl.class); - protected final SearchBuilder AllFieldsSearch; - protected GenericSearchBuilder CountFreePublicIps; + protected final SearchBuilder AllFieldsSearch; + protected GenericSearchBuilder CountFreePublicIps; - public PublicIpv6AddressDaoImpl() { + public UserIpv6AddressDaoImpl() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ); @@ -45,44 +45,44 @@ public class PublicIpv6AddressDaoImpl extends GenericDaoBase listByAccount(long accountId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listByAccount(long accountId) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("accountId", accountId); return listBy(sc); } @Override - public List listByVlanId(long vlanId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listByVlanId(long vlanId) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("vlan", vlanId); return listBy(sc); } @Override - public List listByDcId(long dcId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listByDcId(long dcId) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("dataCenterId", dcId); return listBy(sc); } @Override - public List listByNetwork(long networkId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listByNetwork(long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("network", networkId); return listBy(sc); } @Override - public PublicIpv6AddressVO findByNetworkIdAndIp(long networkId, String ipAddress) { - SearchCriteria sc = AllFieldsSearch.create(); + public UserIpv6AddressVO findByNetworkIdAndIp(long networkId, String ipAddress) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("networkId", networkId); sc.setParameters("ipAddress", ipAddress); return findOneBy(sc); } @Override - public List listByPhysicalNetworkId(long physicalNetworkId) { - SearchCriteria sc = AllFieldsSearch.create(); + public List listByPhysicalNetworkId(long physicalNetworkId) { + SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("physicalNetworkId", physicalNetworkId); return listBy(sc); } diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index ef286bdadb8..0d5425ff218 100755 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -43,9 +43,9 @@ import com.cloud.network.NetworkVO; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PublicIpv6AddressVO; +import com.cloud.network.UserIpv6AddressVO; import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.PublicIpv6AddressDao; +import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; @@ -76,7 +76,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { @Inject NetworkOfferingDao _networkOfferingDao; @Inject - PublicIpv6AddressDao _ipv6Dao; + UserIpv6AddressDao _ipv6Dao; @Inject Ipv6AddressManager _ipv6Mgr; diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 970f5ade04c..96d9245f5e5 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -56,7 +56,7 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; import com.cloud.network.PublicIpAddress; -import com.cloud.network.PublicIpv6Address; +import com.cloud.network.UserIpv6Address; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.element.LoadBalancingServiceProvider; diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index db3a8a53950..c79c965792b 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2550,7 +2550,7 @@ INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (2, INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (3, UUID(), 'snmp','Linux CPU Idle - percentage', '1.3.6.1.4.1.2021.11.11.0', now()); INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (100, UUID(), 'netscaler','Response Time - microseconds', 'RESPTIME', now()); -CREATE TABLE `cloud`.`public_ipv6_address` ( +CREATE TABLE `cloud`.`user_ipv6_address` ( `id` bigint unsigned NOT NULL UNIQUE auto_increment, `uuid` varchar(40), `account_id` bigint unsigned NULL, @@ -2566,13 +2566,13 @@ CREATE TABLE `cloud`.`public_ipv6_address` ( `created` datetime NULL COMMENT 'Date this ip was allocated to someone', PRIMARY KEY (`id`), UNIQUE (`ip_address`, `source_network_id`), - CONSTRAINT `fk_public_ipv6_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `fk_public_ipv6_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `fk_public_ipv6_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), - CONSTRAINT `fk_public_ipv6_address__vlan_id` FOREIGN KEY (`vlan_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_public_ipv6_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, - CONSTRAINT `uc_public_ipv6_address__uuid` UNIQUE (`uuid`), - CONSTRAINT `fk_public_ipv6_address__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE + CONSTRAINT `fk_user_ipv6_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_user_ipv6_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_user_ipv6_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_user_ipv6_address__vlan_id` FOREIGN KEY (`vlan_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_user_ipv6_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_user_ipv6_address__uuid` UNIQUE (`uuid`), + CONSTRAINT `fk_user_ipv6_address__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; SET foreign_key_checks = 1; From 4adc974ab74c8f79f84e16628660543f4e1afcc6 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 17:07:33 -0800 Subject: [PATCH 23/26] IPv6: Disable untested features --- .../api/command/user/network/CreateNetworkCmd.java | 4 ++++ .../apache/cloudstack/api/command/user/vm/DeployVMCmd.java | 7 +++++++ server/src/com/cloud/network/NetworkServiceImpl.java | 4 ---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 580948ac2b1..bbd8b5a7447 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -268,6 +268,10 @@ public class CreateNetworkCmd extends BaseCmd { @Override // an exception thrown by createNetwork() will be caught by the dispatcher. public void execute() throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException{ + if (getStartIpv6() != null && getStartIp() != null) { + throw new InvalidParameterValueException("Cannot support dualstack at this moment!"); + } + Network result = _networkService.createGuestNetwork(this); if (result != null) { NetworkResponse response = _responseGenerator.createNetworkResponse(result); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 83025905cbf..b21b53c831c 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -302,6 +302,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { if (requestedIpv6 != null) { requestedIpv6 = requestedIpv6.toLowerCase(); } + if (requestedIpv6 != null) { + throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); + } IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6); ipToNetworkMap.put(networkId, addrs); } @@ -404,6 +407,10 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { + if (getIp6Address() != null) { + throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); + } + //Verify that all objects exist before passing them to the service Account owner = _accountService.getActiveAccountById(getEntityOwnerId()); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index e1c020b828b..a5fd0e929b7 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -735,10 +735,6 @@ public class NetworkServiceImpl implements NetworkService, Manager { UserContext.current().setAccountId(owner.getAccountId()); - if (startIPv6 != null && startIP != null) { - throw new InvalidParameterValueException("Cannot support dualstack at this moment!"); - } - boolean ipv4 = false, ipv6 = false; if (startIP != null) { ipv4 = true; From f45576bce59272faae9e8bcf188b112d8c215b0a Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 19:46:30 -0800 Subject: [PATCH 24/26] IPv6: Fix missed AddressFormat in nic table --- api/src/com/cloud/network/Networks.java | 2 +- server/src/com/cloud/network/NetworkManagerImpl.java | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index b15661910b4..e3d21584ad8 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -48,7 +48,7 @@ public class Networks { public enum AddressFormat { Ip4, Ip6, - Mixed + DualStack } /** diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 863b3c1ae01..0b047992a4c 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1317,10 +1317,8 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { vo.setDefaultNic(profile.isDefaultNic()); - if (profile.getIp4Address() != null) { - vo.setIp4Address(profile.getIp4Address()); - vo.setAddressFormat(AddressFormat.Ip4); - } + vo.setIp4Address(profile.getIp4Address()); + vo.setAddressFormat(profile.getFormat()); if (profile.getMacAddress() != null) { vo.setMacAddress(profile.getMacAddress()); @@ -3372,7 +3370,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener { nic.setIp6Gateway(vlan.getIp6Gateway()); nic.setIp6Cidr(vlan.getIp6Cidr()); if (ipv4) { - nic.setFormat(AddressFormat.Mixed); + nic.setFormat(AddressFormat.DualStack); } else { nic.setIsolationUri(IsolationType.Vlan.toUri(vlan.getVlanTag())); nic.setBroadcastType(BroadcastDomainType.Vlan); From f57cbaacd690e8d8ba5bb2c5d6b5be68e9c7478b Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 20:01:04 -0800 Subject: [PATCH 25/26] IPv6: Fix VlanIpRangeResponse --- .../api/response/VlanIpRangeResponse.java | 33 +++++++++++++++++++ .../src/com/cloud/api/ApiResponseHelper.java | 18 ++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java index bfde73963c1..e3cac68f4f4 100644 --- a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java @@ -80,6 +80,19 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network this belongs to") private String physicalNetworkId; + @SerializedName(ApiConstants.START_IPV6) @Param(description="the start ipv6 of the VLAN IP range") + private String startIpv6; + + @SerializedName(ApiConstants.END_IPV6) @Param(description="the end ipv6 of the VLAN IP range") + private String endIpv6; + + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + + public void setId(String id) { this.id = id; } @@ -157,4 +170,24 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit public String getphysicalNetworkId() { return physicalNetworkId; } + + public String getStartIpv6() { + return startIpv6; + } + + public void setStartIpv6(String startIpv6) { + this.startIpv6 = startIpv6; + } + + public void setEndIpv6(String endIpv6) { + this.endIpv6 = endIpv6; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index b6a9a3733e5..0c562e993e3 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -481,9 +481,21 @@ public class ApiResponseHelper implements ResponseGenerator { // get start ip and end ip of corresponding vlan String ipRange = vlan.getIpRange(); - String[] range = ipRange.split("-"); - vlanResponse.setStartIp(range[0]); - vlanResponse.setEndIp(range[1]); + if (ipRange != null) { + String[] range = ipRange.split("-"); + vlanResponse.setStartIp(range[0]); + vlanResponse.setEndIp(range[1]); + } + + vlanResponse.setIp6Gateway(vlan.getIp6Gateway()); + vlanResponse.setIp6Cidr(vlan.getIp6Cidr()); + + String ip6Range = vlan.getIp6Range(); + if (ip6Range != null) { + String[] range = ip6Range.split("-"); + vlanResponse.setStartIpv6(range[0]); + vlanResponse.setEndIpv6(range[1]); + } if (vlan.getNetworkId() != null) { Network nw = ApiDBUtils.findNetworkById(vlan.getNetworkId()); From ed777bb7f33c653424e4169b7bde54ef272c4783 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 30 Jan 2013 22:13:46 -0800 Subject: [PATCH 26/26] IPv6: Check startipv6, endipv6 and ip6Gateway with ip range --- server/src/com/cloud/network/NetworkServiceImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index a5fd0e929b7..44677272ace 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -796,6 +796,15 @@ public class NetworkServiceImpl implements NetworkService, Manager { if (!NetUtils.isValidIp6Cidr(ip6Cidr)) { throw new InvalidParameterValueException("Invalid ip6cidr"); } + if (!NetUtils.isIp6InRange(startIPv6, ip6Cidr)) { + throw new InvalidParameterValueException("startIPv6 is not in ip6cidr indicated network range!"); + } + if (!NetUtils.isIp6InRange(endIPv6, ip6Cidr)) { + throw new InvalidParameterValueException("endIPv6 is not in ip6cidr indicated network range!"); + } + if (!NetUtils.isIp6InRange(ip6Gateway, ip6Cidr)) { + throw new InvalidParameterValueException("ip6Gateway is not in ip6cidr indicated network range!"); + } int cidrSize = NetUtils.getIp6CidrSize(ip6Cidr); // Ipv6 cidr limit should be at least /64