diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index f085e9f3029..5aede053d50 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -63,6 +63,7 @@ public class Networks { Storage("storage", Integer.class), Lswitch("lswitch", String.class), Mido("mido", String.class), + Pvlan("pvlan", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1165c7b34f6..9581f54ca61 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -223,6 +223,7 @@ public class ApiConstants { public static final String VLAN = "vlan"; public static final String REMOVE_VLAN="removevlan"; public static final String VLAN_ID = "vlanid"; + public static final String ISOLATED_PVLAN = "isolatedpvlan"; public static final String VM_AVAILABLE = "vmavailable"; public static final String VM_LIMIT = "vmlimit"; public static final String VM_TOTAL = "vmtotal"; 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 fc7bd9fdd3f..7f699fe0cc9 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 @@ -86,6 +86,9 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network") private String vlan; + @Parameter(name=ApiConstants.ISOLATED_PVLAN, type=CommandType.STRING, description="the isolated private vlan for this network") + private String isolatedPvlan; + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="network domain") private String networkDomain; @@ -141,6 +144,10 @@ public class CreateNetworkCmd extends BaseCmd { return vlan; } + public String getIsolatedPvlan() { + return isolatedPvlan; + } + public String getAccountName() { return accountName; } 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 46ae35a4a54..176dc00ec0e 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 @@ -1014,6 +1014,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else if (nic.getBroadcastType() == BroadcastDomainType.Lswitch) { // Nicira Logical Switch return network.getNetwork(); + } else if (nic.getBroadcastType() == BroadcastDomainType.Pvlan) { + URI broadcastUri = nic.getBroadcastUri(); + assert broadcastUri.getScheme().equals(BroadcastDomainType.Pvlan.scheme()); + long vlan = Long.parseLong(NetUtils.getPrimaryPvlanFromUri(broadcastUri)); + return enableVlanNetwork(conn, vlan, network); } throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri()); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 37ca793c556..a47f3b3c80f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2505,6 +2505,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (uri != null) { String[] vlan = uri.toString().split("vlan:\\/\\/"); networkVlanId = vlan[1]; + //For pvlan + networkVlanId = networkVlanId.split("-")[0]; } if (vlanId != null) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 4af716ca12a..e11135161db 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -128,7 +128,8 @@ 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, String ip6Gateway, String ip6Cidr) + long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, + String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; /** diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 5179e872686..7a09eb553f8 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1874,7 +1874,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @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, String ip6Gateway, String ip6Cidr) + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String ip6Gateway, String ip6Cidr, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1964,6 +1965,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (ipv6) { throw new InvalidParameterValueException("IPv6 is not supported with security group!"); } + if (isolatedPvlan != null) { + throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!"); + } // Only Account specific Isolated network with sourceNat service disabled are allowed in security group // enabled zone if ( ntwkOff.getGuestType() != GuestType.Shared ){ @@ -2094,13 +2098,20 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } 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); - } + if (isolatedPvlan == null) { + userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); + if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); + } else { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); + } + } else { + if (vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!"); + } + userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanId, isolatedPvlan)); + userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan); + } } List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, @@ -2697,7 +2708,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L 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, 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 " + @@ -3551,8 +3562,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L 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.setBroadcastType(BroadcastDomainType.Vlan); + //nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + nic.setBroadcastType(network.getBroadcastDomainType()); + nic.setBroadcastUri(network.getBroadcastUri()); nic.setFormat(AddressFormat.Ip4); nic.setReservationId(String.valueOf(ip.getVlanTag())); nic.setMacAddress(ip.getMacAddress()); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 2dcb47d0cd8..7c4d7027c6b 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -828,6 +828,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); + String isolatedPvlan = cmd.getIsolatedPvlan(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1014,6 +1015,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } + if (isolatedPvlan != null && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared)) { + throw new InvalidParameterValueException("Can only support create Private VLAN 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 @@ -1045,6 +1050,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) { throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!"); } + if (isolatedPvlan != null && providersConfiguredForExternalNetworking(ntwkProviders)) { + throw new InvalidParameterValueException("Cannot support private vlan on network offering with external devices!"); + } if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && @@ -1115,7 +1123,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { 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, ip6Gateway, ip6Cidr); + networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, + ip6Gateway, ip6Cidr, isolatedPvlan); } if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) { @@ -3363,7 +3372,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { 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, null); + null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, 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/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index bc7bb0c75f2..18690d72ed5 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1965,7 +1965,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis //2) Create network Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null); + networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null, null); return guestNetwork; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 617994888bd..8f2d103d343 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2164,7 +2164,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use 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); + null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, null); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException( @@ -4005,7 +4005,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use 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); + null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, null); // if the network offering has persistent set to true, implement the network if (requiredOfferings.get(0).getIsPersistent()) { DeployDestination dest = new DeployDestination(zone, null, null, null); diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index e9987bd1b66..3381d60c564 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -249,7 +249,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @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, String gatewayv6, String cidrv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // 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 9b18358e258..7dcc970405b 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -831,7 +831,8 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @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, String gatewayv6, String cidrv6) + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String gatewayv6, String cidrv6, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, 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 5988dd5f337..4dd404d4cc3 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Formatter; @@ -1290,4 +1291,29 @@ public class NetUtils { } return resultIp; } + + public static URI generateUriForPvlan(String primaryVlan, String isolatedPvlan) { + return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan); + } + + public static String getPrimaryPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 1) { + return null; + } + return vlans[0]; + } + + public static String getIsolatedPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 2) { + return null; + } + for (String vlan : vlans) { + if (vlan.startsWith("i")) { + return vlan.replace("i", " ").trim(); + } + } + return null; + } } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 28bd71f18d7..16d3402f0e6 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -17,6 +17,7 @@ package com.cloud.utils.net; import java.math.BigInteger; +import java.net.URI; import java.util.SortedSet; import java.util.TreeSet; @@ -128,4 +129,11 @@ public class NetUtilsTest extends TestCase { assertFalse(NetUtils.isIp6InRange("1234:5678:abcd::1", null)); assertTrue(NetUtils.isIp6InRange("1234:5678:abcd::1", "1234:5678::1-1234:5679::1")); } + + public void testPvlan() { + URI uri = NetUtils.generateUriForPvlan("123", "456"); + assertTrue(uri.toString().equals("pvlan://123-i456")); + assertTrue(NetUtils.getPrimaryPvlanFromUri(uri).equals("123")); + assertTrue(NetUtils.getIsolatedPvlanFromUri(uri).equals("456")); + } }