From 9c9e2ec9ccd2609246610c798d4a8d8f3bc5aee7 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 01/12] PVLAN: Add pvlan in createNetworkCommand --- api/src/com/cloud/network/Networks.java | 1 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../user/network/CreateNetworkCmd.java | 7 ++++ .../xen/resource/CitrixResourceBase.java | 5 +++ .../ConfigurationManagerImpl.java | 2 ++ .../src/com/cloud/network/NetworkManager.java | 3 +- .../com/cloud/network/NetworkManagerImpl.java | 35 +++++++++++++------ .../com/cloud/network/NetworkServiceImpl.java | 13 +++++-- .../com/cloud/network/vpc/VpcManagerImpl.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 4 +-- .../cloud/network/MockNetworkManagerImpl.java | 2 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 3 +- utils/src/com/cloud/utils/net/NetUtils.java | 26 ++++++++++++++ .../com/cloud/utils/net/NetUtilsTest.java | 8 +++++ 14 files changed, 93 insertions(+), 19 deletions(-) diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index f085e9f3029..5aede053d50 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -63,6 +63,7 @@ public class Networks { Storage("storage", Integer.class), Lswitch("lswitch", String.class), Mido("mido", String.class), + Pvlan("pvlan", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1165c7b34f6..9581f54ca61 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -223,6 +223,7 @@ public class ApiConstants { public static final String VLAN = "vlan"; public static final String REMOVE_VLAN="removevlan"; public static final String VLAN_ID = "vlanid"; + public static final String ISOLATED_PVLAN = "isolatedpvlan"; public static final String VM_AVAILABLE = "vmavailable"; public static final String VM_LIMIT = "vmlimit"; public static final String VM_TOTAL = "vmtotal"; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index fc7bd9fdd3f..7f699fe0cc9 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -86,6 +86,9 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network") private String vlan; + @Parameter(name=ApiConstants.ISOLATED_PVLAN, type=CommandType.STRING, description="the isolated private vlan for this network") + private String isolatedPvlan; + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="network domain") private String networkDomain; @@ -141,6 +144,10 @@ public class CreateNetworkCmd extends BaseCmd { return vlan; } + public String getIsolatedPvlan() { + return isolatedPvlan; + } + public String getAccountName() { return accountName; } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 46ae35a4a54..176dc00ec0e 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1014,6 +1014,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else if (nic.getBroadcastType() == BroadcastDomainType.Lswitch) { // Nicira Logical Switch return network.getNetwork(); + } else if (nic.getBroadcastType() == BroadcastDomainType.Pvlan) { + URI broadcastUri = nic.getBroadcastUri(); + assert broadcastUri.getScheme().equals(BroadcastDomainType.Pvlan.scheme()); + long vlan = Long.parseLong(NetUtils.getPrimaryPvlanFromUri(broadcastUri)); + return enableVlanNetwork(conn, vlan, network); } throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri()); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 37ca793c556..a47f3b3c80f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2505,6 +2505,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (uri != null) { String[] vlan = uri.toString().split("vlan:\\/\\/"); networkVlanId = vlan[1]; + //For pvlan + networkVlanId = networkVlanId.split("-")[0]; } if (vlanId != null) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 4af716ca12a..e11135161db 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -128,7 +128,8 @@ public interface NetworkManager { Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, - long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) + long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, + String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; /** diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 5179e872686..7a09eb553f8 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1874,7 +1874,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @DB public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String ip6Gateway, String ip6Cidr, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1964,6 +1965,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (ipv6) { throw new InvalidParameterValueException("IPv6 is not supported with security group!"); } + if (isolatedPvlan != null) { + throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!"); + } // Only Account specific Isolated network with sourceNat service disabled are allowed in security group // enabled zone if ( ntwkOff.getGuestType() != GuestType.Shared ){ @@ -2094,13 +2098,20 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } if (vlanId != null) { - userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); - userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); - if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { - userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); - } else { - userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); - } + if (isolatedPvlan == null) { + userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); + if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); + } else { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); + } + } else { + if (vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!"); + } + userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanId, isolatedPvlan)); + userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan); + } } List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, @@ -2697,7 +2708,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guestNetwork = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network" , owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork, zoneId, ACLType.Account, - null, null, null, null); + null, null, null, null, null); if (guestNetwork == null) { s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " + @@ -3551,8 +3562,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); - nic.setBroadcastType(BroadcastDomainType.Vlan); - nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + //nic.setBroadcastType(BroadcastDomainType.Vlan); + //nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + nic.setBroadcastType(network.getBroadcastDomainType()); + nic.setBroadcastUri(network.getBroadcastUri()); nic.setFormat(AddressFormat.Ip4); nic.setReservationId(String.valueOf(ip.getVlanTag())); nic.setMacAddress(ip.getMacAddress()); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 2dcb47d0cd8..7c4d7027c6b 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -828,6 +828,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); + String isolatedPvlan = cmd.getIsolatedPvlan(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1014,6 +1015,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } + if (isolatedPvlan != null && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared)) { + throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!"); + } + // Regular user can create Guest Isolated Source Nat enabled network only if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated @@ -1045,6 +1050,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) { throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!"); } + if (isolatedPvlan != null && providersConfiguredForExternalNetworking(ntwkProviders)) { + throw new InvalidParameterValueException("Cannot support private vlan on network offering with external devices!"); + } if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && @@ -1115,7 +1123,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); } network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr); + networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, + ip6Gateway, ip6Cidr, isolatedPvlan); } if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) { @@ -3363,7 +3372,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (privateNetwork == null) { //create Guest network privateNetwork = _networkMgr.createGuestNetwork(ntwkOff.getId(), networkName, displayText, gateway, cidr, vlan, - null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null, null, null); + null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null, null, null, null); s_logger.debug("Created private network " + privateNetwork); } else { s_logger.debug("Private network already exists: " + privateNetwork); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index bc7bb0c75f2..18690d72ed5 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1965,7 +1965,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis //2) Create network Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null); + networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null, null); return guestNetwork; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 617994888bd..8f2d103d343 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2164,7 +2164,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use s_logger.debug("Creating network for account " + owner + " from the network offering id=" +requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null, - null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); + null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, null); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException( @@ -4005,7 +4005,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, - null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); + null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, null); // if the network offering has persistent set to true, implement the network if (requiredOfferings.get(0).getIsPersistent()) { DeployDestination dest = new DeployDestination(zone, null, null, null); diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index e9987bd1b66..3381d60c564 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -249,7 +249,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 9b18358e258..7dcc970405b 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -831,7 +831,8 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String gatewayv6, String cidrv6, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 5988dd5f337..4dd404d4cc3 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Formatter; @@ -1290,4 +1291,29 @@ public class NetUtils { } return resultIp; } + + public static URI generateUriForPvlan(String primaryVlan, String isolatedPvlan) { + return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan); + } + + public static String getPrimaryPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 1) { + return null; + } + return vlans[0]; + } + + public static String getIsolatedPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 2) { + return null; + } + for (String vlan : vlans) { + if (vlan.startsWith("i")) { + return vlan.replace("i", " ").trim(); + } + } + return null; + } } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 28bd71f18d7..16d3402f0e6 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -17,6 +17,7 @@ package com.cloud.utils.net; import java.math.BigInteger; +import java.net.URI; import java.util.SortedSet; import java.util.TreeSet; @@ -128,4 +129,11 @@ public class NetUtilsTest extends TestCase { assertFalse(NetUtils.isIp6InRange("1234:5678:abcd::1", null)); assertTrue(NetUtils.isIp6InRange("1234:5678:abcd::1", "1234:5678::1-1234:5679::1")); } + + public void testPvlan() { + URI uri = NetUtils.generateUriForPvlan("123", "456"); + assertTrue(uri.toString().equals("pvlan://123-i456")); + assertTrue(NetUtils.getPrimaryPvlanFromUri(uri).equals("123")); + assertTrue(NetUtils.getIsolatedPvlanFromUri(uri).equals("456")); + } } From b64039bafd194be78f0a873d4b2431d01931febf Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 02/12] 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. --- .../cloud/agent/api/PvlanSetupCommand.java | 130 ++++++++++++++ .../xen/resource/CitrixResourceBase.java | 46 ++++- scripts/vm/hypervisor/xenserver/ovs-pvlan | 168 ++++++++++++++++++ .../vm/hypervisor/xenserver/xenserver60/patch | 6 +- scripts/vm/network/ovs-pvlan-cleanup.sh | 23 +++ scripts/vm/network/ovs-pvlan-dhcp-host.sh | 104 +++++++++++ .../vm/network/ovs-pvlan-vm-in-dhcp-host.sh | 88 +++++++++ scripts/vm/network/ovs-pvlan-vm.sh | 90 ++++++++++ .../network/element/VirtualRouterElement.java | 11 ++ .../VirtualNetworkApplianceManager.java | 4 + .../VirtualNetworkApplianceManagerImpl.java | 87 ++++++++- .../src/com/cloud/vm/UserVmManagerImpl.java | 45 +++++ ...MockVpcVirtualNetworkApplianceManager.java | 7 + 13 files changed, 804 insertions(+), 5 deletions(-) create mode 100644 api/src/com/cloud/agent/api/PvlanSetupCommand.java create mode 100755 scripts/vm/hypervisor/xenserver/ovs-pvlan create mode 100755 scripts/vm/network/ovs-pvlan-cleanup.sh create mode 100755 scripts/vm/network/ovs-pvlan-dhcp-host.sh create mode 100755 scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh create mode 100755 scripts/vm/network/ovs-pvlan-vm.sh 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 00000000000..22a828afa8b --- /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; + } +} 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 176dc00ec0e..34b590e40c9 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) { diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan new file mode 100755 index 00000000000..2c1e3af8f77 --- /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}) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index c9125f4c5b2..c767f1af7df 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 diff --git a/scripts/vm/network/ovs-pvlan-cleanup.sh b/scripts/vm/network/ovs-pvlan-cleanup.sh new file mode 100755 index 00000000000..7493bedeff6 --- /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 + 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 00000000000..e12fbce0f18 --- /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 -p -i -d -m -v -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 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 00000000000..de37882159c --- /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 -p -i -d -m -v -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 diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh new file mode 100755 index 00000000000..8ac20df5ad1 --- /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 -p -i -d -m -v -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 + diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index f601f4fa2e4..d9c43567d06 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; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index f49ab79b500..4dfd78c2a52 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 vm, DeployDestination dest, List routers) throws ResourceUnavailableException; + + void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 6620e0a6379..bb31e1cf5e8 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -62,6 +62,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; @@ -2210,6 +2211,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 vms = _userVmDao.listByHostId(hostId); + for (UserVmVO vm : vms) { + if (vm.getState() != State.Running) { + continue; + } + List 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 profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { @@ -2505,11 +2572,18 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List guestNetworks = new ArrayList(); List 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"); @@ -2537,6 +2611,13 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V VMInstanceVO vm = profile.getVirtualMachine(); DomainRouterVO domR = _routerDao.findById(vm.getId()); processStopOrRebootAnswer(domR, answer); + List 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); + } + } } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8f2d103d343..7a9fc4731e7 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -69,6 +69,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; @@ -2751,6 +2752,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 profile, DeployDestination dest, @@ -2812,6 +2841,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; @@ -2942,6 +2976,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " stop due to exception ", ex); } } + + VMInstanceVO vm = profile.getVirtualMachine(); + List 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() { diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index ef5478bb1f8..5278b339e19 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 + + } + } From 05885457ecc32e4714914056c11244e0d021bf50 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 03/12] PVLAN: Simplify OVS policy We can resubmit the packet against the flow table to get simplier result. Now we don't need to check if VM is in the same host as DHCP server or not. --- .../cloud/agent/api/PvlanSetupCommand.java | 25 ++---- .../xen/resource/CitrixResourceBase.java | 18 ++-- .../hypervisor/xenserver/ovs-get-dhcp-port.sh | 26 ++++++ scripts/vm/hypervisor/xenserver/ovs-pvlan | 68 ++++---------- .../vm/hypervisor/xenserver/xenserver60/patch | 2 +- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 34 +++++-- .../vm/network/ovs-pvlan-vm-in-dhcp-host.sh | 88 ------------------- scripts/vm/network/ovs-pvlan-vm.sh | 15 +++- .../network/element/VirtualRouterElement.java | 10 --- .../VirtualNetworkApplianceManager.java | 2 - .../VirtualNetworkApplianceManagerImpl.java | 53 +---------- ...MockVpcVirtualNetworkApplianceManager.java | 8 -- 12 files changed, 104 insertions(+), 245 deletions(-) create mode 100644 scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh delete mode 100755 scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index 22a828afa8b..e5d4da09003 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -23,17 +23,16 @@ import com.cloud.utils.net.NetUtils; public class PvlanSetupCommand extends Command { public enum Type { DHCP, - VM, - VM_IN_DHCP_HOST + VM } private String op; private String bridge; private String primary; private String isolated; private String vmMac; + private String dhcpName; private String dhcpMac; private String dhcpIp; - private boolean strict; private Type type; protected PvlanSetupCommand() {} @@ -45,12 +44,12 @@ public class PvlanSetupCommand extends Command { 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) + static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpName, String dhcpMac, String dhcpIp) { PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri); + cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; @@ -63,14 +62,6 @@ public class PvlanSetupCommand extends Command { 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; @@ -120,11 +111,11 @@ public class PvlanSetupCommand extends Command { return type; } - public boolean isStrict() { - return strict; + public String getDhcpName() { + return dhcpName; } - public void setStrict(boolean strict) { - this.strict = strict; + public void setDhcpName(String dhcpName) { + this.dhcpName = dhcpName; } } 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 34b590e40c9..933f4d33eff 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 @@ -1475,13 +1475,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String isolatedPvlan = cmd.getIsolated(); String op = cmd.getOp(); String bridge = cmd.getBridge(); - String result = null; + String dhcpName = cmd.getDhcpName(); String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + + String result = null; 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); + "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-name", dhcpName, + "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); @@ -1489,7 +1492,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe 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, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "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); @@ -1497,15 +1500,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } 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); } diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh new file mode 100644 index 00000000000..a30b180bed0 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh @@ -0,0 +1,26 @@ +#!/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 + +bridge=$1 +dhcp_name=$2 +dom_id=`xe vm-list is-control-domain=false power-state=running params=dom-id name-label=$dhcp_name|cut -d ':' -f 2 |tr -d ' ' ` +iface="vif${dom_id}.0" +port=`ovs-ofctl show $bridge|grep $iface|cut -d '(' -f 1|tr -d ' '` +echo $port diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 2c1e3af8f77..372d3c8d05b 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -33,8 +33,8 @@ 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" +vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" +getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" def echo(fn): @@ -53,17 +53,21 @@ def setup_pvlan_dhcp(session, args): 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"); + dhcp_name = args.pop("dhcp-name") + 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("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) + dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) 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]) + "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac, + "-P", dhcp_port]) if res: result = "FAILURE:%s" % res return result; @@ -71,7 +75,7 @@ def setup_pvlan_dhcp(session, args): 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]) + "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac]) if res: result = "FAILURE:%s" % res return result; @@ -82,9 +86,10 @@ def setup_pvlan_dhcp(session, args): return result @echo -def setup_pvlan_vm_alone(session, args): +def setup_pvlan_vm(session, args): op = args.pop("op") bridge = args.pop("bridge") + primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") vm_mac = args.pop("vm-mac") trunk_port = 1 @@ -94,58 +99,24 @@ def setup_pvlan_vm_alone(session, args): 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]) + logging.debug("About to setup vm on the switch:%s" % bridge) + res = lib.do_cmd([vmSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) if res: result = "FAILURE:%s" % res return result; - logging.debug("Setup vm alone on switch program done") + logging.debug("Setup vm 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]) + logging.debug("About to remove vm on the switch:%s" % bridge) + res = lib.do_cmd([vmSetupPath, "-D", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) if res: result = "FAILURE:%s" % res return result; - logging.debug("Remove vm alone on switch program done") + logging.debug("Remove vm 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() @@ -163,6 +134,5 @@ def cleanup(session, args): 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, + "setup-pvlan-vm": setup_pvlan_vm, "cleanup":cleanup}) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index c767f1af7df..97595190904 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -69,6 +69,6 @@ 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 +ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index e12fbce0f18..93f56534beb 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -16,20 +16,26 @@ # specific language governing permissions and limitations # under the License. +#!/bin/bash + +source ovs-func.sh + usage() { - printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 + printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -P -v -h \n" $(basename $0) >&2 exit 2 } br= pri_vlan= sec_iso_vlan= +dhcp_name= dhcp_ip= dhcp_mac= +dhcp_port= vm_mac= op= -while getopts 'ADb:p:i:d:m:v:h' OPTION +while getopts 'ADb:p:i:d:m:v:n:P:h' OPTION do case $OPTION in A) op="add" @@ -42,10 +48,14 @@ do ;; i) sec_iso_vlan="$OPTARG" ;; + n) dhcp_name="$OPTARG" + ;; d) dhcp_ip="$OPTARG" ;; m) dhcp_mac="$OPTARG" ;; + P) dhcp_port="$OPTARG" + ;; v) vm_mac="$OPTARG" ;; h) usage @@ -78,6 +88,12 @@ then exit 1 fi +if [ -z "$dhcp_name" ] +then + echo Missing parameter DHCP NAME! + exit 1 +fi + if [ -z "$dhcp_ip" ] then echo Missing parameter DHCP IP! @@ -90,12 +106,18 @@ then exit 1 fi +if [ "$op" == "add" -a -z "$dhcp_port" ] +then + echo Missing parameter DHCP PORT! + 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 + ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=strip_vlan,output:$dhcp_port 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 diff --git a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh deleted file mode 100755 index de37882159c..00000000000 --- a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/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 -p -i -d -m -v -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 diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh index 8ac20df5ad1..4bad11c7624 100755 --- a/scripts/vm/network/ovs-pvlan-vm.sh +++ b/scripts/vm/network/ovs-pvlan-vm.sh @@ -16,6 +16,8 @@ # specific language governing permissions and limitations # under the License. +#!/bin/bash + usage() { printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 exit 2 @@ -72,6 +74,12 @@ then exit 1 fi +if [ -z "$pri_vlan" ] +then + echo Missing parameter secondary isolate vlan! + exit 1 +fi + if [ -z "$sec_iso_vlan" ] then echo Missing parameter secondary isolate vlan! @@ -82,9 +90,10 @@ 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 + ovs-ofctl add-flow $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,resubmit:$trunk_port + ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:1 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 + ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac + ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac fi diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index d9c43567d06..5c73bcdd80e 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -215,16 +215,6 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl throw new ResourceUnavailableException("Can't find at least one running router!", 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; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index 4dfd78c2a52..075b014cb0b 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -105,6 +105,4 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, List routers) throws ResourceUnavailableException; - - void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index bb31e1cf5e8..d22c7fc6d31 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2211,35 +2211,6 @@ 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 vms = _userVmDao.listByHostId(hostId); - for (UserVmVO vm : vms) { - if (vm.getState() != State.Running) { - continue; - } - List 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; @@ -2248,7 +2219,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress(), nic.getIp4Address()); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), router.getInstanceName(), 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 { @@ -2260,23 +2231,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V 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 profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { @@ -2577,7 +2531,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (network.getTrafficType() == TrafficType.Guest) { guestNetworks.add(network); if (nic.getBroadcastUri().getScheme().equals("pvlan")) { - result = setupDhcpForPvlanOnHost(true, router, nic); + result = setupDhcpForPvlan(true, router, nic); } } } @@ -2615,9 +2569,10 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V for (Nic nic : routerNics) { Network network = _networkModel.getNetwork(nic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest && nic.getBroadcastUri().getScheme().equals("pvlan")) { - setupDhcpForPvlanOnHost(false, domR, nic); + setupDhcpForPvlan(false, domR, nic); } } + } } diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index 5278b339e19..e86fc09ce2c 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -401,12 +401,4 @@ VpcVirtualNetworkApplianceService { // TODO Auto-generated method stub return null; } - - @Override - public void setupVmWithDhcpHostForPvlan(boolean add, - DomainRouterVO router, NicProfile nic) throws ResourceUnavailableException { - // TODO Auto-generated method stub - - } - } From 142f3b30f44f279b34ce845ffaec853ef68be36d Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 04/12] PVLAN: Remove bridge parameter in PvlanSetupCommand Bridge is hypervisor dependent, shouldn't appear in PvlanSetupCommand. --- .../com/cloud/agent/api/PvlanSetupCommand.java | 16 +++++----------- .../xen/resource/CitrixResourceBase.java | 2 +- .../VirtualNetworkApplianceManagerImpl.java | 2 +- server/src/com/cloud/vm/UserVmManagerImpl.java | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index e5d4da09003..0426219def2 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -26,7 +26,6 @@ public class PvlanSetupCommand extends Command { VM } private String op; - private String bridge; private String primary; private String isolated; private String vmMac; @@ -37,27 +36,26 @@ public class PvlanSetupCommand extends Command { protected PvlanSetupCommand() {} - protected PvlanSetupCommand(Type type, String op, String bridge, URI uri) + protected PvlanSetupCommand(Type type, String op, URI uri) { this.type = type; this.op = op; - this.bridge = bridge; this.primary = NetUtils.getPrimaryPvlanFromUri(uri); this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); } - static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpName, String dhcpMac, String dhcpIp) + static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String dhcpName, String dhcpMac, String dhcpIp) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri); cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; } - static public PvlanSetupCommand createVmSetup(String op, String bridge, URI uri, String vmMac) + static public PvlanSetupCommand createVmSetup(String op, URI uri, String vmMac) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, bridge, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri); cmd.setVmMac(vmMac); return cmd; } @@ -71,10 +69,6 @@ public class PvlanSetupCommand extends Command { return op; } - public String getBridge() { - return bridge; - } - public String getPrimary() { return primary; } 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 933f4d33eff..d25938f1f57 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 @@ -1474,12 +1474,12 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String primaryPvlan = cmd.getPrimary(); String isolatedPvlan = cmd.getIsolated(); String op = cmd.getOp(); - String bridge = cmd.getBridge(); String dhcpName = cmd.getDhcpName(); String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + String bridge = "xenbr0"; String result = null; if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index d22c7fc6d31..59a9f057162 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2219,7 +2219,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), router.getInstanceName(), 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 { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7a9fc4731e7..6ea295259a9 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2761,7 +2761,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // "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()); + PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), nic.getMacAddress()); Answer answer = null; try { answer = _agentMgr.send(hostId, cmd); From 40386fc4cb6841c8cc6b8458c9ebd80d4c8ffb4f Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:09 -0700 Subject: [PATCH 05/12] PVLAN: Add network label parameter to PvlanSetupCommand We need it to find the real bridge/switch to program on the OVS. --- .../cloud/agent/api/PvlanSetupCommand.java | 16 +++++++---- .../xen/resource/CitrixResourceBase.java | 19 ++++++++++--- .../vm/hypervisor/xenserver/ovs-get-bridge.sh | 27 +++++++++++++++++++ .../hypervisor/xenserver/ovs-get-dhcp-port.sh | 0 scripts/vm/hypervisor/xenserver/ovs-pvlan | 13 ++++++--- .../vm/hypervisor/xenserver/xenserver60/patch | 1 + .../VirtualNetworkApplianceManagerImpl.java | 4 ++- .../src/com/cloud/vm/UserVmManagerImpl.java | 5 +++- 8 files changed, 72 insertions(+), 13 deletions(-) create mode 100755 scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh mode change 100644 => 100755 scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index 0426219def2..ee1f046d6d9 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -33,29 +33,31 @@ public class PvlanSetupCommand extends Command { private String dhcpMac; private String dhcpIp; private Type type; + private String networkTag; protected PvlanSetupCommand() {} - protected PvlanSetupCommand(Type type, String op, URI uri) + protected PvlanSetupCommand(Type type, String op, URI uri, String networkTag) { this.type = type; this.op = op; this.primary = NetUtils.getPrimaryPvlanFromUri(uri); this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); + this.networkTag = networkTag; } - static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String dhcpName, String dhcpMac, String dhcpIp) + static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String networkTag, String dhcpName, String dhcpMac, String dhcpIp) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri, networkTag); cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; } - static public PvlanSetupCommand createVmSetup(String op, URI uri, String vmMac) + static public PvlanSetupCommand createVmSetup(String op, URI uri, String networkTag, String vmMac) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri, networkTag); cmd.setVmMac(vmMac); return cmd; } @@ -112,4 +114,8 @@ public class PvlanSetupCommand extends Command { public void setDhcpName(String dhcpName) { this.dhcpName = dhcpName; } + + public String getNetworkTag() { + return networkTag; + } } 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 d25938f1f57..d616e1bcd58 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 @@ -1478,11 +1478,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + String networkTag = cmd.getNetworkTag(); + + XsLocalNetwork nw = null; + String nwNameLabel = null; + try { + nw = getNativeNetworkForTraffic(conn, TrafficType.Guest, networkTag); + nwNameLabel = nw.getNetwork().getNameLabel(conn); + } catch (XenAPIException e) { + s_logger.warn("Fail to get network", e); + return new Answer(cmd, false, e.toString()); + } catch (XmlRpcException e) { + s_logger.warn("Fail to get network", e); + return new Answer(cmd, false, e.toString()); + } - String bridge = "xenbr0"; String result = null; if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { - result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "nw-label", nwNameLabel, "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-name", dhcpName, "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { @@ -1492,7 +1505,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe 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", "op", op, "bridge", bridge, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "op", op, "nw-label", nwNameLabel, "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); diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh b/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh new file mode 100755 index 00000000000..f56ddf9020f --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh @@ -0,0 +1,27 @@ +#!/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. + +nw_label=$1 +br=`xe network-list name-label="$nw_label" params=bridge |cut -d ':' -f 2 |tr -d ' ' ` +pbr=`ovs-vsctl br-to-parent $br` +while [ "$br" != "$pbr" ] +do + br=$pbr + pbr=`ovs-vsctl br-to-parent $br` +done +echo $pbr diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh old mode 100644 new mode 100755 diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 372d3c8d05b..956ea6d7978 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -36,6 +36,7 @@ dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" +getBridgePath = "/opt/xensource/bin/ovs-get-bridge.sh" def echo(fn): def wrapped(*v, **k): @@ -46,11 +47,10 @@ def echo(fn): return res return wrapped - @echo def setup_pvlan_dhcp(session, args): op = args.pop("op") - bridge = args.pop("bridge") + nw_label = args.pop("nw-label") primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") dhcp_name = args.pop("dhcp-name") @@ -61,6 +61,10 @@ def setup_pvlan_dhcp(session, args): if res != "SUCCESS": return "FAILURE:%s" % res + logging.debug("Network is:%s" % (nw_label)) + bridge = lib.do_cmd([getBridgePath, nw_label]) + logging.debug("Determine bridge/switch is :%s" % (bridge)) + if op == "add": logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) @@ -88,7 +92,7 @@ def setup_pvlan_dhcp(session, args): @echo def setup_pvlan_vm(session, args): op = args.pop("op") - bridge = args.pop("bridge") + nw_label = args.pop("nw-label") primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") vm_mac = args.pop("vm-mac") @@ -98,6 +102,9 @@ def setup_pvlan_vm(session, args): if res != "SUCCESS": return "FAILURE:%s" % res + bridge = lib.do_cmd([getBridgePath, nw_label]) + logging.debug("Determine bridge/switch is :%s" % (bridge)) + if op == "add": logging.debug("About to setup vm on the switch:%s" % bridge) res = lib.do_cmd([vmSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index 97595190904..fe36ba9cb84 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -72,3 +72,4 @@ ovs-pvlan-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 ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin +ovs-get-bridge.sh=..,0755,/opt/xensource/bin diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 59a9f057162..a5098aeabd8 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2219,7 +2219,9 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); + Network network = _networkDao.findById(nic.getNetworkId()); + String networkTag = _networkModel.getNetworkTag(router.getHypervisorType(), network); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), networkTag, router.getInstanceName(), 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 { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 6ea295259a9..683f0daa1ee 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2761,7 +2761,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // "delete" would remove all the rules(if using ovs) related to this vm op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), nic.getMacAddress()); + Network network = _networkDao.findById(nic.getNetworkId()); + Host host = _hostDao.findById(hostId); + String networkTag = _networkModel.getNetworkTag(host.getHypervisorType(), network); + PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), networkTag, nic.getMacAddress()); Answer answer = null; try { answer = _agentMgr.send(hostId, cmd); From 3c3d67769b9b82c04ed670754fda8e36b7afc66a Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:09 -0700 Subject: [PATCH 06/12] PVLAN: PvlanSetupCommand for KVM support --- .../resource/LibvirtComputingResource.java | 76 +++++++++++++++++++ .../hypervisor/kvm/resource/OvsVifDriver.java | 2 +- ...get-dhcp-port.sh => ovs-get-dhcp-iface.sh} | 3 +- scripts/vm/hypervisor/xenserver/ovs-pvlan | 6 +- .../vm/hypervisor/xenserver/xenserver60/patch | 2 +- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 15 ++-- 6 files changed, 89 insertions(+), 15 deletions(-) rename scripts/vm/hypervisor/xenserver/{ovs-get-dhcp-port.sh => ovs-get-dhcp-iface.sh} (92%) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 0064edf6a68..dc8bf9d86f7 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -125,6 +125,7 @@ import com.cloud.agent.api.PlugNicAnswer; import com.cloud.agent.api.PlugNicCommand; 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; @@ -267,6 +268,8 @@ ServerResource { private String _createTmplPath; private String _heartBeatPath; private String _securityGroupPath; + private String _ovsPvlanDhcpHostPath; + private String _ovsPvlanVmPath; private String _routerProxyPath; private String _host; private String _dcId; @@ -587,6 +590,18 @@ ServerResource { "Unable to find the router_proxy.sh"); } + _ovsPvlanDhcpHostPath = Script.findScript(networkScriptsDir, "ovs-pvlan-dhcp-host.sh"); + if ( _ovsPvlanDhcpHostPath == null) { + throw new ConfigurationException( + "Unable to find the ovs-pvlan-dhcp-host.sh"); + } + + _ovsPvlanVmPath = Script.findScript(networkScriptsDir, "ovs-pvlan-vm.sh"); + if ( _ovsPvlanVmPath == null) { + throw new ConfigurationException( + "Unable to find the ovs-pvlan-vm.sh"); + } + String value = (String) params.get("developer"); boolean isDeveloper = Boolean.parseBoolean(value); @@ -1202,6 +1217,8 @@ ServerResource { return execute((CheckNetworkCommand) cmd); } else if (cmd instanceof NetworkRulesVmSecondaryIpCommand) { return execute((NetworkRulesVmSecondaryIpCommand) cmd); + } else if (cmd instanceof PvlanSetupCommand) { + return execute((PvlanSetupCommand) cmd); } else { s_logger.warn("Unsupported command "); return Answer.createUnsupportedCommandAnswer(cmd); @@ -1517,6 +1534,65 @@ ServerResource { } } + private Answer execute(PvlanSetupCommand cmd) { + String primaryPvlan = cmd.getPrimary(); + String isolatedPvlan = cmd.getIsolated(); + String op = cmd.getOp(); + String dhcpName = cmd.getDhcpName(); + String dhcpMac = cmd.getDhcpMac(); + String dhcpIp = cmd.getDhcpIp(); + String vmMac = cmd.getVmMac(); + boolean add = true; + + String opr = "-A"; + if (op.equals("delete")) { + opr = "-D"; + add = false; + } + + String result = null; + Connect conn; + try { + if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { + Script script = new Script(_ovsPvlanDhcpHostPath, _timeout, s_logger); + if (add) { + conn = LibvirtConnection.getConnectionByVmName(dhcpName); + List ifaces = getInterfaces(conn, dhcpName); + InterfaceDef guestNic = ifaces.get(0); + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName, + "-d", dhcpIp, "-m", dhcpMac, "-I", guestNic.getDevName()); + } else { + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName, + "-d", dhcpIp, "-m", dhcpMac); + } + result = script.execute(); + if (result != null) { + 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) { + Script script = new Script(_ovsPvlanVmPath, _timeout, s_logger); + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-v", vmMac); + result = script.execute(); + if (result != null) { + 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); + } + } + } catch (LibvirtException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return new Answer(cmd, true, result); + } + private void VifHotPlug(Connect conn, String vmName, String vlanId, String macAddr) throws InternalErrorException, LibvirtException { NicTO nicTO = new NicTO(); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index 37761aa5555..ac226e212e5 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -79,7 +79,7 @@ public class OvsVifDriver extends VifDriverBase { } String trafficLabel = nic.getName(); if (nic.getType() == Networks.TrafficType.Guest) { - if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan + if ((nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) && !vlanId.equalsIgnoreCase("untagged")) { if(trafficLabel != null && !trafficLabel.isEmpty()) { s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel); diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh similarity index 92% rename from scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh rename to scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh index a30b180bed0..6b30ee62a06 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh +++ b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh @@ -22,5 +22,4 @@ bridge=$1 dhcp_name=$2 dom_id=`xe vm-list is-control-domain=false power-state=running params=dom-id name-label=$dhcp_name|cut -d ':' -f 2 |tr -d ' ' ` iface="vif${dom_id}.0" -port=`ovs-ofctl show $bridge|grep $iface|cut -d '(' -f 1|tr -d ' '` -echo $port +echo $iface diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 956ea6d7978..c821870d64d 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -34,7 +34,7 @@ xePath = "/opt/xensource/bin/xe" lib.setup_logging("/var/log/ovs-pvlan.log") dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" -getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" +getDhcpIfacePath = "/opt/xensource/bin/ovs-get-dhcp-iface.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" getBridgePath = "/opt/xensource/bin/ovs-get-bridge.sh" @@ -67,11 +67,11 @@ def setup_pvlan_dhcp(session, args): if op == "add": logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) - dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) + dhcp_iface = lib.do_cmd([getDhcpIfacePath, bridge, dhcp_name]) logging.debug("About to setup dhcp vm on the switch:%s" % bridge) res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac, - "-P", dhcp_port]) + "-I", dhcp_iface]) if res: result = "FAILURE:%s" % res return result; diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index fe36ba9cb84..9af32b1457a 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -71,5 +71,5 @@ ovs-pvlan=..,0755,/etc/xapi.d/plugins ovs-pvlan-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 -ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin +ovs-get-dhcp-iface.sh=..,0755,/opt/xensource/bin ovs-get-bridge.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index 93f56534beb..73d735f822e 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -18,10 +18,8 @@ #!/bin/bash -source ovs-func.sh - usage() { - printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -P -v -h \n" $(basename $0) >&2 + printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -I -v -h \n" $(basename $0) >&2 exit 2 } @@ -31,11 +29,11 @@ sec_iso_vlan= dhcp_name= dhcp_ip= dhcp_mac= -dhcp_port= vm_mac= +iface= op= -while getopts 'ADb:p:i:d:m:v:n:P:h' OPTION +while getopts 'ADb:p:i:d:m:v:n:I:h' OPTION do case $OPTION in A) op="add" @@ -54,7 +52,7 @@ do ;; m) dhcp_mac="$OPTARG" ;; - P) dhcp_port="$OPTARG" + I) iface="$OPTARG" ;; v) vm_mac="$OPTARG" ;; @@ -106,14 +104,15 @@ then exit 1 fi -if [ "$op" == "add" -a -z "$dhcp_port" ] +if [ "$op" == "add" -a -z "$iface" ] then - echo Missing parameter DHCP PORT! + echo Missing parameter DHCP VM interface! exit 1 fi if [ "$op" == "add" ] then + dhcp_port=`ovs-ofctl show $br | grep $iface | cut -d '(' -f 1|tr -d ' '` ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port From 70da1b3be3b80d1bcc1ae652d9be81d26d3ef807 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 2 May 2013 16:32:07 -0700 Subject: [PATCH 07/12] PVLAN: Fix KVM ovs driver cannot get vlan id issue --- .../kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index ac226e212e5..eac32485e53 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -76,6 +76,8 @@ public class OvsVifDriver extends VifDriverBase { } else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) { logicalSwitchUuid = nic.getBroadcastUri().getSchemeSpecificPart(); + } else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) { + vlanId = NetUtils.getPrimaryPvlanFromUri(nic.getBroadcastUri()); } String trafficLabel = nic.getName(); if (nic.getType() == Networks.TrafficType.Guest) { From 87b7a8450742b28183bc3e3245ba791959ce4e98 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 6 May 2013 12:14:19 -0700 Subject: [PATCH 08/12] CLOUDSTACK-2348: PVLAN - UI - infrastructure menu - create guest network - add new field Private VLAN ID. --- ui/scripts/system.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 7aa0566fbef..5eb88e0cf20 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -1375,7 +1375,10 @@ label: 'label.vlan.id', docID: 'helpGuestNetworkZoneVLANID' }, - + isolatedpvlanId: { + label: 'Private VLAN ID' + }, + scope: { label: 'label.scope', docID: 'helpGuestNetworkZoneScope', @@ -1589,11 +1592,15 @@ if(this.id == selectedNetworkOfferingId) { if(this.specifyvlan == false) { $form.find('.form-item[rel=vlanId]').hide(); - cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional + cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional + + $form.find('.form-item[rel=isolatedpvlanId]').hide(); } else { $form.find('.form-item[rel=vlanId]').css('display', 'inline-block'); - cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required + cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required + + $form.find('.form-item[rel=isolatedpvlanId]').css('display', 'inline-block'); } return false; //break each loop } @@ -1679,7 +1686,10 @@ if(($form.find('.form-item[rel=vlanId]').css("display") != "none") && (args.data.vlanId != null && args.data.vlanId.length > 0)) array1.push("&vlan=" + todb(args.data.vlanId)); - + + if(($form.find('.form-item[rel=isolatedpvlanId]').css("display") != "none") && (args.data.isolatedpvlanId != null && args.data.isolatedpvlanId.length > 0)) + array1.push("&isolatedpvlan=" + todb(args.data.isolatedpvlanId)); + if($form.find('.form-item[rel=domainId]').css("display") != "none") { array1.push("&domainId=" + args.data.domainId); From 0c7bd0777b9a5a5ec326b0d15fb0b3ef584235ab Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Mon, 6 May 2013 17:51:33 -0700 Subject: [PATCH 09/12] PVLAN: Optimize pvlan scripts --- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 2 -- scripts/vm/network/ovs-pvlan-vm.sh | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index 73d735f822e..64565ff45d1 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -114,12 +114,10 @@ if [ "$op" == "add" ] then dhcp_port=`ovs-ofctl show $br | grep $iface | cut -d '(' -f 1|tr -d ' '` ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port - ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=strip_vlan,output:$dhcp_port 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 diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh index 4bad11c7624..fd384814cc4 100755 --- a/scripts/vm/network/ovs-pvlan-vm.sh +++ b/scripts/vm/network/ovs-pvlan-vm.sh @@ -91,7 +91,7 @@ trunk_port=1 if [ "$op" == "add" ] then ovs-ofctl add-flow $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,resubmit:$trunk_port - ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:1 + ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:$trunk_port else ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac From 25e992dc8e1f2c202fba9c845d5913e2308ded90 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Tue, 7 May 2013 13:02:41 -0700 Subject: [PATCH 10/12] CLOUDSTACK-2348: PVLAN - UI - Infrastructure menu - guest network - add broadcast URI field to listView and detailView. --- ui/scripts/system.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 5eb88e0cf20..022f29995f3 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -1340,6 +1340,7 @@ name: { label: 'label.name' }, type: { label: 'label.type' }, vlan: { label: 'label.vlan.id' }, + broadcasturi: { label: 'broadcast URI' }, cidr: { label: 'IPv4 CIDR' }, ip6cidr: { label: 'IPv6 CIDR'} //scope: { label: 'label.scope' } @@ -2057,6 +2058,7 @@ } }, vlan: { label: 'label.vlan.id' }, + broadcasturi: { label: 'broadcast URI' }, scope: { label: 'label.scope' }, networkofferingdisplaytext: { label: 'label.network.offering' }, networkofferingid: { From 065d2561b9532c6f7536d22ce067d6085238a76b Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Mon, 13 May 2013 11:40:40 -0700 Subject: [PATCH 11/12] CLOUDSTACK-2392: Not allow create pvlan network with ipv6 --- server/src/com/cloud/network/NetworkServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 7c4d7027c6b..ebada5c3fc3 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1019,6 +1019,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!"); } + if (isolatedPvlan != null && ipv6) { + throw new InvalidParameterValueException("Can only support create Private VLAN network with IPv4!"); + } + // 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 From 2bcf71638dba9a252378c251bbd32e6f72f74028 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 9 May 2013 19:44:14 -0700 Subject: [PATCH 12/12] PVLAN: Add integration test --- test/integration/smoke/test_pvlan.py | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 test/integration/smoke/test_pvlan.py diff --git a/test/integration/smoke/test_pvlan.py b/test/integration/smoke/test_pvlan.py new file mode 100644 index 00000000000..4eb76e1cdb7 --- /dev/null +++ b/test/integration/smoke/test_pvlan.py @@ -0,0 +1,86 @@ +# 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. +""" test for private vlan isolation +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr +import telnetlib + +#Import System modules +import time +_multiprocess_shared_ = True + +class TestPVLAN(cloudstackTestCase): + + zoneId = 1 + networkOfferingId = 7 + vlan = 1234 + isolatedpvlan = 567 + + def setUp(self): + self.apiClient = self.testClient.getApiClient() + + def test_create_pvlan_network(self): + self.debug("Test create pvlan network") + createNetworkCmd = createNetwork.createNetworkCmd() + createNetworkCmd.name = "pvlan network" + createNetworkCmd.displaytext = "pvlan network" + createNetworkCmd.netmask = "255.255.255.0" + createNetworkCmd.gateway = "10.10.10.1" + createNetworkCmd.startip = "10.10.10.10" + createNetworkCmd.gateway = "10.10.10.20" + createNetworkCmd.vlan = "1234" + createNetworkCmd.isolatedpvlan = "567" + createNetworkCmd.zoneid = self.zoneId + createNetworkCmd.networkofferingid = self.networkOfferingId + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + self.networkId = createNetworkResponse.id + self.broadcasttype = createNetworkResponse.broadcastdomaintype + self.broadcasturi = createNetworkResponse.broadcasturi + + self.assertIsNotNone(createNetworkResponse.id, "Network failed to create") + self.assertTrue(createNetworkResponse.broadcastdomaintype, "Pvlan") + self.assertTrue(createNetworkResponse.broadcasturi, "pvlan://1234-i567") + + self.debug("Clean up test pvlan network") + deleteNetworkCmd = deleteNetwork.deleteNetworkCmd() + deleteNetworkCmd.id = self.networkId; + self.apiClient.deleteNetwork(deleteNetworkCmd) + + #Test invalid parameter + + # CLOUDSTACK-2392: Should not allow create pvlan with ipv6 + createNetworkCmd.ip6gateway="fc00:1234::1" + createNetworkCmd.ip6cidr="fc00:1234::/64" + createNetworkCmd.startipv6="fc00:1234::10" + createNetworkCmd.endipv6="fc00:1234::20" + err = 0; + try: + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + except Exception as e: + err = 1; + self.debug("Try alloc with ipv6, got:%s" % e) + self.assertEqual(err, 1, "Shouldn't allow create PVLAN network with IPv6"); + +