Skip to content

Commit c6cc2ef

Browse files
authored
Merge pull request #5 from shapeblue/pvlansupport-itelligence
Enable PVLAN support on L2 networks
2 parents de129a9 + 4935f7d commit c6cc2ef

File tree

36 files changed

+939
-85
lines changed

36 files changed

+939
-85
lines changed

api/src/main/java/com/cloud/network/Network.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.ArrayList;
2222
import java.util.List;
2323

24+
import com.cloud.exception.InvalidParameterValueException;
25+
import org.apache.commons.lang.StringUtils;
2426
import org.apache.commons.lang.builder.ToStringBuilder;
2527
import org.apache.commons.lang.builder.ToStringStyle;
2628

@@ -44,6 +46,24 @@ enum GuestType {
4446
Shared, Isolated, L2
4547
}
4648

49+
enum PVlanType {
50+
Community, Isolated, Promiscuous;
51+
52+
static PVlanType fromValue(String type) {
53+
if (StringUtils.isBlank(type)) {
54+
return null;
55+
} else if (type.equalsIgnoreCase("promiscuous") || type.equalsIgnoreCase("p")) {
56+
return Promiscuous;
57+
} else if (type.equalsIgnoreCase("community") || type.equalsIgnoreCase("c")) {
58+
return Community;
59+
} else if (type.equalsIgnoreCase("isolated") || type.equalsIgnoreCase("i")) {
60+
return Isolated;
61+
} else {
62+
throw new InvalidParameterValueException("Unexpected Private VLAN type: " + type);
63+
}
64+
}
65+
}
66+
4767
String updatingInSequence = "updatingInSequence";
4868
String hideIpAddressUsage = "hideIpAddressUsage";
4969

@@ -416,4 +436,6 @@ public void setIp6Address(String ip6Address) {
416436
boolean isStrechedL2Network();
417437

418438
String getExternalId();
439+
440+
PVlanType getPvlanType();
419441
}

api/src/main/java/com/cloud/network/NetworkProfile.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,4 +314,9 @@ public String getExternalId() {
314314
return externalId;
315315
}
316316

317+
@Override
318+
public PVlanType getPvlanType() {
319+
return null;
320+
}
321+
317322
}

api/src/main/java/com/cloud/offering/NetworkOffering.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public enum State {
3838
}
3939

4040
public enum Detail {
41-
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering, domainid, zoneid
41+
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering, domainid, zoneid, pvlanType
4242
}
4343

