You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ya...@apache.org on 2013/04/22 01:21:26 UTC

[1/2] git commit: updated refs/heads/pvlan to 4c0f775

Updated Branches:
  refs/heads/pvlan [created] 4c0f775e6


PVLAN: Add pvlan in createNetworkCommand


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/c26244d1
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/c26244d1
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/c26244d1

Branch: refs/heads/pvlan
Commit: c26244d18a4ae93614195b7f1945d174a35623d1
Parents: bb841d6
Author: Sheng Yang <sh...@citrix.com>
Authored: Thu Apr 11 17:39:39 2013 -0700
Committer: Sheng Yang <sh...@citrix.com>
Committed: Thu Apr 11 17:39:39 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/network/Networks.java            |    1 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../api/command/user/network/CreateNetworkCmd.java |    7 +++
 .../xen/resource/CitrixResourceBase.java           |    5 ++
 .../configuration/ConfigurationManagerImpl.java    |    2 +
 server/src/com/cloud/network/NetworkManager.java   |    3 +-
 .../src/com/cloud/network/NetworkManagerImpl.java  |   35 ++++++++++-----
 .../src/com/cloud/network/NetworkServiceImpl.java  |   13 +++++-
 .../src/com/cloud/network/vpc/VpcManagerImpl.java  |    2 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |    4 +-
 .../com/cloud/network/MockNetworkManagerImpl.java  |    2 +-
 .../test/com/cloud/vpc/MockNetworkManagerImpl.java |    3 +-
 utils/src/com/cloud/utils/net/NetUtils.java        |   26 +++++++++++
 utils/test/com/cloud/utils/net/NetUtilsTest.java   |    8 +++
 14 files changed, 93 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/api/src/com/cloud/network/Networks.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java
