public Network createGuestNetwork()

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;
    }