4444
public final static String SystemPublicNetwork = "System-Public-Network";

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ public class ApiConstants {
372372
public static final String REMOVE_VLAN = "removevlan";
373373
public static final String VLAN_ID = "vlanid";
374374
public static final String ISOLATED_PVLAN = "isolatedpvlan";
375+
public static final String ISOLATED_PVLAN_TYPE = "isolatedpvlantype";
375376
public static final String ISOLATION_URI = "isolationuri";
376377
public static final String VM_AVAILABLE = "vmavailable";
377378
public static final String VM_LIMIT = "vmlimit";

api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ public class CreateNetworkCmd extends BaseCmd {
9696
@Parameter(name = ApiConstants.ISOLATED_PVLAN, type = CommandType.STRING, description = "the isolated private VLAN for this network")
9797
private String isolatedPvlan;
9898

99+
@Parameter(name = ApiConstants.ISOLATED_PVLAN_TYPE, type = CommandType.STRING,
100+
description = "the isolated private VLAN type for this network")
101+
private String isolatedPvlanType;
102+
99103
@Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, description = "network domain")
100104
private String networkDomain;
101105

@@ -216,6 +220,10 @@ public String getExternalId() {
216220
return externalId;
217221
}
218222

223+
public String getIsolatedPvlanType() {
224+
return isolatedPvlanType;
225+
}
226+
219227
@Override
220228
public boolean isDisplay() {
221229
if(displayNetwork == null)

api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ public class NicResponse extends BaseResponse {
118118
@Param(description = "ID of the VLAN/VNI if available", since="4.14.0")
119119
private Integer vlanId;
120120

121+
@SerializedName(ApiConstants.ISOLATED_PVLAN)
122+
@Param(description = "the isolated private VLAN if available", since="4.14.0")
123+
private Integer isolatedPvlanId;
124+
125+
@SerializedName(ApiConstants.ISOLATED_PVLAN_TYPE)
126+
@Param(description = "the isolated private VLAN type if available", since="4.14.0")
127+
private String isolatedPvlanType;
128+
121129
@SerializedName(ApiConstants.ADAPTER_TYPE)
122130
@Param(description = "Type of adapter if available", since="4.14.0")
123131
private String adapterType;
@@ -325,6 +333,22 @@ public void setVlanId(Integer vlanId) {
325333
this.vlanId = vlanId;
326334
}
327335

336+
public Integer getIsolatedPvlanId() {
337+
return isolatedPvlanId;
338+
}
339+
340+
public void setIsolatedPvlanId(Integer isolatedPvlanId) {
341+
this.isolatedPvlanId = isolatedPvlanId;
342+
}
343+
344+
public String getIsolatedPvlanType() {
345+
return isolatedPvlanType;
346+
}
347+
348+
public void setIsolatedPvlanType(String isolatedPvlanType) {
349+
this.isolatedPvlanType = isolatedPvlanType;
350+
}
351+
328352
public String getAdapterType() {
329353
return adapterType;
330354
}

api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstance.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ public static class Nic {
270270

271271
private Integer vlan;
272272

273+
private Integer pvlan;
274+
275+
private String pvlanType;
276+
273277
private List<String> ipAddress;
274278

275279
private String pciSlot;
@@ -314,6 +318,22 @@ public void setVlan(Integer vlan) {
314318
this.vlan = vlan;
315319
}
316320

321+
public Integer getPvlan() {
322+
return pvlan;
323+
}
324+
325+
public void setPvlan(Integer pvlan) {
326+
this.pvlan = pvlan;
327+
}
328+
329+
public String getPvlanType() {
330+
return pvlanType;
331+
}
332+
333+
public void setPvlanType(String pvlanType) {
334+
this.pvlanType = pvlanType;
335+
}
336+
317337
public List<String> getIpAddress() {
318338
return ipAddress;
319339
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationC
180180

181181
Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner,
182182
Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
183-
Boolean displayNetworkEnabled, String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
183+
Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
184184

185185
UserDataServiceProvider getPasswordResetProvider(Network network);
186186

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@
4141

4242
import com.cloud.agent.api.PrepareForMigrationAnswer;
4343
import com.cloud.agent.api.to.DpdkTO;
44+
import com.cloud.network.dao.NetworkDetailVO;
45+
import com.cloud.network.dao.NetworkDetailsDao;
46+
import com.cloud.offering.NetworkOffering;
4447
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
48+
import org.apache.cloudstack.api.ApiConstants;
4549
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
4650
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
4751
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
@@ -320,6 +324,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
320324
private AsyncJobManager _jobMgr;
321325
@Inject
322326
private StorageManager storageMgr;
327+
@Inject
328+
private NetworkDetailsDao networkDetailsDao;
323329

324330
VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this);
325331

@@ -4001,6 +4007,13 @@ public boolean plugNic(final Network network, final NicTO nic, final VirtualMach
40014007
final VMInstanceVO router = _vmDao.findById(vm.getId());
40024008
if (router.getState() == State.Running) {
40034009
try {
4010+
NetworkDetailVO pvlanTypeDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.ISOLATED_PVLAN_TYPE);
4011+
if (pvlanTypeDetail != null) {
4012+
Map<NetworkOffering.Detail, String> nicDetails = nic.getDetails() == null ? new HashMap<>() : nic.getDetails();
4013+
s_logger.debug("Found PVLAN type: " + pvlanTypeDetail.getValue() + " on network details, adding it as part of the PlugNicCommand");
4014+
nicDetails.putIfAbsent(NetworkOffering.Detail.pvlanType, pvlanTypeDetail.getValue());
4015+
nic.setDetails(nicDetails);
4016+
}
40044017
final PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails());
40054018
final Commands cmds = new Commands(Command.OnError.Stop);
40064019
cmds.addCommand("plugnic", plugNicCmd);

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@
3838
import javax.inject.Inject;
3939
import javax.naming.ConfigurationException;
4040

41+
import com.cloud.network.dao.NetworkDetailVO;
42+
import com.cloud.network.dao.NetworkDetailsDao;
4143
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
44+
import org.apache.cloudstack.api.ApiConstants;
4245
import org.apache.cloudstack.context.CallContext;
4346
import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
4447
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
@@ -222,6 +225,8 @@
222225
import com.cloud.vm.dao.VMInstanceDao;
223226
import com.google.common.base.Strings;
224227

228+
import static org.apache.commons.lang.StringUtils.isNotBlank;
229+
225230
/**
226231
* NetworkManagerImpl implements NetworkManager.
227232
*/
@@ -251,6 +256,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
251256
@Inject
252257
NetworkDao _networksDao;
253258
@Inject
259+
NetworkDetailsDao networkDetailsDao;
260+
@Inject
254261
NicDao _nicDao;
255262
@Inject
256263
RulesManager _rulesMgr;
@@ -698,6 +705,11 @@ public void doInTransactionWithoutResult(final TransactionStatus status) {
698705
finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId()));
699706
networks.add(networkPersisted);
700707

708+
if (network.getPvlanType() != null) {
709+
NetworkDetailVO detailVO = new NetworkDetailVO(networkPersisted.getId(), ApiConstants.ISOLATED_PVLAN_TYPE, network.getPvlanType().toString(), true);
710+
networkDetailsDao.persist(detailVO);
711+
}
712+
701713
if (predefined instanceof NetworkVO && guru instanceof NetworkGuruAdditionalFunctions){
702714
final NetworkGuruAdditionalFunctions functions = (NetworkGuruAdditionalFunctions) guru;
703715
functions.finalizeNetworkDesign(networkPersisted.getId(), ((NetworkVO)predefined).getVlanIdAsUUID());
@@ -2159,7 +2171,7 @@ public void expungeNics(final VirtualMachineProfile vm) {
21592171
public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
21602172
boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
21612173
final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
2162-
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
2174+
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
21632175

21642176
final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
21652177
final DataCenterVO zone = _dcDao.findById(zoneId);
@@ -2271,16 +2283,25 @@ public Network createGuestNetwork(final long networkOfferingId, final String nam
22712283

22722284
if (vlanSpecified) {
22732285
URI uri = BroadcastDomainType.fromString(vlanId);
2286+
// Aux: generate secondary URI for secondary VLAN ID (if provided) for performing checks
2287+
URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null;
22742288
//don't allow to specify vlan tag used by physical network for dynamic vlan allocation
22752289
if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) {
22762290
throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone "
22772291
+ zone.getName());
22782292
}
2293+
if (secondaryUri != null && !(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) &&
2294+
_dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(secondaryUri)).size() > 0) {
2295+
throw new InvalidParameterValueException("The VLAN tag " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone "
2296+
+ zone.getName());
2297+
}
22792298
if (! UuidUtils.validateUUID(vlanId)){
22802299
// For Isolated and L2 networks, don't allow to create network with vlan that already exists in the zone
2281-
if (ntwkOff.getGuestType() == GuestType.Isolated || !hasGuestBypassVlanOverlapCheck(bypassVlanOverlapCheck, ntwkOff)) {
2300+
if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2 || !hasGuestBypassVlanOverlapCheck(bypassVlanOverlapCheck, ntwkOff)) {
22822301
if (_networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), null).size() > 0) {
22832302
throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists or overlaps with other network vlans in zone " + zoneId);
2303+
} else if (secondaryUri != null && _networksDao.listByZoneAndUriAndGuestType(zoneId, secondaryUri.toString(), null).size() > 0) {
2304+
throw new InvalidParameterValueException("Network with vlan " + isolatedPvlan + " already exists or overlaps with other network vlans in zone " + zoneId);
22842305
} else {
22852306
final List<DataCenterVnetVO> dcVnets = _datacenterVnetDao.findVnet(zoneId, BroadcastDomainType.getValue(uri));
22862307
//for the network that is created as part of private gateway,
@@ -2427,8 +2448,15 @@ public Network doInTransaction(final TransactionStatus status) {
24272448
if (vlanIdFinal.equalsIgnoreCase(Vlan.UNTAGGED)) {
24282449
throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!");
24292450
}
2430-
userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanIdFinal, isolatedPvlan));
2451+
URI uri = NetUtils.generateUriForPvlan(vlanIdFinal, isolatedPvlan);
2452+
if (_networksDao.listByPhysicalNetworkPvlan(physicalNetworkId, uri.toString(), isolatedPvlanType).size() > 0) {
2453+
throw new InvalidParameterValueException("Network with primary vlan " + vlanIdFinal +
2454+
" and secondary vlan " + isolatedPvlan + " type " + isolatedPvlanType +
2455+
" already exists or overlaps with other network pvlans in zone " + zoneId);
2456+
}
2457+
userNetwork.setBroadcastUri(uri);
24312458
userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan);
2459+
userNetwork.setPvlanType(isolatedPvlanType);
24322460
}
24332461
}
24342462

0 commit comments

Comments
 (0)