index f085e9f..5aede05 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;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index c518830..bd441eb 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -222,6 +222,7 @@ public class ApiConstants {
     public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";
     public static final String VLAN = "vlan";
     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";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
----------------------------------------------------------------------
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 fc7bd9f..7f699fe 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;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
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 c50f13c..e467dc7 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());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 8dbf081..a36a100 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -2410,6 +2410,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) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/src/com/cloud/network/NetworkManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java
index 851f7f5..d2d2d5c 100755
--- a/server/src/com/cloud/network/NetworkManager.java
+++ b/server/src/com/cloud/network/NetworkManager.java
@@ -127,7 +127,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;
 
     /**

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/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 a16288f..60dc1f0 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -1867,7 +1867,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);
@@ -1957,6 +1958,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 ){
@@ -2085,13 +2089,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<NetworkVO> networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId,
@@ -2675,7 +2686,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 " +
@@ -3516,8 +3527,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());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 4eb620c..7bb7188 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -813,6 +813,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);
@@ -999,6 +1000,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
@@ -1030,6 +1035,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) &&
@@ -1100,7 +1108,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) {
@@ -3214,7 +3223,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);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/src/com/cloud/network/vpc/VpcManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
index 3948f2e..e693273 100644
--- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1937,7 +1937,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;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/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 24bce8b..9edddb4 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -2143,7 +2143,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(
@@ -3807,7 +3807,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);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/test/com/cloud/network/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java
index 6da48ec..f1965a4 100755
--- a/server/test/com/cloud/network/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java
@@ -256,7 +256,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;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
index ead0051..9f455a6 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -848,7 +848,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;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/utils/src/com/cloud/utils/net/NetUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java
index 5988dd5..4dd404d 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;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c26244d1/utils/test/com/cloud/utils/net/NetUtilsTest.java
----------------------------------------------------------------------
diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java
index 28bd71f..16d3402 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"));
+    }
 }


[2/2] git commit: updated refs/heads/pvlan to 4c0f775

Posted by ya...@apache.org.
Implement PVLAN on Xen

Start/stop vm/dhcp server are done. Not done with VM migration.

A new command(PvlanSetupCommand) is sent for setting up PVLAN for vms. Currently
it's focus on OVS implementation. Need to be more abstruct and add vSwitch part.



Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/4c0f775e
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/4c0f775e
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/4c0f775e

Branch: refs/heads/pvlan
Commit: 4c0f775e6e8dc14a1f3646fb30211a6de15dd48d
Parents: c26244d
Author: Sheng Yang <sh...@citrix.com>
Authored: Thu Apr 11 17:39:57 2013 -0700
Committer: Sheng Yang <sh...@citrix.com>
Committed: Thu Apr 11 17:39:57 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/PvlanSetupCommand.java |  130 +++++++++++
 .../xen/resource/CitrixResourceBase.java           |   46 ++++-
 scripts/vm/hypervisor/xenserver/ovs-pvlan          |  168 +++++++++++++++
 scripts/vm/hypervisor/xenserver/xenserver60/patch  |    6 +-
 scripts/vm/network/ovs-pvlan-cleanup.sh            |   23 ++
 scripts/vm/network/ovs-pvlan-dhcp-host.sh          |  104 +++++++++
 scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh    |   88 ++++++++
 scripts/vm/network/ovs-pvlan-vm.sh                 |   90 ++++++++
 .../network/element/VirtualRouterElement.java      |   11 +
 .../router/VirtualNetworkApplianceManager.java     |    4 +
 .../router/VirtualNetworkApplianceManagerImpl.java |   87 +++++++-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |   45 ++++
 .../vpc/MockVpcVirtualNetworkApplianceManager.java |    7 +
 13 files changed, 804 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/api/src/com/cloud/agent/api/PvlanSetupCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java
new file mode 100644
index 0000000..22a828a
--- /dev/null
+++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java
@@ -0,0 +1,130 @@
+// 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.agent.api;
+
+import java.net.URI;
+
+import com.cloud.utils.net.NetUtils;
+
+public class PvlanSetupCommand extends Command {
+	public enum Type {
+		DHCP,
+		VM,
+		VM_IN_DHCP_HOST
+	}
+	private String op;
+	private String bridge;
+	private String primary;
+	private String isolated;
+	private String vmMac;
+	private String dhcpMac;
+	private String dhcpIp;
+	private boolean strict;
+	private Type type;
+
+	protected PvlanSetupCommand() {}
+	
+	protected PvlanSetupCommand(Type type, String op, String bridge, URI uri)
+	{
+		this.type = type;
+		this.op = op;
+		this.bridge = bridge;
+		this.primary = NetUtils.getPrimaryPvlanFromUri(uri);
+		this.isolated = NetUtils.getIsolatedPvlanFromUri(uri);
+		this.strict = true;
+	}
+	
+	static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpMac, String dhcpIp)
+	{
+		PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri);
+		cmd.setDhcpMac(dhcpMac);
+		cmd.setDhcpIp(dhcpIp);
+		return cmd;
+	}
+	
+	static public PvlanSetupCommand createVmSetup(String op, String bridge, URI uri, String vmMac)
+	{
+		PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, bridge, uri);
+		cmd.setVmMac(vmMac);
+		return cmd;
+	}
+	
+	static public PvlanSetupCommand createVmInDhcpHostSetup(String op, String bridge, URI uri, String dhcpMac, String vmMac)
+	{
+		PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM_IN_DHCP_HOST, op, bridge, uri);
+		cmd.setDhcpMac(dhcpMac);
+		cmd.setVmMac(vmMac);
+		return cmd;
+	}
+	
+	@Override
+	public boolean executeInSequence() {
+		return true;
+	}
+
+	public String getOp() {
+		return op;
+	}
+
+	public String getBridge() {
+		return bridge;
+	}
+
+	public String getPrimary() {
+		return primary;
+	}
+
+	public String getIsolated() {
+		return isolated;
+	}
+
+	public String getVmMac() {
+		return vmMac;
+	}
+
+	protected void setVmMac(String vmMac) {
+		this.vmMac = vmMac;
+	}
+
+	public String getDhcpMac() {
+		return dhcpMac;
+	}
+
+	protected void setDhcpMac(String dhcpMac) {
+		this.dhcpMac = dhcpMac;
+	}
+
+	public String getDhcpIp() {
+		return dhcpIp;
+	}
+
+	protected void setDhcpIp(String dhcpIp) {
+		this.dhcpIp = dhcpIp;
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+	public boolean isStrict() {
+		return strict;
+	}
+
+	public void setStrict(boolean strict) {
+		this.strict = strict;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
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 e467dc7..ab26c7a 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
@@ -604,6 +604,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             return execute((NetworkRulesVmSecondaryIpCommand)cmd);
         } else if (clazz == ScaleVmCommand.class) {
             return execute((ScaleVmCommand) cmd);
+        } else if (clazz == PvlanSetupCommand.class) {
+            return execute((PvlanSetupCommand) cmd);
         } else {
             return Answer.createUnsupportedCommandAnswer(cmd);
         }
@@ -1054,7 +1056,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             vifr = vif.getRecord(conn);
             s_logger.debug("Created a vif " + vifr.uuid + " on " + nic.getDeviceId());
         }
-
+        
         return vif;
     }
 
@@ -1465,6 +1467,48 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             }
         }
     }
+    
+    private Answer execute(PvlanSetupCommand cmd) {
+    	Connection conn = getConnection();
+    	
+    	String primaryPvlan = cmd.getPrimary();
+    	String isolatedPvlan = cmd.getIsolated();
+    	String op = cmd.getOp();
+    	String bridge = cmd.getBridge();
+    	String result = null;
+    	String dhcpMac = cmd.getDhcpMac();
+    	String dhcpIp = cmd.getDhcpIp();
+    	String vmMac = cmd.getVmMac();
+    	if (cmd.getType() == PvlanSetupCommand.Type.DHCP) {
+    		result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge,
+    				"primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac);
+    		if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
+    			s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac);
+    			return new Answer(cmd, false, result);
+    		} else {
+    			s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac);
+    		}
+    	} else if (cmd.getType() == PvlanSetupCommand.Type.VM) {
+    		result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-alone", "op", op, "bridge", bridge,
+    				"primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac);
+    		if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
+    			s_logger.warn("Failed to program pvlan for vm with mac " + vmMac);
+    			return new Answer(cmd, false, result);
+    		} else {
+    			s_logger.info("Programmed pvlan for vm with mac " + vmMac);
+    		}
+    	} else if (cmd.getType() == PvlanSetupCommand.Type.VM_IN_DHCP_HOST) {
+    		result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-dhcp", "op", op, "bridge", bridge,
+    				"primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac, "dhcp-mac", dhcpMac);
+    		if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
+    			s_logger.warn("Failed to program pvlan for vm in dhcp host with mac " + vmMac);
+    			return new Answer(cmd, false, result);
+    		} else {
+    			s_logger.info("Programmed pvlan for vm in dhcp host with mac " + vmMac);
+    		}
+    	}
+    	return new Answer(cmd, true, result);
+    }
 
     @Override
     public StartAnswer execute(StartCommand cmd) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/hypervisor/xenserver/ovs-pvlan
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan
new file mode 100755
index 0000000..2c1e3af
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# 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.
+
+
+import cloudstack_pluginlib as lib
+import logging
+import os
+import sys
+import subprocess
+import time
+import XenAPIPlugin
+
+sys.path.append("/opt/xensource/sm/")
+import util
+
+from time import localtime as _localtime, asctime as _asctime
+
+xePath = "/opt/xensource/bin/xe"
+lib.setup_logging("/var/log/ovs-pvlan.log")
+dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh"
+vmAloneSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh"
+vmDhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-vm-in-dhcp-host.sh"
+pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh"
+
+def echo(fn):
+    def wrapped(*v, **k):
+        name = fn.__name__
+        util.SMlog("#### VMOPS enter  %s ####" % name)
+        res = fn(*v, **k)
+        util.SMlog("#### VMOPS exit  %s ####" % name)
+        return res
+    return wrapped
+
+
+@echo
+def setup_pvlan_dhcp(session, args):
+    op = args.pop("op")
+    bridge = args.pop("bridge")
+    primary = args.pop("primary-pvlan")
+    isolated = args.pop("isolated-pvlan")
+    dhcp_ip = args.pop("dhcp-ip");
+    dhcp_mac = args.pop("dhcp-mac");
+
+    res = lib.check_switch()
+    if res != "SUCCESS":
+        return "FAILURE:%s" % res
+
+    if op == "add":
+        logging.debug("About to setup dhcp vm on the switch:%s" % bridge)
+        res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary,
+            "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Setup dhcp vm on switch program done")
+    elif op == "delete":
+        logging.debug("About to remove dhcp the switch:%s" % bridge)
+        res = lib.do_cmd([dhcpSetupPath, "-D", "-b", bridge, "-p", primary,
+            "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Remove DHCP on switch program done")
+    
+    result = "true"
+    logging.debug("Setup_pvlan_dhcp completed with result:%s" % result)
+    return result
+
+@echo
+def setup_pvlan_vm_alone(session, args):
+    op = args.pop("op")
+    bridge = args.pop("bridge")
+    isolated = args.pop("isolated-pvlan")
+    vm_mac = args.pop("vm-mac")
+    trunk_port = 1
+
+    res = lib.check_switch()
+    if res != "SUCCESS":
+        return "FAILURE:%s" % res
+
+    if op == "add":
+        logging.debug("About to setup vm alone on the switch:%s" % bridge)
+        res = lib.do_cmd([vmAloneSetupPath, "-A", "-b", bridge, "-i", isolated, "-v", vm_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Setup vm alone on switch program done")
+    elif op == "delete":
+        logging.debug("About to remove vm alone on the switch:%s" % bridge)
+        res = lib.do_cmd([vmAloneSetupPath, "-D", "-b", bridge, "-i", isolated, "-v", vm_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Remove vm alone on switch program done")
+
+    result = "true"
+    logging.debug("Setup_pvlan_vm_alone completed with result:%s" % result)
+    return result
+
+@echo
+def setup_pvlan_vm_dhcp(session, args):
+    op = args.pop("op")
+    bridge = args.pop("bridge")
+    isolated = args.pop("isolated-pvlan")
+    vm_mac = args.pop("vm-mac")
+    dhcp_mac = args.pop("dhcp-mac");
+    trunk_port = 1
+
+    res = lib.check_switch()
+    if res != "SUCCESS":
+        return "FAILURE:%s" % res
+
+    if op == "add":
+        logging.debug("About to setup vm dhcp on the switch:%s" % bridge)
+        res = lib.do_cmd([vmDhcpSetupPath, "-A", "-b", bridge, "-i", isolated,
+            "-v", vm_mac, "-m", dhcp_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Setup vm dhcp on switch program done")
+    elif op == "delete":
+        logging.debug("About to remove vm dhcp on the switch:%s" % bridge)
+        res = lib.do_cmd([vmDhcpSetupPath, "-D", "-b", bridge, "-i", isolated,
+            "-v", vm_mac, "-m", dhcp_mac])
+	if res:
+	    result = "FAILURE:%s" % res
+	    return result;
+	logging.debug("Remove vm dhcp on switch program done")
+
+    result = "true"
+    logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result)
+    return result
+
+@echo
+def cleanup(session, args):
+    res = lib.check_switch()
+    if res != "SUCCESS":
+        return "FAILURE:%s" % res
+
+    res = lib.do_cmd([pvlanCleanUpPath])
+    if res:
+        result = "FAILURE:%s" % res
+        return result;
+
+    result = "true"
+    logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result)
+    return result
+
+if __name__ == "__main__":
+    XenAPIPlugin.dispatch({"setup-pvlan-dhcp": setup_pvlan_dhcp,
+                           "setup-pvlan-vm-alone": setup_pvlan_vm_alone,
+                           "setup-pvlan-vm-dhcp": setup_pvlan_vm_dhcp,
+                           "cleanup":cleanup})

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/hypervisor/xenserver/xenserver60/patch
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch
index c9125f4..c767f1a 100644
--- a/scripts/vm/hypervisor/xenserver/xenserver60/patch
+++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch
@@ -67,4 +67,8 @@ bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin
 swift=..,0755,/opt/xensource/bin
 swiftxen=..,0755,/etc/xapi.d/plugins
 s3xen=..,0755,/etc/xapi.d/plugins
-
+ovs-pvlan=..,0755,/etc/xapi.d/plugins
+ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin
+ovs-pvlan-vm-in-dhcp-host.sh=../../../network,0755,/opt/xensource/bin
+ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin
+ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/network/ovs-pvlan-cleanup.sh
----------------------------------------------------------------------
diff --git a/scripts/vm/network/ovs-pvlan-cleanup.sh b/scripts/vm/network/ovs-pvlan-cleanup.sh
new file mode 100755
index 0000000..7493bed
--- /dev/null
+++ b/scripts/vm/network/ovs-pvlan-cleanup.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+#!/bin/bash
+
+ovs-ofctl del-flows xenbr0
+ovs-ofctl add-flow xenbr0 priority=0,actions=NORMAL
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/network/ovs-pvlan-dhcp-host.sh
----------------------------------------------------------------------
diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh
new file mode 100755
index 0000000..e12fbce
--- /dev/null
+++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh
@@ -0,0 +1,104 @@
+#!/bin/bash
+# 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.
+
+usage() {
+  printf "Usage: %s: (-A|-D) -b <bridge/switch> -p <primary vlan> -i <secondary isolated vlan> -d <DHCP server IP> -m <DHCP server MAC> -v <VM MAC> -h \n" $(basename $0) >&2
+  exit 2
+}
+
+br=
+pri_vlan=
+sec_iso_vlan=
+dhcp_ip=
+dhcp_mac=
+vm_mac=
+op=
+
+while getopts 'ADb:p:i:d:m:v:h' OPTION
+do
+  case $OPTION in
+  A)  op="add"
+      ;;
+  D)  op="del"
+      ;;
+  b)  br="$OPTARG"
+      ;;
+  p)  pri_vlan="$OPTARG"
+      ;;
+  i)  sec_iso_vlan="$OPTARG"
+      ;;
+  d)  dhcp_ip="$OPTARG"
+      ;;
+  m)  dhcp_mac="$OPTARG"
+      ;;
+  v)  vm_mac="$OPTARG"
+      ;;
+  h)  usage
+      exit 1
+      ;;
+  esac
+done
+
+if [ -z "$op" ]
+then
+    echo Missing operation pararmeter!
+    exit 1
+fi
+
+if [ -z "$br" ]
+then
+    echo Missing parameter bridge!
+    exit 1
+fi
+
+if [ -z "$pri_vlan" ]
+then
+    echo Missing parameter primary vlan!
+    exit 1
+fi
+
+if [ -z "$sec_iso_vlan" ]
+then
+    echo Missing parameter secondary isolate vlan!
+    exit 1
+fi
+
+if [ -z "$dhcp_ip" ]
+then
+    echo Missing parameter DHCP IP!
+    exit 1
+fi
+
+if [ -z "$dhcp_mac" ]
+then
+    echo Missing parameter DHCP MAC!
+    exit 1
+fi
+
+if [ "$op" == "add" ]
+then
+    ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=mod_vlan_vid:$pri_vlan,NORMAL
+    ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=NORMAL
+    ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=mod_vlan_vid:$pri_vlan,NORMAL
+    ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=mod_vlan_vid:$pri_vlan,NORMAL
+else
+    ovs-ofctl del-flows --strict $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip
+    ovs-ofctl del-flows --strict $br priority=180,arp,nw_dst=$dhcp_ip
+    ovs-ofctl del-flows --strict $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac
+    ovs-ofctl del-flows --strict $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67
+fi

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh
----------------------------------------------------------------------
diff --git a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh
new file mode 100755
index 0000000..de37882
--- /dev/null
+++ b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# 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.
+
+usage() {
+  printf "Usage: %s: (-A|-D) -b <bridge/switch> -p <primary vlan> -i <secondary isolated vlan> -d <DHCP server IP> -m <DHCP server MAC> -v <VM MAC> -h \n" $(basename $0) >&2
+  exit 2
+}
+
+br=
+pri_vlan=
+sec_iso_vlan=
+dhcp_ip=
+dhcp_mac=
+vm_mac=
+op=
+
+while getopts 'ADb:p:i:d:m:v:h' OPTION
+do
+  case $OPTION in
+  A)  op="add"
+      ;;
+  D)  op="del"
+      ;;
+  b)  br="$OPTARG"
+      ;;
+  p)  pri_vlan="$OPTARG"
+      ;;
+  i)  sec_iso_vlan="$OPTARG"
+      ;;
+  d)  dhcp_ip="$OPTARG"
+      ;;
+  m)  dhcp_mac="$OPTARG"
+      ;;
+  v)  vm_mac="$OPTARG"
+      ;;
+  h)  usage
+      exit 1
+      ;;
+  esac
+done
+
+if [ -z "$op" ]
+then
+    echo Missing operation pararmeter!
+    exit 1
+fi
+
+if [ -z "$br" ]
+then
+    echo Missing parameter bridge!
+    exit 1
+fi
+
+if [ -z "$vm_mac" ]
+then
+    echo Missing parameter VM MAC!
+    exit 1
+fi
+
+if [ -z "$dhcp_mac" ]
+then
+    echo Missing parameter DHCP MAC!
+    exit 1
+fi
+
+if [ "$op" == "add" ]
+then
+    ovs-ofctl add-flow $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac,actions=NORMAL
+    ovs-ofctl add-flow $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67,actions=NORMAL
+else
+    ovs-ofctl del-flows --strict $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac
+    ovs-ofctl del-flows --strict $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67
+fi

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/scripts/vm/network/ovs-pvlan-vm.sh
----------------------------------------------------------------------
diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh
new file mode 100755
index 0000000..8ac20df
--- /dev/null
+++ b/scripts/vm/network/ovs-pvlan-vm.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+# 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.
+
+usage() {
+  printf "Usage: %s: (-A|-D) -b <bridge/switch> -p <primary vlan> -i <secondary isolated vlan> -d <DHCP server IP> -m <DHCP server MAC> -v <VM MAC> -h \n" $(basename $0) >&2
+  exit 2
+}
+
+br=
+pri_vlan=
+sec_iso_vlan=
+dhcp_ip=
+dhcp_mac=
+vm_mac=
+op=
+
+while getopts 'ADb:p:i:d:m:v:h' OPTION
+do
+  case $OPTION in
+  A)  op="add"
+      ;;
+  D)  op="del"
+      ;;
+  b)  br="$OPTARG"
+      ;;
+  p)  pri_vlan="$OPTARG"
+      ;;
+  i)  sec_iso_vlan="$OPTARG"
+      ;;
+  d)  dhcp_ip="$OPTARG"
+      ;;
+  m)  dhcp_mac="$OPTARG"
+      ;;
+  v)  vm_mac="$OPTARG"
+      ;;
+  h)  usage
+      exit 1
+      ;;
+  esac
+done
+
+if [ -z "$op" ]
+then
+    echo Missing operation pararmeter!
+    exit 1
+fi
+
+if [ -z "$br" ]
+then
+    echo Missing parameter bridge!
+    exit 1
+fi
+
+if [ -z "$vm_mac" ]
+then
+    echo Missing parameter VM MAC!
+    exit 1
+fi
+
+if [ -z "$sec_iso_vlan" ]
+then
+    echo Missing parameter secondary isolate vlan!
+    exit 1
+fi
+
+trunk_port=1
+
+if [ "$op" == "add" ]
+then
+    ovs-ofctl add-flow $br priority=50,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,output:$trunk_port
+else
+    # it would delete any rule related to this vm, not only the rule added above
+    ovs-ofctl del-flows $br dl_src=$vm_mac
+fi
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/server/src/com/cloud/network/element/VirtualRouterElement.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java
index 169db32..7f956e5 100755
--- a/server/src/com/cloud/network/element/VirtualRouterElement.java
+++ b/server/src/com/cloud/network/element/VirtualRouterElement.java
@@ -31,6 +31,7 @@ import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElement
 import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd;
 import org.apache.log4j.Logger;
 
+import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.agent.api.to.LoadBalancerTO;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.dao.ConfigurationDao;
@@ -48,6 +49,7 @@ import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkModel;
+import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.PhysicalNetworkServiceProvider;
 import com.cloud.network.PublicIpAddress;
@@ -214,6 +216,15 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl
                     DataCenter.class, network.getDataCenterId());
         }
         
+        // Setup PVlan for vm if necessary
+        if (network.getTrafficType() == TrafficType.Guest && network.getBroadcastDomainType() == BroadcastDomainType.Pvlan) {
+        	assert routers.size() == 1;
+        	DomainRouterVO router = routers.get(0);
+        	if (router.getHostId() == dest.getHost().getId()) {
+        		_routerMgr.setupVmWithDhcpHostForPvlan(true, router, nic);
+        	}
+        }
+        
         return true;      
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java
index f49ab79..4dfd78c 100644
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java
@@ -19,6 +19,7 @@ package com.cloud.network.router;
 import java.util.List;
 import java.util.Map;
 
+import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -35,6 +36,7 @@ import com.cloud.user.User;
 import com.cloud.uservm.UserVm;
 import com.cloud.utils.component.Manager;
 import com.cloud.vm.DomainRouterVO;
+import com.cloud.vm.Nic;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.VirtualMachineProfile;
 
@@ -103,4 +105,6 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA
 	
 	boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile<UserVm> vm, DeployDestination dest, 
 	        List<DomainRouterVO> routers) throws ResourceUnavailableException;
+
+	void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException;
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index afdbbca..c9ce83c 100755
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -61,6 +61,7 @@ import com.cloud.agent.api.GetDomRVersionCmd;
 import com.cloud.agent.api.ModifySshKeysCommand;
 import com.cloud.agent.api.NetworkUsageAnswer;
 import com.cloud.agent.api.NetworkUsageCommand;
+import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StopAnswer;
 import com.cloud.agent.api.check.CheckSshAnswer;
@@ -2196,6 +2197,72 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
         return dhcpRange;
     }
 
+    private boolean setupDhcpForPvlanOnHost(boolean add, DomainRouterVO router, Nic routerNic) {
+    	if (!routerNic.getBroadcastUri().getScheme().equals("pvlan")) {
+    		return false;
+    	}
+    	setupDhcpForPvlan(add, router, routerNic);
+    	Long hostId = router.getHostId();
+    	List<UserVmVO> vms = _userVmDao.listByHostId(hostId);
+    	for (UserVmVO vm : vms) {
+    		if (vm.getState() != State.Running) {
+    			continue;
+    		}
+    		List<NicVO> nics = _nicDao.listByVmId(vm.getId());
+    		for (NicVO nic : nics) {
+    			if (nic.getNetworkId() == routerNic.getNetworkId()) {
+    				try {
+    					Network network = _networkDao.findById(routerNic.getNetworkId());
+    					NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), 
+    							null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network));
+						setupVmWithDhcpHostForPvlan(add, router, profile);
+					} catch (ResourceUnavailableException e) {
+						s_logger.warn("Fail to program pvlan on nic " + nic.getMacAddress(), e);
+						return false;
+					}
+    			}
+    		}
+    	}
+    	return true;
+    }
+    
+    private boolean setupDhcpForPvlan(boolean add, DomainRouterVO router, Nic nic) {
+    	if (!nic.getBroadcastUri().getScheme().equals("pvlan")) {
+    		return false;
+    	}
+    	String op = "add";
+    	if (!add) {
+    		op = "delete";
+    	}
+    	PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress(), nic.getIp4Address());
+    	Commands cmds = new Commands(cmd);
+    	// In fact we send command to the host of router, we're not programming router but the host
+    	try {
+			sendCommandsToRouter(router, cmds);
+		} catch (AgentUnavailableException e) {
+            s_logger.warn("Agent Unavailable ", e);
+			return false;
+		}
+    	return true;
+    }
+    
+    @Override
+    public void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException
+    {
+    	if (!profile.getBroadCastUri().getScheme().equals("pvlan")) {
+    		return;
+    	}
+    	String op = "add";
+    	if (!add) {
+    		op = "delete";
+    	}
+    	NicVO routerNic = _nicDao.findByInstanceIdAndNetworkId(profile.getNetworkId(), router.getId());
+    	PvlanSetupCommand cmd = PvlanSetupCommand.createVmInDhcpHostSetup(op, "xenbr0", profile.getBroadCastUri(), routerNic.getMacAddress(), profile.getMacAddress());
+    	Commands cmds = new Commands(cmd);
+    	// In fact we send command to the host of router, we're not programming router but the host
+    	sendCommandsToRouter(router, cmds);
+    }
+    
     @Override
     public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, 
             DeployDestination dest, ReservationContext context) throws ResourceUnavailableException {
@@ -2491,11 +2558,18 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
         List<Network> guestNetworks = new ArrayList<Network>();
         
         List<? extends Nic> routerNics = _nicDao.listByVmId(profile.getId());
-        for (Nic routerNic : routerNics) {
-            Network network = _networkModel.getNetwork(routerNic.getNetworkId());
+        for (Nic nic : routerNics) {
+        	Network network = _networkModel.getNetwork(nic.getNetworkId());
             if (network.getTrafficType() == TrafficType.Guest) {
                 guestNetworks.add(network);
-            } 
+                if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
+                	result = setupDhcpForPvlanOnHost(true, router, nic);
+                }
+            }
+        }
+        
+        if (!result) {
+        	return result;
         }
         
         answer = cmds.getAnswer("getDomRVersion");
@@ -2523,6 +2597,13 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
             VMInstanceVO vm = profile.getVirtualMachine();
             DomainRouterVO domR = _routerDao.findById(vm.getId());
             processStopOrRebootAnswer(domR, answer);
+            List<? extends Nic> routerNics = _nicDao.listByVmId(profile.getId());
+            for (Nic nic : routerNics) {
+            	Network network = _networkModel.getNetwork(nic.getNetworkId());
+            	if (network.getTrafficType() == TrafficType.Guest && nic.getBroadcastUri().getScheme().equals("pvlan")) {
+            		setupDhcpForPvlanOnHost(false, domR, nic);
+            	}
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/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 9edddb4..ae9c7c7 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -53,6 +53,7 @@ import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.PlugNicAnswer;
 import com.cloud.agent.api.PlugNicCommand;
+import com.cloud.agent.api.PvlanSetupCommand;
 import com.cloud.agent.api.StartAnswer;
 import com.cloud.agent.api.StopAnswer;
 import com.cloud.agent.api.UnPlugNicAnswer;
@@ -2681,6 +2682,34 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         return true;
     }
 
+    private boolean setupVmForPvlan(boolean add, Long hostId, NicVO nic) {
+        if (!nic.getBroadcastUri().getScheme().equals("pvlan")) {
+    		return false;
+    	}
+        String op = "add";
+        if (!add) {
+        	// "delete" would remove all the rules(if using ovs) related to this vm
+        	op = "delete";
+        }
+    	PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress());
+        Answer answer = null;
+        try {
+            answer = _agentMgr.send(hostId, cmd);
+        } catch (OperationTimedoutException e) {
+            s_logger.warn("Timed Out", e);
+            return false;
+        } catch (AgentUnavailableException e) {
+            s_logger.warn("Agent Unavailable ", e);
+            return false;
+        }
+
+        boolean result = true;
+        if (answer == null || !answer.getResult()) {
+        	result = false;
+        }
+        return result;
+    }
+    
     @Override
     public boolean finalizeDeployment(Commands cmds,
             VirtualMachineProfile<UserVmVO> profile, DeployDestination dest,
@@ -2742,6 +2771,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                 originalIp = nic.getIp4Address();
                 guestNic = nic;
                 guestNetwork = network;
+                if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
+                	if (!setupVmForPvlan(true, hostId, nic)) {
+                		return false;
+                	}
+                }
             }
         }
         boolean ipChanged = false;
@@ -2865,6 +2899,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                                 + " stop due to exception ", ex);
             }
         }
+        
+        VMInstanceVO vm = profile.getVirtualMachine();
+        List<NicVO> nics = _nicDao.listByVmId(vm.getId());
+        for (NicVO nic : nics) {
+            NetworkVO network = _networkDao.findById(nic.getNetworkId());
+            if (network.getTrafficType() == TrafficType.Guest) {
+                if (nic.getBroadcastUri().getScheme().equals("pvlan")) {
+                	setupVmForPvlan(false, vm.getHostId(), nic);
+                }
+            }
+        }
     }
 
     public String generateRandomPassword() {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c0f775e/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java
index ef5478b..5278b33 100644
--- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java
+++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java
@@ -402,4 +402,11 @@ VpcVirtualNetworkApplianceService {
         return null;
     }
 
+	@Override
+	public void setupVmWithDhcpHostForPvlan(boolean add,
+			DomainRouterVO router, NicProfile nic) throws ResourceUnavailableException {
+		// TODO Auto-generated method stub
+		
+	}
+
 }