in server/src/main/java/com/cloud/network/NetworkServiceImpl.java [1487:1857]
public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
Long networkOfferingId = cmd.getNetworkOfferingId();
String gateway = cmd.getGateway();
String startIP = cmd.getStartIp();
String endIP = cmd.getEndIp();
String netmask = cmd.getNetmask();
String networkDomain = cmd.getNetworkDomain();
boolean adminCalledUs = cmd instanceof CreateNetworkCmdByAdmin;
String vlanId = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getVlan() : null;
boolean bypassVlanOverlapCheck = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck();
boolean hideIpAddressUsage = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage();
String routerIPv4 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIp() : null;
String routerIPv6 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6() : null;
Long asNumber = cmd.getAsNumber();
String name = cmd.getNetworkName();
String displayText = cmd.getDisplayText();
Account caller = CallContext.current().getCallingAccount();
Long physicalNetworkId = cmd.getPhysicalNetworkId();
Long domainId = cmd.getDomainId();
Boolean subdomainAccess = cmd.getSubdomainAccess();
Long vpcId = cmd.getVpcId();
String startIPv6 = cmd.getStartIpv6();
String endIPv6 = cmd.getEndIpv6();
String ip6Gateway = cmd.getIp6Gateway();
String ip6Cidr = cmd.getIp6Cidr();
boolean displayNetwork = ! Boolean.FALSE.equals(cmd.getDisplayNetwork());
Long aclId = cmd.getAclId();
String isolatedPvlan = cmd.getIsolatedPvlan();
String externalId = cmd.getExternalId();
String isolatedPvlanType = cmd.getIsolatedPvlanType();
Long associatedNetworkId = cmd.getAssociatedNetworkId();
Integer publicMtu = cmd.getPublicMtu();
Integer privateMtu = cmd.getPrivateMtu();
String ip4Dns1 = cmd.getIp4Dns1();
String ip4Dns2 = cmd.getIp4Dns2();
String ip6Dns1 = cmd.getIp6Dns1();
String ip6Dns2 = cmd.getIp6Dns2();
Integer networkCidrSize = cmd.getCidrSize();
List<Long> bgpPeerIds = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getBgpPeerIds() : null;
// Validate network offering id
NetworkOffering ntwkOff = getAndValidateNetworkOffering(networkOfferingId);
Account owner = getOwningAccount(cmd, caller);
PhysicalNetwork pNtwk = getAndValidatePhysicalNetwork(physicalNetworkId);
DataCenter zone = getAndValidateZone(cmd, pNtwk);
_accountMgr.checkAccess(owner, ntwkOff, zone);
validateZoneAvailability(caller, zone);
validateNetworkCreationSupported(zone.getId(), zone.getName(), ntwkOff.getGuestType());
ACLType aclType = getAclType(caller, cmd.getAclType(), ntwkOff);
if (ntwkOff.getGuestType() != GuestType.Shared && (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) {
throw new InvalidParameterValueException("Router IP can be specified only for Shared networks");
}
if (ntwkOff.getGuestType() == GuestType.Shared && !_networkModel.isProviderForNetworkOffering(Provider.VirtualRouter, networkOfferingId)
&& (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) {
throw new InvalidParameterValueException("Virtual Router is not a supported provider for the Shared network, hence router ip should not be provided");
}
boolean isDomainSpecific = isDomainSpecificNetworkRequested(caller, domainId, subdomainAccess, ntwkOff, aclType);
if (aclType == ACLType.Domain) {
owner = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM);
}
// The network name is unique under the account
if (!AllowDuplicateNetworkName.valueIn(owner.getAccountId())) {
List<NetworkVO> existingNetwork = _networksDao.listByAccountIdNetworkName(owner.getId(), name);
if (!existingNetwork.isEmpty()) {
throw new InvalidParameterValueException("Another network with same name already exists within account: " + owner.getAccountName());
}
}
boolean ipv4 = false, ipv6 = false;
if (org.apache.commons.lang3.StringUtils.isNoneBlank(gateway, netmask)) {
ipv4 = true;
}
if (StringUtils.isNoneBlank(ip6Cidr, ip6Gateway)) {
ipv6 = true;
}
if (gateway != null) {
try {
// getByName on a literal representation will only check validity of the address
// http://docs.oracle.com/javase/6/docs/api/java/net/InetAddress.html#getByName(java.lang.String)
InetAddress gatewayAddress = InetAddress.getByName(gateway);
if (gatewayAddress instanceof Inet6Address) {
ipv6 = true;
} else {
ipv4 = true;
}
} catch (UnknownHostException e) {
logger.error("Unable to convert gateway IP to a InetAddress", e);
throw new InvalidParameterValueException("Gateway parameter is invalid");
}
}
// Start and end IP address are mandatory for shared networks.
if (ntwkOff.getGuestType() == GuestType.Shared && vpcId == null) {
if (!AllowEmptyStartEndIpAddress.valueIn(owner.getAccountId()) &&
(startIP == null && endIP == null) &&
(startIPv6 == null && endIPv6 == null)) {
throw new InvalidParameterValueException("Either IPv4 or IPv6 start and end address are mandatory");
}
}
String cidr = null;
if (ipv4) {
// if end ip is not specified, default it to startIp
if (startIP != null) {
if (!NetUtils.isValidIp4(startIP)) {
throw new InvalidParameterValueException("Invalid format for the startIp parameter");
}
if (endIP == null) {
endIP = startIP;
} else if (!NetUtils.isValidIp4(endIP)) {
throw new InvalidParameterValueException("Invalid format for the endIp parameter");
}
if (!(gateway != null && netmask != null)) {
throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in");
}
}
if (gateway != null && netmask != null) {
if (NetUtils.isNetworkorBroadcastIP(gateway, netmask)) {
if (logger.isDebugEnabled()) {
logger.debug("The gateway IP provided is " + gateway + " and netmask is " + netmask + ". The IP is either broadcast or network IP.");
}
throw new InvalidParameterValueException("Invalid gateway IP provided. Either the IP is broadcast or network IP.");
}
if (!NetUtils.isValidIp4(gateway)) {
throw new InvalidParameterValueException("Invalid gateway");
}
if (!NetUtils.isValidIp4Netmask(netmask)) {
throw new InvalidParameterValueException("Invalid netmask");
}
cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
}
}
if (ipv6) {
if (endIPv6 == null) {
endIPv6 = startIPv6;
}
_networkModel.checkIp6Parameters(startIPv6, endIPv6, ip6Gateway, ip6Cidr);
if (!GuestType.Shared.equals(ntwkOff.getGuestType())) {
_networkModel.checkIp6CidrSizeEqualTo64(ip6Cidr);
}
if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared) {
throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!");
}
if(StringUtils.isAllBlank(ip6Dns1, ip6Dns2, zone.getIp6Dns1(), zone.getIp6Dns2())) {
throw new InvalidParameterValueException("Can only create IPv6 network if the zone has IPv6 DNS! Please configure the zone IPv6 DNS1 and/or IPv6 DNS2.");
}
if (!ipv4 && ntwkOff.getGuestType() == GuestType.Shared && _networkModel.isProviderForNetworkOffering(Provider.VirtualRouter, networkOfferingId)) {
throw new InvalidParameterValueException("Currently IPv6-only Shared network with Virtual Router provider is not supported.");
}
}
if (NetworkOffering.NetworkMode.ROUTED.equals(ntwkOff.getNetworkMode())
&& !routedIpv4Manager.isRoutedNetworkVpcEnabled(zone.getId())) {
throw new InvalidParameterValueException("Routed network is not enabled in this zone");
}
if (isNonVpcNetworkSupportingDynamicRouting(ntwkOff) && ntwkOff.isSpecifyAsNumber() && asNumber == null) {
throw new InvalidParameterValueException("AS number is required for the network but not passed.");
}
validateNetworkCidrSize(caller, networkCidrSize, cidr, ntwkOff, owner.getAccountId(), zone.getId());
validateSharedNetworkRouterIPs(gateway, startIP, endIP, netmask, routerIPv4, routerIPv6, startIPv6, endIPv6, ip6Cidr, ntwkOff);
Pair<String, String> ip6GatewayCidr = null;
if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) {
ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId());
if (ipv6) {
ip6GatewayCidr = ipv6Service.preAllocateIpv6SubnetForNetwork(zone);
ip6Gateway = ip6GatewayCidr.first();
ip6Cidr = ip6GatewayCidr.second();
}
}
if (StringUtils.isNotBlank(isolatedPvlan)) {
if (!_accountMgr.isRootAdmin(caller.getId())) {
throw new InvalidParameterValueException("Only ROOT admin is allowed to create Private VLAN network");
}
if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() == GuestType.Isolated) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with advanced shared or L2 network!");
}
if (ipv6) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with IPv4!");
}
}
Pair<String, PVlanType> pvlanPair = getPrivateVlanPair(isolatedPvlan, isolatedPvlanType, vlanId);
String secondaryVlanId = pvlanPair.first();
PVlanType privateVlanType = pvlanPair.second();
if ((StringUtils.isNotBlank(secondaryVlanId) || privateVlanType != null) && StringUtils.isBlank(vlanId)) {
throw new InvalidParameterValueException("VLAN ID has to be set in order to configure a Private VLAN");
}
performBasicPrivateVlanChecks(vlanId, secondaryVlanId, privateVlanType);
if (!_accountMgr.isRootAdmin(caller.getId())) {
validateNetworkOfferingForNonRootAdminUser(ntwkOff);
}
// Ignore vlanId if it is passed but specifyvlan=false in network offering
if (ntwkOff.getGuestType() == GuestType.Shared && ! ntwkOff.isSpecifyVlan() && vlanId != null) {
throw new InvalidParameterValueException("Cannot specify vlanId when create a network from network offering with specifyvlan=false");
}
// Don't allow to specify vlan if the caller is not ROOT admin
if (!_accountMgr.isRootAdmin(caller.getId()) && (ntwkOff.isSpecifyVlan() || vlanId != null || bypassVlanOverlapCheck)) {
throw new InvalidParameterValueException("Only ROOT admin is allowed to specify vlanId or bypass vlan overlap check");
}
// Validate BGP peers
if (CollectionUtils.isNotEmpty(bgpPeerIds)) {
if (vpcId != null) {
throw new InvalidParameterValueException("The BGP peers of VPC tiers will inherit from the VPC, do not add separately.");
}
if (!routedIpv4Manager.isDynamicRoutedNetwork(ntwkOff)) {
throw new InvalidParameterValueException("The network offering does not support Dynamic routing");
}
routedIpv4Manager.validateBgpPeers(owner, zone.getId(), bgpPeerIds);
}
if (ipv4) {
// For non-root admins check cidr limit - if it's allowed by global config value
if (!_accountMgr.isRootAdmin(caller.getId()) && cidr != null) {
String[] cidrPair = cidr.split("\\/");
int cidrSize = Integer.parseInt(cidrPair[1]);
if (cidrSize < _cidrLimit) {
throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit);
}
}
}
Collection<String> ntwkProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(ntwkOff, physicalNetworkId).values();
if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) {
throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!");
}
if (StringUtils.isNotBlank(secondaryVlanId) && 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) && isSharedNetworkOfferingWithServices(networkOfferingId)) {
// validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone
checkSharedNetworkCidrOverlap(zone.getId(), pNtwk.getId(), cidr);
} else {
// if the guest network is for the VPC, if any External Provider are supported in VPC
// cidr will not be null as it is generated from the super cidr of vpc.
// if cidr is not null and network is not part of vpc then throw the exception
if (vpcId == null) {
throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!");
}
}
}
// Vlan is created in 1 cases - works in Advance zone only:
// 1) GuestType is Shared
boolean createVlan = (startIP != null && endIP != null && zone.getNetworkType() == NetworkType.Advanced && ((ntwkOff.getGuestType() == Network.GuestType.Shared)
|| (ntwkOff.getGuestType() == GuestType.Isolated && !areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))));
if (!createVlan) {
// Only support advance shared network in IPv6, which means createVlan is a must
if (ipv6 && ntwkOff.getGuestType() != GuestType.Isolated) {
createVlan = true;
}
}
// Can add vlan range only to the network which allows it
if (createVlan && !ntwkOff.isSpecifyIpRanges()) {
throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), NETWORK_OFFERING_ID);
}
if (GuestType.Shared == ntwkOff.getGuestType()) {
if (!ntwkOff.isSpecifyIpRanges()) {
throw new CloudRuntimeException("The 'specifyipranges' parameter should be true for Shared Networks");
}
if (ipv4 && Objects.isNull(startIP)) {
throw new CloudRuntimeException("IPv4 address range needs to be provided");
}
if (ipv6) {
logger.info(String.format("ip range for network '%s' is specified as %s - %s", name, startIPv6, endIPv6));
}
}
Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zone.getId());
mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu);
Network associatedNetwork = null;
if (associatedNetworkId != null) {
if (vlanId != null) {
throw new InvalidParameterValueException("Associated network and vlanId are mutually exclusive");
}
if (!_networkMgr.isSharedNetworkWithoutSpecifyVlan(ntwkOff)) {
throw new InvalidParameterValueException("Can only create Shared network with associated network if specifyVlan is false");
}
associatedNetwork = implementAssociatedNetwork(associatedNetworkId, caller, owner, zone,
aclType == ACLType.Domain ? domainId : null,
aclType == ACLType.Account ? owner.getAccountId() : null,
cidr, startIP, endIP);
}
checkNetworkDns(ipv6, ntwkOff, vpcId, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
if (vpcId != null && VpcManager.VpcTierNamePrepend.value()) {
Vpc vpc = _vpcDao.findById(vpcId);
if (vpc != null) {
name = getVpcPrependedNetworkName(name, vpc);
}
}
Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zone.getId(),
domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan,
externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize);
// retrieve, acquire and associate the correct IP addresses
checkAndSetRouterSourceNatIp(owner, cmd, network);
if (hideIpAddressUsage) {
_networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false));
}
if (ip6GatewayCidr != null) {
ipv6Service.assignIpv6SubnetToNetwork(ip6Cidr, network.getId());
}
// assign to network
if (NetworkOffering.NetworkMode.ROUTED.equals(ntwkOff.getNetworkMode())) {
routedIpv4Manager.assignIpv4SubnetToNetwork(network);
}
if (isNonVpcNetworkSupportingDynamicRouting(ntwkOff)) {
try {
bgpService.allocateASNumber(zone.getId(), asNumber, network.getId(), null);
} catch (CloudRuntimeException ex) {
deleteNetwork(network.getId(), true);
throw ex;
}
}
if (CollectionUtils.isNotEmpty(bgpPeerIds)) {
routedIpv4Manager.persistBgpPeersForGuestNetwork(network.getId(), bgpPeerIds);
}
// if the network offering has persistent set to true, implement the network
if (ntwkOff.isPersistent()) {
return implementedNetworkInCreation(caller, zone, network);
}
return network;
}