if (!ipv4 && !ipv6) {
throw new InvalidParameterValueException("Please specify IPv4 or IPv6 address.");
}
// Validate the zone
DataCenterVO zone = _zoneDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Please specify a valid zone.");
}
// ACL check
checkZoneAccess(UserContext.current().getCaller(), zone);
// Validate the physical network
if (_physicalNetworkDao.findById(physicalNetworkId) == null) {
throw new InvalidParameterValueException("Please specify a valid physical network id");
}
// Validate the pod
if (podId != null) {
Pod pod = _podDao.findById(podId);
if (pod == null) {
throw new InvalidParameterValueException("Please specify a valid pod.");
}
if (pod.getDataCenterId() != zoneId) {
throw new InvalidParameterValueException("Pod id=" + podId + " doesn't belong to zone id=" + zoneId);
}
// pod vlans can be created in basic zone only
if (zone.getNetworkType() != NetworkType.Basic || network.getTrafficType() != TrafficType.Guest) {
throw new InvalidParameterValueException("Pod id can be specified only for the networks of type "
+ TrafficType.Guest + " in zone of type " + NetworkType.Basic);
}
}
// 1) if vlan is specified for the guest network range, it should be the
// same as network's vlan
// 2) if vlan is missing, default it to the guest network's vlan
if (network.getTrafficType() == TrafficType.Guest) {
String networkVlanId = null;
URI uri = network.getBroadcastUri();
if (uri != null) {
String[] vlan = uri.toString().split("vlan:\\/\\/");
networkVlanId = vlan[1];
// For pvlan
networkVlanId = networkVlanId.split("-")[0];
}
if (vlanId != null) {
// if vlan is specified, throw an error if it's not equal to
// network's vlanId
if (networkVlanId != null && !networkVlanId.equalsIgnoreCase(vlanId)) {
throw new InvalidParameterValueException("Vlan doesn't match vlan of the network");
}
} else {
vlanId = networkVlanId;
}
} else if (network.getTrafficType() == TrafficType.Public && vlanId == null) {
// vlan id is required for public network
throw new InvalidParameterValueException("Vlan id is required when add ip range to the public network");
}
if (vlanId == null) {
vlanId = Vlan.UNTAGGED;
}
VlanType vlanType = forVirtualNetwork ? VlanType.VirtualNetwork : VlanType.DirectAttached;
if (vlanOwner != null && zone.getNetworkType() != NetworkType.Advanced) {
throw new InvalidParameterValueException("Vlan owner can be defined only in the zone of type "
+ NetworkType.Advanced);
}
if (ipv4) {
// Make sure the gateway is valid
if (!NetUtils.isValidIp(vlanGateway)) {
throw new InvalidParameterValueException("Please specify a valid gateway");
}
// Make sure the netmask is valid
if (!NetUtils.isValidIp(vlanNetmask)) {
throw new InvalidParameterValueException("Please specify a valid netmask");
}
}
if (ipv6) {
if (!NetUtils.isValidIpv6(vlanIp6Gateway)) {
throw new InvalidParameterValueException("Please specify a valid IPv6 gateway");
}
if (!NetUtils.isValidIp6Cidr(vlanIp6Cidr)) {
throw new InvalidParameterValueException("Please specify a valid IPv6 CIDR");
}
}
if (ipv4) {
String newCidr = NetUtils.getCidrFromGatewayAndNetmask(vlanGateway, vlanNetmask);
// Check if the new VLAN's subnet conflicts with the guest network
// in
// the specified zone (guestCidr is null for basic zone)
String guestNetworkCidr = zone.getGuestNetworkCidr();
if ( guestNetworkCidr != null ) {
if (NetUtils.isNetworksOverlap(newCidr, guestNetworkCidr)) {
throw new InvalidParameterValueException(
"The new IP range you have specified has overlapped with the guest network in zone: "
+ zone.getName() + ". Please specify a different gateway/netmask.");
}
}
// Check if there are any errors with the IP range
checkPublicIpRangeErrors(zoneId, vlanId, vlanGateway, vlanNetmask, startIP, endIP);
// Throw an exception if this subnet overlaps with subnet on other VLAN,
// if this is ip range extension, gateway, network mask should be same and ip range should not overlap
List<VlanVO> vlans = _vlanDao.listByZone(zone.getId());
for (VlanVO vlan : vlans) {
String otherVlanGateway = vlan.getVlanGateway();
String otherVlanNetmask = vlan.getVlanNetmask();
// Continue if it's not IPv4
if ( otherVlanGateway == null || otherVlanNetmask == null ) {
continue;
}
if ( vlan.getNetworkId() == null ) {
continue;
}
String otherCidr = NetUtils.getCidrFromGatewayAndNetmask(otherVlanGateway, otherVlanNetmask);
if( !NetUtils.isNetworksOverlap(newCidr, otherCidr)) {
continue;
}
// from here, subnet overlaps
if ( !vlanId.equals(vlan.getVlanTag()) ) {
boolean overlapped = false;
if( network.getTrafficType() == TrafficType.Public ) {
overlapped = true;
} else {
Long nwId = vlan.getNetworkId();
if ( nwId != null ) {
Network nw = _networkModel.getNetwork(nwId);
if ( nw != null && nw.getTrafficType() == TrafficType.Public ) {
overlapped = true;
}
}
}
if ( overlapped ) {
throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag()
+ " in zone " + zone.getName()
+ " has overlapped with the subnet. Please specify a different gateway/netmask.");
}
}
String[] otherVlanIpRange = vlan.getIpRange().split("\\-");
String otherVlanStartIP = otherVlanIpRange[0];
String otherVlanEndIP = null;
if (otherVlanIpRange.length > 1) {
otherVlanEndIP = otherVlanIpRange[1];
}
//extend IP range
if (!vlanGateway.equals(otherVlanGateway) || !vlanNetmask.equals(vlan.getVlanNetmask())) {
throw new InvalidParameterValueException("The IP range has already been added with gateway "
+ otherVlanGateway + " ,and netmask " + otherVlanNetmask
+ ", Please specify the gateway/netmask if you want to extend ip range" );
}
if (NetUtils.ipRangesOverlap(startIP, endIP, otherVlanStartIP, otherVlanEndIP)) {
throw new InvalidParameterValueException("The IP range already has IPs that overlap with the new range." +
" Please specify a different start IP/end IP.");
}
}
}
String ipv6Range = null;
if (ipv6) {
ipv6Range = startIPv6;
if (endIPv6 != null) {
ipv6Range += "-" + endIPv6;
}
List<VlanVO> vlans = _vlanDao.listByZone(zone.getId());
for (VlanVO vlan : vlans) {
if (vlan.getIp6Gateway() == null) {
continue;
}
if (vlanId.equals(vlan.getVlanTag())) {
if (NetUtils.isIp6RangeOverlap(ipv6Range, vlan.getIp6Range())) {
throw new InvalidParameterValueException("The IPv6 range with tag: " + vlan.getVlanTag()
+ " already has IPs that overlap with the new range. Please specify a different start IP/end IP.");
}
if (!vlanIp6Gateway.equals(vlan.getIp6Gateway())) {
throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " has already been added with gateway " + vlan.getIp6Gateway()
+ ". Please specify a different tag.");
}
}
}
}
// Check if the vlan is being used
if (_zoneDao.findVnet(zoneId, physicalNetworkId, vlanId).size() > 0) {
throw new InvalidParameterValueException("The VLAN tag " + vlanId
+ " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName());
}
String ipRange = null;
if (ipv4) {
ipRange = startIP;
if (endIP != null) {
ipRange += "-" + endIP;
}
}
// Everything was fine, so persist the VLAN
Transaction txn = Transaction.currentTxn();
txn.start();
VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId,
physicalNetworkId, vlanIp6Gateway, vlanIp6Cidr, ipv6Range);
s_logger.debug("Saving vlan range " + vlan);
vlan = _vlanDao.persist(vlan);
// IPv6 use a used ip map, is different from ipv4, no need to save