PVLAN : Implementing PVLAN deployment capability for VMware deployments in cloudstack.
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/15be9777 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/15be9777 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/15be9777 Branch: refs/heads/vmware-datamodel Commit: 15be97772e1b41801867beef25ae66dfaf286458 Parents: a29e393 Author: Vijayendra Bhamidipati <vijayendra.bhamidip...@citrix.com> Authored: Thu May 16 08:15:22 2013 -0700 Committer: Sheng Yang <sheng.y...@citrix.com> Committed: Thu May 16 14:50:16 2013 -0700 ---------------------------------------------------------------------- core/src/com/cloud/agent/api/PlugNicCommand.java | 9 +- .../hypervisor/vmware/resource/VmwareResource.java | 121 ++++++++---- .../src/com/cloud/network/NetworkManagerImpl.java | 2 + .../VpcVirtualNetworkApplianceManagerImpl.java | 45 ++--- server/src/com/cloud/vm/UserVmManagerImpl.java | 5 +- .../vmware/mo/DistributedVirtualSwitchMO.java | 77 ++++++++ .../hypervisor/vmware/mo/HypervisorHostHelper.java | 152 +++++++++++++- 7 files changed, 333 insertions(+), 78 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/core/src/com/cloud/agent/api/PlugNicCommand.java ---------------------------------------------------------------------- diff --git a/core/src/com/cloud/agent/api/PlugNicCommand.java b/core/src/com/cloud/agent/api/PlugNicCommand.java index b896e45..d10c680 100644 --- a/core/src/com/cloud/agent/api/PlugNicCommand.java +++ b/core/src/com/cloud/agent/api/PlugNicCommand.java @@ -17,11 +17,13 @@ package com.cloud.agent.api; import com.cloud.agent.api.to.NicTO; +import com.cloud.vm.VirtualMachine; public class PlugNicCommand extends Command { NicTO nic; String instanceName; + VirtualMachine.Type vmType; public NicTO getNic() { return nic; @@ -35,12 +37,17 @@ public class PlugNicCommand extends Command { protected PlugNicCommand() { } - public PlugNicCommand(NicTO nic, String instanceName) { + public PlugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype) { this.nic = nic; this.instanceName = instanceName; + this.vmType = vmtype; } public String getVmName() { return instanceName; } + + public VirtualMachine.Type getVMType() { + return vmType; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java ---------------------------------------------------------------------- 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 37ddaa1..be47754 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 @@ -16,6 +16,32 @@ // under the License. package com.cloud.hypervisor.vmware.resource; +import java.io.File; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.channels.SocketChannel; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TimeZone; +import java.util.UUID; + +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; @@ -47,7 +73,6 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.DeleteVMSnapshotAnswer; import com.cloud.agent.api.DeleteVMSnapshotCommand; -import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.GetDomRVersionAnswer; import com.cloud.agent.api.GetDomRVersionCmd; import com.cloud.agent.api.GetHostStatsAnswer; @@ -78,6 +103,7 @@ import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.PoolEjectCommand; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.RebootAnswer; @@ -85,8 +111,8 @@ import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.RevertToVMSnapshotAnswer; import com.cloud.agent.api.RevertToVMSnapshotCommand; -import com.cloud.agent.api.ScaleVmCommand; import com.cloud.agent.api.ScaleVmAnswer; +import com.cloud.agent.api.ScaleVmCommand; import com.cloud.agent.api.SetupAnswer; import com.cloud.agent.api.SetupCommand; import com.cloud.agent.api.SetupGuestNetworkAnswer; @@ -101,6 +127,7 @@ import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.api.UnPlugNicAnswer; import com.cloud.agent.api.UnPlugNicCommand; +import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.ValidateSnapshotAnswer; import com.cloud.agent.api.ValidateSnapshotCommand; @@ -135,14 +162,14 @@ import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; -import com.cloud.agent.api.storage.CreateVolumeOVACommand; -import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; -import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; -import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.CreateAnswer; import com.cloud.agent.api.storage.CreateCommand; import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ResizeVolumeAnswer; @@ -250,30 +277,6 @@ import com.vmware.vim25.VirtualMachineGuestOsIdentifier; import com.vmware.vim25.VirtualMachinePowerState; import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualSCSISharing; -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import javax.naming.ConfigurationException; -import java.io.File; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.URI; -import java.nio.channels.SocketChannel; -import java.rmi.RemoteException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.TimeZone; -import java.util.UUID; public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService { @@ -495,6 +498,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return execute((UnregisterVMCommand) cmd); } else if (clz == ScaleVmCommand.class) { return execute((ScaleVmCommand) cmd); + } else if (clz == PvlanSetupCommand.class) { + return execute((PvlanSetupCommand) cmd); } else { answer = Answer.createUnsupportedCommandAnswer(cmd); } @@ -1037,7 +1042,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String domrGIP = cmd.getAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP); String domrName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); String gw = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY); - String cidr = Long.toString(NetUtils.getCidrSize(nic.getNetmask()));; + String cidr = Long.toString(NetUtils.getCidrSize(nic.getNetmask())); String domainName = cmd.getNetworkDomain(); String dns = cmd.getDefaultDns1(); if (dns == null || dns.isEmpty()) { @@ -1376,7 +1381,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO nicTo = cmd.getNic(); VirtualDevice nic; - Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false); + Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, cmd.getVMType());; if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -1643,7 +1648,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, true); } else { networkInfo = HypervisorHostHelper.prepareNetwork(this._publicTrafficInfo.getVirtualSwitchName(), "cloud.public", - vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false); + vmMo.getRunningHost(), vlanId, null, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false); } int nicIndex = allocPublicNicIndex(vmMo); @@ -2537,7 +2542,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo)); boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); - Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus); + VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); + Pair<ManagedObjectReference, String> networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType); if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -2719,16 +2725,28 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return poolMors; } + + private String getPvlanInfo(NicTO nicTo) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { + return NetUtils.getIsolatedPvlanFromUri(nicTo.getBroadcastUri()); + } + return null; + } + private String getVlanInfo(NicTO nicTo, String defaultVlan) { if (nicTo.getBroadcastType() == BroadcastDomainType.Native) { return defaultVlan; } - - if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan || nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { if (nicTo.getBroadcastUri() != null) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan) + // For vlan, the broadcast uri is of the form vlan://<vlanid> return nicTo.getBroadcastUri().getHost(); + else + // for pvlan, the broacast uri will be of the form pvlan://<vlanid>-i<pvlanid> + return NetUtils.getPrimaryPvlanFromUri(nicTo.getBroadcastUri()); } else { - s_logger.warn("BroadcastType is not claimed as VLAN, but without vlan info in broadcast URI. Use vlan info from labeling: " + defaultVlan); + s_logger.warn("BroadcastType is not claimed as VLAN or PVLAN, but without vlan info in broadcast URI. Use vlan info from labeling: " + defaultVlan); return defaultVlan; } } @@ -2737,7 +2755,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return defaultVlan; } - private Pair<ManagedObjectReference, String> prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus) throws Exception { + private Pair<ManagedObjectReference, String> prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) throws Exception { Pair<String, String> switchName; TrafficType trafficType; VirtualSwitchType switchType; @@ -2761,12 +2779,22 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Prepare network on " + switchType + " " + switchName + " with name prefix: " + namePrefix); if (VirtualSwitchType.StandardVirtualSwitch == switchType) { - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), - nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, + networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, + hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, !namePrefix.startsWith("cloud.private")); } else { - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), + String vlanId = getVlanInfo(nicTo, switchName.second()); + String svlanId = null; + boolean pvlannetwork = (getPvlanInfo(nicTo) == null)?false:true; + if (vmType != null && vmType.equals(VirtualMachine.Type.DomainRouter) && pvlannetwork) { + // plumb this network to the promiscuous vlan. + svlanId = vlanId; + } else { + // plumb this network to the isolated vlan. + svlanId = getPvlanInfo(nicTo); + } + networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, vlanId, svlanId, nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus); } @@ -3253,7 +3281,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO[] nics = vm.getNics(); for (NicTO nic : nics) { // prepare network on the host - prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false); + prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); @@ -3917,6 +3945,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + protected Answer execute(PvlanSetupCommand cmd) { + // Pvlan related operations are performed in the start/stop command paths + // for vmware. This function is implemented to support mgmt layer code + // that issue this command. Note that pvlan operations are supported only + // in Distributed Virtual Switch environments for vmware deployments. + return new Answer(cmd, true, "success"); + } + protected Answer execute(UnregisterVMCommand cmd){ if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource UnregisterVMCommand: " + _gson.toJson(cmd)); @@ -4134,6 +4170,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + @Override public CreateVolumeOVAAnswer execute(CreateVolumeOVACommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource CreateVolumeOVACommand: " + _gson.toJson(cmd)); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/server/src/com/cloud/network/NetworkManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 01a0384d..c58ef22 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -3004,6 +3004,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Random _rand = new Random(System.currentTimeMillis()); + @Override public List<? extends Nic> listVmNics(Long vmId, Long nicId) { List<NicVO> result = null; if (nicId == null) { @@ -3014,6 +3015,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return result; } + @Override public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { String ipaddr = null; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 7007374..9992b7c 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -27,24 +27,6 @@ import java.util.TreeSet; import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.network.vpc.NetworkACLItem; -import com.cloud.network.vpc.NetworkACLItemDao; -import com.cloud.network.vpc.NetworkACLItemVO; -import com.cloud.network.vpc.NetworkACLManager; -import com.cloud.network.vpc.PrivateGateway; -import com.cloud.network.vpc.PrivateIpAddress; -import com.cloud.network.vpc.PrivateIpVO; -import com.cloud.network.vpc.StaticRoute; -import com.cloud.network.vpc.StaticRouteProfile; -import com.cloud.network.vpc.Vpc; -import com.cloud.network.vpc.VpcGateway; -import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.VpcVO; -import com.cloud.network.vpc.dao.PrivateIpDao; -import com.cloud.network.vpc.dao.StaticRouteDao; -import com.cloud.network.vpc.dao.VpcDao; -import com.cloud.network.vpc.dao.VpcGatewayDao; -import com.cloud.network.vpc.dao.VpcOfferingDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -108,6 +90,24 @@ import com.cloud.network.dao.Site2SiteCustomerGatewayVO; import com.cloud.network.dao.Site2SiteVpnConnectionDao; import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.NetworkACLItemDao; +import com.cloud.network.vpc.NetworkACLItemVO; +import com.cloud.network.vpc.NetworkACLManager; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.PrivateIpAddress; +import com.cloud.network.vpc.PrivateIpVO; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcGateway; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.PrivateIpDao; +import com.cloud.network.vpc.dao.StaticRouteDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcGatewayDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; @@ -127,7 +127,6 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile.Param; import com.cloud.vm.dao.VMInstanceDao; - @Component @Local(value = {VpcVirtualNetworkApplianceManager.class, VpcVirtualNetworkApplianceService.class}) public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplianceManagerImpl implements VpcVirtualNetworkApplianceManager{ @@ -339,7 +338,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian DomainRouterVO router = _routerDao.findById(vm.getId()); if (router.getState() == State.Running) { try { - PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName(), vm.getType()); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("plugnic", plugNicCmd); @@ -748,7 +747,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian // if (rule.getSourceCidrList() == null && (rule.getPurpose() == Purpose.Firewall || rule.getPurpose() == Purpose.NetworkACL)) { // _firewallDao.loadSourceCidrs((FirewallRuleVO)rule); // } - NetworkACLTO ruleTO = new NetworkACLTO((NetworkACLItemVO)rule, guestVlan, rule.getTrafficType()); + NetworkACLTO ruleTO = new NetworkACLTO(rule, guestVlan, rule.getTrafficType()); rulesTO.add(ruleTO); } } @@ -828,7 +827,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian _routerDao.update(routerVO.getId(), routerVO); } } - PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, publicNic.getNetworkId(), publicNic.getBroadcastUri().toString()), router.getInstanceName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, publicNic.getNetworkId(), publicNic.getBroadcastUri().toString()), router.getInstanceName(), router.getType()); cmds.addCommand(plugNicCmd); VpcVO vpc = _vpcDao.findById(router.getVpcId()); NetworkUsageCommand netUsageCmd = new NetworkUsageCommand(router.getPrivateIpAddress(), router.getInstanceName(), true, publicNic.getIp4Address(), vpc.getCidr()); @@ -851,7 +850,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian for (Pair<Nic, Network> nicNtwk : guestNics) { Nic guestNic = nicNtwk.first(); //plug guest nic - PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, guestNic.getNetworkId(), null), router.getInstanceName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, guestNic.getNetworkId(), null), router.getInstanceName(), router.getType()); cmds.addCommand(plugNicCmd); if (!_networkModel.isPrivateGateway(guestNic)) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/server/src/com/cloud/vm/UserVmManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7416cae..aa06529 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2898,6 +2898,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use originalIp = nic.getIp4Address(); guestNic = nic; guestNetwork = network; + // In vmware, we will be effecting pvlan settings in portgroups in StartCommand. + if (profile.getHypervisorType() != HypervisorType.VMware) { if (nic.getBroadcastUri().getScheme().equals("pvlan")) { if (!setupVmForPvlan(true, hostId, nic)) { return false; @@ -2905,6 +2907,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } } + } boolean ipChanged = false; if (originalIp != null && !originalIp.equalsIgnoreCase(returnedIp)) { if (returnedIp != null && guestNic != null) { @@ -4336,7 +4339,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use UserVmVO vmVO = _vmDao.findById(vm.getId()); if (vmVO.getState() == State.Running) { try { - PlugNicCommand plugNicCmd = new PlugNicCommand(nic,vm.getName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(nic,vm.getName(), vm.getType()); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("plugnic",plugNicCmd); _agentMgr.send(dest.getHost().getId(),cmds); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java index 247be2a..b00b97c 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java @@ -17,13 +17,20 @@ package com.cloud.hypervisor.vmware.mo; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.DVPortgroupConfigSpec; +import com.vmware.vim25.DVSConfigInfo; import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.TaskInfo; +import com.vmware.vim25.VMwareDVSConfigInfo; +import com.vmware.vim25.VMwareDVSConfigSpec; +import com.vmware.vim25.VMwareDVSPvlanMapEntry; public class DistributedVirtualSwitchMO extends BaseMO { private static final Logger s_logger = Logger.getLogger(DistributedVirtualSwitchMO.class); @@ -46,4 +53,74 @@ public class DistributedVirtualSwitchMO extends BaseMO { // TODO(sateesh): Update numPorts _context.getService().reconfigureDVPortgroupTask(dvPortGroupMor, dvPortGroupSpec); } + + public void updateVMWareDVSwitch(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception { + _context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec); + } + + public TaskInfo updateVMWareDVSwitchGetTask(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception { + ManagedObjectReference task = _context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec); + TaskInfo info = (TaskInfo) (_context.getVimClient().getDynamicProperty(task, "info")); + boolean waitvalue = _context.getVimClient().waitForTask(task); + return info; + } + + public String getDVSConfigVersion(ManagedObjectReference dvSwitchMor) throws Exception { + assert (dvSwitchMor != null); + DVSConfigInfo dvsConfigInfo = (DVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config"); + return dvsConfigInfo.getConfigVersion(); + } + + public Map<Integer, HypervisorHostHelper.PvlanType> retrieveVlanPvlan(int vlanid, int secondaryvlanid, ManagedObjectReference dvSwitchMor) throws Exception { + assert (dvSwitchMor != null); + + Map<Integer, HypervisorHostHelper.PvlanType> result = new HashMap<Integer, HypervisorHostHelper.PvlanType>(); + + VMwareDVSConfigInfo configinfo = (VMwareDVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config"); + List<VMwareDVSPvlanMapEntry> pvlanconfig = null; + pvlanconfig = configinfo.getPvlanConfig(); + + if (null == pvlanconfig || 0 == pvlanconfig.size()) { + return result; + } + // Iterate through the pvlanMapList and check if the specified vlan id and pvlan id exist. If they do, set the fields in result accordingly. + + for (VMwareDVSPvlanMapEntry mapEntry : pvlanconfig) { + int entryVlanid = mapEntry.getPrimaryVlanId(); + int entryPvlanid = mapEntry.getSecondaryVlanId(); + if (entryVlanid == entryPvlanid) { + // promiscuous + if (vlanid == entryVlanid) { + // pvlan type will always be promiscuous in this case. + result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } else if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) { + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + } else { + if (vlanid == entryVlanid) { + // vlan id in entry is promiscuous + result.put(vlanid, HypervisorHostHelper.PvlanType.promiscuous); + } else if (vlanid == entryPvlanid) { + result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) { + //promiscuous + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.promiscuous); + } else if (secondaryvlanid == entryPvlanid) { + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + + } + // If we already know that the vlanid is being used as a non primary vlan, it's futile to + // go over the entire list. Return. + if (result.containsKey(vlanid) && result.get(vlanid) != HypervisorHostHelper.PvlanType.promiscuous) + return result; + + // If we've already found both vlanid and pvlanid, we have enough info to make a decision. Return. + if (result.containsKey(vlanid) && result.containsKey(secondaryvlanid)) + return result; + } + return result; + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15be9777/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 7f323c5..20f8478 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -39,6 +39,7 @@ import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import com.vmware.vim25.AlreadyExistsFaultMsg; import com.vmware.vim25.BoolPolicy; import com.vmware.vim25.DVPortSetting; import com.vmware.vim25.DVPortgroupConfigInfo; @@ -59,7 +60,11 @@ import com.vmware.vim25.ObjectContent; import com.vmware.vim25.OvfCreateImportSpecParams; import com.vmware.vim25.OvfCreateImportSpecResult; import com.vmware.vim25.OvfFileItem; +import com.vmware.vim25.TaskInfo; +import com.vmware.vim25.VMwareDVSConfigSpec; import com.vmware.vim25.VMwareDVSPortSetting; +import com.vmware.vim25.VMwareDVSPvlanConfigSpec; +import com.vmware.vim25.VMwareDVSPvlanMapEntry; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualLsiLogicController; @@ -67,6 +72,7 @@ import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VirtualSCSISharing; +import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanSpec; @@ -124,12 +130,17 @@ public class HypervisorHostHelper { } } - public static String composeCloudNetworkName(String prefix, String vlanId, Integer networkRateMbps, String vSwitchName) { + public static String composeCloudNetworkName(String prefix, String vlanId, String svlanId, Integer networkRateMbps, String vSwitchName) { StringBuffer sb = new StringBuffer(prefix); - if(vlanId == null || UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) + if(vlanId == null || UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) { sb.append(".untagged"); - else + } else { sb.append(".").append(vlanId); + if (svlanId != null) { + sb.append(".").append("s" + svlanId); + } + + } if(networkRateMbps != null && networkRateMbps.intValue() > 0) sb.append(".").append(String.valueOf(networkRateMbps)); @@ -412,7 +423,7 @@ public class HypervisorHostHelper { */ public static Pair<ManagedObjectReference, String> prepareNetwork(String physicalNetwork, String namePrefix, - HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, + HostMO hostMo, String vlanId, String secondaryvlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, VirtualSwitchType vSwitchType, int numPorts, String gateway, boolean configureVServiceInNexus) throws Exception { ManagedObjectReference morNetwork = null; VmwareContext context = hostMo.getContext(); @@ -428,20 +439,28 @@ public class HypervisorHostHelper { boolean createGCTag = false; String networkName; Integer vid = null; + Integer spvlanid = null; // secondary pvlan id if(vlanId != null && !UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) { createGCTag = true; vid = Integer.parseInt(vlanId); } - networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, physicalNetwork); + if (secondaryvlanId != null) { + spvlanid = Integer.parseInt(secondaryvlanId); + } + networkName = composeCloudNetworkName(namePrefix, vlanId, secondaryvlanId, networkRateMbps, physicalNetwork); if (vSwitchType == VirtualSwitchType.VMwareDistributedVirtualSwitch) { + VMwareDVSConfigSpec dvsSpec = null; DVSTrafficShapingPolicy shapingPolicy; - VmwareDistributedVirtualSwitchVlanSpec vlanSpec; + VmwareDistributedVirtualSwitchVlanSpec vlanSpec = null; + VmwareDistributedVirtualSwitchPvlanSpec pvlanSpec = null; + //VMwareDVSPvlanConfigSpec pvlanSpec = null; DVSSecurityPolicy secPolicy; VMwareDVSPortSetting dvsPortSetting; DVPortgroupConfigSpec dvPortGroupSpec; DVPortgroupConfigInfo dvPortgroupInfo; + //DVSConfigInfo dvsInfo; dvSwitchName = physicalNetwork; // TODO(sateesh): Remove this after ensuring proper default value for vSwitchName throughout traffic types @@ -462,13 +481,95 @@ public class HypervisorHostHelper { dvSwitchMo = new DistributedVirtualSwitchMO(context, morDvSwitch); shapingPolicy = getDVSShapingPolicy(networkRateMbps); - if (vid != null) { - vlanSpec = createDVPortVlanIdSpec(vid); + secPolicy = createDVSSecurityPolicy(); + + // First, if both vlan id and pvlan id are provided, we need to + // reconfigure the DVSwitch to have a tuple <vlan id, pvlan id> of + // type isolated. + if (vid != null && spvlanid != null) { + // First check if the vlan/pvlan pair already exists on this dvswitch. + + Map<Integer, HypervisorHostHelper.PvlanType> vlanmap = dvSwitchMo.retrieveVlanPvlan(vid, spvlanid, morDvSwitch); + if (vlanmap.size() != 0) { + // Then either vid or pvlanid or both are already being used. + if (vlanmap.containsKey(vid) && vlanmap.get(vid) != HypervisorHostHelper.PvlanType.promiscuous) { + // This VLAN ID is already setup as a non-promiscuous vlan id on the DVS. Throw an exception. + String msg = "VLAN ID " + vid + " is already in use as a " + vlanmap.get(vid).toString() + " VLAN on the DVSwitch"; + s_logger.error(msg); + throw new Exception(msg); + } + if ((vid != spvlanid) && vlanmap.containsKey(spvlanid) && vlanmap.get(spvlanid) != HypervisorHostHelper.PvlanType.isolated) { + // This PVLAN ID is already setup as a non-isolated vlan id on the DVS. Throw an exception. + String msg = "PVLAN ID " + spvlanid + " is already in use as a " + vlanmap.get(spvlanid).toString() + " VLAN in the DVSwitch"; + s_logger.error(msg); + throw new Exception(msg); + } + } + + // First create a DVSconfig spec. + dvsSpec = new VMwareDVSConfigSpec(); + // Next, add the required primary and secondary vlan config specs to the dvs config spec. + if (!vlanmap.containsKey(vid)) { + VMwareDVSPvlanConfigSpec ppvlanConfigSpec = createDVPortPvlanConfigSpec(vid, vid, PvlanType.promiscuous, PvlanOperation.add); + dvsSpec.getPvlanConfigSpec().add(ppvlanConfigSpec); + } + if ( !vid.equals(spvlanid) && !vlanmap.containsKey(spvlanid)) { + VMwareDVSPvlanConfigSpec spvlanConfigSpec = createDVPortPvlanConfigSpec(vid, spvlanid, PvlanType.isolated, PvlanOperation.add); + dvsSpec.getPvlanConfigSpec().add(spvlanConfigSpec); + } + + if (dvsSpec.getPvlanConfigSpec().size() > 0) { + // We have something to configure on the DVS... so send it the command. + // When reconfiguring a vmware DVSwitch, we need to send in the configVersion in the spec. + // Let's retrieve this switch's configVersion first. + String dvsConfigVersion = dvSwitchMo.getDVSConfigVersion(morDvSwitch); + dvsSpec.setConfigVersion(dvsConfigVersion); + // Reconfigure the dvs using this spec. + + try { + TaskInfo reconfigTask = dvSwitchMo.updateVMWareDVSwitchGetTask(morDvSwitch, dvsSpec); + } catch (Exception e) { + if(e instanceof AlreadyExistsFaultMsg) { + s_logger.info("Specified vlan id (" + vid + ") private vlan id (" + spvlanid + ") tuple already configured on VMWare DVSwitch"); + // Do nothing, good if the tuple's already configured on the dvswitch. } else { + // Rethrow the exception + s_logger.error("Failed to configure vlan/pvlan tuple on VMware DVSwitch: " + vid + "/" + spvlanid + ", failure message: " + e.getMessage()); + e.printStackTrace(); + throw e; + } + } + } + // Else the vlan/pvlan pair already exists on the DVSwitch, and we needn't configure it again. + } + + // Next, create the port group. For this, we need to create a VLAN spec. + if (vid == null) { vlanSpec = createDVPortVlanSpec(); + } else { + if (spvlanid == null) { + // Create vlan spec. + vlanSpec = createDVPortVlanIdSpec(vid); + } else { + // Create a pvlan spec. The pvlan spec is different from the pvlan config spec + // that we created earlier. The pvlan config spec is used to configure the switch + // with a <primary vlanId, secondary vlanId> tuple. The pvlan spec is used + // to configure a port group (i.e., a network) with a secondary vlan id. We don't + // need to mention more than the secondary vlan id because one secondary vlan id + // can be associated with only one primary vlan id. Give vCenter the secondary vlan id, + // and it will find out the associated primary vlan id and do the rest of the + // port group configuration. + pvlanSpec = createDVPortPvlanIdSpec(spvlanid); } - secPolicy = createDVSSecurityPolicy(); + } + + // NOTE - VmwareDistributedVirtualSwitchPvlanSpec extends VmwareDistributedVirtualSwitchVlanSpec. + if (pvlanSpec != null) { + dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, pvlanSpec); + } else { dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, vlanSpec); + } + dvPortGroupSpec = createDvPortGroupSpec(networkName, dvsPortSetting, numPorts); if (!dataCenterMo.hasDvPortGroup(networkName)) { @@ -627,7 +728,6 @@ public class HypervisorHostHelper { dvsPortSetting.setSecurityPolicy(secPolicy); dvsPortSetting.setInShapingPolicy(shapingPolicy); dvsPortSetting.setOutShapingPolicy(shapingPolicy); - return dvsPortSetting; } @@ -658,6 +758,35 @@ public class HypervisorHostHelper { return shapingPolicy; } + public static VmwareDistributedVirtualSwitchPvlanSpec createDVPortPvlanIdSpec(int pvlanId) { + VmwareDistributedVirtualSwitchPvlanSpec pvlanIdSpec = new VmwareDistributedVirtualSwitchPvlanSpec(); + pvlanIdSpec.setPvlanId(pvlanId); + return pvlanIdSpec; + } + + public enum PvlanOperation { + add, + edit, + remove + } + + public enum PvlanType { + promiscuous, + isolated, + community, // We don't use Community + } + + public static VMwareDVSPvlanConfigSpec createDVPortPvlanConfigSpec(int vlanId, int secondaryVlanId, PvlanType pvlantype, PvlanOperation operation) { + VMwareDVSPvlanConfigSpec pvlanConfigSpec = new VMwareDVSPvlanConfigSpec(); + VMwareDVSPvlanMapEntry map = new VMwareDVSPvlanMapEntry(); + map.setPvlanType(pvlantype.toString()); + map.setPrimaryVlanId(vlanId); + map.setSecondaryVlanId(secondaryVlanId); + pvlanConfigSpec.setPvlanEntry(map); + + pvlanConfigSpec.setOperation(operation.toString()); + return pvlanConfigSpec; + } public static VmwareDistributedVirtualSwitchVlanIdSpec createDVPortVlanIdSpec(int vlanId) { VmwareDistributedVirtualSwitchVlanIdSpec vlanIdSpec = new VmwareDistributedVirtualSwitchVlanIdSpec(); vlanIdSpec.setVlanId(vlanId); @@ -706,7 +835,7 @@ public class HypervisorHostHelper { vid = Integer.parseInt(vlanId); } - networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, vSwitchName); + networkName = composeCloudNetworkName(namePrefix, vlanId, null, networkRateMbps, vSwitchName); HostNetworkSecurityPolicy secPolicy = null; if (namePrefix.equalsIgnoreCase("cloud.private")) { secPolicy = new HostNetworkSecurityPolicy(); @@ -1036,6 +1165,7 @@ public class HypervisorHostHelper { context.uploadVmdkFile(ovfFileItem.isCreate() ? "PUT" : "POST", urlToPost, absoluteFile, bytesAlreadyWritten, new ActionDelegate<Long> () { + @Override public void action(Long param) { progressReporter.reportProgress((int)(param * 100 / totalBytes)); }