Skip to content

Commit a490249

Browse files
committed
CLOUDSTACK-10047: Portgroup vlan-trunking options for dvswitch
This allows admins to define a network with comma separated vlan id and vlan range such as vlan://200-400,21,30-50 and use the provided vlan range to configure vlan-trunking for a portgroup in dvswitch based environment. VLAN overlap checks are performed for: - isolated network against existing shared and isolated networks - dedicated vlan ranges for the physical/public network for the zone - shared network against existing isolated network Allow shared networks to bypass vlan overlap checks: This allows admins to create shared networks with a `bypassvlanoverlapcheck` API flag which when set to 'true' will create a shared network without performing vlan overlap checks against isolated network and against the vlans allocated to the datacenter's physical network (vlan ranges). Notes: - No vlan-range overlap checks are performed when creating shared networks - Multiple vlan id/ranges should include the vlan:// scheme prefix Signed-off-by: Rohit Yadav <[email protected]>
1 parent 825b817 commit a490249

File tree

26 files changed

+353
-127
lines changed

26 files changed

+353
-127
lines changed

api/src/com/cloud/network/Networks.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ public <T> URI toUri(T value) {
7575
throw new CloudRuntimeException("Unable to convert to broadcast URI: " + value);
7676
}
7777
}
78+
@Override
79+
public String getValueFrom(URI uri) {
80+
return uri.getAuthority();
81+
}
7882
},
7983
Vswitch("vs", String.class), LinkLocal(null, null), Vnet("vnet", Long.class), Storage("storage", Integer.class), Lswitch("lswitch", String.class) {
8084
@Override

api/src/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class ApiConstants {
3636
public static final String BIND_PASSWORD = "bindpass";
3737
public static final String BYTES_READ_RATE = "bytesreadrate";
3838
public static final String BYTES_WRITE_RATE = "byteswriterate";
39+
public static final String BYPASS_VLAN_OVERLAP_CHECK = "bypassvlanoverlapcheck";
3940
public static final String CATEGORY = "category";
4041
public static final String CAN_REVERT = "canrevert";
4142
public static final String CA_CERTIFICATES = "cacertificates";

api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkCmdByAdmin.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public class CreateNetworkCmdByAdmin extends CreateNetworkCmd {
4040
@Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network")
4141
private String vlan;
4242

43+
@Parameter(name=ApiConstants.BYPASS_VLAN_OVERLAP_CHECK, type=CommandType.BOOLEAN, description="when true bypasses VLAN id/range overlap check during network creation for shared networks")
44+
private Boolean bypassVlanOverlapCheck;
45+
4346
/////////////////////////////////////////////////////
4447
/////////////////// Accessors ///////////////////////
4548
/////////////////////////////////////////////////////
@@ -48,6 +51,13 @@ public String getVlan() {
4851
return vlan;
4952
}
5053

54+
public Boolean getBypassVlanOverlapCheck() {
55+
if (bypassVlanOverlapCheck != null) {
56+
return bypassVlanOverlapCheck;
57+
}
58+
return false;
59+
}
60+
5161
/////////////////////////////////////////////////////
5262
/////////////// API Implementation///////////////////
5363
/////////////////////////////////////////////////////

api/test/com/cloud/network/NetworksTest.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616
// under the License.
1717
package com.cloud.network;
1818

19-
import java.net.URISyntaxException;
20-
21-
import org.junit.Assert;
22-
import org.junit.Before;
23-
import org.junit.Test;
24-
2519
import com.cloud.dc.Vlan;
2620
import com.cloud.network.Networks.BroadcastDomainType;
2721
import com.cloud.network.Networks.IsolationType;
2822
import com.cloud.utils.exception.CloudRuntimeException;
23+
import org.junit.Assert;
24+
import org.junit.Before;
25+
import org.junit.Test;
26+
27+
import java.net.URI;
28+
import java.net.URISyntaxException;
2929

3030
/**
3131
* @author dhoogland
@@ -43,6 +43,13 @@ public void emptyBroadcastDomainTypeTest() throws URISyntaxException {
4343
Assert.assertEquals("an empty uri should mean a broadcasttype of undecided", BroadcastDomainType.UnDecided, type);
4444
}
4545

46+
@Test
47+
public void vlanCommaSeparatedTest() throws URISyntaxException {
48+
Assert.assertEquals(BroadcastDomainType.getValue(new URI("vlan://100")), "100");
49+
Assert.assertEquals(BroadcastDomainType.getValue(new URI("vlan://100-200")), "100-200");
50+
Assert.assertEquals(BroadcastDomainType.getValue(new URI("vlan://10-50,12,11,112-170")), "10-50,12,11,112-170");
51+
}
52+
4653
@Test
4754
public void vlanBroadcastDomainTypeTest() throws URISyntaxException {
4855
String uri1 = "vlan://1";

engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationC
145145

146146
boolean destroyNetwork(long networkId, ReservationContext context, boolean forced);
147147

148-
Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner,
149-
Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
150-
Boolean displayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
148+
Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner,
149+
Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
150+
Boolean displayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
151151

152152
UserDataServiceProvider getPasswordResetProvider(Network network);
153153

engine/components-api/src/com/cloud/configuration/ConfigurationManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ NetworkOfferingVO createNetworkOffering(String name, String displayText, Traffic
214214
Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive);
215215

216216
Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP,
217-
String vlanGateway, String vlanNetmask, String vlanId, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr)
217+
String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr)
218218
throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException;
219219

220220
void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException;

engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,10 @@
3232
import java.util.concurrent.Executors;
3333
import java.util.concurrent.ScheduledExecutorService;
3434
import java.util.concurrent.TimeUnit;
35+
3536
import javax.inject.Inject;
3637
import javax.naming.ConfigurationException;
3738

38-
import com.cloud.network.dao.NetworkDetailsDao;
39-
import com.cloud.network.dao.RemoteAccessVpnDao;
40-
import com.cloud.network.dao.RemoteAccessVpnVO;
41-
import com.cloud.network.dao.VpnUserDao;
42-
import com.cloud.network.element.RedundantResource;
43-
import com.cloud.network.router.VirtualRouter;
44-
import com.cloud.vm.DomainRouterVO;
45-
import com.cloud.vm.dao.DomainRouterDao;
46-
import org.apache.log4j.Logger;
4739
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
4840
import org.apache.cloudstack.context.CallContext;
4941
import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
@@ -58,6 +50,8 @@
5850
import org.apache.cloudstack.framework.messagebus.PublishScope;
5951
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
6052
import org.apache.cloudstack.region.PortableIpDao;
53+
import org.apache.log4j.Logger;
54+
6155
import com.cloud.agent.AgentManager;
6256
import com.cloud.agent.Listener;
6357
import com.cloud.agent.api.AgentControlAnswer;
@@ -129,6 +123,7 @@
129123
import com.cloud.network.dao.NetworkAccountDao;
130124
import com.cloud.network.dao.NetworkAccountVO;
131125
import com.cloud.network.dao.NetworkDao;
126+
import com.cloud.network.dao.NetworkDetailsDao;
132127
import com.cloud.network.dao.NetworkDomainDao;
133128
import com.cloud.network.dao.NetworkDomainVO;
134129
import com.cloud.network.dao.NetworkServiceMapDao;
@@ -139,17 +134,22 @@
139134
import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
140135
import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO;
141136
import com.cloud.network.dao.PhysicalNetworkVO;
137+
import com.cloud.network.dao.RemoteAccessVpnDao;
138+
import com.cloud.network.dao.RemoteAccessVpnVO;
139+
import com.cloud.network.dao.VpnUserDao;
142140
import com.cloud.network.element.AggregatedCommandExecutor;
143141
import com.cloud.network.element.DhcpServiceProvider;
144142
import com.cloud.network.element.DnsServiceProvider;
145143
import com.cloud.network.element.IpDeployer;
146144
import com.cloud.network.element.LoadBalancingServiceProvider;
147145
import com.cloud.network.element.NetworkElement;
146+
import com.cloud.network.element.RedundantResource;
148147
import com.cloud.network.element.StaticNatServiceProvider;
149148
import com.cloud.network.element.UserDataServiceProvider;
150149
import com.cloud.network.guru.NetworkGuru;
151150
import com.cloud.network.guru.NetworkGuruAdditionalFunctions;
152151
import com.cloud.network.lb.LoadBalancingRulesManager;
152+
import com.cloud.network.router.VirtualRouter;
153153
import com.cloud.network.rules.FirewallManager;
154154
import com.cloud.network.rules.FirewallRule;
155155
import com.cloud.network.rules.FirewallRule.Purpose;
@@ -197,6 +197,7 @@
197197
import com.cloud.utils.fsm.NoTransitionException;
198198
import com.cloud.utils.fsm.StateMachine2;
199199
import com.cloud.utils.net.NetUtils;
200+
import com.cloud.vm.DomainRouterVO;
200201
import com.cloud.vm.Nic;
201202
import com.cloud.vm.Nic.ReservationStrategy;
202203
import com.cloud.vm.NicIpAlias;
@@ -209,6 +210,7 @@
209210
import com.cloud.vm.VirtualMachine;
210211
import com.cloud.vm.VirtualMachine.Type;
211212
import com.cloud.vm.VirtualMachineProfile;
213+
import com.cloud.vm.dao.DomainRouterDao;
212214
import com.cloud.vm.dao.NicDao;
213215
import com.cloud.vm.dao.NicIpAliasDao;
214216
import com.cloud.vm.dao.NicIpAliasVO;
@@ -2017,9 +2019,9 @@ public void expungeNics(final VirtualMachineProfile vm) {
20172019
@Override
20182020
@DB
20192021
public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
2020-
String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, Boolean subdomainAccess,
2021-
final Long vpcId, final String ip6Gateway, final String ip6Cidr, final Boolean isDisplayNetworkEnabled, final String isolatedPvlan)
2022-
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
2022+
boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
2023+
final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
2024+
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
20232025

20242026
final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
20252027
// this method supports only guest network creation
@@ -2136,19 +2138,19 @@ public Network createGuestNetwork(final long networkOfferingId, final String nam
21362138
}
21372139

21382140
if (vlanSpecified) {
2141+
URI uri = BroadcastDomainType.fromString(vlanId);
21392142
//don't allow to specify vlan tag used by physical network for dynamic vlan allocation
2140-
if (_dcDao.findVnet(zoneId, pNtwk.getId(), vlanId).size() > 0) {
2143+
if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) {
21412144
throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone "
21422145
+ zone.getName());
21432146
}
21442147
if (! UuidUtils.validateUUID(vlanId)){
2145-
final String uri = BroadcastDomainType.fromString(vlanId).toString();
21462148
// For Isolated networks, don't allow to create network with vlan that already exists in the zone
21472149
if (ntwkOff.getGuestType() == GuestType.Isolated) {
2148-
if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) {
2149-
throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId);
2150+
if (_networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), null).size() > 0) {
2151+
throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists or overlaps with other network vlans in zone " + zoneId);
21502152
} else {
2151-
final List<DataCenterVnetVO> dcVnets = _datacenterVnetDao.findVnet(zoneId, vlanId.toString());
2153+
final List<DataCenterVnetVO> dcVnets = _datacenterVnetDao.findVnet(zoneId, BroadcastDomainType.getValue(uri));
21522154
//for the network that is created as part of private gateway,
21532155
//the vnet is not coming from the data center vnet table, so the list can be empty
21542156
if (!dcVnets.isEmpty()) {
@@ -2177,8 +2179,8 @@ public Network createGuestNetwork(final long networkOfferingId, final String nam
21772179
} else {
21782180
// don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or
21792181
// shared network with same Vlan ID in the zone
2180-
if (_networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Isolated) > 0 ) {
2181-
throw new InvalidParameterValueException("There is a isolated/shared network with vlan id: " + vlanId + " already exists " + "in zone " + zoneId);
2182+
if (!bypassVlanOverlapCheck && _networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), GuestType.Isolated).size() > 0 ) {
2183+
throw new InvalidParameterValueException("There is an existing isolated/shared network that overlaps with vlan id:" + vlanId + " in zone " + zoneId);
21822184
}
21832185
}
21842186
}

engine/schema/src/com/cloud/dc/dao/DataCenterVnetDao.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ public interface DataCenterVnetDao extends GenericDao<DataCenterVnetVO, Long> {
2727

2828
public List<DataCenterVnetVO> listAllocatedVnetsInRange(long dcId, long physicalNetworkId, Integer start, Integer end);
2929

30-
public List<DataCenterVnetVO> findVnet(long dcId, String vnet);
31-
3230
public int countZoneVlans(long dcId, boolean onlyCountAllocated);
3331

32+
public List<DataCenterVnetVO> findVnet(long dcId, String vnet);
33+
3434
public List<DataCenterVnetVO> findVnet(long dcId, long physicalNetworkId, String vnet);
3535

3636
public void add(long dcId, long physicalNetworkId, List<String> vnets);

engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,11 @@
1616
// under the License.
1717
package com.cloud.dc.dao;
1818

19-
import java.sql.PreparedStatement;
20-
import java.sql.SQLException;
21-
import java.util.Date;
22-
import java.util.List;
23-
import java.util.Map;
24-
25-
import javax.inject.Inject;
26-
import javax.naming.ConfigurationException;
27-
28-
import org.springframework.stereotype.Component;
29-
3019
import com.cloud.dc.DataCenterVnetVO;
3120
import com.cloud.network.dao.AccountGuestVlanMapDao;
3221
import com.cloud.network.dao.AccountGuestVlanMapVO;
22+
import com.cloud.utils.NumbersUtil;
23+
import com.cloud.utils.UriUtils;
3324
import com.cloud.utils.db.DB;
3425
import com.cloud.utils.db.GenericDaoBase;
3526
import com.cloud.utils.db.GenericSearchBuilder;
@@ -40,6 +31,16 @@
4031
import com.cloud.utils.db.SearchCriteria.Op;
4132
import com.cloud.utils.db.TransactionLegacy;
4233
import com.cloud.utils.exception.CloudRuntimeException;
34+
import org.springframework.stereotype.Component;
35+
36+
import javax.inject.Inject;
37+
import javax.naming.ConfigurationException;
38+
import java.sql.PreparedStatement;
39+
import java.sql.SQLException;
40+
import java.util.ArrayList;
41+
import java.util.Date;
42+
import java.util.List;
43+
import java.util.Map;
4344

4445
/**
4546
* DataCenterVnetDaoImpl maintains the one-to-many relationship between
@@ -99,30 +100,43 @@ public void lockRange(long dcId, long physicalNetworkId, Integer start, Integer
99100
lockRows(sc, null, true);
100101
}
101102

102-
@Override
103-
public List<DataCenterVnetVO> findVnet(long dcId, String vnet) {
104-
SearchCriteria<DataCenterVnetVO> sc = VnetDcSearch.create();
105-
;
106-
sc.setParameters("dc", dcId);
107-
sc.setParameters("vnet", vnet);
108-
return listBy(sc);
109-
}
110-
111103
@Override
112104
public int countZoneVlans(long dcId, boolean onlyCountAllocated) {
113105
SearchCriteria<Integer> sc = onlyCountAllocated ? countAllocatedZoneVlans.create() : countZoneVlans.create();
114106
sc.setParameters("dc", dcId);
115107
return customSearch(sc, null).get(0);
116108
}
117109

110+
private List<DataCenterVnetVO> findOverlappingVnets(final long dcId, final Long physicalNetworkId, final String vnet) {
111+
final List<Integer> searchVnets = UriUtils.expandVlanUri(vnet);
112+
final List<DataCenterVnetVO> overlappingVnets = new ArrayList<>();
113+
if (searchVnets != null && searchVnets.size() > 0) {
114+
SearchCriteria<DataCenterVnetVO> sc = VnetDcSearch.create();
115+
sc.setParameters("dc", dcId);
116+
if (physicalNetworkId != null) {
117+
sc.setParameters("physicalNetworkId", physicalNetworkId);
118+
}
119+
for (final DataCenterVnetVO dcVNet : listBy(sc)) {
120+
if (dcVNet == null || dcVNet.getVnet() == null) {
121+
continue;
122+
}
123+
final Integer vnetValue = NumbersUtil.parseInt(dcVNet.getVnet(), -1);
124+
if (vnetValue != -1 && searchVnets.contains(vnetValue)) {
125+
overlappingVnets.add(dcVNet);
126+
}
127+
}
128+
}
129+
return overlappingVnets;
130+
}
131+
118132
@Override
119-
public List<DataCenterVnetVO> findVnet(long dcId, long physicalNetworkId, String vnet) {
120-
SearchCriteria<DataCenterVnetVO> sc = VnetDcSearch.create();
121-
sc.setParameters("dc", dcId);
122-
sc.setParameters("physicalNetworkId", physicalNetworkId);
123-
sc.setParameters("vnet", vnet);
133+
public List<DataCenterVnetVO> findVnet(long dcId, String vnet) {
134+
return findOverlappingVnets(dcId, null, vnet);
135+
}
124136

125-
return listBy(sc);
137+
@Override
138+
public List<DataCenterVnetVO> findVnet(long dcId, long physicalNetworkId, String vnet) {
139+
return findOverlappingVnets(dcId, physicalNetworkId, vnet);
126140
}
127141

128142
@Override

engine/schema/src/com/cloud/network/dao/NetworkDao.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long>, StateDao<State,
6161

6262
List<NetworkVO> listBy(long accountId, long networkId);
6363

64-
long countByZoneAndUri(long zoneId, String broadcastUri);
65-
66-
long countByZoneUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType);
64+
List<NetworkVO> listByZoneAndUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType);
6765

6866
List<NetworkVO> listByZone(long zoneId);
6967

0 commit comments

Comments
 (0)